Sign in to follow this  
ayush3017

Ragdoll wrong transformation matrix ruins skinned mesh

Recommended Posts

Its a DirectX matrix question so I thought this section is appropriate. Ok, here is the problem I was about to complete my game but then my mind demanded more so I thought of applying ragdolls in my game:
1. My game uses nVIDIA PhysX engine.
2. Im currently using hardware skinning.
3. I create my ragdoll using box shapes.
4. The ragdoll creation is ok as I have tested it in Visual debugger.
5. After applying ragdoll I get the transforms of each actor and apply it directly to the skinned mesh. So here is the problem. After applying this my mesh is not drawn correctly. I know that you cannot just apply directly the transforms to the bones but here Im totally clueless. Here are the screens:
Ragdoll switched off
Ragdoll on

And here is the code of ragdoll creation:


void peds::CreateRagdoll()
{
NxQuat qRotLeft, qRotRight, qRotAround;
qRotLeft.fromAngleAxis(90, NxVec3(0,0,1));
qRotRight.fromAngleAxis(-90, NxVec3(0,0,1));
qRotAround.fromAngleAxis(180, NxVec3(0,0,1));
transformation.resize(player.pedsMesh.NumBones());

ragdollActors.resize(player.pedsMesh.NumBones());
//boxMeshes.resize(player.pedsMesh.NumBones());

//Get current bone transforms from skinned mesh and make ragdoll actors
//depending upon the transforms
vector<D3DXMATRIX> a = player.pedsMesh.getTransforms();

//Disable character controller collision
player.pedsMesh.playerController->getActor()->raiseActorFlag(NX_AF_DISABLE_COLLISION);

//-----
///Create Ragdoll Actors////
//-----
/Code removed


for(int x=0 ; x< player.pedsMesh.NumBones() ; x++)
{
NxMat34 b;
b.setColumnMajor44(a[x]);

ragdollActors[x]->setGlobalPosition(b.t);
ragdollActors[x]->setSolverIterationCount(50);
}

//Create Actors
//COde removed


//Transform the ragdoll created to current player position
for(int x=0 ; x<player.pedsMesh.NumBones() ; x++)
{


D3DXMatrixMultiply(&a[x], &a[x], &player.pedsMesh.wowMatrix);
NxMat34 b;
b.setColumnMajor44(a[x]);
ragdollActors[x]->setGlobalPosition(b.t);
ragdollActors[x]->putToSleep();
}
}



Code fo getting actor transforms and applying it to skinned mesh:



if(!ragdollAvailable)
{
//Get current player matrix and apply it to world matrix
effect->SetMatrix("world", &player.pedsMesh.wowMatrix);
//Get bone transforms
effect->SetMatrixArray("gFinalXForms", player.pedsMesh.getFinalXFormArray(), player.pedsMesh.NumBones());
}
else
{

effect->SetMatrix("world", &worldMatrix);
//Get actor transforms and apply it to skined mesh
//<-- This is the wrong stuff --->
for(int x=0 ; x<player.pedsMesh.NumBones() ; x++)
{
// Get actors global pose in world space
ragdollActors[x]->getGlobalPose().getColumnMajor44(transformation[x]);
D3DXMatrixScaling(&scale, 2.5f, 2.5f, 2.5f);
D3DXMatrixMultiply(&transformation[x], &scale, &transformation[x]);
}

//effect->SetMatrix("world", &scale);
effect->SetMatrixArray("gFinalXForms", &transformation[0], player.pedsMesh.NumBones());

}




And here is the most common skinning shader code !


float4x4 world;
float4x4 view;
float4x4 projection;
float3 eyePos;
float4x4 InverseTransposeView;

uniform extern float4x4 gFinalXForms[35];

texture colorMap;
sampler colorMapSampler = sampler_state
{
Texture = <colorMap>;
MinFilter = Anisotropic;
MagFilter = Linear;
MipFilter = Linear;
MaxAnisotropy = 16;
};

struct OutputVS
{
float4 vPos : POSITION0;
float2 vTex0 : TEXCOORD0;
float3 vWorldPos : TEXCOORD1;
float3 vWorldNrm : TEXCOORD2;
float3 eyeVec : TEXCOORD3;
float4 vPos1 : TEXCOORD4;
};


struct OutputPS
{
float4 vMaterial : COLOR0;
float4 vWorldNrm : COLOR1;
float4 vWorldPosXY : COLOR2;
};

