C#如何通过位运算将4个0-255字节打包为整数实现数据压缩
C# 字节打包为整数的实现方案
核心逻辑:32位int刚好可以存储4个8位字节,通过移位和或运算实现打包,通过移位和强转实现解包,全程无精度损失,符合你的压缩需求。
前置转换规则
- pos分量/MatID:取值范围0~200,直接强转
byte类型即可 - RGB颜色:取值0~255,直接强转
byte类型即可 - 法线分量:取值-1~1,转byte公式:
byte normalByte = (byte)Math.Clamp((normalVal * 127f) + 128f, 0, 255);解包时反向公式:float normalVal = (normalByte - 128) / 127f
打包实现
// 通用工具方法:将4个byte按顺序打包为1个int public static int PackBytes(byte b1, byte b2, byte b3, byte b4) { return (b1 << 24) | (b2 << 16) | (b3 << 8) | b4; } // 业务场景打包示例 // 1. 打包pos和MatID:字节顺序为 X分量 -> Y分量 -> Z分量 -> MatID int packedPos = PackBytes((byte)pos.x, (byte)pos.y, (byte)pos.z, (byte)color.y); // 2. 打包颜色:字节顺序为 R分量 -> G分量 -> B分量 -> 预留位(填0即可) int packedColor = PackBytes((byte)color.x, (byte)color.y, (byte)color.z, 0); // 3. 打包法线:字节顺序为 X转byte -> Y转byte -> Z转byte -> 预留位(填0即可) byte nx = (byte)Math.Clamp((normal.x * 127f) + 128f, 0, 255); byte ny = (byte)Math.Clamp((normal.y * 127f) + 128f, 0, 255); byte nz = (byte)Math.Clamp((normal.z * 127f) + 128f, 0, 255); int packedNormal = PackBytes(nx, ny, nz, 0);
解包实现
// 通用工具方法:将int拆分为4个byte,返回顺序和打包时的b1~b4完全对应 public static (byte b1, byte b2, byte b3, byte b4) UnpackBytes(int packedVal) { byte b1 = (byte)(packedVal >> 24); byte b2 = (byte)(packedVal >> 16); byte b3 = (byte)(packedVal >> 8); byte b4 = (byte)packedVal; return (b1, b2, b3, b4); } // 业务场景解包示例 // 1. 解包位置和材质ID var (xByte, yByte, zByte, matIdByte) = UnpackBytes(packedPos); float3 pos = new float3(xByte, yByte, zByte); int matId = matIdByte; // 2. 解包颜色 var (rByte, gByte, bByte, _) = UnpackBytes(packedColor); float4 color = new float4(rByte, gByte, bByte, 0); color.y = matId; // 还原材质ID到原始结构的color.y字段 // 3. 解包法线 var (nxByte, nyByte, nzByte, _) = UnpackBytes(packedNormal); float3 normal = new float3( (nxByte - 128) / 127f, (nyByte - 128) / 127f, (nzByte - 128) / 127f );
注意事项
- 所有输入值建议提前校验范围,避免溢出,比如pos分量超过200时需要先做截断或归一化处理
- 如果担心int符号位导致移位异常,可以把打包返回值类型改为
uint,逻辑完全一致,兼容性更好 - 法线转换加
Math.Clamp是为了避免浮点精度误差导致值超出0~255范围的问题
内容的提问来源于stack exchange,提问作者NuclearWolf
相关产品推荐
相关产品推荐

