Hello,

I am studying the shader in Unity’s Demo: Book of Dead. I am trying to implement the tree animation of the demo. I am guessing the author encoded two floats into one uint3, and bake the info into the uv3 of the model, and try to to some unpacking work in the shader to retrive the two floats.

This is the code in the shader:

```
float UnpackFixedToSFloat(uint val, float range, uint bits, uint shift) {
const uint BitMask = (1 << bits) - 1;
val = (val >> shift) & BitMask;
float fval = val / (float)BitMask;
return (fval * 2.f - 1.f) * range;
}
float UnpackFixedToUFloat(uint val, float range, uint bits, uint shift) {
const uint BitMask = (1 << bits) - 1;
val = (val >> shift) & BitMask;
float fval = val / (float)BitMask;
return fval * range;
}
// Needs to match shader packing in baking tool
bool UnpackPivot0(uint3 packedData, inout float3 pivotPos0, inout float3 pivotFwd0) {
if(packedData.y & 0xFFFF0000) {
pivotPos0.x = UnpackFixedToSFloat(packedData.x, 8.f, 10, 22);
pivotPos0.y = UnpackFixedToUFloat(packedData.x, 32.f, 12, 10);
pivotPos0.z = UnpackFixedToSFloat(packedData.x, 8.f, 10, 0);
pivotFwd0.x = UnpackFixedToSFloat(packedData.y, 1.f, 8, 24);
pivotFwd0.z = UnpackFixedToSFloat(packedData.y, 1.f, 7, 17);
pivotFwd0.y = sqrt(1.f - saturate(dot(pivotFwd0.xz, pivotFwd0.xz))) * (((packedData.y >> 16) & 1) ? 1.f : -1.f);
pivotFwd0 = normalize(pivotFwd0);
return true;
}
return false;
}
// Needs to match shader packing in baking tool
bool UnpackPivot1(uint3 packedData, inout float3 pivotPos1, inout float3 pivotFwd1) {
if(packedData.y & 0x0000FFFF) {
pivotFwd1.x = UnpackFixedToSFloat(packedData.y, 1.f, 8, 8);
pivotFwd1.z = UnpackFixedToSFloat(packedData.y, 1.f, 7, 1);
pivotFwd1.y = sqrt(1.f - saturate(dot(pivotFwd1.xz, pivotFwd1.xz))) * ((packedData.y & 1) ? 1.f : -1.f);
pivotFwd1 = normalize(pivotFwd1);
pivotPos1.x = UnpackFixedToSFloat(packedData.z, 8.f, 10, 22);
pivotPos1.y = UnpackFixedToUFloat(packedData.z, 32.f, 12, 10);
pivotPos1.z = UnpackFixedToSFloat(packedData.z, 8.f, 10, 0);
return true;
}
return false;
}
void AnimateVegetationHierarchyPivot(inout float3 worldPos, inout float3 worldNrm, float3 pivotData, float3 pivotColor, float3 objectRoot, float timeNudge) {
if(_WindEnabled == 0)
return;
uint3 packedData = asuint(pivotData);
float3 pivotPos0, pivotPos1, pivotFwd0, pivotFwd1;
bool pivotEnabled0 = UnpackPivot0(packedData, pivotPos0, pivotFwd0);
bool pivotEnabled1 = UnpackPivot1(packedData, pivotPos1, pivotFwd1);
...//Do animation based on the pivot position and pivot direction
}
```

I am very curious on this part. I am like 99% sure that Pivot0 is the level0 pivot, which means the pivot linking the trunk and branch. Pivot1 is the level1 pivot, which means the pivot linking the branch and leaf.

However, I don’t understand the packing/unpacking algorithm here. Why do they write two different packing/unpacking functions? The only information needed to do the animation is the pivot’s position and pivot direction. If UnpackFixedToSFloat can do it, why do they need UnpackFixedToUFloat?

Moreover, I think cg language has the built-in packing/unpacking method, which is:

```
public static float f3_f(float3 c)
{
return dot(round(c * 255), new float3(65536, 256, 1));
}
public static float3 f_f3(float f)
{
return frac(f / new float3(16777216, 65536, 256));
}
```

And in the shader:

```
#define f3_f(c) (dot(round((c) * 255), float3(65536, 256, 1)))
#define f_f3(f) (frac((f) / float3(16777216, 65536, 256)))
```

Why don’t they use this built-in method?