Sign in to follow this  
MichaelWojcik

Generating correct bone indices in the vertex structure

Recommended Posts

Hello I am implementing animation into my game although I am currently stuck. I have gotten animation to work before with my CActor class that encapsulates the d3dx animation system and am quite experienced with it. But it is the first time I am doing it with shaders ( via hlsl ). And I have narrowed down the problem ( through playing around with my shader and other tests ) that the bone indices are not correct. The shader is not indexing into the correct final tranformations of its corresponding bone. I make the call to ConvertToIndexedBlendedMesh to convert the mesh to a skinned mesh. This should be responsible for generating the correct vertex data including bone indices. // Convert the mesh to a skinned mesh hRet = pSkinInfo->ConvertToIndexedBlendedMesh( pMesh, D3DXMESHOPT_VERTEXCACHE, pSkinInfo->GetNumBones(), pMeshContainer->pAdjacency, pMeshContainer->pAdjacency, NULL, NULL, &pMeshContainer->InfluenceCount, &pMeshContainer->AttribGroupCount, &pMeshContainer->pBoneCombination, pMeshOut ); if ( FAILED(hRet) ) return hRet; In my current case, I have a cube that has a root bone ( it is not animated ) and a single child bone that influences all the vertices 1.0 and is animated by performing a uniform scaleon the cube in the x,y,z. When I load the animated mesh, it does not move at all. But it is only when I manually go into the shader and replace the code like this. // Snippit from the animated mesh's shader where boneIndex is int4 boneIndex : BLENDINDICES0 and gFinalMatrixForms is a matrix array contianing the final tranforms for each bones tranformation matrix // From this float4 p = weight0 * mul(float4(posL, 1.0f), gFinalMatrixForms[boneIndex[0]]); // to this float4 p = weight0 * mul(float4(posL, 1.0f), gFinalMatrixForms[1]); This makes the mesh animate, which makes sence because in the case above, the gFinalMatrixForms[1] is the animated bone's final transformation matrix index ( the child scaling bone ). So my question is, what are some possibilities I may be doing wrong for generating incorrect bone indices for the vertices? I Appreciate it Thanks

Share this post


Link to post
Share on other sites
One thing you could try is using PIX to examine the vertex buffer, and draw calls.

You'd probably get better advice if you posted the code that you use to write the indices into the vertex buffer, along with the shader and vertex declaration. The chances are that at least one of those three isn't correct.

Share this post


Link to post
Share on other sites
There could be a couple reasons why you're shader doesn't work correctly.

I doubt this has any relation to your problem, but: is there a reason why you need the adjacency information? If not, set your adjacency arguments to NULL in ConvertToIndexedBlendedMesh. I've never used the same table for both adjacency in and out. If you do need the adjacency info, you might try using separate tables for in and out. Do you generate the adjacency info from the mesh prior to that call?

It's more likely that the indices are being generated correctly and your problems lie elsewhere. Have you actually examined the indices generated to confirm they're incorrect?

Are you sure you're loading the final transforms correctly into the shader? Are you sure your shader input arguments and semantics are correct?

Share this post


Link to post
Share on other sites
Thanks for the replies


"It's more likely that the indices are being generated correctly and your problems lie elsewhere."


The reason I thought otherwise was becuase I tested each gFinalMatrixForms[ boneIndex[x] ] manually plugging in values 0 to 3 for x but none of the indices seemed to work. For this mesh only gFinalMatrixForms[ 1 ] has been working thus far.


"Have you actually examined the indices generated to confirm they're incorrect?"


I havent seen what values they hold, how do I check them?

This is my vertex declaration before and after the ConvertToIndexedBlendedMesh call

Vertex Format Before ConvertToIndexedBlendedMesh
Type = D3DDECLTYPE_FLOAT3; Usage = D3DDECLUSAGE_POSITION
Type = D3DDECLTYPE_FLOAT3; Usage = D3DDECLUSAGE_TANGENT
Type = D3DDECLTYPE_FLOAT3; Usage = D3DDECLUSAGE_BINORMAL
Type = D3DDECLTYPE_FLOAT3; Usage = D3DDECLUSAGE_NORMAL
Type = D3DDECLTYPE_FLOAT2; Usage = D3DDECLUSAGE_TEXCOORD

Vertex Format After ConvertToIndexedBlendedMesh
Type = D3DDECLTYPE_FLOAT3; Usage = D3DDECLUSAGE_POSITION
Type = D3DDECLTYPE_UBYTE4; Usage = D3DDECLUSAGE_BLENDINDICES
Type = D3DDECLTYPE_FLOAT3; Usage = D3DDECLUSAGE_TANGENT
Type = D3DDECLTYPE_FLOAT3; Usage = D3DDECLUSAGE_BINORMAL
Type = D3DDECLTYPE_FLOAT3; Usage = D3DDECLUSAGE_NORMAL
Type = D3DDECLTYPE_FLOAT2; Usage = D3DDECLUSAGE_TEXCOORD

On a side note, and it may be already clear, but I believe there is no weight semantic here becuase there is only 1 weight in this animated mesh. And in the shader I perform the differance to generate the lastWeight.

