各种顶点格式和vbo
Posted
技术标签:
【中文标题】各种顶点格式和vbo【英文标题】:Various vertex format and vbo 【发布时间】:2017-06-02 22:12:43 【问题描述】:我使用如下渲染循环;
-
孤立数据并映射缓冲区。
记录命令并将生成的顶点写入缓冲区。
取消映射缓冲区。
迭代可以更改状态、绑定纹理或绘制的命令。
目前我使用单一交错顶点格式 (SoA),它具有我的任何着色器都可以使用的所有属性。
struct OneSizeFitAllVertex
float pos[3];
float uv0[2];
float uv1[2];
float col[4];
;
例如,当使用仅使用位置和颜色的更简单的着色器时,我只会在映射内存中写入我关心的属性,着色器代码会简单地忽略所有未使用的属性。
因为这感觉很浪费,我正在考虑为每个着色器使用不同的顶点格式。
使用简单着色器渲染的简单对象将使用 SimpleVertex:
struct SimpleVertex
float pos[3];
float col[4];
;
而其他多纹理对象将使用多纹理着色器进行渲染并使用 MultitextureVertex:
struct MultitextureVertex
float pos[3];
float uv0[2];
float uv1[2];
;
我应该如何处理这些不同的格式?
我是否应该在同一个映射缓冲区中写入所有不同格式的顶点并在绘制之前更改我的 AttribPointers?这样可以节省一些空间。
我应该为每种顶点格式映射不同的缓冲区吗?也许效率更高。
或者我应该保持“一刀切”的顶点格式吗?这更容易。
我很想知道在这种情况下什么是最佳做法。 谢谢。
【问题讨论】:
除了我最喜欢的“让你的生活最轻松,并且最快地完成工作”的建议之外,如果移动到多个顶点结构会导致你重复数据(例如,你会使用两个单独的数组中的相同位置值),那会很糟糕。不清楚的一件事是您是否在相同数据上使用不同的着色器(例如,如果您有一个对象,并通过切换着色器在不同外观之间切换),或者每个着色器都有自己的数据。但是,如果所有着色器都使用同一个数组中的数据,那么您的方法是最简单的。 【参考方案1】:根据您的底层系统架构可能会有很多变化,但我们假设您使用的是带有专用图形内存的独立 GPU(例如 AMD 或 NVIDIA)。
您没有提及是否将属性交错在一个 结构数组 (AoS) 中(可能类似于以下内容):
struct Vertex
float position[3];
float normal[3];
float uv[2];
...
;
或将相似的属性组合在一起(通常称为数组结构或(SoA))
struct VertexAttributes
float positions[N][3];
float normals[N][3];
float uv[N][2];
...
;
考虑到您使用的是缓冲区映射方法,这很重要。当您映射整个缓冲区时,GPU 可能需要将其缓冲区版本复制到 CPU,CPU 为您提供更新值的指针。当您取消映射缓冲区时,驱动程序会将缓冲区复制回 GPU。使用 AoS 布局和您的技术,您将触及整个缓冲区的小部分,并且由于 GPU 驱动程序不知道您更新了哪些内存位,因此唯一的办法就是复制整个事情回到GPU。根据大小的不同,这可能会在多个级别上产生重大影响(CPU 缓存读取利用率低、消耗大量 CPU 到 GPU 总线带宽等)。不幸的是,如果您只更新一小部分顶点属性,则没有很好的选择。但是,如果您要更新所有属性,这种方法是可以的(尽管通常建议使用 glBufferSubData
或类似的命令,这会将从 GPU 读回的内容保存到 CPU)。
相反,如果您使用 SoA 方法,映射整个缓冲区会导致类似的问题,但情况可能会更好。由于特定属性的值在内存中是连续的,因此您可以使用 glMapBufferRange
之类的东西仅映射到您需要的内存中(但同样,出于前面所述的原因,我仍然建议使用 glBufferSubData
)。鉴于您当前的情况,我建议您这样做。
【讨论】:
我正在使用 AoS,但这不是重点。我的问题是如果我有使用 struct vert_uv float pos[3]; 的程序我应该怎么做? float uv[2] ; 和 struct vert_col float pos[3];浮动列[4] ;?抱歉解释不佳,当我想办法更清楚地表达它时,我会尝试更新我的问题。以上是关于各种顶点格式和vbo的主要内容,如果未能解决你的问题,请参考以下文章
我的OpenGL学习进阶之旅介绍顶点缓冲区对象VBO和元素数组缓冲区对象EBO,并对比使用VBO和不使用VBO绘制三角形的效果