# skeletal animation + light = fubar, help?

## Recommended Posts

drdlord    122
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 on other sites
Domini    126
Can you post a screenshot? I'm curious about what this looks like. It may help someone figure it out.

##### Share on other sites
turnpast    1011
Sounds like a problem with normals. Are you using the shader or the World(N) transforms to do the vertex blending?

##### Share on other sites
drdlord    122
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 on other sites
turnpast    1011
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 on other sites
drdlord    122
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 on other sites
yzzid    146
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 on other sites
drdlord    122
Thank you yzzid, can I ask what video card you ran it on? is this a ati vs nvida thing or somthing...

##### Share on other sites
drdlord    122
just updated video drivers, no change :(

##### Share on other sites
afterburn    124
I think your subject needs to be formed with left hand assignment. .....

skeletal animation + light = fubar
fubar = skeletal animation + light

##### Share on other sites
yzzid    146
I ran it on a GeForce 6800.

##### Share on other sites
mhamlin    520
It's fubared on my system, too. I've a Radeon 9800 xt.

##### Share on other sites
drdlord    122
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 on other sites
Jiia    592
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 on other sites
drdlord    122
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 on other sites
yzzid    146
First of all, are you cloning the mesh to an FVF format that includes normals when it is loaded?

##### Share on other sites
Jiia    592
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 on other sites
yzzid    146
Works fine on my Radeon 9600XT also.
Are you sure this is the right project as the mesh isn't really animating? All it does is move around.

##### Share on other sites
drdlord    122
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 on other sites
drdlord    122
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 on other sites
RenderTarget    398
Can you post your rendering code (including where you build your matrix palette after AdvanceTime())?

##### Share on other sites
drdlord    122
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 on other sites
RenderTarget    398
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 on other sites
drdlord    122
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*

## 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