Opengl 我是否应该在统一缓冲区或着色器存储缓冲区对象内部使用“vec3”?
Opengl 我是否应该在统一缓冲区或着色器存储缓冲区对象内部使用“vec3”?,opengl,opengl-es,glsl,vulkan,Opengl,Opengl Es,Glsl,Vulkan,vec3类型是一种非常好的类型。它只需要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++代码中,我可以这样做来创建匹配的数据结构: str
vec3
类型是一种非常好的类型。它只需要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++代码中,我可以这样做来创建匹配的数据结构:
struct UBO
{
vector4 data1;
vector3 data2;
float data3;
};
struct SSBO
{
vector4 data1;
vector3 data2;
float data3;
};
这是个好主意吗?不永远不要这样做
声明UBOs/SSBO时,假设所有3元素向量类型都不存在。这包括具有3行的列主矩阵或具有3列的行主矩阵。假设唯一的类型是标量、2和4元素向量(以及矩阵)。如果你这样做,你会省去很多悲伤
如果您想要vec3+浮点的效果,则应手动打包:
是的,您必须使用data2and3.w
来获取其他值。处理它
如果您想要vec3
s的数组,那么将它们设置为vec4
s的数组。使用三元素向量的矩阵也是如此。只需从SSBO/UBO中删除整个3元素向量概念;从长远来看,你会过得更好
您应该避免使用vec3的原因有两个:
它不会像C/C++那样做
如果使用<代码> STD140版式,那么您可能需要定义与GLSL中定义匹配的C或C++数据结构。这使得两者很容易混合搭配。而std140的
layout至少可以在大多数情况下做到这一点。但是,在<>代码> VEC3 S.时,它的布局规则与C和C++编译器的布局规则不符。
考虑下面的C++定义,用于<代码> VEC3类型:
struct vec3a { float a[3]; };
struct vec3f { float x, y, z; };
这两种类型都是完全合法的。这些类型的sizeof
和布局将与std140
要求的大小和布局匹配。但是它与std140
强加的对齐行为不匹配
考虑这一点:
//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++编译器,<代码> sieOS/<代码>,<代码> Bubja A< /C>和 BuffixF将是24。这意味着b
的偏移量将为12
然而,在std140布局中,vec3
始终与4个单词对齐。因此,Block.b
的偏移量为16
现在,您可以尝试使用C++11的alignas
功能(或C11类似的\u alignas
功能)来解决这个问题:
如果编译器支持16字节对齐,这将起作用。或者至少在Block\u a
和Block\u 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++对齐规则不允许这样的事情发生。如果类型与X字节边界对齐,则使用该类型将消耗X字节的倍数
因此,要匹配std140的布局,需要根据使用的确切位置选择类型。如果后跟一个浮点
,则必须使用vec3a
;如果后面跟的是超过4字节对齐的类型,则必须使用vec3a_16
或者,您不能在着色器中使用vec3
s,从而避免所有这些增加的复杂性
请注意,基于alignas(8)
的vec2
不会出现此问题。C/C++结构和数组也不会使用正确的对齐说明符(尽管较小类型的数组也有自己的问题)。此问题仅在使用裸vec3
时发生
实现支持是模糊的
即使你做的每件事都是对的,但大家都知道,实现不正确地实现了vec3
的古怪布局规则。一些实现有效地将C++对齐规则强加给GLSL。因此,如果使用<代码> VEC3<代码>,它会像C++那样对待一个16字节对齐的类型。在这些实现中,vec3
后跟float
将像vec4
后跟float
一样工作
是的,这是实施者的错。但是,由于无法修复实现,因此必须解决它。最合理的方法是完全避免使用vec3
请注意,对于Vulkan(以及使用SPIR-V的OpenGL),SDK的GLSL编译器可以做到这一点,因此您不必为此担心。好吧,我最近对其进行了反向工程,至少glslagvalidator
按照预期将其紧密打包在SPIR-V中(成员偏移量分别为0、16和28)。若只是关于对齐,那个么更好的例子是vec3跟随标量浮点。@NicolBolas,还有歧义(我想你们会知道的,因为我相信你们是关于它的GitHub问题的始作俑者)。在OGL规范中,它比VK更清楚(因为它至少定义了所使用的大多数术语),我认为“前一个成员消耗的基本机器单元”对于vec3
,仍然意味着3nb(“对齐”不应该改变这一点,这不是这个词的意思)@AzP:std430的布局规则的唯一变化是标量和两个元素向量的数组和结构的基本对齐方式。它对vec3
s没有任何改变,因为它们的基本对齐方式始终是vec4
的对齐方式。读了这篇文章后,我学到了一件重要的事情:规范允许float
在内存中紧跟vec3
,因此它们总共占用16个字节。这似乎是vec3
与vec4
在对齐方面的主要(如果不是唯一)区别特征。即尺寸!=仅当向量的三个分量也不是数组时,才进行基本对齐
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;
};
//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;
};