簡體   English   中英

OpenGL-繪制存儲在VBO中的大量信息

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

我有相當大的C ++對象,這些對象將網格數據加載到內存中,然后根據OnDisplay回調進行繪制。

問題是刷新速度確實很慢,我懷疑這是因為我的代碼編寫不正確。

無論如何; 這是我的班級的樣子(顯示的函數原型可以讓您了解我的班級的設置方式)。

我想知道的是,如果大多數VBO都沒有更改,是否可以以某種方式僅調用內存中的“ glDrawElements”函數,然后跳過如下所示的Begin和end draw函數。

甚至更好

如果有一個神奇的OpenGL函數,我可以通過一次調用來調用它,OpenGL可以渲染我所有未更改的Buffer ID,而我可以只專注於繪制已更改的Buffer 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);    
} 

我想知道的是,如果大多數VBO都沒有更改,是否可以以某種方式僅調用內存中的“ glDrawElements”函數,然后跳過如下所示的Begin和end draw函數。

opengl中有一個功能可以做到這一點,稱為頂點數組緩沖區(VAO) 此功能使您可以將開始繪制時所擁有的內容保存到一個對象中(非常類似於VBO),將其綁定,取消綁定,節省時間,這樣您就不必每次都手動綁定所有緩沖區。 我真的不記得了,因為當它被支持時,它是opengl3的一項核心功能,據我所知,據我所知,即使是OpenGL ES 2.0也可以通過extension來支持。

如果有一個神奇的OpenGL函數,我可以通過一次調用來調用它,OpenGL可以渲染我所有未更改的Buffer ID,而我可以只專注於繪制已更改的Buffer ID和相機?

如果我正確理解這一點,則需要類似緩存的渲染,這樣就不必在每次需要一個函數時都可以手動調用glDrawElements,該函數可以放入所有緩沖區ID並告訴它“渲染這些”。 據我所知,最接近的是實例渲染 ,但這是它的局限性。

我認為這里可能還有別的東西,因為VBO已經可以使您的渲染速度更快,並且GPU不喜歡小型模型,大型模型對於GPU確實非常有用,因為它有機會使用其漂亮的功能,超級duper緩存以及其他功能。不要太快,因為對於小型模型,沒有機會了,因為在緩存開始填充之前,模型已經呈現。 因此,如果在您的情況下運行緩慢,則可能是其他原因,因為您所做的幾乎是使GPU達到其最高性能的理想之選,因此我建議運行gDebugger之類的東西來剖析這是功能或代碼消耗最大的部分時間,如果看起來還可以的話,請嘗試使用GPU調試器/分析器查看耗時最多的時間(例如用於nVidia的NVPerfKit )。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM