OpenGL打包顶点属性

Posted

技术标签:

【中文标题】OpenGL打包顶点属性【英文标题】:OpenGL packing vertex attributes 【发布时间】:2018-03-24 02:41:49 【问题描述】:

在OpenGL中,是否最好将顶点属性分开:

layout(location = 0) in vec4 v_Position;
layout(location = 1) in vec3 v_Normal;
layout(location = 2) in vec3 v_Tanget;
layout(location = 3) in vec3 v_Bitanget;
layout(location = 4) in vec2 v_UV;

或者像这样包装它们:

layout(location = 0) in vec4 v_Position;
layout(location = 1) in vec3 v_Normal;
layout(location = 2) in vec4 v_TangetAndU;
layout(location = 3) in vec4 v_BitangetAndV;

..常用作性能优化?我的印象是,如果您的性能受到几何图形数量的限制,您可能能够从“打包”版本中获得额外 20% 的顶点。这是正确的吗?

【问题讨论】:

【参考方案1】:

顶点获取的主要成本将是读取内存的成本。您的数据越大,读取所需的时间就越多。因此,这种包装并不是特别有用。使用normalized integers 和vertex formats 正确打包数据最终会更好。

您通常可以不使用 16 位无符号归一化整数作为纹理坐标。这使您的纹理坐标占用每个顶点 4 个字节:

glVertexAttribFormat(4, 2, GL_UNSIGNED_SHORT​, GL_TRUE, ...);

您的法线/切线/双切线应使用GL_INT_2_10_10_10_REV,它将整个法线打包成 32 位。 XYZ 各有 10 位,最后 2 位用于您不会使用的 W 组件。所以法线/切线/双切线总共将占用每个顶点 12 字节:

glVertexAttribFormat(1, 4, GL_INT_2_10_10_10_REV, GL_TRUE, ...);
glVertexAttribFormat(2, 4, GL_INT_2_10_10_10_REV, GL_TRUE, ...);
glVertexAttribFormat(3, 4, GL_INT_2_10_10_10_REV, GL_TRUE, ...);

即使您将位置保留为 3 个浮点数(无需传递第四个浮点数),顶点的总大小将为每个顶点 12 + 12 + 4 = 28 个字节。对原始代码的任一版本都有重大改进。如果对位置使用 16 位浮点数,则可以将其降低到每个顶点 24 个字节(属性应始终以 4 字节边界开始)。

请注意,尝试将 UV 打包到切线/副切线中不适用于 10/10/10/2 格式,因为 2 位对于纹理坐标来说是不够的。

打包此类数据,尤其是 10/10/10/2 格式,需要小心谨慎,但总体而言,从长远来看,这将比玩具有 in-shader 属性的游戏好得多。

【讨论】:

【参考方案2】:

为了添加一些真实世界的数据,我更改了以下用于绘制线条的代码:

attribute vec4 a_points;

void main() 
  vec2 point1 = a_points.xy;
  vec2 point2 = a_points.zw;

  // ...

attribute vec2 a_point1;
attribute vec2 a_point2;

void main() 
  // ...

它还提高了我在 iPad (PowerVR Series7XT Plus GPU) 上游戏的 FPS 从

因此,如果有疑问,我的建议是保持顶点属性分开。

【讨论】:

以上是关于OpenGL打包顶点属性的主要内容,如果未能解决你的问题,请参考以下文章

Modern OpenGL - 顶点数组、属性与绑定点(OpenGL 4.5+)

OpenGL顶点属性未启用

我的OpenGL学习进阶之旅顶点属性顶点数组

我的OpenGL学习进阶之旅顶点属性顶点数组

为啥禁用顶点属性数组零时OpenGL绘图失败?

OpenGL重叠顶点属性