Ragdoll wrong transformation matrix ruins skinned mesh

Started by
3 comments, last by ayush3017 13 years, 4 months ago
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.
Advertisement
I think I should change my question: How to get transformation from rigid bodies (ragdoll actors) and apply it correctly to skinned mesh??
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:



If you still have issues you can addme to msn: camus_mm@hotmail.com
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:



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

Hey Camus, thanks for the reply. I'll try it and post the results.

This topic is closed to new replies.

Advertisement