我应该在统一的缓冲区或着色器存储缓冲区对象内使用“vec3”吗?

vec3types是一个非常好的types。 它只需要3个浮点数,而我有数据只需要3个浮点数。 我想在UBO和/或SSBO的结构中使用一个:

 layout(std140) uniform UBO { vec4 data1; vec3 data2; float data3; }; layout(std430) buffer SSBO { vec4 data1; vec3 data2; float data3; }; 

然后,在我的C或C ++代码中,我可以这样做来创build匹配的数据结构:

 struct UBO { vector4 data1; vector3 data2; float data3; }; struct SSBO { vector4 data1; vector3 data2; float data3; }; 

这是一个好主意吗?

没有! 永远不要这样做!

声明UBO / SSBO时,假设所有3元素vector和matrixtypes都不存在 。 假设唯一的types是标量,2和4个元素向量(和matrix)。 如果你这样做的话,你会为自己节省很多的痛苦。

如果你想要一个vec3 +浮动的效果,那么你应该手动打包:

 layout(std140) uniform UBO { vec4 data1; vec4 data2and3; }; 

是的,你将不得不使用data2and3.w来获得另一个值。 处理它。

如果你想要vec3的数组,然后让他们vec4的数组。 使用3元素向量的matrix也是如此。 只要从SSBOs / UBOs中消除3元素载体的全部概念, 从长远来看,你会好得多。

有两个原因你应该避免vec3

它不会做什么C / C ++

如果使用std140布局,那么您可能需要定义C或C ++中与GLSL中的定义相匹配的数据结构。 这使得两者之间很容易混搭。 在大多数情况下, std140布局至less可以做到这一点。 但是当涉及到vec3时,其布局规则与C和C ++编译器通常的布局规则不匹配。

考虑一下vec3types的以下C ++定义:

 struct vec3a { float a[3]; }; struct vec3f { float x, y, z; }; 

这两个都是完全合法的types。 这些types的大小和布局将匹配std140所需的大小和布局。 但它不符合std140强制的alignment行为。

考虑这个:

 //GLSL layout(std140) uniform Block { vec3 a; vec3 b; } block; //C++ struct Block_a { vec3a a; vec3a b; }; struct Block_f { vec3f a; vec3f b; }; 

在大多数C ++编译器中, Block_aBlock_b sizeof将是24.这意味着b Block_b将是12。

然而,在std140布局中, vec3总是alignment到4个字。 因此Block.b的偏移量为16。

现在,您可以尝试使用C ++ 11的alignasfunction(或C11的类似_Alignasfunction)来解决这个问题:

 struct alignas(16) vec3a_16 { float a[3]; }; struct alignas(16) vec3f_16 { float x, y, z; }; struct Block_a { vec3a_16 a; vec3a_16 b; }; struct Block_f { vec3f_16 a; vec3f_16 b; }; 

如果编译器支持16字节alignment,这将工作。 或者至less,它将在Block_aBlock_f的情况下工作。

但在这种情况下不起作用:

 //GLSL layout(std140) Block2 { vec3 a; float b; } block2; //C++ struct Block2_a { vec3a_16 a; float b; }; struct Block2_f { vec3f_16 a; float b; }; 

按照std140的规则,每个vec3必须以16字节的边界开始。 但vec3消耗 16个字节的存储空间; 它只消耗12.由于float可以在4字节的边界上开始,所以vec3后面跟着一个float将占用16个字节。

但是C ++alignment的规则不允许这样的事情。 如果某个types与X字节边界alignment,那么使用该types将消耗X字节的倍数。

所以匹配std140的布局要求你根据使用的地方select一个types。 如果后面跟着一个float ,则必须使用vec3a ; 如果后面跟着一个大于4字节的types,那么你必须使用vec3a_16

或者你可以在着色器中不使用vec3 ,避免所有这些增加了复杂性。

请注意,基于alignas(8)vec2不会有这个问题。 C / C ++也不会使用正确的alignment说明符来构造&数组(尽pipe数组较小的types有它们自己的问题)。 这个问题发生在使用裸vec3

实施支持是模糊的

即使你做的一切都是正确的,实现已经被错误地实现了vec3的古怪的布局规则。 一些实现有效地将C ++alignment规则强加给GLSL。 所以,如果你使用vec3 ,它会像C ++一样对待一个16字节的alignmenttypes。 在这些实现中,一个vec3后跟一个float将像vec4跟随一个float

是的,这是实施者的错。 但是由于您无法修复实施,您必须解决此问题。 而最合理的做法是完全避免vec3

请注意,对于Vulkan,SDK的GLSL编译器可以正确使用,所以您无需为此担心。