OpenGL包装顶点属性

OpenGL包装顶点属性,opengl,glsl,Opengl,Glsl,在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)

在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%的顶点。这是否正确?

顶点获取的主要成本是读取内存的成本。数据越大,读取时间就越长。因此,这种包装不是特别有用。最终,最好使用您的数据库正确地打包数据

对于纹理坐标,通常可以使用16位无符号规格化整数。这使得纹理坐标在每个顶点上占用4个字节:

glVertexAttribFormat(4, 2, GL_UNSIGNED_SHORT​, GL_TRUE, ...);
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, ...);
法线/切线/位切线应使用
GL_INT_2_10_10_10_REV
,将整个法线打包为32位。XYZ每个都有10位,最后2位是一个您不使用的W组件。因此,法线/切线/位切线总计将占用每个顶点12个字节:

glVertexAttribFormat(4, 2, GL_UNSIGNED_SHORT​, GL_TRUE, ...);
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打包到tangent/bitangent中无法使用10/10/10/2格式,因为对于纹理坐标而言,2个比特几乎不够

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