Jump to content
  • Advertisement
Sign in to follow this  
lucky6969b

My skinnedMesh never deforms?

This topic is 2213 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts


void CMesh::Render()
{
RenderFrame(NULL);
}
void CMesh::RenderFrame( Bone *bone )
{
if(bone == NULL)bone = (Bone*)_root;
//If there is a mesh to render...
if(bone->pMeshContainer != NULL)
{
MeshContainer *boneMesh = (MeshContainer*)bone->pMeshContainer;
D3DXMATRIX invWorld;
D3DXMatrixInverse(&invWorld, NULL, &bone->combinedTransform);
D3DXMatrixTranspose(&invWorld, &invWorld);

if (boneMesh->pSkinInfo != NULL)
{


// set up bone transforms
int numBones = boneMesh->pSkinInfo->GetNumBones();
for(int i=0;i < numBones;i++)
{
// boneMatrixPtrs come from combinedMatrix which combined off transformationMatrix
D3DXMatrixMultiply(&boneMesh->currentBoneMatrices,
&boneMesh->boneOffsetMatrices,
boneMesh->boneMatrixPtrs);
}

D3DXMATRIX view, proj, identity;
g_pEffect2->SetMatrixArray("gFinalXForms", boneMesh->currentBoneMatrices, boneMesh->pSkinInfo->GetNumBones());
D3DXMatrixIdentity(&identity);
//Render the mesh
for(int i=0;i < (int)boneMesh->NumAttributeGroups;i++)
{
int mtrlIndex = boneMesh->attributeTable.AttribId;
Mtrl m;
m.ambient = boneMesh->materials[mtrlIndex].Ambient;
m.diffuse = boneMesh->materials[mtrlIndex].Diffuse;
m.spec = boneMesh->materials[mtrlIndex].Specular;
m.specPower = boneMesh->materials[mtrlIndex].Power;
g_pEffect2->SetValue("gMtrl", &m, sizeof(m));


g_pEffect2->SetMatrix("gWVP", &(bone->combinedTransform * m_ViewProj));
g_pEffect2->SetMatrix("gWorld", &bone->combinedTransform);
g_pEffect2->SetMatrix("gWorldInvTrans", &invWorld);

if (!boneMesh->textures.empty())
g_pEffect2->SetTexture("gTex", boneMesh->textures[mtrlIndex]);

D3DXHANDLE hTech = g_pEffect2->GetTechniqueByName("VBlend2Tech");
g_pEffect2->SetTechnique(hTech);
g_pEffect2->Begin(NULL, NULL);
g_pEffect2->BeginPass(0);
boneMesh->MeshData.pMesh->DrawSubset(mtrlIndex);
g_pEffect2->EndPass();
g_pEffect2->End();
}
}
else
{
// Normal mesh
}
}
}
}
if(bone->pFrameSibling != NULL)RenderFrame((Bone*)bone->pFrameSibling);
if(bone->pFrameFirstChild != NULL)RenderFrame((Bone*)bone->pFrameFirstChild);
}


