使用实例数组时如何最小化glVertexAttribPointer调用? [英] How to minimize glVertexAttribPointer calls when using Instanced Arrays?

查看:121
本文介绍了使用实例数组时如何最小化glVertexAttribPointer调用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have OpenGL code using one VAO for all model data and two VBOs. The first for standard vertex attributes like position and normal and the second for the model matrices. I am using instanced draw, so I load the model matrices as instanced arrays (which are basically vertex attributes).

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

First I load the standard vertex attributes to a VBO and setup everything once with glVertexAttribPointer. Then I load the model matrices to another VBO. Now I have to call glVertexAttribPointerin the draw loop. Can I somehow prevent this?

代码如下:

// 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中存储顶点数据和矩阵的方法.然后的问题是如何正确设置步幅.我无法提出解决方案.

I thought of the approach of storing vertex data and matrices in one VBO. The problem is then how to set the strides correctly. I couldn't come up with a solution.

任何帮助将不胜感激.

推荐答案

如果您有权访问基础-实例渲染(需要GL 4.2或 ARB_base_instance ),那么你可以做到这一点.将实例化属性的内容与非实例化属性的内容一起放置在设置中:

If you have access to base-instance rendering (requires GL 4.2 or ARB_base_instance), then you could do this. Put the instanced attribute stuff in the setup with the non-instanced attribute stuff:

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.您的抽奖电话变为:

Then you just bind the VAO when you're ready to render these models. Your draw call becomes:

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

即使在GL 4之前的版本中,此功能也是令人惊讶地广泛使用. x硬件(只要它具有最新的驱动程序).

This feature is surprisingly widely available, even on pre-GL 4.x hardware (as long as it has recent drivers).

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

Without base instance rendering however, there's nothing you can do. You will have to adjust the instance pointers for each new set of instances you want to render. This is in fact why base instance rendering exists.

这篇关于使用实例数组时如何最小化glVertexAttribPointer调用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