GLSL中的std140注意事项

一、关于bool的注意事项

以下是笔者在学习OpenGL相关内容时遇到的问题

struct UniformBufferObject {
    alignas(16) igm::vec3 viewPos;
    alignas(4) bool useColor;
};

这是我在C++程序中声明的一个UBO,对应于着色器中的:

layout(std140, binding = 1) uniform UniformBufferObject {
    vec3 viewPos;
    bool useColor;
} ubo;

我在C++程序中给声明的UBO进行赋值,也就是

UniformBufferObject ubo;
ubo.viewPos = igm::vec3(1.0f);
ubo.useColor = false;

但是这段代码在实际运行中并不能得到正确的答案,原因就在于笔者对C++的alignas(4)用法不熟悉
首先先看GLSL中的std140布局规则(以下内容引用自LearnOpenGL

类型布局规则
标量,比如int和bool每个标量的基准对齐量为N
向量2N或者4N。这意味着vec3的基准对齐量为4N
标量或向量的数组每个元素的基准对齐量与vec4的相同
矩阵储存为列向量的数组,每个向量的基准对齐量与vec4的相同
结构体等于所有元素根据规则计算后的大小,但会填充到vec4大小的倍数

std140布局规则的对齐偏移量实例

layout (std140) uniform ExampleBlock
{
   					// 基准对齐量       // 对齐偏移量
   float value;     // 4               // 0 
   vec3 vector;     // 16              // 16  (必须是16的倍数,所以 4->16)
   mat4 matrix;     // 16              // 32  (列 0)
        			// 16              // 48  (列 1)
        			// 16              // 64  (列 2)
       			    // 16              // 80  (列 3)
   float values[3]; // 16              // 96  (values[0])
        			// 16              // 112 (values[1])
        			// 16              // 128 (values[2])
   bool boolean;    // 4               // 144
   int integer;     // 4               // 148
};

因此可以知道,我们的UBO占用16个字节,在我们C++的处理中确实可以让struct UniformBufferObject对齐到16字节,通过std::cout << sizeof(UniformBufferObject) << std::endl;得到16就是一个验证。

layout(std140, binding = 1) uniform UniformBufferObject {
					// 基准对齐量       // 对齐偏移量
    vec3 viewPos;  	// 16			   // 0
    bool useColor;  // 4			   // 12
} ubo;

但最重要的是struct UniformBufferObject中的alignas(4) bool useColor;,由于bool类型在C++中只占一个字节,如果我们对useColor进行赋值时只会对alignas(4)对齐到的4字节的第一个字节进行赋值,后续三个字节是由C++进行随机填充的,用以下代码就可以查看ubo中的字节码

struct UniformBufferObject {
    alignas(16) igm::vec3 viewPos;
    alignas(4) bool useColor;
};

UniformBufferObject ubo;
ubo.viewPos = igm::vec3(1.0f);
ubo.useColor = false;

// Convert the struct pointer to char pointer
char* bytes = reinterpret_cast<char*>(&ubo);

// Print bytes in hexadecimal format
std::cout << "Byte representation of ubo:" << std::endl;
for (size_t i = 0; i < sizeof(ubo); ++i) {
    std::cout << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(bytes[i]) << " ";
}
std::cout << std::endl;

输出结果为:

Byte representation of ubo:
00 00 ffffff80 3f 00 00 ffffff80 3f 00 00 ffffff80 3f 00 ffffffcc ffffffcc ffffffcc

可以看到对齐到四字节的bool类型最终字节码为00 ffffffcc ffffffcc ffffffcc,也就是说,当该串字节传入GLSL时,最后四字节的表示不等于0,因此也就不为false,由于GLSL基于std140的解释会将bool类型的四个字节合到一起进行解释,因此我们需要对四个字节一起进行赋值,一个简单的办法就是alignas(4) bool useColor;更改为alignas(4) int useColor;,我们在C++中也将四个字节当作一个整体进行赋值,这样就能保证GLSL中四个字节所解释成的bool类型为正确的数值,重新运行上诉代码
输出结果为:

Byte representation of ubo:
00 00 ffffff80 3f 00 00 ffffff80 3f 00 00 ffffff80 3f 00 00 00 00

由此保证了C++中的数据与GLSL中的数据的解释一致性。

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Sumzeek丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值