2. After some digging I found that this is a fairly common problem and there are functions for packing and unpacking a Single into a Color:
float4 EncodeFloatRGBA(float v)
{
float4 kEncodeMul = float4(1.0, 255.0, 65025.0, 16581375.0);
float kEncodeBit = 1.0 / 255.0;
float4 enc = kEncodeMul * v;
enc = frac(enc);
enc -= enc.yzww * kEncodeBit;
return enc;
}
float DecodeFloatRGBA(float4 enc)
{
float4 kDecodeDot = float4(1.0, 1 / 255.0, 1 / 65025.0, 1 / 16581375.0);
return dot(enc, kDecodeDot);
}
EDIT: I found other samples that use multiples of 256 instead of 255. I don’t know why this uses 255, but I imagine 256 is better. I also like that you can just truncate float4 to float3, for example, to only hold 24 bits of precision rather than 32.