//=============================================================================
// vblend2.fx by Frank Luna (C) 2004 All Rights Reserved.
//
// Does vertex blending with _two_ bone influences per vertex and
// phong directional lighting.
//
// NOTE: Assumes the bone transformations are rigid body so that we
// do not need to apply the inverse transpose. (We do not make
// this assumption with the world matrix though.)
//=============================================================================
struct Mtrl
{
float4 ambient;
float4 diffuse;
float4 spec;
float specPower;
};
struct DirLight
{
float4 ambient;
float4 diffuse;
float4 spec;
float3 dirW;
};
uniform extern float4x4 gWorld;
uniform extern float4x4 gWorldInvTrans;
uniform extern float4x4 gWVP;
uniform extern float4x4 gFinalXForms[100];
uniform extern Mtrl gMtrl;
uniform extern DirLight gLight;
uniform extern float3 gEyePosW;
uniform extern texture gTex;
sampler TexS = sampler_state
{
Texture = <gTex>;
MinFilter = LINEAR;
MagFilter = LINEAR;
MipFilter = LINEAR;
AddressU = WRAP;
AddressV = WRAP;
};
struct OutputVS
{
float4 posH : POSITION0;
float3 normalW : TEXCOORD0;
float3 toEyeW : TEXCOORD1;
float2 tex0 : TEXCOORD2;
};
OutputVS VBlend2VS(float3 posL : POSITION0,
float3 normalL : NORMAL0,
float2 tex0 : TEXCOORD0,
float weight0 : BLENDWEIGHT0,
int4 boneIndex : BLENDINDICES0)
{
// Zero out our output.
OutputVS outVS = (OutputVS)0;
// Do the vertex blending calculation for posL and normalL.
float weight1 = 1.0f - weight0;

float4 p = weight0 * mul(float4(posL, 1.0f), gFinalXForms[boneIndex[0]]);
p += weight1 * mul(float4(posL, 1.0f), gFinalXForms[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).
float4 n = weight0 * mul(float4(normalL, 0.0f), gFinalXForms[boneIndex[0]]);
n += weight1 * mul(float4(normalL, 0.0f), gFinalXForms[boneIndex[1]]);
n.w = 0.0f;
// Transform normal to world space.
outVS.normalW = mul(n, gWorldInvTrans).xyz;
// Transform vertex position to world space.
float3 posW = mul(p, gWorld).xyz;
// Compute the vector from the vertex to the eye.
outVS.toEyeW = gEyePosW - posW;
// Transform to homogeneous clip space.
outVS.posH = mul(p, gWVP);
// Pass on texture coordinates to be interpolated in rasterization.
outVS.tex0 = tex0;
// Done--return the output.
return outVS;
}
float4 VBlend2PS(float3 normalW : TEXCOORD0, float3 toEyeW : TEXCOORD1, float2 tex0 : TEXCOORD2) : COLOR
{
// Interpolated normals can become unnormal--so normalize.
normalW = normalize(normalW);
toEyeW = normalize(toEyeW);
// Light vector is opposite the direction of the light.
float3 lightVecW = -gLight.dirW;
// Compute the reflection vector.
float3 r = reflect(-lightVecW, normalW);
// Determine how much (if any) specular light makes it into the eye.
float t = pow(max(dot(r, toEyeW), 0.0f), gMtrl.specPower);
// Determine the diffuse light intensity that strikes the vertex.
float s = max(dot(lightVecW, normalW), 0.0f);
// Compute the ambient, diffuse and specular terms separatly.
float3 spec = t*(gMtrl.spec*gLight.spec).rgb;
float3 diffuse = s*(gMtrl.diffuse*gLight.diffuse).rgb;
float3 ambient = gMtrl.ambient*gLight.ambient;
// Get the texture color.
float4 texColor = tex2D(TexS, tex0);
// Combine the color from lighting with the texture color.
//float3 color = (ambient + diffuse)*texColor.rgb + spec;
float3 color = (ambient + diffuse).rgb + spec;
// Sum all the terms together and copy over the diffuse alpha.
//return float4(color, gMtrl.diffuse.a*texColor.a);
return float4(color, gMtrl.diffuse.a);
}
technique VBlend2Tech
{
pass P0
{
Lighting = true;
AlphaBlendEnable = TRUE;
DestBlend = INVSRCALPHA;
SrcBlend = SRCALPHA;
// Specify the vertex and pixel shader associated with this pass.
vertexShader = compile vs_2_0 VBlend2VS();
pixelShader = compile ps_2_0 VBlend2PS();
}
}

The skinnedmesh never get affected by the world transformation, nor deformed
I can see the gFinalXForm values changing, there is skininfo for each frame's meshcontainer (not each of them)
Anythings that I need to take care of and I have forgotten?
[attachment=10876:Skin_problem.jpg]
Thanks
Jack Edited by lucky6969b

Share this post


Link to post
Share on other sites
Advertisement
I'm not sure if that is the problem, but in my code if I use mul(matrix, vector) works, but mul(vector, matrix) doesn't. So try to invert them.

Share this post


Link to post
Share on other sites
One additional question, I know that skinned mesh has two types. First is continuous, second is discrete (one mesh for the head, another for the neck etc)
Which one do you prefer?
Thanks
Jack

Share this post


Link to post
Share on other sites
Well, that depends on the kinds of things you want to do with the mesh.
I use a continuous mesh, with instanced skinning. and I also use up to 4 bones for each vertex.
With this method you have less control over the mesh, But you gain a lot of speed.
Did the change I suggest fix the problem? Edited by Such1

Share this post


Link to post
Share on other sites
Sorry, I was traveling, I meant you should invert all of your multiplications, cause they are all inverted. And it seems by the image that you are drawing the faces inverted too, are u useing backface culling? Could you post your updated code then?

Share this post


Link to post
Share on other sites
Hi Such1,
I must say thank you for your time first. One thing remarkable is that when I use fixed pipeline, it does animate. When I use shader, it doesn't work.
I don't know where to specify backface culling anyway...

Rendering code

void CObjects::RenderFrame( FrameEx *bone )
{
if(bone == NULL) return;
//If there is a mesh to render...
if(bone->pMeshContainer != NULL)
{
MeshContainer *boneMesh = (MeshContainer*)bone->pMeshContainer;
D3DXMATRIX invWorld;
D3DXMatrixInverse(&invWorld, NULL, &bone->combinedTransform);
D3DXMatrixTranspose(&invWorld, &invWorld);

if (boneMesh->pSkinInfo != NULL)
{


// set up bone transforms
int numBones = boneMesh->pSkinInfo->GetNumBones();
for(int i=0;i < numBones;i++)
{
// boneMatrixPtrs come from combinedMatrix which combined off transformationMatrix
D3DXMatrixMultiply(&boneMesh->currentBoneMatrices,
&boneMesh->boneOffsetMatrices,
boneMesh->boneMatrixPtrs);
}

D3DXMATRIX view, proj, identity;
g_pEffect2->SetMatrixArray("gFinalXForms", boneMesh->currentBoneMatrices, boneMesh->pSkinInfo->GetNumBones());
D3DXMatrixIdentity(&identity);
//Render the mesh
for(int i=0;i < (int)boneMesh->dwNumAttributeGroups;i++)
{
int mtrlIndex = boneMesh->attributeTable.AttribId;
Mtrl m;
m.ambient = boneMesh->materials[mtrlIndex].Ambient;
m.diffuse = boneMesh->materials[mtrlIndex].Diffuse;
m.spec = boneMesh->materials[mtrlIndex].Specular;
m.specPower = boneMesh->materials[mtrlIndex].Power;
g_pEffect2->SetValue("gMtrl", &m, sizeof(m));


//_effect->SetValue("vMaterialColor", &boneMesh->materials.Diffuse, sizeof(D3DCOLORVALUE));
//m_pDevice->SetMaterial(&(boneMesh->materials[mtrlIndex]));
g_pEffect2->SetMatrix("gWVP", &(bone->combinedTransform * m_ViewProj));
g_pEffect2->SetMatrix("gWorld", &bone->combinedTransform);
g_pEffect2->SetMatrix("gWorldInvTrans", &invWorld);

// if (!boneMesh->textures.empty())
// g_pEffect2->SetTexture("gTex", boneMesh->textures[mtrlIndex]);

D3DXHANDLE hTech = g_pEffect2->GetTechniqueByName("VBlend2Tech");
g_pEffect2->SetTechnique(hTech);
g_pEffect2->Begin(NULL, NULL);
g_pEffect2->BeginPass(0);
boneMesh->MeshData.pMesh->DrawSubset(mtrlIndex);
g_pEffect2->EndPass();
g_pEffect2->End();
}
}
else
{
//Normal Static Mesh
g_pEffect1->SetMatrix("gWVP", &(bone->combinedTransform * m_ViewProj));
g_pEffect1->SetMatrix("gWorld", &bone->combinedTransform);
g_pEffect1->SetMatrix("gWorldInvTrans", &invWorld);
D3DXHANDLE hTech = g_pEffect1->GetTechniqueByName("PhongDirLtTexTech");
g_pEffect1->SetTechnique(hTech);
//Render the mesh
for(int i=0;i < (int)boneMesh->materials.size();i++)
{
if (boneMesh->materials.Diffuse.a == 1.0f)
{
//g_pEffect1->SetValue("vMaterialColor", &boneMesh->materials.Diffuse, sizeof(D3DCOLORVALUE));
//m_pDevice->SetMaterial(&boneMesh->materials);
Mtrl m;
m.ambient = boneMesh->materials.Ambient;
m.diffuse = boneMesh->materials.Diffuse;
m.spec = boneMesh->materials.Specular;
m.specPower = boneMesh->materials.Power;
g_pEffect1->SetValue("gMtrl", &m, sizeof(m));

// if (!boneMesh->textures.empty())
// g_pEffect1->SetTexture("gTex", boneMesh->textures);
g_pEffect1->Begin(NULL, NULL);
g_pEffect1->BeginPass(0);
boneMesh->MeshData.pMesh->DrawSubset(i);
g_pEffect1->EndPass();
g_pEffect1->End();
}

}
}
if(bone->pFrameSibling != NULL)RenderFrame((FrameEx*)bone->pFrameSibling);
if(bone->pFrameFirstChild != NULL)RenderFrame((FrameEx*)bone->pFrameFirstChild);

}


skinning.fx

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

// Do the vertex blending calculation for posL and normalL.
float weight1 = 1.0f - weight0;

float4 p = weight0 * mul(gFinalXForms[boneIndex[0]],float4(posL, 1.0f));
p += weight1 * mul(gFinalXForms[boneIndex[1]],float4(posL, 1.0f));
p.w = 1.0f;

// We can use the same matrix to transform normals since we are assuming
// no scaling (i.e., rigid-body).
float4 n = weight0 * mul(gFinalXForms[boneIndex[0]],float4(normalL, 0.0f));
n += weight1 * mul(gFinalXForms[boneIndex[1]],float4(normalL, 0.0f));
n.w = 0.0f;
// Transform normal to world space.
outVS.normalW = mul(gWorldInvTrans,n).xyz;

// Transform vertex position to world space.
float3 posW = mul(gWorld,p).xyz;

// Compute the vector from the vertex to the eye.
outVS.toEyeW = gEyePosW - posW;

// Transform to homogeneous clip space.
outVS.posH = mul(gWVP,p );

// Pass on texture coordinates to be interpolated in rasterization.
outVS.tex0 = tex0;
// Done--return the output.
return outVS;
}
Edited by lucky6969b

Share this post


Link to post
Share on other sites
Here is the fixed pipeline code that works for blended meshes, but not working quite well for static meshes

void CObject::RenderFrame(LPD3DXFRAME pFrame)
{
if(pFrame == NULL)
return;
LPD3DXMESHCONTAINER pCurMeshContainer = pFrame->pMeshContainer;
while(pCurMeshContainer != NULL)
{
MESHCONTAINER *pMeshContainer = (MESHCONTAINER*)pCurMeshContainer;
if(pMeshContainer != NULL)
{
if(pMeshContainer->pSkinInfo != NULL)
{
if(m_pMesh->IsVertexBlending()) // non-indexed hardware skinning
{
DWORD AttribIdPrev = UNUSED32;
LPD3DXBONECOMBINATION pBoneComb = (LPD3DXBONECOMBINATION)pMeshContainer->pBoneCombinationBuf->GetBufferPointer();
D3DXMATRIX matTemp;

// draw using default vtx processing of the device (typically HW)
for (int iAttrib = 0; iAttrib < pMeshContainer->dwNumAttributeGroups; iAttrib++)
{
DWORD NumBlend = 0;
for (DWORD i = 0; i < pMeshContainer->dwNumInfl; ++i)
if (pBoneComb[iAttrib].BoneId != UINT_MAX)
NumBlend = i;
// first calculate the world matrices for the current set of blend weights and get the accurate count of the number of blends
for (DWORD i = 0; i < pMeshContainer->dwNumInfl; ++i)
{
int iMatrixIndex = pBoneComb[iAttrib].BoneId;
if (iMatrixIndex != UINT_MAX)
{
D3DXMatrixMultiply( &matTemp, &pMeshContainer->pBoneOffsetMatrices[iMatrixIndex], pMeshContainer->ppBoneMatrixPtrs[iMatrixIndex] );
m_pDevice->SetTransform( D3DTS_WORLDMATRIX( i ), &matTemp );
}
}
m_pDevice->SetRenderState(D3DRS_VERTEXBLEND, NumBlend);
// lookup the material used for this subset of faces
if ((AttribIdPrev != pBoneComb[iAttrib].AttribId) || (AttribIdPrev == UNUSED32))
{
m_pDevice->SetMaterial( &pMeshContainer->pMaterials[pBoneComb[iAttrib].AttribId].MatD3D );
m_pDevice->SetTexture( 0, pMeshContainer->ppTextures[pBoneComb[iAttrib].AttribId] );
AttribIdPrev = pBoneComb[iAttrib].AttribId;
}
// draw the subset now that the correct material and matrices are loaded
pMeshContainer->MeshData.pMesh->DrawSubset(iAttrib);
}
m_pDevice->SetRenderState(D3DRS_VERTEXBLEND, false);
}
else // use software skinning
{
D3DXMATRIX matIdentity;
DWORD cBones = pMeshContainer->pSkinInfo->GetNumBones();
DWORD iBone;
PBYTE pbVerticesSrc;
PBYTE pbVerticesDest;
// set up bone transforms
for (iBone = 0; iBone < cBones; ++iBone)
{
D3DXMatrixMultiply(&pMeshContainer->pBoneMatrices[iBone],
&pMeshContainer->pBoneOffsetMatrices[iBone],
pMeshContainer->ppBoneMatrixPtrs[iBone]
);
}
// set world transform to identity or else will get previous object's transformation
D3DXMatrixIdentity(&matIdentity);
m_pDevice->SetTransform(D3DTS_WORLD, &matIdentity);
pMeshContainer->pOrigMesh->LockVertexBuffer(D3DLOCK_READONLY, (LPVOID*)&pbVerticesSrc);
pMeshContainer->MeshData.pMesh->LockVertexBuffer(0, (LPVOID*)&pbVerticesDest);
// generate skinned mesh
pMeshContainer->pSkinInfo->UpdateSkinnedMesh(
pMeshContainer->pBoneMatrices, NULL, pbVerticesSrc, pbVerticesDest);
pMeshContainer->pOrigMesh->UnlockVertexBuffer();
pMeshContainer->MeshData.pMesh->UnlockVertexBuffer();
for (DWORD iAttrib = 0; iAttrib < pMeshContainer->dwNumAttributeGroups; iAttrib++)
{
m_pDevice->SetMaterial(&(pMeshContainer->pMaterials[pMeshContainer->pAttributeTable[iAttrib].AttribId].MatD3D));
m_pDevice->SetTexture(0, pMeshContainer->ppTextures[pMeshContainer->pAttributeTable[iAttrib].AttribId]);
pMeshContainer->MeshData.pMesh->DrawSubset(pMeshContainer->pAttributeTable[iAttrib].AttribId);
}
}
}
else
{
// static mesh
m_pDevice->SetTransform(D3DTS_WORLD, &m_matWorld);
for(int i = 0; i < pFrame->pMeshContainer->NumMaterials; i++)
{
m_pDevice->SetMaterial(&pFrame->pMeshContainer->pMaterials.MatD3D);
m_pDevice->SetTexture(0, pMeshContainer->ppTextures);
pMeshContainer->MeshData.pMesh->DrawSubset(i);
}
}
}
pCurMeshContainer = pCurMeshContainer->pNextMeshContainer;
}
// go down the tree
if(pFrame->pFrameFirstChild != NULL)
RenderFrame(pFrame->pFrameFirstChild);
if(pFrame->pFrameSibling != NULL)
RenderFrame(pFrame->pFrameSibling);
}

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!