HLSL: Setting matrices

Started by
8 comments, last by kauna 12 years, 8 months ago
Hello,

I want to implement Skeletal animation with skinning on the GPU. I have my own Mesh class, which is subdivided into several SubMeshes (each SubMesh is a part of the geometry). The Mesh has a skeleton, which is just a hierarchy of bones/matrices. Only the SubMeshes are renderable.

Now if I want to render the Mesh, I put all SubMeshes into my RenderQueue. Each SubMesh is kinda like a render package and they do not know each other. Thus each SubMesh has to send its own Matrices to the Shader. For example lets say my Mesh has 5 Bones/Matrices and I have 2 Submeshes. SubMesh0 uses Matrices 0,1, and 3 and Submesh1 uses matrices 2 and 4.
Thus in the HLSL shader I have an array:
float4x4 mat[5];

and if I render SubMesh0 I just have to update mat[0], mat[1] and mat[3] (because the vertices of SubMesh0) will only index these 3 matrices.

First of all: Is my design ok?

Second: How can I set individual matrices in an HLSL array? I know there is the method ID3DXConstantTable::SetMatrixArray, but this only allows me to update a consecutive array of matrices. Is there a way to only update some matrices in the array?
Advertisement

Hello,

I want to implement Skeletal animation with skinning on the GPU. I have my own Mesh class, which is subdivided into several SubMeshes (each SubMesh is a part of the geometry). The Mesh has a skeleton, which is just a hierarchy of bones/matrices. Only the SubMeshes are renderable.

Now if I want to render the Mesh, I put all SubMeshes into my RenderQueue. Each SubMesh is kinda like a render package and they do not know each other. Thus each SubMesh has to send its own Matrices to the Shader. For example lets say my Mesh has 5 Bones/Matrices and I have 2 Submeshes. SubMesh0 uses Matrices 0,1, and 3 and Submesh1 uses matrices 2 and 4.
Thus in the HLSL shader I have an array:
float4x4 mat[5];

and if I render SubMesh0 I just have to update mat[0], mat[1] and mat[3] (because the vertices of SubMesh0) will only index these 3 matrices.

First of all: Is my design ok?

Second: How can I set individual matrices in an HLSL array? I know there is the method ID3DXConstantTable::SetMatrixArray, but this only allows me to update a consecutive array of matrices. Is there a way to only update some matrices in the array?


- In D3D11 terms you matrices could be in constant buffers and in D3D11 terms you would update the whole constant buffer. Practically it is more efficient to update all the matrices at once.

I am using a system per "submesh" where I reindex all the bones, so that they are always starting from 0 and are consequentive. Since they are in sequence, they can be updated as an array. This way the mesh can have altogether a lot more bones than can fit in the shader constants, but the maximum bones is limit for each submesh, not for the mesh.

I hope you understand.

Cheers!





Yes, I think I know what you mean. But for my first version (this is the first time ever I make something with animations) I want to stay with the "global" indices into the Mesh skeleton.

I forget to mention I am using DX9, so I do not have constant buffers. All I have is a float4x4 mats[10] in my HLSL shader.

Yes, I think I know what you mean. But for my first version (this is the first time ever I make something with animations) I want to stay with the "global" indices into the Mesh skeleton.

I forget to mention I am using DX9, so I do not have constant buffers. All I have is a float4x4 mats[10] in my HLSL shader.


Yeah I figured that you are using D3D9, so you don't have constant buffers. My point is also that some day "float4x4 mats[10]" may not be enough.

You may use [color=#1C2837][size=2]SetMatrixArray to update only 1 matrix too.

You may use [color=#1C2837][size=2]SetMatrixArray to update only 1 matrix too.

How should this work? The function only wants the name of the shader matrix and a number of matrices. It doesn't have a start offset, so I can't say "Update matrix 3 of the array", can I?

[quote name='kauna' timestamp='1313493667' post='4849799']
You may use [color="#1C2837"]SetMatrixArray to update only 1 matrix too.

How should this work? The function only wants the name of the shader matrix and a number of matrices. It doesn't have a start offset, so I can't say "Update matrix 3 of the array", can I?
[/quote]

Good point. Well, to use SetMatrix[color=#1C2837][size=2], you'll need the handles to the individual matrices.
[color=#1C2837][size=2]

[color=#1C2837][size=2]Cheers!

[quote name='schupf' timestamp='1313495877' post='4849810']
[quote name='kauna' timestamp='1313493667' post='4849799']
You may use [color="#1C2837"]SetMatrixArray to update only 1 matrix too.

How should this work? The function only wants the name of the shader matrix and a number of matrices. It doesn't have a start offset, so I can't say "Update matrix 3 of the array", can I?
[/quote]

Good point. Well, to use SetMatrix[color=#1C2837][size=2], you'll need the handles to the individual matrices.
[color=#1C2837][size=2]

[color=#1C2837][size=2]Cheers!
[/quote]
I have the feeling that its impossible to get the handle to an individual element inside an HLSL array. I guess there is no other way then just updating the whole matrix array for every SubMesh. Even though this means I update some matrices multiple times.

I have the feeling that its impossible to get the handle to an individual element inside an HLSL array. I guess there is no other way then just updating the whole matrix array for every SubMesh. Even though this means I update some matrices multiple times.



Actually it isn't impossible.

[font=arial, sans-serif][size=2]pEffect->GetParameterByName(0, "[/font][color=#1C2837][size=2]mats[0][font=arial, sans-serif][size=2]");[/font]
[font=arial, sans-serif][size=2]pEffect->GetParameterByName(0, "[/font][color=#1C2837][size=2]mats[1][font=arial, sans-serif][size=2]");[/font]
[font="arial, sans-serif"]...[/font]
[font="arial, sans-serif"]
[/font]
[font="arial, sans-serif"]should give you the correct handles.[/font]
[font="arial, sans-serif"]
[/font]
[font="arial, sans-serif"]Best regards![/font]
[font="arial, sans-serif"]
[/font]
Ah cool, sounds good, thanks!

Do you think updating individual matrices is worth the effort it? Or would it be faster to just update all bone matrices for every SubMesh?
In other words:

// This SubMesh only needs bone matrices 0, 2 and 5
constantTable->SetMatrix("mat0", mat0);
constantTable->SetMatrix("mat2", mat2);
constantTable->SetMatrix("mat5", mat5);

vs

// Just update all!
constantTable->SetMatrixArray("mats", mats, 10);

What is faster?

Ah cool, sounds good, thanks!

Do you think updating individual matrices is worth the effort it? Or would it be faster to just update all bone matrices for every SubMesh?
In other words:

// This SubMesh only needs bone matrices 0, 2 and 5
constantTable->SetMatrix("mat0", mat0);
constantTable->SetMatrix("mat2", mat2);
constantTable->SetMatrix("mat5", mat5);

vs

// Just update all!
constantTable->SetMatrixArray("mats", mats, 10);

What is faster?


Which is faster depends on many factors. I'd say that you won't see a difference whichever method you'll decide to use. In general it is good to reduce D3D API calls (although here it is question of the effect api which is a bit different). Perhaps the code will scale up a bit better with the setmatrixarray.

Cheers!

This topic is closed to new replies.

Advertisement