$20 to anyone who can figure out whats wrong with this code.

Started by
26 comments, last by phresnel 15 years, 3 months ago
Well I have been spending way to much time on this problem, I'm trying to get matrices from PhysX to work with my skinning shader so I can create ragdolls but I can't figure out how to change the center of rotation so that it lines up with the bone. I will give anyone who can figure it out $20 through paypal also if your post helps me figure it out I will still give you the $20.


	void Render( D3DXMATRIX mView, D3DXMATRIX mProj )
	{
		D3DXMATRIX inv_base_bone, inv_rb_world, rb_world, inv_world, world, rot, pos, inv_pos; // Define Matices.
		vector<D3DXMATRIX> matrices; // Create matrix array.
		matrices.resize(bones.size()); // Resize matrix array to fit all bone actors
		bones[mesh->root_bone]->getGlobalPose().getColumnMajor44( rb_world); // Get root bone matrix.
		D3DXMatrixInverse( &inv_rb_world, NULL, &rb_world); // Inverse root bone matrix.
		D3DXMatrixMultiply( &inv_world, &inv_rb_world, &mesh->bones[mesh->root_bone].matrix  ); // Get inversed world matrix.
		D3DXMatrixInverse( &world, NULL, &inv_world); // Get world matrix
		for(UINT i = 0; i < bones.size(); i++ )
		{
			bones->getGlobalPose().getColumnMajor44( matrices ); // Get world space bone matrix.
			if( mesh->bones.size() > 0) // Check if there are any bones in this mesh, if not then this bone actor was created from the mesh and should be in world space. 
			{
				D3DXMatrixMultiply( &matrices, &matrices, &inv_world ); // Bring the bone in to model space.
				D3DXMatrixInverse( &inv_base_bone, NULL, &mesh->bones.matrix ); // Get the inverse of the bone's model space matrix. 
				D3DXMatrixMultiply( &matrices, &inv_base_bone, &matrices ); // Multiply the matrix by the inverse of the bone's model space matrix so that the bone moves by the difference.

				// I thought the code below would give the matrix the correct center of rotation but it's still at the origin.
				D3DXMatrixTranslation( &pos, mesh->bones.matrix._41, mesh->bones.matrix._42, mesh->bones.matrix._43 ); // Create translation matrix with zero rotation.
				rot = matrices; // Create rotation matrix.
				rot._41 = 0; rot._42 = 0;rot._43 = 0; // Set rotation matrix's translation to [0, 0 ,0]
				D3DXMatrixMultiply( &matrices, &pos, &rot ); // Rotate the matrix with a correct translation.
				D3DXMatrixInverse( &inv_pos, NULL, &pos ); // Get the inverse of the translation matrix. 
				D3DXMatrixMultiply( &matrices, &matrices, &inv_pos ); // Correct the translation back.

				D3DXMatrixMultiply( &matrices, &matrices, &world ); // Put the bone back in to world space.
			}
		}
		mesh->Render( matrices, mView, mProj ); // Send all bone matrices, view matrix and the projection matrix to be rendered.
		matrices.clear(); // Delete the list of matrices.
	}



Shader source:

Texture2D txDiffuse
< 
string UIName = "Base Texture";
>;
SamplerState samLinear
{
    Filter = MIN_MAG_MIP_LINEAR;
    AddressU = Wrap;
    AddressV = Wrap;
};

TextureCube txEnvironment
<
string UIName = "Environment Map";
>;
SamplerState envSampler
{
	Filter = MIN_MAG_MIP_LINEAR;
	AddressU = Clamp;
	AddressV = Clamp;
	AddressW = Clamp;
};

float Environment_map_intensity
<
	string UIName = "Intensity";
	float UIMin = 0.000000;
	float UIMax = 1.000000;
	float UIStep = 0.01;
	string UIWidget = "slider";
> = 1.000000;

float4 Ambient  <
	string UIName = "Ambient";
> = float4( 0.47f, 0.47f, 0.47f, 1.0f );
	
