Sign in to follow this  
drdlord

skeletal animation + light = fubar, help?

Recommended Posts

I'm trying to get Direct3D skinning, (skeletal animation, the ablity to move arms etc in a mesh) working. I have it working on tiny.x got her to walk in a nice circle... Then I tried to add lighting... Simply turning on lighting seems to strech her head and arms strangly as if the bone transformation matricies were wrong. I can create and remove this error simply by changing true vs false on m_pd3dDevice->SetRenderState(D3DRS_LIGHTING, TRUE); The lighting itself seems to work, parts of the mesh get darker, (although it's not very smooth, are the normals in tiny.x not right?) Any ideas on what might be causing this? tiny looks perfect when lighting is off. Thank you in advance for helping me figure out this strange error

Share this post


Link to post
Share on other sites
Ok, I've made a screenshot of it with and without light.

http://servers.lanified.wappo.net/skinning_light.jpg
http://servers.lanified.wappo.net/skinning.jpg

I'm using world transforms, I wondered if it was normals so I tried both adding D3DXComputeNormals(this->MeshData.pMesh, NULL);
and m_pd3dDevice->SetRenderState( D3DRS_NORMALIZENORMALS, TRUE ); nether seemed to help.

Any ideas? I've posted my visual studio .net 2003 project including sources here if someone wants to look at it:

http://servers.lanified.wappo.net/skinning.zip

[Edited by - Coder on August 5, 2004 4:51:03 PM]

Share this post


Link to post
Share on other sites
Wow, this it much stranger than I envisioned. I don't think that normals can cause that strange of an effect. Looks more like some of the verts got mis-transformed. You say that this only happens when you turn lighting on? Have you tried using the shader (provided with the blending sample) instead? I am not sure I can help you with this, but perhaps someone else has some ideas. Have you tried it on different graphics cards?

Share this post


Link to post
Share on other sites
Unfortunatly I only have 1 computer with a graphics card worth mentioning, (radeon 9700 pro) so I can't test it on other cards.

I did include the executable in the zip file I posted though so if you have the time please try it and tell me the results, (exe is under debug, move it to the same dir as tiny.x and run; should work, light is enabled in that compile)

as for shaders I havn't learned them yet... but I'll give it a try. Eventualy I want to be able to move bones myself rather than relying on animations in the .x file do shaders allow this?

This is really bugging me I've gone over my code at least a dozen times and I can't see the bug it's pretty close to the indexed shaderless mode of the sample in d3d9.0b under meshes\skinnedmesh and that one works...

Thanks for the ideas hope someone can tell me where I messed up

Share this post


Link to post
Share on other sites
I downloaded the project and everything looks fine on my machine so it doesn't look like anything is wrong with your code.
I would try updating your video drivers.

Share this post


Link to post
Share on other sites
ok, so it's not just me... looks like a ati vs nvidia thing. but the sample skinned mesh works so what am I doing that ati cards hate?

*begins madly running around the room pulling his hair out*

Where am I screwing up???? GAAAAAA!!!!!!

we now return to our sane discussion currently in progress

Share this post


Link to post
Share on other sites
I've had this happen several times! It's most likely that you are forgetting to normalize something, or a matrix is getting messed up somewhere. It might even be something to do with the default values of the matrix / transform.

Are you using D3DX routines to animate?

Share this post


Link to post
Share on other sites
Well I've tried D3DXComputeNormals(this->MeshData.pMesh, NULL);
and m_pd3dDevice->SetRenderState( D3DRS_NORMALIZENORMALS, TRUE ); to fix the normals and it's the tiny.x from the sdk so it should work.

I don't see any matricies messing up and I've looked at least a dozen times, (doesn't mean I'm not blind though...)

The matricies are being initialized with D3DXMatrixIdentity then I'm using a LPD3DXANIMATIONCONTROLLER and setting the time.

Any ideas on what's wrong? or even what section of code to look closer at? As I said I've looked over the whole project quite a few times and I must be blind because I can't see the error. Oh well time to look again I guess... Anyone willing to look at my code and try to help me find what I'm doing wrong?

Share this post


Link to post
Share on other sites
I didn't mean the normals of your vertices. I don't think it's possible to have normals messed up to the point that they stretch the polygons of your mesh. Pretty sure normals just determine how light bounces off of each triangle.

