

最近想要提高一下GBuffer的数据利用率,所以很容易想到通过损失数据精度的方式在一个通道里存多个数据,因为有些数据的精度的确也不需要那么高,只需要几位就可以满足需求了。

首先我们要先了解RT的格式

因为RT的有些位存的是符号,有些位存的是数据,有些位存的是小数精度

我们需要增加GBuffer数据的利用率,自然就需要对数据进行位操作,这里有个前提,假设我们的RenderTarget的格式为无符号DXGI_FORMAT_B8G8R8A8_UNORM_SRGB
所以我们每个通道最大值为255且8位都是用来存数据的
我们来做个实验
uint A = 13;uint B = 12;float CustomData = (float)((A << 0 ) | (B << 4)) / (float)0xFF;uint Raw = CustomData * 0xFF;uint DA = (Raw >> 0) & 0x0F;uint DB = (Raw >> 4) & 0x0F;return DB;

我们把数据A压入前四位,把B压入高四位,所以这样的话我们的A和B的最大值为16
这里需要注意的是十六进制数字的写法为0x开头,八进制的数字为0开头
例如在八进制中,9的写法为011

在十六进制中15的写法为0x0F

如果我们想要得到一个二进制Mask,我们可以参考UE的写法

直接用位运算做一个Mask
例如1<<4 就会得到一个 0001 0000
例如1<<5 就会得到一个 0010 0000
如果我们想要一个 1111 0000 的Mask也很简单只需要 0x0F << 4即可
0000 0100
如果我们想要一个 0011 0000的Mask可以写作:3 << 4即可
所以回到我们一开始的问题如果我想要把多个数据压缩到一个GBuffer的一个通道里,可以如下这么做:
voidEncodeNPRData(inout float4 GBufferCustomData, infloat ShadowFalloff, infloat ShadowStep){//注意这里的GBuffer.CustomData必须是R8G8B8A8的格式才行,这里要特别注意!不然编码会出问题//把ShadowFalloff存储在GBufferCustomData.b的低4位uint ShadowFalloffRaw = (uint)ShadowFalloff & 0x0F;uint ShadowStepRaw = (uint)ShadowStep & 0x0F;uint RawData = (ShadowFalloffRaw << 0) | (ShadowStepRaw << 4);GBufferCustomData.b = (float)RawData / (float)0xFF;}voidDecodeEncodeNPRData(in float4 GBufferCustomData, outfloat ShadowFalloff, outfloat ShadowStep){uint RawData = (uint)round(GBufferCustomData.b * (float)0xFF);uint ShadowFalloffRaw = RawData & 0x0F;uint ShadowStepRaw = (RawData & (0x0F << 4)) >> 4;ShadowFalloff = ShadowFalloffRaw;ShadowStep = ShadowStepRaw;}
我们可以在材质编辑器里测试下我们上面的代码


Enjoy it.



2024/4/19
像素格式与纹理压缩 - 可可西 - 博客园: https://www.cnblogs.com/kekec/p/11909187.html
鸣谢:感谢作者的授权转载,欢迎大家投稿,一起分享交流游戏开发技术。
作者:YivanLee
原文:https://zhuanlan.zhihu.com/p/693440024
关注【游戏开发技术教程】
游戏开发技术、技巧、教程和资源,答疑解惑,内推面试