float4 Diffuse  <
	string UIName = "Diffuse";
> = float4( 0.47f, 0.47f, 0.47f, 1.0f );

float4 lightPos : Position <  string UIName = "Light Position"; string Object = "PointLight";> ={0.0f, 0.0f, -10.0f, 0.0f};

float4x4 World				: WORLD;
float4x4 View				: WORLDVIEW;
float4x4 Projection			: PROJECTION;
float4x4 Bones[256]			: WORLDMATRIXARRAY;

struct VS_INPUT
{
	float4 pos			: POSITION;
	float3 norm			: NORMAL;
	float2 tex			: TEXCOORD0;
	float4 bw			: TEXCOORD1;
	float4 bi			: TEXCOORD2;
};

struct PS_INPUT
{
	float4 pos			: SV_POSITION;
	float4 pos2			: POSITION;
	float2 tex			: TEXCOORD0;
	float3 norm			: NORMAL;
};


PS_INPUT VS( VS_INPUT In )
{
	PS_INPUT Out = (PS_INPUT)0;
   	Out.pos = 0;
    	Out.pos += mul(In.pos, Bones[In.bi.x]) * In.bw.x;
    	Out.pos += mul(In.pos, Bones[In.bi.y]) * In.bw.y;
    	Out.pos += mul(In.pos, Bones[In.bi.z]) * In.bw.z;
    	Out.pos += mul(In.pos, Bones[In.bi.w]) * In.bw.w;

	Out.norm = 0;

	Out.norm += mul(In.norm, (float3x3)Bones[In.bi.x]) * In.bw.x;
	Out.norm += mul(In.norm, (float3x3)Bones[In.bi.y]) * In.bw.y;
	Out.norm += mul(In.norm, (float3x3)Bones[In.bi.z]) * In.bw.z;
	Out.norm += mul(In.norm, (float3x3)Bones[In.bi.w]) * In.bw.w;

    	Out.pos = mul(mul(Out.pos, View), Projection);
	Out.tex = In.tex;
	return Out;
}


float4 PS( PS_INPUT input) : SV_Target
{
float4 color = txDiffuse.Sample( samLinear, input.tex );
float a = color.w;
color = (color * (dot(input.norm,normalize(input.pos2-lightPos)))) + ( Environment_map_intensity * txEnvironment.Sample( envSampler, -reflect( normalize( input.pos2 - View[3] ).xyz, input.norm.xyz )));
color.w = a;
return color;
}

technique10 Render
{
	pass P0
	{
		SetVertexShader( CompileShader( vs_4_0, VS() ) );
		SetGeometryShader( NULL );
		SetPixelShader( CompileShader( ps_4_0, PS() ) );
	}
}



[Edited by - CodaKiller on January 20, 2009 11:33:12 AM]
Remember Codeka is my alternate account, just remember that!
Advertisement
The people here will gladly help you solve problems for free. You having offered money makes me feel uneasy about replying to this.

    vector<D3DXMATRIX> matrices; // Create matrix array.    matrices.resize(bones.size()); // Resize matrix array to fit all bone actors
Your comments are redundant, but you can better write this like so:
    vector<D3DXMATRIX> matrices( bones.size() );


    bones[mesh->root_bone]->getGlobalPose().getColumnMajor44( rb_world); // Get root bone matrix.
It's more idiomatic to have that return something rather than using references. It took a lot of staring before I understood. This is the only reason I'm not complaining about a redundant comment again.

    D3DXMatrixInverse( &inv_rb_world, NULL, &rb_world); // Inverse root bone matrix.    D3DXMatrixMultiply( &inv_world, &inv_rb_world, &mesh->bones[mesh->root_bone].matrix  ); // Get inversed world matrix.    D3DXMatrixInverse( &world, NULL, &inv_world); // Get world matrix