OutputVS VS_Lambert(float3 posL : POSITION0,
float3 tangentL : TANGENT0,
float3 binormalL : BINORMAL0,
float3 normalL : NORMAL0,
float2 tex0 : TEXCOORD0,
float4 weight0 : BLENDWEIGHT0,
float4 boneIndex : BLENDINDICES)
{

OutputVS outVS = (OutputVS)0;

float4 vertex = float4(posL, 1);
float LastWeight = 0.0f;
float4 p = 0.0f;
float4 n = 0.0f;

float BlendWeightsArray[4] = (float[4])weight0;
int4 IndexVector = D3DCOLORtoUBYTE4(boneIndex);
int IndexArray[4] = (int[4])IndexVector;


for(int x=0 ; x<3 ; x++)
{
LastWeight = LastWeight + BlendWeightsArray[x];
p += BlendWeightsArray[x] * mul(float4(posL, 1.0f), gFinalXForms[IndexArray[x]]);
n += BlendWeightsArray[x] * mul(float4(normalL, 0.0f), gFinalXForms[IndexArray[x]]);

}

LastWeight = 1.0f - LastWeight;
p += LastWeight * mul(float4(posL, 1.0f), gFinalXForms[IndexArray[3]]);
n += LastWeight * mul(float4(normalL, 0.0f), gFinalXForms[IndexArray[3]]);

// p.w = 1.0f;
//n.w = 0.0f;




n = normalize(n);


float4x4 ViewSpace = mul(world, view);
outVS.vWorldPos = mul(p, ViewSpace);
float3 vWorldPos = mul(p, ViewSpace);
outVS.eyeVec = p.xyz - eyePos;
float4x4 viewProjection = mul(view, projection);
outVS.vPos = mul(float4(outVS.vWorldPos, 1), projection);
outVS.vPos1 = outVS.vPos;
outVS.vTex0 = tex0;

outVS.vWorldNrm = normalize(mul(n, (float3x3) InverseTransposeView));

return outVS;
}

//-----------------------------------------------------------------------------
// Pixel shader.
//-----------------------------------------------------------------------------


OutputPS PS_Lambert(OutputVS i) : COLOR
{
OutputPS o;

float distance1 = distance(i.eyeVec, float3(0, 0, 0));

float4 texColor = tex2D(colorMapSampler, i.vTex0);

distance1 /= 460;

//LOD alpha transition
//clip(texColor - distance1/2);

//clip(texColor.a - 0.2f);


//clip(texColor.a - 0.5f);
o.vMaterial.rgb = texColor * 1.5f;
//o.vMaterial.rgb = float3(0.6f, 0.6f, 0.6f);
o.vMaterial.a = texColor.a;

o.vWorldNrm.xyz = 0.5f * (i.vWorldNrm + 1.0f);
o.vWorldNrm.w = 0.0;

o.vWorldPosXY = float4(i.vWorldPos.xyz, 0);


return o;
}



What should I do to correctly transform my skinned mesh??
Thanks.

Share this post


Link to post
Share on other sites
Hi, I lost the reply refreshing by mistake the current page, the main idea is that actors are in world space, and the bone are in bone space, that's why you get that weird results, use the offset matrix of each bone to set to world space, now you can transform with the actors orientation, and make sure to set actor matrix translation to zero to keep connected the bones, because the actor local axis may or may not be the same of the mesh bone.

ActorMatrix - 4° row to zero
OFFSETMATRIX - Offset bone Matrix
BONEMATRIX - Bone Matrix, transformed by his parents.

M' = OFFSETMATRIX*BONEMATRIX;
FMATRIX = M'*ActorMatrix;

I had the same problem, is just make clear what is on bone space and what is on world space, my results:

http://www.youtube.com/watch?v=IFXVPOROPZM

If you still have issues you can addme to msn: camus_mm@hotmail.com

Share this post


Link to post
Share on other sites
Hi, I lost the reply refreshing by mistake the current page, the main idea is that actors are in world space, and the bone are in bone space, that's why you get that weird results, use the offset matrix of each bone to set to world space, now you can transform with the actors orientation, and make sure to set actor matrix translation to zero to keep connected the bones, because the actor local axis may or may not be the same of the mesh bone.

ActorMatrix - 4° row to zero
OFFSETMATRIX - Offset bone Matrix
BONEMATRIX - Bone Matrix, transformed by his parents.

M' = OFFSETMATRIX*BONEMATRIX;
FMATRIX = M'*ActorMatrix;

I had the same problem, is just make clear what is on bone space and what is on world space, my results:

http://www.youtube.com/watch?v=IFXVPOROPZM

If you still have issues you can addme to msn: camus_mm@hotmail.com

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