Sign in to follow this  
CodaKiller

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

Recommended Posts

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[i]->getGlobalPose().getColumnMajor44( matrices[i] ); // 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[i], &matrices[i], &inv_world ); // Bring the bone in to model space.
				D3DXMatrixInverse( &inv_base_bone, NULL, &mesh->bones[i].matrix ); // Get the inverse of the bone's model space matrix. 
				D3DXMatrixMultiply( &matrices[i], &inv_base_bone, &matrices[i] ); // 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[i].matrix._41, mesh->bones[i].matrix._42, mesh->bones[i].matrix._43 ); // Create translation matrix with zero rotation.
				rot = matrices[i]; // Create rotation matrix.
				rot._41 = 0; rot._42 = 0;rot._43 = 0; // Set rotation matrix's translation to [0, 0 ,0]
				D3DXMatrixMultiply( &matrices[i], &pos, &rot ); // Rotate the matrix with a correct translation.
				D3DXMatrixInverse( &inv_pos, NULL, &pos ); // Get the inverse of the translation matrix. 
				D3DXMatrixMultiply( &matrices[i], &matrices[i], &inv_pos ); // Correct the translation back.

				D3DXMatrixMultiply( &matrices[i], &matrices[i], &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]

Share this post


Link to post
Share on other sites
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[i]->getGlobalPose().getColumnMajor44( matrices[i] ); // 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[i].matrix._41, mesh->bones[i].matrix._42, mesh->bones[i].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[i].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).

Share this post


Link to post
Share on other sites
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?

Share this post


Link to post
Share on other sites
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[i]->getGlobalPose().getColumnMajor44( matrices[i] ); // 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]

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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]

Share this post


Link to post
Share on other sites
"D3DXMatrixTranslation( &pos, mesh->bones[i].matrix._41, mesh->bones[i].matrix._42, mesh->bones[i].matrix._43 );"

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

Try to transpose it, just for fun.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
Quote:
Original post by M2tM
This may help, it's basically exactly what I do in opengl for rotating around a specified origin:
*** Source Snippet Removed ***

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.


Thats what I'm already doing, I translate it to the origin I want then I multiply it by the rotation and then move it back to it's original position.

Thats at "// I thought the code below would give the matrix the correct center of rotation but it's still at the origin." which is actually working but it's not moving it to the right origin or something else is wrong thats making it the wrong origin, idk...

Share this post


Link to post
Share on other sites
Ah, I see, that picture is a "desired effect" so my opengl version transcribed into direct x would probably solve you. I mis-read and thought that second picture with the two bones rotated on the second bone's pivot was what you had working.

Have you made sure your rotation origin is what you think it is? Try stepping through the bugger with a debugger.

and go through my example and make sure each step is actually being done.

Share this post


Link to post
Share on other sites
CodaKiller, did see janta's post about the type of matrix D3D functions expect? I just want to point it out again to make sure that you see it. D3D expects row major matrices. However, you're getting a column major matrix.

Share this post


Link to post
Share on other sites
I'm not too experienced with directx, but I am familiar with this process that you are trying to do. It looks like you only set inv_world once, instead of for each bone. If you use the same inv_world translate matrix for each bone, they will use the same point of rotation.

Here is an image to hopefully explain better:

[IMG]http://i217.photobucket.com/albums/cc94/Oot_Oot_Ima_Monk/skeletalanimation.gif[/IMG]

Share this post


Link to post
Share on other sites
Quote:
Original post by MikeTacular
CodaKiller, did see janta's post about the type of matrix D3D functions expect? I just want to point it out again to make sure that you see it. D3D expects row major matrices. However, you're getting a column major matrix.


Quote:
NOTE: While Direct3D matrices are technically row major, they have an additional semantic difference to OpenGL matrices which cancels this out; therefore, use this same code for Direct3D.


This is from the PhysX documentation, it's talking about the getColumnMajor44 command and of course I would have made sure I had a working matrix before I would have posted here.

Share this post


Link to post
Share on other sites
Quote:
Original post by MortusMaximus
I'm not too experienced with directx, but I am familiar with this process that you are trying to do. It looks like you only set inv_world once, instead of for each bone. If you use the same inv_world translate matrix for each bone, they will use the same point of rotation.