Again, the comments are redundant, but here's where some good ones could really help someone like me who doesn't know much about graphics understand what's happening. It can also help knowledgeable people understand what you're doing better, sometimes. Why are you doing this? To what end? The answers would be in good commenting. The comments that are the are redundant because one can deduce WHAT you're doing without any real effort by looking at the names of the functions and arguments, but WHY is not so obvious.

    for(UINT i = 0; i < bones.size(); i++ )    {        bones->getGlobalPose().getColumnMajor44( matrices ); // Get world space bone matrix.        if( mesh->bones.size() > 0) // Check if there are any bones in this mesh, if not then this bone actor was created from the mesh and should be in world space.
This is just confusing. I don't know the difference between bones and mesh->bones and even if you explained it, the name collision, unless actually very meaningful, will be hard to understand.

    // I thought the code below would give the matrix the correct center of rotation but it's still at the origin.    D3DXMatrixTranslation( &pos, mesh->bones.matrix._41, mesh->bones.matrix._42, mesh->bones.matrix._43 );
Now, we're getting somewhere. My googling says that this function inputs an output, x, y, and z. What's this 41, 42, 43 crap? I mean, 41, 2, and 3 are A, B, and C on the hex ASCII table (again, googled), but why?

So it's still at the origin? Through debugging, have you determined that pos is zero when it goes into and comes our of this function? Then, the logical conclusion would be that mesh->bones.matrix._41, 2, and 3 are zero as well. Your problem then is with how they are initialized.

    matrices.clear(); // Delete the list of matrices.
This is done for you by the std::vector's destructor.

Ironically, there's no commenting in your shader source, but I don't know shader and don't have the patience to read it right now (sorry).
Quote:Original post by Splinter of Chaos
*snip*


The reason he is offering money is because he keeps asking for help on this problem but nobody is ever able to help him. Just look at his posting history. The redundant comments is probably him trying to make it more enticing for people to provide help.

41, 42, 43, etc are probably members of a 4x4 matrix. The first number is the row, the second number is the column (I assume).

@CodaKiller:
Can you please, very clearly, explain what you're trying to do and your problem? Without code? What center of rotation are you trying to change, and what bone are you trying to line it up with, and why do you have to change the center of rotation?
[size=2][ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]
Quote:Original post by MikeTacular
explain what you're trying to do and your problem?


Character animation / Ragdolls / bending joints with smooth skinning weights and indices by a matrix from a PhysX actor.

Quote:Original post by MikeTacular
What center of rotation are you trying to change?




Quote:Original post by MikeTacular
why do you have to change the center of rotation?





I know that the actors that make up the skeleton for this mesh are set up correctly since I can view it through the PhysX visual debugger as seen below:


Quote:Original post by Splinter of Chaos
    for(UINT i = 0; i < bones.size(); i++ )    {        bones->getGlobalPose().getColumnMajor44( matrices ); // Get world space bone matrix.        if( mesh->bones.size() > 0) // Check if there are any bones in this mesh, if not then this bone actor was created from the mesh and should be in world space.
This is just confusing. I don't know the difference between bones and mesh->bones and even if you explained it, the name collision, unless actually very meaningful, will be hard to understand.


mesh->bones are the bones that are in the mesh, bones are the actors in the PhysX scene. mesh->bones.matrix is set in model space or in other words the same space in which vertices are in, the mesh bones are where I got the position of the scene bones and the parent child relationship to create the joints with.

[Edited by - CodaKiller on January 20, 2009 5:17:00 PM]
Remember Codeka is my alternate account, just remember that!
Quote:Original post by MikeTacular
The reason he is offering money is because he keeps asking for help on this problem but nobody is ever able to help him. Just look at his posting history. The redundant comments is probably him trying to make it more enticing for people to provide help.


I see. Codakiller, if you're willing to pay, perhaps you might have luck getting professional help at a place where such a thing is offered. It feels dirty to have that kind of transaction going on here.

BTW: I forgot to ask: Have you gone through, line by line, with a debugger? This seems like just the type of problem they're great at.
Quote:Original post by CodaKiller
Quote:Original post by MikeTacular
why do you have to change the center of rotation?




When rendering, are you translating before rotating, or rotating before translating? In that picture it looks like you're doing the latter when you want the former. It seems like it should be simple (but maybe I'm missing something):

1) Get the world matrix for each bone
2) Translate to the bone's position
3) Rotate according to the bone's angle
4) Render the stuff connected to that bone

