简体   繁体   English

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

[英]OpenGL - Drawing Large Amounts of Information stored in VBO's

I have fairly large C++ objects which load mesh data into memory and then draws based on an OnDisplay callback. 我有相当大的C ++对象,这些对象将网格数据加载到内存中,然后根据OnDisplay回调进行绘制。

The problem is that the refresh rate is really slow which I suspect is because my code is poorly written. 问题是刷新速度确实很慢,我怀疑这是因为我的代码编写不正确。

Anyway; 无论如何; here is what my class looks like (function prototypes shown to give you an idea of how my class is set up). 这是我的班级的样子(显示的函数原型可以让您了解我的班级的设置方式)。

What I want to know is if it is possible to just call the "glDrawElements" function somehow on what is in memory if most of my VBOs haven't changed and skip my Begin and end draw functions as shown below. 我想知道的是,如果大多数VBO都没有更改,是否可以以某种方式仅调用内存中的“ glDrawElements”函数,然后跳过如下所示的Begin和end draw函数。

OR, even better, 甚至更好

If there is a magic OpenGL function I can call that, with one pass, OpenGL can render all of my unchanged Buffer IDs and I can simply focus on drawing the ones that have changed and the camera? 如果有一个神奇的OpenGL函数,我可以通过一次调用来调用它,OpenGL可以渲染我所有未更改的Buffer ID,而我可以只专注于绘制已更改的Buffer ID和相机?

Mostly I will just have the camera moving through the scene. 通常,我只会让摄像机在场景中移动。

I set these functions up based on tutorials and documentation so I know they work; 我根据教程和文档设置了这些功能,因此我知道它们可以工作。 I just want to speed up the drawing, especially when the meshes I am loading in are 100MB + in size. 我只是想加快绘图速度,特别是当我要加载的网格大小超过100MB时。

First, here is my class prototype: 首先,这是我的课程原型:

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.
};

And here is my Initialize Function: 这是我的初始化函数:

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;
}

Here is my BeginDraw Function: 这是我的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);        
    }
}

My Draw function ... 我的绘图功能...

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;            
        }
    }
}

And finally my End Draw Function.... 最后是我的结束抽签功能。

void VBOMesh::EndDraw() const
{
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);    
} 

What I want to know is if it is possible to just call the "glDrawElements" function somehow on what is in memory if most of my VBOs haven't changed and skip my Begin and end draw functions as shown below. 我想知道的是,如果大多数VBO都没有更改,是否可以以某种方式仅调用内存中的“ glDrawElements”函数,然后跳过如下所示的Begin和end draw函数。

There is a feature in opengl that exactly does that, called Vertex Array Buffer (VAO) . opengl中有一个功能可以做到这一点,称为顶点数组缓冲区(VAO) This feature allows you to save what you have in your begin draw into an object ( much like a VBO ) bind it, unbind it, saving you time so you don't have to bind all buffers by hand each time. 此功能使您可以将开始绘制时所拥有的内容保存到一个对象中(非常类似于VBO),将其绑定,取消绑定,节省时间,这样您就不必每次都手动绑定所有缓冲区。 I don't really remember since when it is supported, it is a core feature since opengl3 I'm sure about that, as far as I know even OpenGL ES 2.0 supports this via extension . 我真的不记得了,因为当它被支持时,它是opengl3的一项核心功能,据我所知,据我所知,即使是OpenGL ES 2.0也可以通过extension来支持。

If there is a magic OpenGL function I can call that, with one pass, OpenGL can render all of my unchanged Buffer IDs and I can simply focus on drawing the ones that have changed and the camera? 如果有一个神奇的OpenGL函数,我可以通过一次调用来调用它,OpenGL可以渲染我所有未更改的Buffer ID,而我可以只专注于绘制已更改的Buffer ID和相机?

If I understand this correctly, you want something like a cached rendering so instead of manually calling glDrawElements each time you want a function where you can throw in all your buffer id's and tell it to 'render these'. 如果我正确理解这一点,则需要类似缓存的渲染,这样就不必在每次需要一个函数时都可以手动调用glDrawElements,该函数可以放入所有缓冲区ID并告诉它“渲染这些”。 As far as I know the closest thing to this is instanced rendering , but that comes with it's limitations. 据我所知,最接近的是实例渲染 ,但这是它的局限性。

Altho I think there might be something else here since VBOs already make your rendering fast, and GPUs don't like small models, large models are really good for the GPU since it gets a chance to use its nifty features, super duper caching and what not to make it fast, where with small models there is not chance since before caches start to fill up the model is already rendered. 我认为这里可能还有别的东西,因为VBO已经可以使您的渲染速度更快,并且GPU不喜欢小型模型,大型模型对于GPU确实非常有用,因为它有机会使用其漂亮的功能,超级duper缓存以及其他功能。不要太快,因为对于小型模型,没有机会了,因为在缓存开始填充之前,模型已经呈现。 So if this runs slow in your case it might be something else since what you are doing is almost ideal for a GPU to reach its top performance, I would suggest running something like gDebugger to profile which is the function or code piece that takes the most time and if that seems okay, then try a GPU debugger/profiler to see what takes the most time ( like NVPerfKit for nVidia ). 因此,如果在您的情况下运行缓慢,则可能是其他原因,因为您所做的几乎是使GPU达到其最高性能的理想之选,因此我建议运行gDebugger之类的东西来剖析这是功能或代码消耗最大的部分时间,如果看起来还可以的话,请尝试使用GPU调试器/分析器查看耗时最多的时间(例如用于nVidia的NVPerfKit )。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM