Game Development Community

Get node transform

by Clint S. Brewer · in Torque Game Engine · 12/22/2004 (12:00 am) · 44 replies

Anyone know how to get the position of a specific node from script?

I want to access a named node in my model and create an explosion at that position.

lets just say mount0 for now, but eventually any named node.

thanks
#21
02/14/2008 (12:21 pm)
Hi Clint

Thanks so much for the quick response...

I must plead ignorance, I dont know if I'm doing this on the server or not. My game is not multiplayer and thus I have not been very dilligent in the server/client relationship.

Right now I have implemented the code that Ramen had in the shapebase.h and shapebase.cc files. Then I added the line
if (mShapeInstance)
mShapeInstance->animate();

in the update thread because I could not find tsShapeInstance::processTick() anywhere.

After I did a clean build, I loaded the AIPlayer into the world. Then in the console window i typed
echo(prev.getNodeTransform("longhair"))
And it gave me a result
Then I initiated the animation on my model named "prev"...
prev.PlayThread(0,"hita")

during the animation, I again typed
echo(prev.getNodeTransform("longhair"))

Even though the mesh was in a different location, I got the same transform numbers. Then after the model was done animating, he snapped right back into the position where he started (this is what I'm ultimately trying to change - http://www.garagegames.com/mg/forums/result.thread.php?qt=72100).

I thought that during the onendSequence, I could look at the transform of the "longhair" and then set the position of the entire AIPlayer to that transform.
#22
02/14/2008 (2:33 pm)
@David
Where are you defining the object Prev?

Instead of called it on prev, open the world editor thing(F11) and try using the number it is showing instead. See if that changes anything.

I'll load up my torque and double check all of this is still working in 1.5.2
#23
02/14/2008 (2:48 pm)
Hmmm doesn't seem to be working anymore. I'll see what might have happened.

i used this routine for objects created in the /client/ folder scripts. i don't know if that made those objects a client version or not. i'll keep checking
#24
02/14/2008 (3:11 pm)
Prev is the name of the aiplayer i create upon selection from a dropdown menu...

here is the file - i was uploading this anyway because I'm doing another blog resource soon. I created a "distanceto" function people may find useful.

http://www.homebrewwrestling.com/HBWprob.zip

If you run it you'll see what I mean.

At the character selection screen, this is where i was typing
echo(prev.getNodeTransform("longhair"))
then
prev.PlayThread(0,"hita")
and then during that animation, again...
echo(prev.getNodeTransform("longhair"))

After selecting hulk hogan, then mr. perfect, you can use the arrow keys to hit the other player with the "a" key. However, you can see, they snap right back.

My plan was to capture the longhair transform info and use that to change the aiplayer's position.
You'll see that in the player.cs file, i have...
function power::onEndSequence(%this,%obj,%slot)
{
   echo("the node transform of the wrestler's hair is " @ %obj.getNodeTransform("longhair"));

   %obj.stopThread(%slot);
   echo("obj---"@%obj);
   for(%i=0;%i<$Match.numberOfWrestlers;%i++){
         if($wlist[%i].id.getID() == %obj){%wrest = $wlist[%i];}
         }
    AniDone(%wrest);
}

Eventually after the line echo("the node transform of the wrestler's hair is " @ %obj.getNodeTransform("longhair")); I'd change the player position.

Unless there's a better solution to the animation-based position problem...
#25
02/14/2008 (3:15 pm)
Clint is corrent in what he said about server side objects not being animated. I believe with my examples above (The ice crystals) were created client side. There for the object ID's i used were valid. i'm currently rewriting the getnodetransform function as we speak. I'm going to see if i can have it cross reference the client side version of the object.


Wouldn't it be just so much easier if there wasn't this client/server relation?

Anyhow. I'll post a "fix" in a little while.
#26
02/14/2008 (3:38 pm)
Wouldn't it be just so much easier if there wasn't this client/server relation?

... agreed! :)
#27
02/14/2008 (6:16 pm)
Good new!

//Ramen 2.14/08
ConsoleMethod( ShapeBase, getNodeTransform, const char*, 3, 3, "NodeName")
{
   MatrixF xf(true);

//Check to see if this object is a server objec
	if (object->isServerObject()){
		
		//Obtain a local connection, i have no idea if this will work in a network play
		GameConnection * LocalCon = GameConnection::getLocalClientConnection();
		
		//Should be an index of the object
		S32 gIndex = LocalCon->getGhostIndex(object);
		
		//Obtain connection to server
		GameConnection* con = GameConnection::getConnectionToServer();

		
		//Make a null netobject, point it to the object in the ghost index
		NetObject* nObject = NULL;
		nObject = con->resolveGhost( gIndex );
		
		ShapeBase* shape = dynamic_cast<ShapeBase*>(nObject); 

	   // ok, we are left with local object, so we should be able to get all the transforms properly
		shape->getNodeTransform(argv[2],&xf);
        
   }
   else
	   object->getNodeTransform(argv[2],&xf);  // Used if object is local object to begin with

   Point3F pos;
   xf.getColumn(3,&pos);
   AngAxisF aa(xf);
   char* buff = Con::getReturnBuffer(200);
   dSprintf(buff,200,"%g %g %g %g %g %g %g",
            pos.x,pos.y,pos.z,aa.axis.x,aa.axis.y,aa.axis.z,aa.angle);
   return buff;
}

Here is an updated version of the getnodetransform consoleMethod!
I tested it just now and it seems to work brilliantly. you can feed it a serverObject, and it will do all that fancy resolving, and in the end, give you the ghosted copy's transforms.