Heres the shader code for the relavent area of vertex/normal blending. At the moment, only two weights are supported for the shader.

OutputVS NormalMapDirLightVS(float3 posL : POSITION0,
float3 tangentL : TANGENT0,
float3 binormalL : BINORMAL0,
float3 normalL : NORMAL0,
float2 tex0 : TEXCOORD0,
float weight0 : BLENDWEIGHT0,
int4 boneIndex : BLENDINDICES0)
{
// Zero out our output.
OutputVS outVS = (OutputVS)0;

// FIRST Lets vertex blend ( Skin )

float LastWeight = 1.0f - weight0;

// If there is only one weight.// Not sure to keep this or not just yet
if( LastWeight == 1.0f )
{
// Let the first weight have full influence and zero out
// the other final transforms
weight0 = 1.0f;
LastWeight = 0.0f;
}

//POSITION BLEND
float4 p = weight0 * mul(float4(posL, 1.0f), gFinalMatrixForms[boneIndex[0]]);
p += LastWeight * mul(float4(posL, 1.0f), gFinalMatrixForms[boneIndex[1]]);
p.w = 1.0f;

// We can use the same matrix to transform normals since we are assuming
// no scaling (i.e., rigid-body).

// NORMAL BLEND
float4 NormalL = weight0 * mul(float4(normalL, 0.0f), gFinalMatrixForms[boneIndex[0]]);
NormalL += LastWeight * mul(float4(normalL, 0.0f), gFinalMatrixForms[boneIndex[1]]);
NormalL.w = 0.0f;

// BINORMAL BLEND
float4 BiNormalL = weight0 * mul(float4(binormalL, 0.0f), gFinalMatrixForms[boneIndex[0]]);
BiNormalL += LastWeight * mul(float4(binormalL, 0.0f), gFinalMatrixForms[boneIndex[1]]);
BiNormalL.w = 0.0f;

// TANGENT BLEND
float4 TangentL = weight0 * mul(float4(tangentL, 0.0f), gFinalMatrixForms[boneIndex[0]]);
TangentL += LastWeight * mul(float4(tangentL, 0.0f), gFinalMatrixForms[boneIndex[1]]);
TangentL.w = 0.0f;


.......

"You'd probably get better advice if you posted the code that you use to write the indices into the vertex buffer"

The cube draws fine, so I figured that the vertex indices of the mesh ( not the bone indices ) are correct. Am I incorrect though in thinking this?

Thanks all, further advice is apprecaited. I am more than willing to explain more if I have too.

[Edited by - MichaelWojcik on December 23, 2009 6:40:52 PM]

Share this post


Link to post
Share on other sites
"Are you sure you're loading the final transforms correctly into the shader? Are you sure your shader input arguments and semantics are correct?"

I double checked and there doesent seem to be anything wrong that I know of. I set the shader parameter like so...

HR(pFX->SetMatrixArray (pMesh->m_hFinalMatrixForms, &m_FinalMtxFrameArray[0], pSkinInfo->GetNumBones() ));

where is m_FinalMtxFrameArray is an stdvector continaing the final transformation matrices for each bone.

"is there a reason why you need the adjacency information?"

I changed my call to ConvertToIndexedBlendedMesh like so, but the mesh continues to remain still.

// Convert the mesh to a skinned mesh
hRet = pSkinInfo->ConvertToIndexedBlendedMesh( pMesh, D3DXMESH_MANAGED | D3DXMESH_WRITEONLY, pSkinInfo->GetNumBones(),
0, 0, NULL, NULL,
&pMeshContainer->InfluenceCount,
&pMeshContainer->AttribGroupCount,
&pMeshContainer->pBoneCombination,
pMeshOut );
if ( FAILED(hRet) ) return hRet;

Share this post


Link to post
Share on other sites
You can look at any of the vertices by typedef'ing a structure equivalent to the vertex structure of the mesh. Then lock the mesh vertex buffer, getting a pointer to the vertices. Use a debug routine to look at the vertices.

Something like:

typedef struct TEST_VERTS {
D3DXVECTOR3 pos;
unsigned char indices[4];
D3DXVECTOR3 tangent, binormal, normal;
D3DXVECTOR2 texCoords;
};

TEST_VERTS *vb;
mesh->LockVertexBuffer(0,(LPVOID)&vb);
// look at the vertices vb[0], vb[1], etc.
mesh->UnlockVertexBuffer();

Share this post


Link to post
Share on other sites
That was informative, Thanks.

For every vertex, all four bone indices are zero. Becuase of this, I would think that the shader has no part into the problem. Since ConvertToIndexedBlendedMesh is not generating blend indices ( just filling all the blend indices to zero ) it would seem to be a problem with ConvertToIndexedBlendedMesh function itself, or somthing before that. I've been examining if my contruction of the skininfo is correct and so far I have not seen not problems with it. Has anyone else had problems with ConvertToIndexedBlendedMesh in this way before? I will continue reviewing the ConvertToIndexedBlendedMesh function and before that as well. As always any further advice is welcomed :)

[Edited by - MichaelWojcik on December 24, 2009 4:39:27 PM]

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this