However, if you can get some relative matrix (as opposed to a world matrix) you can multiply the current matrix by that relative matrix and get the new matrix.

P.S. Very nice pictures, it's helping clarify things a lot.
[size=2][ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]
Quote:Original post by Splinter of Chaos
Quote:Original post by MikeTacular
The reason he is offering money is because he keeps asking for help on this problem but nobody is ever able to help him. Just look at his posting history. The redundant comments is probably him trying to make it more enticing for people to provide help.


I see. Codakiller, if you're willing to pay, perhaps you might have luck getting professional help at a place where such a thing is offered. It feels dirty to have that kind of transaction going on here.

BTW: I forgot to ask: Have you gone through, line by line, with a debugger? This seems like just the type of problem they're great at.


What do you mean? There is nothing to debug, I just don't know how to do the math needed and I have payed someone for helping me before, it's not a big deal.

I figure if I have wasted over 80 hours of my life on something it's well worth $20 to find the answer.
Remember Codeka is my alternate account, just remember that!
Quote:Original post by MikeTacular
Quote:Original post by CodaKiller
Quote:Original post by MikeTacular
why do you have to change the center of rotation?




When rendering, are you translating before rotating, or rotating before translating? In that picture it looks like you're doing the latter when you want the former. It seems like it should be simple (but maybe I'm missing something):

1) Get the world matrix for each bone
2) Translate to the bone's position
3) Rotate according to the bone's angle
4) Render the stuff connected to that bone

However, if you can get some relative matrix (as opposed to a world matrix) you can multiply the current matrix by that relative matrix and get the new matrix.

P.S. Very nice pictures, it's helping clarify things a lot.


Thats just it, it seems simple but when I actually do it nothing happens, I know it's an error in the way I am calculating it but I have no idea whats wrong.

EDIT: Wait no, I believe it is offsetting the center of rotation but it's way off from where it should be.

[Edited by - CodaKiller on January 20, 2009 6:14:26 PM]
Remember Codeka is my alternate account, just remember that!
"D3DXMatrixTranslation( &pos, mesh->bones.matrix._41, mesh->bones.matrix._42, mesh->bones.matrix._43 );"

This provides a ROW MAJOR matrix. You have taken that into account have you?

Try to transpose it, just for fun.
This may help, it's basically exactly what I do in opengl for rotating around a specified origin:
   glPushMatrix();   if(!translateTo.atOrigin()){      glTranslated(translateTo.x, translateTo.y, translateTo.z);   }   if(!scaleTo.atOrigin()){      glScaled(scaleTo.x, scaleTo.y, scaleTo.z);   }   if(!rotateTo.atOrigin()){      glTranslated(rotateOrigin.x, rotateOrigin.y, rotateOrigin.z);      glRotated(rotateTo.x, 1.0, 0.0, 0.0);      glRotated(rotateTo.y, 0.0, 1.0, 0.0);      glRotated(rotateTo.z, 0.0, 0.0, 1.0);      glTranslated(-rotateOrigin.x, -rotateOrigin.y, -rotateOrigin.z);   }   drawthebone   glPopMatrix()


NOTE: atOrigin() is a function that basically checks to see if the vector is 0, 0, 0

See the rotate part? That's where you can specify to rotate around a specified origin.

However you do that in directx would be it.

Not sure if this is helpful. I store objects with a local translation and scale value and then also a rotation value and a rotation origin. That is what all these points relate to... It sounds like you're already doing this though and the problem lies with your shader (which I am not familiar with), so this is more an explanation to the people asking you why you're doing what you are.
_______________________"You're using a screwdriver to nail some glue to a ming vase. " -ToohrVyk

This topic is closed to new replies.

Advertisement