I meant a matrix or quaternion being normalized. When this happened to me, the polygons stretched just as your picture, but when I move the camera, they moved with it. Like certain vertices where attached to the center of the camera vector.

I think mine was because a matrix was out of range; the values of it got messed up. Even though I did several things that caused it to happen, I can't remember what they were :(

Share this post


Link to post
Share on other sites
yzzid: I'm doing the clone if nessisary, (and debug says it isn't) the same way as the sdk sample, I tried forcing it, no luck.

what do you mean isn't animating? on mine the tiny spins slowly as it walks. (that's what it's suposed to do)

Jiia: that sounds likly but I don't see what I'm doing to cause it. The strech doesn't snap to the camera though and I'm not changing the matricies directly yet just using the LPD3DXANIMATIONCONTROLLER to animate them.

update: I tried using identity for all the matricies in the render, without light turned on it worked tiny has arms out and feet together just like a static mesh render of her. Once I turned light on though the parts that used to strech, (head, arms) disapeared... this is getting more confusing to me... I give it the matrix identity it should be in default position not invisible...

Share this post


Link to post
Share on other sites
screenshot of identity problem:

with light enabled:
http://servers.lanified.wappo.net/skinning_identity.jpg

with light disabled:
http://servers.lanified.wappo.net/skinning_identity_no_light.jpg

All I'm doing is changing true vs false on light enable why is that making part of the mesh invisible. It's the standard tiny.x...

Share this post


Link to post
Share on other sites
render starts here:


//--------------------------------------------------------------------
//mesh
//--------------------------------------------------------------------

m_time = 0.01f;
//render mesh
if(m_pmesh != NULL)
{
D3DXMATRIX matRotation;
D3DXMATRIX matResult;
LPD3DXMATRIX matMeshLink = m_pmesh->getWorldMat();

D3DXMatrixRotationY(&matRotation, D3DX_PI/180);
D3DXMatrixMultiply(matMeshLink, matMeshLink, &matRotation);

m_pmesh->setTime(m_time);
m_pmesh->render();
}



m_pmesh->setTime is defined here:


/**
* sets up the bones in the mesh to the appropriate position for the
* given time in the animation uses the world matrix setup in move
* @param time the time in the animation
*/

void Mesh::setTime(float time)
{
if(m_pAnimController != NULL)
m_pAnimController->AdvanceTime(time, NULL);

updateFrame((MY_D3DXFRAME*)m_pFrameRoot, m_worldMatrix);

}

/**
* traverses the bones in a mesh setting them relitave to each other
* @param curFrame the current frame to work on
* @param parentMatrix the matrix of the parent of the current frame
*/

void Mesh::updateFrame( MY_D3DXFRAME *curFrame,
LPD3DXMATRIX parentMatrix )
{
if(curFrame->LinkedTransformationMatrix != NULL)
{
D3DXMatrixMultiply( &curFrame->CombinedTransformationMatrix,
&curFrame->TransformationMatrix,
curFrame->LinkedTransformationMatrix );
}
else
{
D3DXMatrixMultiply( &curFrame->CombinedTransformationMatrix,
&curFrame->TransformationMatrix, parentMatrix );
}

if (curFrame->pFrameSibling != NULL)
updateFrame( (MY_D3DXFRAME*)curFrame->pFrameSibling,
parentMatrix );
if (curFrame->pFrameFirstChild != NULL)
updateFrame( (MY_D3DXFRAME*)curFrame->pFrameFirstChild,
&curFrame->CombinedTransformationMatrix );
}





and m_pmesh->render(); does this



/**
* renders the mesh, (setup world transform before calling)
*/

void Mesh::render()
{
renderFrame(m_pFrameRoot);
}

/**
* renders a frame in the mesh
*/

void Mesh::renderFrame(LPD3DXFRAME frame)
{
MeshInfo *info = (MeshInfo*)frame->pMeshContainer;
while(info != NULL)
{
info->render();
info = (MeshInfo*)info->pNextMeshContainer;
}
if (frame->pFrameSibling != NULL)
renderFrame(frame->pFrameSibling);
if (frame->pFrameFirstChild != NULL)
renderFrame(frame->pFrameFirstChild);
}


/**
* renders the mesh container
*/

