目前,我的场景由模型组成。模型由网格组成。每个网格都有自己的缓冲区,其中有8个(顶点,法线,texCoords,切线,bitangents,boneWeights)。我这样渲染每个帧:
void drawModel(Model &model) {
...
for (size_t i = 0; i < model.shape->meshes.size(); i++) {
...
pointer(cs.inPosition, 3, model.shape->meshes[i].getVerticesBuffer());
pointer(cs.inNormal, 3, model.shape->meshes[i].getNormalsBuffer());
pointer(cs.inTangent, 3, model.shape->meshes[i].getTangentsBuffer());
pointer(cs.inBitangent, 3, model.shape->meshes[i].getBitangentsBuffer());
pointer(cs.inTexCoord, 2, model.shape->meshes[i].getTexCoordsBuffer());
...
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, model.shape->meshes[i].getIndicesBuffer());
glDrawElements(GL_TRIANGLES, model.shape->meshes[i].indices.size(), GL_UNSIGNED_INT, nullptr);
}
}
pointer()
代码:
inline void pointer(GLint location, int count, GLuint buffer) {
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glVertexAttribPointer(
location, // attribute location
count, // count (1, 2, 3 or 4)
GL_FLOAT, // type
GL_FALSE, // is normalized?
0, // step
nullptr // offset
);
}
整个场景我也只使用一个VAO。
如何优化此代码(也许我应该只为模型创建这些缓冲区,而不是为每个网格创建?也许值得为每个模型分配一个单独的VAO?)?我的场景由相当多的顶点(大约500k)组成,并且显示了相当低的FPS(大约35)。
答案 0 :(得分:3)
在启动和初始化期间而不是在渲染循环期间创建VAO。正如@ Ripi2所说,更改它会导致上下文滚动。
VAO将保持状态,其中包括引用了哪些缓冲区(但不保存仍存储在VBO中的缓冲区数据)以及所有顶点属性数据。使用VAO的全部目的是避免必须始终重置该东西。为每个顶点缓冲区创建一个(或为每个模型创建一个),将其存储在Model或Shape类中。渲染时,只需在glDraw *之前绑定和取消绑定。
请注意缓冲区中的字节对齐。最好不要让单个值越过对齐边界,因为这会增加着色器中的获取时间,并且并非所有缓存友好。对每个顶点组件使用隔行缓冲区而不是单独的缓冲区可以使此操作更容易,而不会牺牲缓冲区中的太多空间。但是,为每个属性使用单独的缓冲区是一种常见的做法-例如,Unity使用这种方法-因此可能无济于事。
对于复杂的场景,您还至少要实现平截锥体剔除。遮挡剔除和其他半高级功能也将有助于减少渲染时间。在绘制之前对模型进行从前到后的排序可以减少过度绘制,因为不会为封闭的片段调用片段着色器。
如果您有许多共享材料的小模型,请考虑在一次绘制调用中绘制它们。如果您有很多相同的模型,请考虑使用实例化图纸。
此外,不要害羞地添加一些时序数据并使用您最喜欢的性能分析工具来确定性能瓶颈。