When testing, ensure the object in question is onscreen, or it seems torque doesn't animate them. makes sense i guess.

I should also note, i have no clue about dynamic casting and the horrible side effects if things go wrong. but that seemed to do the trick at one point.
#28
02/14/2008 (6:53 pm)
Do I still add this above it...?
//Ramen Added//
void ShapeBase::getNodeTransform(const char* nodeName,MatrixF* mat)
{
   // Returns mount point to world space transform
   S32 ni = mDataBlock->shape->findNode(nodeName);
      if (ni != -1) {
         MatrixF nodeTransform = mShapeInstance->mNodeTransforms[ni];
         const Point3F& scale = getScale();

         // The position of the mount point needs to be scaled.
         Point3F position = nodeTransform.getPosition();
         position.convolve( scale );
         nodeTransform.setPosition( position );

         // Also we would like the object to be scaled to the model.
         mat->mul(mObjToWorld, nodeTransform);
         return;
   }
   *mat = mObjToWorld;
}
#29
02/14/2008 (6:57 pm)
The new code needs to replace the old console method called getnodetransform. it can go anywhere, but i usually put it at the end of shapebase.cc. But i guess to answer you question, yes that code goes above it.


I updated my original post from way back when with this newer code
#30
02/15/2008 (6:14 am)
First, thanks SO much for all your hard work on this.

I feel ashamed, but I still can't get it to work during an animation.

I have the new console method and the ShapeBase::getNodeTransform inside my shapebase.cc
I added the virtual void getNodeTransform(const char* nodeName,MatrixF* mat); line to my shapebase.h file

I also added
if (mShapeInstance)
mShapeInstance->animate();

right after the void ShapeBase::updateThread(Thread& st) {

and before the switch statement.

any ideas? would it have something to do with the way I'm implementing the code on the front end?
If I evoke the statement echo(prev.getNodeTransform("longhair")) on the character select screen, then play my animations and evoke it again during the animation, should I not get different values for the transform? Maybe I've done your engine code correctly, but I've set something up in my game wrong.
#31
02/15/2008 (2:34 pm)
It should give you different values, i tested it with the default character. the number changes every time i call it while the orc is in the root animation. try calling it with a different named node and see what happens.

If the node is not found, it will simply return the transform of the root node of the object. Are you 100% sure the node is named longhair?

Also, try pressing F11 and seeing what number the player object in question is given, and instead of using prev use that number in the console.

If you have an instant messenger type program contact me that way if you want.
#32
02/16/2008 (8:19 am)
That's it!

I was 100% sure that prev was the correct name - I do several "hidemesh" commands on it which work. But I wasn't 100% sure that "longhair" was correct. longhair is the name of a mesh that is linked via a skin modifier. I assumed that any mesh within my model is considered a "node" - and I really thought that when I was getting values. That was the key.

I assumed that since I was getting values that it was finding it. I thought it would return null values if it couldnt find it. I didnt realize that it would instead return the values of the root node.

So I changed "longhair" to a random node that's linked to the right and called "Dummy12"

Bingo. It worked.

If anyone else in interested... here's how I emulate the animation-based movement...

Create a dummy node.
I'm not sure where to link it yet - I'll test this later. probably either bip01, the feet, or the detail64.
I'll name mine DummyPos

on the function
function [playerdatablock]::onEndSequence(%this,%obj,%slot){

add:
%obj.setTransform(%obj.getNodeTransform("DummyPos"));

Thanks again for all your help
#33
02/23/2008 (6:26 am)
Glad to see you got your animation movement problems sorted.

Ramen-sama - any idea how to get this to work even with off-screen objects? And, corect me if I'm wrong, but if you use getImageTransform on a ShapeBase with a mounted image, the transform is correctly animated - how does that work?
#34
02/23/2008 (11:48 am)
I believe the objects offscree are not animated. So you'd have to go thru the code to see where it skips the actual animation of an object if it's offscreen.

As for getImageTransform, my getnodetransform code uses almost the exact some code to get the transform. It could be that shapes are clientside only, or it does it's own ghost resolving somewhere else in the code.
#35
02/23/2008 (1:18 pm)
Yeah, I figured, but can't find anything. Scary. Would it do to call animate() in the getNodeTransform method - or does that method then skip the actual animating when off-screen?
#36
02/23/2008 (1:38 pm)
Can't say. I don't know enough about how/why torque does stuff. Could always try and see.
#37
12/07/2009 (8:10 pm)
Im having a problem. When Im calling getNodeTransform this way from player.cpp:

MatrixF xf(true);
MatrixF renderTransform;

renderTransform = getRenderTransform();
for(int i = 0; i<10; i++)
{

MatrixF pointTransform = getNodeTransform(mHitboxes[i].nodeName, xf);

I get this error:
Error 36 error C2664: 'ShapeBase::getNodeTransform' : cannot convert parameter 2 from 'MatrixF' to 'MatrixF *'

Can anyone help me with this please?
#38
12/07/2009 (8:17 pm)
Juan, pass in the address of xf instead of xf itself. ie "&xf", not "xf".
#39
12/08/2009 (11:51 am)
Thanks! Unfortunately that wasn't it. I `did a little research and it appears that I can make it work if I "multiply the player->world transform by the bone->player matrix to get, obviously, the bone->world". The problem is that I don't know who to do this, so I was wondering if any of you guys can help me with this.
#40
12/08/2009 (12:09 pm)
maybe look at the .h file for the matrix class to find the multiplication method.