【问题标题】:How to minimize glVertexAttribPointer calls when using Instanced Arrays?使用实例化数组时如何最小化 glVertexAttribPointer 调用?
【发布时间】:2016-05-29 11:49:58
【问题描述】:

我的 OpenGL 代码使用一个 VAO 处理所有模型数据和两个 VBO。第一个用于标准顶点属性,如位置和法线,第二个用于模型矩阵。我使用的是实例绘制,所以我将模型矩阵加载为实例数组(基本上是顶点属性)。

首先,我将标准顶点属性加载到 VBO 并使用 glVertexAttribPointer 设置所有内容。然后我将模型矩阵加载到另一个 VBO。现在我必须在绘图循环中调用glVertexAttribPointer。我能以某种方式防止这种情况发生吗?

代码如下所示:

// vertex data of all models in one array
GLfloat myvertexdata[myvertexdatasize];

// matrix data of all models in one array
// (one model can have multiple matrices)
GLfloat mymatrixdata[mymatrixsize];

GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, myvertexdatasize*sizeof(GLfloat), myvertexdata, GL_STATIC_DRAW);

glVertexAttribPointer(
          glGetAttribLocation(myprogram, "position"),
          3,
          GL_FLOAT,
          GL_FALSE,
          24,
          (GLvoid*)0
);
glEnableVertexAttribArray(glGetAttribLocation(myprogram, "position"));
glVertexAttribPointer(
          glGetAttribLocation(myprogram, "normal"),
          3,
          GL_FLOAT,
          GL_FALSE,
          24,
          (GLvoid*)12
);
glEnableVertexAttribArray(glGetAttribLocation(myprogram, "normal"));

GLuint matrixbuffer;
glGenBuffers(1, &matrixbuffer);
glBindBuffer(GL_ARRAY_BUFFER, matrixbuffer);
glBufferData(GL_ARRAY_BUFFER, mymatrixsize*sizeof(GLfloat), mymatrixdata, GL_STATIC_DRAW);

glUseProgram(myprogram);


draw loop:
    int vertices_offset = 0;
    int matrices_offset = 0;
    for each model i:
        GLuint loc = glGetAttribLocation(myprogram, "model_matrix_column_1");
        GLsizei matrixbytes = 4*4*sizeof(GLfloat);
        GLsizei columnbytes = 4*sizeof(GLfloat);
        glVertexAttribPointer(
              loc, 
              4, 
              GL_FLOAT, 
              GL_FALSE, 
              matrixbytes,
              (GLvoid*) (matrices_offset*matrixbytes + 0*columnbytes)
        );
        glEnableVertexAttribArray(loc);
        glVertexAttribDivisor(loc, 1); // matrices are in instanced array
        // do this for the other 3 columns too...

        glDrawArraysInstanced(GL_TRIANGLES, vertices_offset, models[i]->num_vertices(), models[i]->num_instances());

        vertices_offset += models[i]->num_vertices();
        matrices_offset += models[i]->num_matrices();

我想到了将顶点数据和矩阵存储在一个 VBO 中的方法。那么问题是如何正确设置步幅。我想不出解决办法。

任何帮助将不胜感激。

【问题讨论】:

    标签: opengl vertex-buffer vertex-array-object


    【解决方案1】:

    如果您有权访问 base-instance rendering(需要 GL 4.2 或 ARB_base_instance),那么您可以这样做。将实例化属性的东西与非实例化的属性一起放入设置中:

    GLuint loc = glGetAttribLocation(myprogram, "model_matrix_column_1");
    
    for(int count = 0; count < 4; ++count, ++loc)
    {
        GLsizei matrixbytes = 4*4*sizeof(GLfloat);
        GLsizei columnbytes = 4*sizeof(GLfloat);
        glVertexAttribPointer(
              loc, 
              4, 
              GL_FLOAT, 
              GL_FALSE, 
              matrixbytes,
              (GLvoid*) (count*columnbytes)
        );
        glEnableVertexAttribArray(loc);
        glVertexAttribDivisor(loc, 1); // matrices are in instanced array
    }
    

    然后,当您准备好渲染这些模型时,您只需绑定 VAO。您的绘图调用变为:

    glDrawArraysInstancedBaseInstance​(GL_TRIANGLES, vertices_offset, models[i]->num_vertices(), models[i]->num_instances(), matrix_offset);
    

    此功能为surprisingly widely available,即使在 GL 4.x 之前的硬件上也是如此(只要它有最新的驱动程序)。

    但是,如果没有基本实例渲染,您将无能为力。您必须为要渲染的每组新实例调整实例指针。这实际上是为什么存在基础实例渲染。

    【讨论】:

    • 位置是否总是后续数字?
    • @mak:您没有发布所有代码,所以我假设您的矩阵属性实际上是mat4,这是完全可以接受的。如果是,则 4 个位置 will be sequentially allocated。尽管确实如此,但您根本不应该获取这些位置。您应该直接在着色器中指定它们。
    • 只执行一次获取位置有什么问题?
    猜你喜欢
    • 1970-01-01
    • 2023-03-31
    • 2013-11-01
    • 2019-09-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多