Last active
February 9, 2022 14:17
-
-
Save float3/3bd231ffe66e46f97958c26b42beff39 to your computer and use it in GitHub Desktop.
2 Bitpacking methods
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // Method 1: | |
| // by MerlinVR | |
| // You can convert the uints to full precision floats using asfloat(half3ToUint(input)) and store floats using uintToHalf3(asuint(inputfloat)) | |
| // Packing/unpacking routines for saving integers to R16G16B16A16_FLOAT textures | |
| // Heavily based off of https://github.com/apitrace/dxsdk/blob/master/Include/d3dx_dxgiformatconvert.inl | |
| // For some reason the last 2 bits get stomped so we'll only allow uint14 for now :( | |
| float uint14ToFloat(uint input) | |
| { | |
| precise float output = (f16tof32((input & 0x00003fff))); | |
| return output; | |
| } | |
| uint floatToUint14(precise float input) | |
| { | |
| uint output = (f32tof16(input)) & 0x00003fff; | |
| return output; | |
| } | |
| // Encodes a 32 bit uint into 3 half precision floats | |
| float3 uintToHalf3(uint input) | |
| { | |
| precise float3 output = float3(uint14ToFloat(input), uint14ToFloat(input >> 14), uint14ToFloat((input >> 28) & 0x0000000f)); | |
| return output; | |
| } | |
| uint half3ToUint(precise float3 input) | |
| { | |
| return floatToUint14(input.x) | (floatToUint14(input.y) << 14) | ((floatToUint14(input.z) & 0x0000000f) << 28); | |
| } | |
| //Method 2: | |
| //Using these 2 functions to bit pack four 8bit variables into a single 32bit variable | |
| uint PackByteQ(uint byte1, uint byte2, uint byte3, uint byte4) | |
| { | |
| return (byte1 << 24) | (byte2 << 16) | (byte3 << 8) | byte4; | |
| } | |
| uint4 UnpackByteQ(uint byteQ) | |
| { | |
| return uint4(byteQ >> 24, (byteQ >> 16) & 0xff, (byteQ >> 8) & 0xff, (byteQ) & 0xff); | |
| } | |
| //These could be changed to pack and unpack different data widths | |
| //Example using 8bit variables: | |
| struct v2f_example | |
| { | |
| float4 vertex : SV_POSITION; | |
| //... // Any pre-required properties | |
| uint4 byteQx4_1 : TEXCOORD1; | |
| uint4 byteQx4_2 : TEXCOORD2; | |
| //... | |
| // uint4 byteQx4_Nth : TEXCOORDNth; | |
| }; | |
| //Inside v2f vert() | |
| //v2f o; | |
| //... | |
| // Pack 16 8bit variables into a 128bit buffer | |
| // Values are set somehow | |
| // uint var1 = 0x11; | |
| // uint var2 = 0x22; | |
| // uint var3 = 0x33; | |
| // uint var4 = 0x44; | |
| // uint var5 = 0x55; | |
| // uint var6 = 0x66; | |
| // uint var7 = 0x77; | |
| // uint var8 = 0x88; | |
| // uint var9 = 0x99; | |
| // uint var10 = 0xaa; | |
| // uint var11 = 0xbb; | |
| // uint var12 = 0xcc; | |
| // uint var13 = 0xdd; | |
| // uint var14 = 0xee; | |
| // uint var15 = 0xff; | |
| // uint var16 = 0x00; | |
| // Values are assumed to be less than 255 | |
| // (This could be asserted by masking values with 255) | |
| // eg: | |
| // var1 &= 0xff; | |
| // uint varQ1 = PackByteQ(var1, var2, var3, var4); | |
| // uint varQ2 = PackByteQ(var5, var6, var7, var8); | |
| // uint varQ3 = PackByteQ(var9, var10, var11, var12); | |
| // uint varQ4 = PackByteQ(var13, var14, var15, var16); | |
| // o.byteQx4_1 = uint4(varQ1, varQ2, varQ3, varQ4); | |
| //... | |
| // Inside frag(v2f in) | |
| // ... | |
| // Unpack 16 8bit variables out of a 128bit buffer | |
| // uint4 ByteQ1 = UnpackByteQ(in.byteQx4_1.x); | |
| // uint4 ByteQ2 = UnpackByteQ(in.byteQx4_1.y); | |
| // uint4 ByteQ3 = UnpackByteQ(in.byteQx4_1.y); | |
| // uint4 ByteQ4 = UnpackByteQ(in.byteQx4_1.z); | |
| // uint var1 = ByteQ1.x; | |
| // uint var2 = ByteQ1.y; | |
| // uint var3 = ByteQ1.w; | |
| // uint var4 = ByteQ1.z; | |
| // uint var5 = ByteQ2.x; | |
| // uint var6 = ByteQ2.y; | |
| // uint var7 = ByteQ2.w; | |
| // uint var8 = ByteQ2.z; | |
| // uint var9 = ByteQ3.x; | |
| // uint var10 = ByteQ3.y; | |
| // uint var11 = ByteQ3.w; | |
| // uint var12 = ByteQ3.z; | |
| // uint var13 = ByteQ4.x; | |
| // uint var14 = ByteQ4.y; | |
| // uint var15 = ByteQ4.w; | |
| // uint var16 = ByteQ4.z; | |
| //... | |
| // Here are some functions that can also pack 2 floats into one 32bit variable: | |
| // This packer reduces the mantissa size, affecting percision of smaller numbers (non IEEE-754 standard) | |
| // Can also result in some values of NaN becoming Inf or -Inf | |
| uint PackHalf2(float x, float y) | |
| { | |
| return (asuint(x) & 0xffff0000) | (asuint(y) >> 16); | |
| } | |
| float2 UnpackHalf2(uint pair) | |
| { | |
| return float2(asfloat(pair & 0xffff0000), asfloat(pair << 16)); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment