我有相当大的C ++对象,它将网格数据加载到内存中,然后根据OnDisplay回调进行绘制。
问题是刷新率真的很慢,我怀疑是因为我的代码写得不好。
反正;这是我班级的样子(显示的函数原型可以让你了解我的班级是如何设置的。)
我想知道的是,是否可以只调用" glDrawElements"如果我的大多数VBO没有改变并跳过我的开始和结束绘制功能,那么以某种方式记忆内存中的内容。
或者,甚至更好,
如果有一个神奇的OpenGL函数,我可以调用它,只需一次通过,OpenGL就可以渲染我所有未更改的缓冲区ID,而我可以专注于绘制已经改变的那些和相机?
大多数情况下,我只是让相机在场景中移动。
我根据教程和文档设置了这些功能,所以我知道它们有效;我只是想加快绘图速度,特别是当我加载的网格尺寸为100MB +时。
首先,这是我的班级原型:
class MyMeshData
{
public:
MyMeshData();
~MyMeshData();
// Save up data into GPU buffers.
bool Initialize(const MeshDataFromFileClass * StaticMeshData);
// Update vertex positions for deformed meshes.
void UpdateVertexPosition(const MeshDataFromFileClass * StaticMeshData, const MyVector4Class * pVertices) const;
// Bind buffers, set vertex arrays, turn on lighting and texture.
void BeginDraw(ShadingMode pShadingMode) const;
// Draw all the faces with specific material with given shading mode.
void Draw(int pMaterialIndex, ShadingMode pShadingMode) const;
// Unbind buffers, reset vertex arrays, turn off lighting and texture.
void EndDraw() const;
// Get the count of material groups
int GetSubMeshCount() const { return mSubMeshes.GetCount(); }
private:
enum
{
VERTEX_VBO,
NORMAL_VBO,
UV_VBO,
INDEX_VBO,
VBO_COUNT,
};
// For every material, record the offsets in every VBO and triangle counts
struct SubMesh
{
SubMesh() : IndexOffset(0), TriangleCount(0) {}
int IndexOffset;
int TriangleCount;
};
GLuint mVBONames[VBO_COUNT];
MyMeshArray<SubMesh*> mSubMeshes;
bool mHasNormal;
bool mHasUV;
bool mAllByControlPoint; // Save data in VBO by control point or by polygon vertex.
};
这是我的初始化函数:
bool Initialize(const MeshDataFromFileClass * StaticMeshData) {
[...]
/*
Earlier code that retrieves data from file removed.
Only the point where the data is transferred to the GPU is shown.
*/
// Create VBOs
glGenBuffers(VBO_COUNT, mVBONames);
// Save vertex attributes into GPU
glBindBuffer(GL_ARRAY_BUFFER, mVBONames[VERTEX_VBO]);
glBufferData(GL_ARRAY_BUFFER, lPolygonVertexCount * VERTEX_STRIDE * sizeof(float), lVertices, GL_STATIC_DRAW);
delete [] lVertices;
if (mHasNormal)
{
glBindBuffer(GL_ARRAY_BUFFER, mVBONames[NORMAL_VBO]);
glBufferData(GL_ARRAY_BUFFER, lPolygonVertexCount * NORMAL_STRIDE * sizeof(float), lNormals, GL_STATIC_DRAW);
delete [] lNormals;
}
if (mHasUV)
{
glBindBuffer(GL_ARRAY_BUFFER, mVBONames[UV_VBO]);
glBufferData(GL_ARRAY_BUFFER, lPolygonVertexCount * UV_STRIDE * sizeof(float), lUVs, GL_STATIC_DRAW);
delete [] lUVs;
}
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mVBONames[INDEX_VBO]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, lPolygonCount * TRIANGLE_VERTEX_COUNT * sizeof(unsigned int), lIndices, GL_STATIC_DRAW);
delete [] lIndices;
}
这是我的BeginDraw功能:
void MyMeshData::BeginDraw(ShadingMode pShadingMode) const
{
glBindBuffer(GL_ARRAY_BUFFER, mVBONames[VERTEX_VBO]);
/*
glVertexPointer(VERTEX_STRIDE, GL_FLOAT, 0, 0);
glEnableClientState(GL_VERTEX_ARRAY);
*/
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, VERTEX_STRIDE, GL_FLOAT, GL_FALSE, 0, 0);
// Set normal array.
if (mHasNormal && pShadingMode == SHADING_MODE_SHADED)
{
glBindBuffer(GL_ARRAY_BUFFER, mVBONames[NORMAL_VBO]);
glNormalPointer(GL_FLOAT, 0, 0);
glEnableClientState(GL_NORMAL_ARRAY);
}
// Set UV array.
if (mHasUV && pShadingMode == SHADING_MODE_SHADED)
{
glBindBuffer(GL_ARRAY_BUFFER, mVBONames[UV_VBO]);
glTexCoordPointer(UV_STRIDE, GL_FLOAT, 0, 0);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
}
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mVBONames[INDEX_VBO]);
if (pShadingMode != SHADING_MODE_SHADED)
{
glColor4fv(DEFAULT_WIREFRAME_COLOR);
}
}
我的画画功能......
void MyMeshData::Draw(int pMaterialIndex, ShadingMode pShadingMode) const
{
// Where to start.
GLsizei lOffset = mSubMeshes[pMaterialIndex]->IndexOffset * sizeof(unsigned int);
if ( pShadingMode == SHADING_MODE_SHADED)
{
const GLsizei lElementCount = mSubMeshes[pMaterialIndex]->TriangleCount * 3;
glDrawElements(GL_TRIANGLES, lElementCount, GL_UNSIGNED_INT, reinterpret_cast<const GLvoid *>(lOffset));
}
else
{
for (int lIndex = 0; lIndex < mSubMeshes[pMaterialIndex]->TriangleCount; ++lIndex)
{
glDrawElements(GL_LINE_LOOP, TRIANGLE_VERTEX_COUNT, GL_UNSIGNED_INT, reinterpret_cast<const GLvoid *>(lOffset));
lOffset += sizeof(unsigned int) * TRIANGLE_VERTEX_COUNT;
}
}
}
最后我的结束绘画功能......
void VBOMesh::EndDraw() const
{
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
答案 0 :(得分:1)
我想知道的是,是否可以打电话给 &#34; glDrawElements&#34;如果我的大部分时间都以某种方式记忆内存中的内容 如图所示,VBO没有改变并跳过我的开始和结束绘制功能 下方。
opengl中有一个功能正是如此,称为Vertex Array Buffer (VAO)。此功能允许您将开始绘制中的内容保存到对象(很像VBO)中绑定它,解除绑定,节省时间,这样您就不必每次都手动绑定所有缓冲区。我真的不记得,因为支持它,这是一个核心功能,因为opengl3我确定这一点,据我所知,即使OpenGL ES 2.0支持这个通过extension。
如果有一个神奇的OpenGL函数我可以调用它,一次通过, OpenGL可以渲染我所有未更改的缓冲区ID,我可以简单地 专注于绘制已经改变的镜头和相机?
如果我理解正确,你需要像缓存渲染这样的东西,而不是每次你想要一个函数时手动调用glDrawElements,你可以扔掉你所有的缓冲区id并告诉它''渲染这些&#39 ;.据我所知,最接近这一点的是instanced rendering,但这有其局限性。
虽然我认为这里可能还有别的东西,因为VBO已经让你的渲染很快,而且GPU不喜欢小型模型,大型模型对GPU来说真的很好,因为它有机会使用它的漂亮功能,超级duper缓存以及什么不能让它变得快速,在小型模型中没有机会,因为在缓存开始填充之前,模型已经被渲染。因此,如果这种情况在你的情况下运行缓慢,它可能是其他东西,因为你正在做的几乎是GPU达到其最佳性能的理想选择,我建议运行类似gDebugger的内容来分析哪个是函数或代码片段花费最多的时间,如果这似乎没问题,那么尝试使用GPU调试器/分析器来查看花费最多时间的内容(例如nVidia的NVPerfKit)。