使用实例化数组时如何最小化 glVertexAttribPointer 调用?
How to minimize glVertexAttribPointer calls when using Instanced Arrays?
我有 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中存储顶点数据和矩阵的方法。接下来的问题是如何正确设置步幅。我想不出解决办法。
如有任何帮助,我们将不胜感激。
如果您有权访问 base-instance rendering (requires GL 4.2 or 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 之前的硬件上也是如此(只要它有最新的驱动程序)。
然而,如果没有基础实例渲染,您将无能为力。您将必须为要渲染的每组新实例调整实例指针。这实际上是为什么 基础实例渲染存在。
我有 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中存储顶点数据和矩阵的方法。接下来的问题是如何正确设置步幅。我想不出解决办法。
如有任何帮助,我们将不胜感激。
如果您有权访问 base-instance rendering (requires GL 4.2 or 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 之前的硬件上也是如此(只要它有最新的驱动程序)。
然而,如果没有基础实例渲染,您将无能为力。您将必须为要渲染的每组新实例调整实例指针。这实际上是为什么 基础实例渲染存在。