Graphics Reference
In-Depth Information
Case
Channels
Vertex Quaternion
x ( int8 )
y ( int8 )
z ( int8 )
h ( 1b )
w ( 7b )
x ( float32 )
y ( float32 )
z ( float32 )
w ( float32 )
Model Transform
Instance Data
x ( int16 )
y ( int16 )
z ( int16 )
w ( 0, calculated )
Bone Transform
x ( float16 )
y ( float16 )
z ( float16 )
w ( float16 )
Tab l e 1. 1. Quaternion packing for different scenarios. h stands for quaternion handed-
ness.
First, we could store in the same byte a handedness bit and a sign bit for w
and then reconstruct w in the shader as we operate onto normalized quaternions.
We abandoned this approach, as unpacking w would lead to the sqrt instruction,
which is costly and should be avoided in the shader.
Instead, we packed a handedness into the first bit and packed w into the
remaining seven last bits (as an unsigned integer). It turned out that even seven
bits is enough in the case of vertex quaternion. Furthermore, this approach
resulted in a very fast unpacking, as shown in Listing 1.1. A nice property of
this packing is that it interpolates correctly in all cases of vertex quaternions and
morph targets. We implicitly use the fact that it is never a case in practice to
interpolate quaternions with different handedness. In this case, the first bit of
quaternions to be interpolated would always be the same, resulting in correct
interpolation of low seven bits.
For model transforms, as we operate them on the CPU side, we store the
quaternion values in float32 format. To pack a quaternion of instance rotation,
we opted for int16 for several reasons. First, we wanted to keep instance vertex
layout as small as possible, and 32-bit formats are definitely an overkill for a
quaternion in terms of precision. Quaternion's values are limited to the [ 1 , 1]
domain, so we need only fixed-point precision. Unfortunately, 8-bit formats were
not enough as they provide around 1-2 angle steps. While this was enough
for a vertex quaternion, in the case of encoding an instance's position, such a
float UnpackFirstBitFromByte ( float argument )
{ return saturate (( argument
255.0 f
127.5 f ) ￿ 100.0 f );
}
float UnpackLow7BitsFromByte ( float firstBit , float argument )
{ return ( argument ￿ 255.0 f
128.0 f ￿ firstBit ) / 127.0 f ;
}
Listing 1.1. Vertex quaternion unpacking.
Search WWH ::




Custom Search