我使用渲染循环如下;
目前我使用的是单个交错顶点格式(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吗?这样可以节省一些空间。
我应该为每种顶点格式映射不同的缓冲区吗?也许更有效率。
或者我应该保持'one size fit all'顶点格式?这更容易。
我很想知道在这种情况下最佳做法是什么。 感谢。
答案 0 :(得分:0)
基于您的底层系统架构可能存在很多变化,但我们假设您使用的是具有专用图形内存的独立GPU(例如,AMD或NVIDIA)。
您没有提及是否在结构数组( AoS )中交错属性(可能类似于以下内容):
RewriteBase /
或将相似的属性组合在一起(通常称为数组结构或( SoA ))
RewriteBase /mysitename/
这是相关的,因为你是缓冲映射方法。当您在整个缓冲区中映射时,GPU可能需要将其缓冲区版本复制到CPU,后者为您提供更新值的指针。取消映射缓冲区时,驱动程序会将缓冲区复制回GPU。使用 AoS 布局和您的技术,您将触摸整个缓冲区的小部分,并且由于GPU驱动程序不知道您更新了哪些内存,因此只能复制整个事情回到GPU。根据大小,这可能会在多个级别产生重大影响(CPU缓存读取利用率较低,消耗大量CPU到GPU总线带宽等)。不幸的是,如果你只更新一小部分顶点属性,那么就没有好的选择。但是,如果您要更新所有属性,这种方法是可以的(尽管通常建议使用struct Vertex {
float position[3];
float normal[3];
float uv[2];
...
};
或类似的命令,这样可以将读回数从GPU保存到CPU。
相反,如果您使用 SoA 方法,映射整个缓冲区将导致类似的问题,但情况会更好。由于特定属性的值在内存中是连续的,因此您可以使用struct VertexAttributes {
float positions[N][3];
float normals[N][3];
float uv[N][2];
...
};
之类的内容仅映射到您需要的内存中(但同样,我仍然建议使用glBufferSubData
来解释前面提到的原因)。鉴于您当前的情况,这是我建议的。