OpenGL - 绘制存储在VBO中的大量信息

时间:2014-05-04 06:27:34

标签: c++ opengl

我有相当大的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);    
} 

1 个答案:

答案 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)。