c++ - 顶点数据应该按每个顶点还是每个属性进行布局?

标签 c++ opengl vertex

我有一段渲染网格的 OpenGL 代码。我使用 VBO 来渲染它们。现在,网格由具有以下属性的顶点组成:

glm::vec3 position;
glm::vec2 uv;
glm::vec4 color;
glm::vec3 normal;
glm::vec3 tangent;
glm::vec3 binormal;

目前,我像这样在每个顶点的基础上渲染顶点:

// Upload a vector of vertices
glBindBuffer(GL_ARRAY_BUFFER, &m_vbo);
glBufferData(GL_ARRAY_BUFFER, m_vertices.size() * sizeof(Vertex), &m_vertices[0], GL_STATIC_DRAW);

// Set the "layout" of the vertex attributes
// Binormal
glVertexAttribPointer(5, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*) (sizeof(glm::vec3) * 3 + sizeof(glm::vec2) + sizeof(glm::vec4)));
// Tangent
glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*) (sizeof(glm::vec3) * 2 + sizeof(glm::vec2) + sizeof(glm::vec4)));
// Normal
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*) (sizeof(glm::vec3) + sizeof(glm::vec2) + sizeof(glm::vec4)));
// Color
glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*) (sizeof(glm::vec3) + sizeof(glm::vec2)));
// UV
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*) (sizeof(glm::vec3)));
// Position
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*) 0);

// Draw
glDrawElements(GL_TRIANGLES, m_indices.size(), GL_UNSIGNED_SHORT, 0);

现在,我看到人们的做法有所不同。有些人首先上传所有的顶点位置,然后是 UV 数据,然后是法线等等。对数据布局进行粗略的可视化:

// P = position, U = uv, N = normal

// Per-vertex layout
PUNPUNPUNPUNPUNPUNPUNPUNPUNPUNPUNPUN

// Per-attribute layout
PPPPPPPPPPPPUUUUUUUUUUUUNNNNNNNNNNNN

这两种布局有什么区别吗?一个或另一个是否会导致任何性能问题,尤其是在数据不断更新的情况下?

最佳答案

您描述的第一个布局通常称为“交错”,并且通常被认为是有利的。原因是它会导致更多的本地内存访问模式,这对缓存更友好。

使用不同布局的一个很好的理由是,如果某些属性的更新频率比其他属性高得多。在极端情况下,其中一些是静态的,而另一些则经常更新,将静态属性保留在一个 VBO 中实际上可能是有益的,使用 GL_STATIC_DRAW ,并使用单独的缓冲区 GL_DYNAMIC_DRAW 经常变化的属性的用法。

@leemes 在上面的评论中提出了另一个有趣的案例:如果您经常只使用属性的一个子集进行绘制调用,那么可能也值得对它们进行不同的分组。在这种情况下,您可以在交错布局中使用始终使用的属性,并将很少使用的属性分开。

尽管如此,您的渲染管线中通常会遇到更大的瓶颈,因此可能很难在目标综合基准之外衡量差异。不过,我认为让一切尽可能精简是最值得的。特别是现在大多数计算机/设备都依靠电池供电,您不想浪费任何东西。

关于c++ - 顶点数据应该按每个顶点还是每个属性进行布局?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26520933/

相关文章:

c++ - 在 Qt 中使用基本类型时挂起

sql - OrientDB 中的 INSERT 和 CREATE VERTEX 有什么区别?

opengl - glVertexAttribPointer 上的内置顶点属性,如 gl_Vertex、gl_Normal

opengl - 核心视频 - displaylink 我需要帮助解释 CVTimeStamp

c++ - glMatrixMode(GL_MODELVIEW)在resize()中有什么用?

c++ - 在 OpenGL 中查看深度缓冲区

java - 从 OpenGL ES 开始。使用像素绘图

.net - 由于 2 秒超时,并非所有 native 全局变量都在混合模式 .Net 应用程序中被破坏

c++ - 在清除之前检查一个 vector ?

c++ - 同一个指针的不同值