[英]C++ Bitshift 4 int_8t into a normal integer (32 bit )
我已经问过如何将 4 int8_t 转换为 32 位 int 的问题,有人告诉我必须先将 int8_t 转换为 uint8_t,然后通过位移将其打包为 32 位 integer。
int8_t offsetX = -10;
int8_t offsetY = 120;
int8_t offsetZ = -60;
using U = std::uint8_t;
int toShader = (U(offsetX) << 24) | (U(offsetY) << 16) | (U(offsetZ) << 8) | (0 << 0);
std::cout << (int)(toShader >> 24) << " "<< (int)(toShader >> 16) << " " << (int)(toShader >> 8) << std::endl;
我的 Output 是
-10 -2440 -624444
当然,这不是我所期望的,有没有人有解决办法?
在着色器中,我想稍后解压 int16,这只能使用 32 位 integer,因为 glsl 没有任何其他数据类型。
int offsetX = data[gl_InstanceID * 3 + 2] >> 24;
int offsetY = data[gl_InstanceID * 3 + 2] >> 16 ;
int offsetZ = data[gl_InstanceID * 3 + 2] >> 8 ;
方括号中写的内容无关紧要,它是关于位的正确移动或括号后的转换。
如果任何偏移量为负,则移位会导致未定义的行为。
解决方案:先将偏移量转换为无符号类型。
然而,这带来了另一个潜在问题:如果转换为unsigned
,那么负数将具有非常大的值,并且在最高有效字节中设置位,并且与这些位进行 OR 运算将始终得到 1,而不管offsetX
和offsetY
。 一个解决方案是转换成一个小的无符号类型( std::uint8_t
),另一个是屏蔽未使用的字节。 前者可能更简单:
using U = std::uint8_t;
int third = U(offsetX) << 24u
| U(offsetY) << 16u
| U(offsetZ) << 8u
| 0u << 0u;
我认为您忘记在移动之前屏蔽您关心的位。
也许这就是您要找的:
int32 offsetX = (data[gl_InstanceID * 3 + 2] & 0xFF000000) >> 24;
int32 offsetY = (data[gl_InstanceID * 3 + 2] & 0x00FF0000) >> 16 ;
int32 offsetZ = (data[gl_InstanceID * 3 + 2] & 0x0000FF00) >> 8 ;
if (offsetX & 0x80) offsetX |= 0xFFFFFF00;
if (offsetY & 0x80) offsetY |= 0xFFFFFF00;
if (offsetZ & 0x80) offsetZ |= 0xFFFFFF00;
如果没有位掩码,X 部分将在offsetY
中结束,而 X 和 Y 部分将在offsetZ
中结束。
在 CPU 端,您可以使用 union 来避免移位、位掩码和分支……
int8_t x,y,z,w; // your 8bit ints
int32_t i; // your 32bit int
union my_union // just helper union for the casting
{
int8_t i8[4];
int32_t i32;
} a;
// 4x8bit -> 32bit
a.i8[0]=x;
a.i8[1]=y;
a.i8[2]=z;
a.i8[3]=w;
i=a.i32;
// 32bit -> 4x8bit
a.i32=i;
x=a.i8[0];
y=a.i8[1];
z=a.i8[2];
w=a.i8[3];
如果你不喜欢联合,同样可以用指针来完成......
当心 GLSL 方面这是不可能的(也不是联合或指针),你必须像其他答案一样使用位移和掩码......
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.