Normal, Tangent, Bitangent (Binormal) optimization

There are some scenarios where memory saving causes a performance improvement too, like handheld devices (in my case, the PS Vita).

One trick it was useful to improve the performance was to store the normal, tangent and bitangent (or binormal) in a memory-efficient way.

In the "normal" way, I'd use 3 arrays of 3 floats each one ( 3 arrays * 3 floats * 4 bytes per float). That makes 36 bytes.

The first optimization we could do would be to store the information using one byte per coordinate instead of floats (4 bytes). You probably are not going to need all that precision. We will need to clamp the values to the range (-127,+127) when storing the data and undo all this stuff when reading them.

But, do you really need to know the all those bitangent coordinates? The bitangent is the cross product between the normal and the tangent, so you only need to know which direction has the bitangent, the flip bit.


We could store that bit in the  tangent "w" coordinate.

This way you are going to need 2 arrays of 4 bytes = 8 bytes instead of the previous 36 bytes

Note the normal "w" coordinate is empty, so you could use it to save some stuff (in my case, the bone index).

Here you have the sample code:
normalData = new Vector4((0x7F * MathUtil.Clamp(currentNormal.X, -1.0f, 1.0f)), (0x7F * MathUtil.Clamp(currentNormal.Y, -1.0f, 1.0f)), (0x7F * MathUtil.Clamp(currentNormal.Z, -1.0f, 1.0f)), boneIndex);
                       
flip = (Vector3.Dot(Vector3.Cross(new Vector3(normalData.X, normalData.Y, normalData.Z), currentUTangent), currentVTangent) > 0) ? -1.0f : 1.0f; 
tangentFlipData = new Vector4((0x7F * MathUtil.Clamp(currentUTangent.X, -1.0f, 1.0f)), (0x7F * MathUtil.Clamp(currentUTangent.Y, -1.0f, 1.0f)), (0x7F * MathUtil.Clamp(currentUTangent.Z, -1.0f, 1.0f)), (0x7F * MathUtil.Clamp(flip, -1.0f, 1.0f)));
                           

Comentarios

Entradas populares