Here is an image to hopefully explain better:

[IMG]http://i217.photobucket.com/albums/cc94/Oot_Oot_Ima_Monk/skeletalanimation.gif[/IMG]


inv_world is just to bring the object back out of model space, it's not possible to compute it for each bone since then it would be the same thing as using identity on all of the matrices.

Share this post


Link to post
Share on other sites
Aha! This explains exactly what I need to do! Finally found something! Whats sad is I was doing something similar but then I thought it was wrong and just delete it.

[Edited by - CodaKiller on January 21, 2009 11:47:06 AM]

Share this post


Link to post
Share on other sites
Quote:
Original post by CodaKiller
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.


Debugging can allow you to see the values of variables line by line. You could see if the values are being properly updated. If not, you can track from where the improper values are coming. You might have, for example, watched the rotations and positions as they changed and seen that not only was the results not as expected, but that it was a flaw in the algorithm.

Then again, as we see, the problem was more deep than originally thought. Debugging might not have helped as much as I expected, but familiarizing your self with the basics of debuggers (marking breakpoints and hovering over variables to see their values) can be very helpful, especially for finding problems in heavily mathematical sections of code. If you're using Visual C++ (which I use ONLY for its debugger and occasional code that requires it), you can just set a breakpoint, compile, and start debugging.

And my point wasn't I don't want you to waste your money, my point is I don't want that going on here. I don't care where you waste your money as long as it's not here (though it's not like I have any authority or can stop you, nor will I comment on it anymore).

[Edited by - Splinter of Chaos on January 21, 2009 8:10:18 PM]

Share this post


Link to post
Share on other sites
To Splinter:

I don't actually have a problem with him offering money for a service, or help on figuring out a problem. It's not really any different from the "Help Wanted" forum. If he wants to offer somebody $20 as incentive, it's between him and whoever accepts the offer. Now, had it been an unethical offer (say, to help with homework), that's a different story. But I see no ethical compromises here.

You may feel that the good nature of the people here, offering help for free, is perhaps cheapened by someone who offers money for the same thing, or that it opens the door for other people making the same offers, but I do not consider that a problem. People do, after all, have a choice in how they want to spend their money / how they want to provide help.

Personally, I give him kudo's for finding a way to get people to pay attention, even though it ended up being for naught.

Share this post


Link to post
Share on other sites
Quote:
Original post by Grafalgar But I see no ethical compromises here.


I don't find it unethical, I find it uncomfortable.

Quote:
You may feel that the good nature of the people here, offering help for free, is perhaps cheapened by someone who offers money for the same thing, or that it opens the door for other people making the same offers, but I do not consider that a problem.


Reminds me of what happened in the indy crowd recently. An allegedly (haven't played it) great game called Braid, which everyone seems to love, comes out, and people can't stop bitching about it being 20 bucks. That's actually normal for an indy game, I thought, but they'd been so spoiled by 10 and 15 dollar indy games that weren't all that great that 20 was for some reason unreasonable.

(I'm not saying Braid's price was immoral, I'm just explaining the effect it had on the group psychology of that instance.)

If people got in the habit of offering 20 dollars for bugs on these forums, the experts might feel cheated when someone comes and asks for that free exchange of information. The people posting problems might feel cheated by not receiving the same level of help. It would be unfair to people who either could not afford it or didn't think it was worth it. As Kant would say, this is not a universalizable act. But, I'm not a Kantian philosopher and I don't believe this was immoral because I don't think it'll catch on. (I examine situations morally by action and environment, not intent. If it caught on, I still wouldn't consider this immoral still because the environment didn't suggest it would.)

I wasn't going to respond to that (I said I wouldn't), but then you hinted that this would be fine on a wider scale.

Quote:
People do, after all, have a choice in how they want to spend their money / how they want to provide help.


But it would not be true to say people can chose how they want to get help. You can't ask for help in physics help under the DX topic or in DX help under the networking thread. I feel that applies to this situation, but I can see why you do not.

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