On one of the slides of their presentation "Batch, Batch, Batch!" guys from NVidia suggest encoding animation matrices for pallet skinning into two float4s as:

• axis/angle

• translate/uniform scale

I wonder how can that be done (including decoding) and why do they say that this leads to:

Video memory overhead: model replication


Encode world matrix as 2 float4s

2 float4 means 2 vectors, encoding these in two vectors is easy and is actually common.

This can easily be done:

  • axis/angle -> axis ( x,y,z 3 floats ), angle ( 1 float ).
  • translate/uniform scale -> ( x,y,z 3 floats ), uniform scale ( 1 float ).

Now decoding this is as easy constructing a 4x4 matrix from scaling, rotation and translation.

Now my interpretation of

Video memory overhead: model replication

If it caused video memory overhead, you can optimize it by using model replication, in other words use the same bone transforms for different models (instancing). Instead of submitting new transform for each new skeleton.

  • \$\begingroup\$ I have two questions: 1) does C# have a method that extracts these elements from a ready Matrix? 2) if I were multiplying a position matrix with the matrix I need compressed in the shader (input.position = mul(input.position, matrix);) how do I need to change my code? I can't understand how you construct a 4x4 matrix from these elements. \$\endgroup\$ – cubrman Dec 14 '13 at 7:21
  • \$\begingroup\$ @cubrman C# is a language, you need to use an external matrix library. Regarding your second question I think you need to understand how matrices work before you can understand this. I suggest picking up matrix tutorial online. like this one chortle.ccsu.edu/vectorlessons/vectorindex.html \$\endgroup\$ – concept3d Dec 14 '13 at 17:49
  • \$\begingroup\$ Thanks for the link. I will pick your answer as the right one because it best fits the question. \$\endgroup\$ – cubrman Dec 14 '13 at 18:25

As concept3d said, a pair of float4s means 8 components total (so half the size of a 16-component matrix), and you can just fit a rotation, translation, and uniform scale value into 8 components. (Although I would use a quaternion rather than axis-angle - that way no trig functions need to be used in the vertex shader to apply the rotation.)

As for the "Video memory overhead: model replication" comment, this is my best guess:

The context of the talk is trying to reduce the number of batches (draw calls) by combining multiple models together in a batch. You would ordinarily have to create a new batch every time you changed the world matrix, so the speaker envisions doing this with bones instead ("matrix palette" is an old hardware feature for making bone matrices available to the vertex shader). Basically you'd attach each model to a different bone and set each bone to the transform needed for that object.

However, this raises a problem where the object has to know which bone it should be attached to. This would be done by adding a new vertex component for the bone index. But this means you need a vertex buffer with multiple copies of the model, each with the bone index set to a different value in all its vertices. Therefore you are paying a lot of video memory overhead by replicating the model several times.

Nowadays we would do all of this with instancing, which solves that problem; but I don't think hardware instancing existed in 2003 or 2004 when this talk was given.

  • \$\begingroup\$ You said: "Basically you'd attach each model to a different bone and set each bone to the transform needed for that object. However, this raises a problem where the object has to know which bone it should be attached to." Could you expand upon it? We are using a palette animation library written by dastle and I am slowly learning how it works. I know that we are sending a huge (up to 56 elements) float4x4 array into a shader for each ModelMesh. The array represents the current frame's animation pose. The only way I see how it can be instanced is by putting more float4x4-s what am I missing? \$\endgroup\$ – cubrman Dec 14 '13 at 7:14
  • \$\begingroup\$ In an instancing system, you have two vertex buffers: the "inner" one, which has the actual vertices for the model (just one copy of it), and the "outer" one, which has one vertex per instance and would contain the matrices for all bones (or a compressed representation thereof, as in the 2-float4 case here). \$\endgroup\$ – Nathan Reed Dec 14 '13 at 9:41
  • \$\begingroup\$ Ok I saw the instancing sample and was familliar with double-buffer hardware instancing system. I also thought about using it for my matrix palette skinning, but I ended up thinking it is infeasible as you can only have so many channels per vertex (my tests led me to the number 16 per name "TEXCOORD", "COLOR",...). I need 56x4 channels for that to work. With compression I will need 56x2 channels. So I will need 7 names for that. So if I reduce the number of bones supported it becomes feasible. Is this how it was supposed to work? \$\endgroup\$ – cubrman Dec 14 '13 at 10:30
  • 1
    \$\begingroup\$ @cubrman You can do whatever animation processing (eval keyframes, transitions/blending, etc.) you want on the CPU, and just put the final bone poses for that frame in the texture. It would be updated every frame, not a static texture. \$\endgroup\$ – Nathan Reed Dec 16 '13 at 17:54
  • 1
    \$\begingroup\$ @cubrman It's not a vertex buffer; it's a dynamic texture. It's a regular texture object, but you create it with dynamic usage and pool, and use LockRect with the discard flag to update it. \$\endgroup\$ – Nathan Reed Dec 17 '13 at 17:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.