void MeshInfo::render()
{
D3DCOLORVALUE blendCol;
blendCol.r = 0.0;
blendCol.g = 0.0;
blendCol.b = 0.0;
blendCol.a = 0.0;

LPDIRECT3DDEVICE9 device;
MeshData.pMesh->GetDevice(&device);

//if skinned mesh
if(pSkinInfo != NULL)
{
if (maxFaceInfl == 1)
device->SetRenderState(D3DRS_VERTEXBLEND, D3DVBF_0WEIGHTS);
else
device->SetRenderState(D3DRS_VERTEXBLEND, maxFaceInfl - 1);

if (maxFaceInfl)
device->SetRenderState(D3DRS_INDEXEDVERTEXBLENDENABLE, TRUE);

D3DXMATRIX matTemp;
//loop through each combination of bones
for (UINT i = 0; i < numBoneCombo; i++)
{
//loop through all posible bones
for (UINT j = 0; j < pSkinInfo->GetNumBones(); j++)
{
UINT index = boneComb[i].BoneId[j];
//if index is UINT_MAX then the bone isn't used in this combo
if (index != UINT_MAX)
{
D3DXMatrixMultiply( &matTemp,
pSkinInfo->GetBoneOffsetMatrix(j),
bones[j] );
device->SetTransform(D3DTS_WORLDMATRIX(j), &matTemp);
}
}

D3DMATERIAL9 tempMat = pMaterials[boneComb[i].AttribId].MatD3D;
tempMat.Diffuse.r = (tempMat.Diffuse.r + blendCol.r)/2;
tempMat.Diffuse.g = (tempMat.Diffuse.g + blendCol.g)/2;
tempMat.Diffuse.b = (tempMat.Diffuse.b + blendCol.b)/2;
tempMat.Diffuse.a = (tempMat.Diffuse.a + blendCol.a)/2;

tempMat.Ambient = tempMat.Diffuse;

device->SetMaterial(&tempMat);
device->SetTexture(0,pTextures[boneComb[i].AttribId]);
MeshData.pMesh->DrawSubset(i);
}

// reset blending state
device->SetRenderState(D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE);
device->SetRenderState(D3DRS_VERTEXBLEND, 0);
}
else //standard mesh
{
device->SetTransform(D3DTS_WORLD, bones[0]);

for (DWORD i = 0; i < NumMaterials; i++)
{
D3DMATERIAL9 tempMat = pMaterials[i].MatD3D;

tempMat.Diffuse.r = (tempMat.Diffuse.r + blendCol.r)/2;
tempMat.Diffuse.g = (tempMat.Diffuse.g + blendCol.g)/2;
tempMat.Diffuse.b = (tempMat.Diffuse.b + blendCol.b)/2;
tempMat.Diffuse.a = (tempMat.Diffuse.a + blendCol.a)/2;

// tempMat.Diffuse = blendCol;
tempMat.Ambient = tempMat.Diffuse;
device->SetMaterial(&tempMat);
device->SetTexture(0, pTextures[i]);
MeshData.pMesh->DrawSubset(i);
}
}
}



does that help?

Share this post


Link to post
Share on other sites
Well, just looking at it I'm seeing something that may or may not help. In MeshInfo::render(), the line

for (UINT j = 0; j < pSkinInfo->GetNumBones(); j++)

is not quite correct unless your entire bone array fits in your matrix palette (in which case you'd only have one bone combination). Should be

for (UINT j = 0; j < dwPaletteSize; j++)

where dwPaletteSize is the value you passed in for paletteSize in ConvertToIndexedBlendedMesh().

Though, I just had a thought. You're using fixed function indexed blending. Are you taking into account the palette size is halved if you're using normals (if lighting is on)? I bet that's the thing: When you convert to the blended mesh, halve the palette size if lighting is on. (It's buried deep in the docs somewhere, and easy to miss; it's so the runtime can use half the available palette for inverse transpose versions of matrices to transform normals behind the scenes.) It'll probably require more draw calls (more bone combinations) but it's a necessity if you're doing fixed-function indexed skinning.

Share this post


Link to post
Share on other sites
YAY!!!! It works!!!! I was asuming the matrix pallet was big enough, (and aparently on some cards it was) stupid assumption though.

Thank you all for replying and helping me out

*does a happy dance*

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