Animate geometry manually?
by Frederic "Intruder" Tessier · in Torque Game Engine · 03/11/2003 (4:01 pm) · 7 replies
Hello folks!
Well i was wondering if it will be possible to animate directly a node (object) in the hierarchy of my model. For example I have a vehicle with a properller (which is one of the many node/object contain in the model), instead of saving the animation in the DTS file i simply access the geometry to do the actual rotation. Which will give more freedom on how much degree it turn, the acceleration (speed) and so on.
I know we can apply several transformation to the whole object (translation or rotation on every axis). But i didnt find yet anywhere they talk about moving only part of it, which i think could be usefull to make something more dynamic than a static animation.
Thanks for your collaboration in advance.
Well i was wondering if it will be possible to animate directly a node (object) in the hierarchy of my model. For example I have a vehicle with a properller (which is one of the many node/object contain in the model), instead of saving the animation in the DTS file i simply access the geometry to do the actual rotation. Which will give more freedom on how much degree it turn, the acceleration (speed) and so on.
I know we can apply several transformation to the whole object (translation or rotation on every axis). But i didnt find yet anywhere they talk about moving only part of it, which i think could be usefull to make something more dynamic than a static animation.
Thanks for your collaboration in advance.
#2
03/11/2003 (11:31 pm)
You could simply embed the animation in the .dts and adjust the scale for the velocity, that is how the player's run animation is done.
#3
1. Your code must unload the shape instace that is created and re-load it again. My sample code has an example of how to do this. I just mention it to explain why the code seems more involved than it needs to be.
2. Your code must flag the nodes you want to change as "hands off". Again my sample code has an example of doing this but there is a side effect you must be aware of. Once you tell Torque that a node is "hands off" then that node can no longer contribute to an animation. That node can still be attached to other nodes that *are* part of an animation...but the node that you want to control directly cannot have any rotations for it...they will be lost once you mark that node as "hands off". In short: you can use a node in an animation or you can set it manually but not both.
3. There is a way to do what you want (I think) without actually resorting to manually setting node transforms. I'll get to that at end of post.
OK...so here is the sample code. Clark F gave me these three methods on the tank class used in think tanks. They demonstrate the technique:
A couple of notes on what I did to make this work
1. Make a getDataBlock() method that returns a datablock typed
for your class as the code aboves assumes you have.
2. Add these datamembers to your class, in the above example
that would be the "TankData" claass.
Good luck! I'm a lazy bastid and I don't even post to the forums much because I am so greedy with my time. The only reason I took the time to do it this time is because I really owe it to Clark and Joe and all the helpful and friendly people in the Garage Games development community who help me with problems like this. The #garagegames irc channel on the irc.maxgaming.net IRC net work is also a great source of help and information.
NOTE on doing it a different way:
If what you want to do is control the speed of a propeller spinning there is another, simpler, way to do that. Make a blend anim seq that moves the propeller around 360. Then make a thread in your C++ code for that anim. Then...dont "play" the anim in the normal way...instead control the thread "position" from 0...1 (which now maps to 0 to 360 degres) manually with code. An example of this is the "look anims" used to aim the players arms up and down. You will see the code that controls the thread in updateLookAnimation().
03/12/2003 (9:39 am)
It is possible to do what you are asking (to manually control the position and/or rotation of a node in a model) and thanks to Joe M. and Clark F. (friendly folks at Brave Tree) I now have code that shows me how to do it. There is a bit of detail to making it work and there are some things you need to know about using that method.1. Your code must unload the shape instace that is created and re-load it again. My sample code has an example of how to do this. I just mention it to explain why the code seems more involved than it needs to be.
2. Your code must flag the nodes you want to change as "hands off". Again my sample code has an example of doing this but there is a side effect you must be aware of. Once you tell Torque that a node is "hands off" then that node can no longer contribute to an animation. That node can still be attached to other nodes that *are* part of an animation...but the node that you want to control directly cannot have any rotations for it...they will be lost once you mark that node as "hands off". In short: you can use a node in an animation or you can set it manually but not both.
3. There is a way to do what you want (I think) without actually resorting to manually setting node transforms. I'll get to that at end of post.
OK...so here is the sample code. Clark F gave me these three methods on the tank class used in think tanks. They demonstrate the technique:
bool TankData::preload(bool server, char errorBuffer[256])
{
if (!Parent::preload(server,errorBuffer))
return false;
// .... extra stuff happening at top of your ::preload
// load shape resource...
if (shapeName && shapeName[0])
{
// Resolve shapename
shapeResource = ResourceManager->load(shapeName,false);
if (!bool(shapeResource))
{
dSprintf(errorBuffer, 256, "TankData: Couldn't load shape \"%s\"",shapeName);
return false;
}
if(!server && !shapeResource->preloadMaterialList() && NetConnection::filesWereDownloaded())
return false;
}
// get nodes from shape
turretNode = shapeResource->findNode("codeTurret");
weaponNode = shapeResource->findNode("codeWeapon");
// any other nodes you might need...
AssertFatal(turretNode>=0,"TankData::preload: missing node codeTurret");
AssertFatal(weaponNode>=0,"TankData::preload: missing node codeWeapon");
// get instance of shape if needed for preload processing...
TSShapeInstance * si = new TSShapeInstance(shapeResource,false);
// do stuff with shape instance ... for example for a vehicle you
// might need to execute code like this to get collision planes...
/*
if (collisionDetails[0] != -1) {
MatrixF imat(1);
PlaneExtractorPolyList polyList;
polyList.mPlaneList = &rigidBody.mPlaneList;
polyList.setTransform(&imat, Point3F(1,1,1));
si->animate(collisionDetails[0]);
si->buildPolyList(&polyList,collisionDetails[0]);
}
*/
// delete this temp shape instance
delete si;
si = NULL;
return true;
}
bool Tank::onNewDataBlock(GameBaseData * dptr)
{
if (!Parent::onNewDataBlock(dptr) || !dptr)
return false;
// rid us of old shape instance...
delete mShapeInstance;
mShapeInstance = NULL;
// NOTE: you will need to delete and any *other* shape instances
// might be using in your class here and recrete them below like mShapeInstance
// load new shape instance...
AssertFatal(bool(getDataBlock()->shapeResource),
"Tank::onNewDataBlock: no shape resource");
mShapeInstance = new TSShapeInstance(getDataBlock()->shapeResource, isClientObject());
// recreate other new shape instances here
// mark callback nodes (for turret/weapon control)
mShapeInstance->setNodeAnimationState(getDataBlock()->turretNode,TSShapeInstance::MaskNodeHandsOff);
mShapeInstance->setNodeAnimationState(getDataBlock()->weaponNode,TSShapeInstance::MaskNodeHandsOff);
// NOTE: in the case of a turret both the client and server will need to mess with the
// these nodes...in some case you may have a need to do this on the client only...if
// so then enclose processing on those nods in a if(isClientObject()) statement
// leaf classes must call this...one annoying side-effect
// is that if we derive from Tank we get two calls to
// the script onAdd method.
scriptOnNewDataBlock();
return true;
}
void Tank::updateAnimation(bool muzzleOnly)
{
// NOTE: here is the meat of the code. In this case the *turretNode* controls
// the YAW of a tank and the *weaponNode* controls the pitch of the weapon
// mounted to the turret. The methods getTurretHor() and getTurretVert() return
// appropriate values for this purpose
// set turret...
S32 node = getDataBlock()->turretNode;
MatrixF * mat = &mShapeInstance->mNodeTransforms[node];
Point3F defaultPos = getDataBlock()->shapeResource->defaultTranslations[node];
F32 turretH = getTurretHor();
mat->set(EulerF(0,0,turretH));
mat->setColumn(3,defaultPos);
// set weapon...
node = getDataBlock()->weaponNode;
mat = &mShapeInstance->mNodeTransforms[node];
defaultPos = getDataBlock()->shapeResource->defaultTranslations[node];
F32 turretV = getTurretVert();
mat->set(EulerF(turretV,0,0));
mat->setColumn(3,defaultPos);
// do any other node changing...including posible clientside only ones...
// you can also advance threads at this point (as long as their anims dont
// depend upon nodes you just marked as "hands off"...
// now we must tell the animatino system we have been setting nodes by hand
mShapeInstance->setDirty(TSShapeInstance::TransformDirty);
mShapeInstance->animate();
}A couple of notes on what I did to make this work
1. Make a getDataBlock() method that returns a datablock typed
for your class as the code aboves assumes you have.
2. Add these datamembers to your class, in the above example
that would be the "TankData" claass.
Resource<TSShape> shapeResource; S32 turretNode; S32 weaponNode;
Good luck! I'm a lazy bastid and I don't even post to the forums much because I am so greedy with my time. The only reason I took the time to do it this time is because I really owe it to Clark and Joe and all the helpful and friendly people in the Garage Games development community who help me with problems like this. The #garagegames irc channel on the irc.maxgaming.net IRC net work is also a great source of help and information.
NOTE on doing it a different way:
If what you want to do is control the speed of a propeller spinning there is another, simpler, way to do that. Make a blend anim seq that moves the propeller around 360. Then make a thread in your C++ code for that anim. Then...dont "play" the anim in the normal way...instead control the thread "position" from 0...1 (which now maps to 0 to 360 degres) manually with code. An example of this is the "look anims" used to aim the players arms up and down. You will see the code that controls the thread in updateLookAnimation().
#4
Maybe im just telling you the same thing as the previous post I don't know I got lost.
Matt
03/12/2003 (11:46 am)
I am not a code expert or anything but I would think The simpilist way to acheive what your trying to do would be to write in a standard node Similair to "HUB"(in Wheeled Vehicle) and have it scale according to the speed of the vehicle. You might be able to just use The code that is used for HUB but call it PROP and have the engine load a Propellar and treat it the same as the wheel. We are doing something similiar for our vehicle class and it works great. From what I remember it wasn't very hard to get running either.Maybe im just telling you the same thing as the previous post I don't know I got lost.
Matt
#5
Well we already have split our objects into sub-objects, what i was looking at is to code something in C++ directly instead of using standard animation sequence.
@Jared
I know ;-), but to have more freedom in certain situation it will be better to do it manually (move the geometry). But how do you ajust the velocity (you mean the speed right)? Is there a way to also do this via scripting?
@Paul
Wow that was quite a long reply to read ;-), it was very helpfull. Ill have to experiment with it when i have more time,
i have other pressing matter to fix before 8-(. Thanks again!
1 - Ok that mean that each time you have setup a DTS file it get instantiate as an object and if i want to modify i have to unload and reload it again? I was thinking i could have access the object itself and then go the node i want. It seems more complex than i though!
2 - "hands off" that will tell TGE to not take care of it for any kind of animation. But if i do this anyway this mean that i want to control it myself, so it should be ok, unless it is part of another node that is suppose to be animated. But is it possible to go back to "hands on"?
3 - Ill take a look at the blend anim, indeed that could do the tricks like you said to get the propeller rotate to different angle.
@Matthew
Ill take a look at the HUB for the wheel like you mention, thanks for the tips!
03/12/2003 (6:41 pm)
@EdwardWell we already have split our objects into sub-objects, what i was looking at is to code something in C++ directly instead of using standard animation sequence.
@Jared
I know ;-), but to have more freedom in certain situation it will be better to do it manually (move the geometry). But how do you ajust the velocity (you mean the speed right)? Is there a way to also do this via scripting?
@Paul
Wow that was quite a long reply to read ;-), it was very helpfull. Ill have to experiment with it when i have more time,
i have other pressing matter to fix before 8-(. Thanks again!
1 - Ok that mean that each time you have setup a DTS file it get instantiate as an object and if i want to modify i have to unload and reload it again? I was thinking i could have access the object itself and then go the node i want. It seems more complex than i though!
2 - "hands off" that will tell TGE to not take care of it for any kind of animation. But if i do this anyway this mean that i want to control it myself, so it should be ok, unless it is part of another node that is suppose to be animated. But is it possible to go back to "hands on"?
3 - Ill take a look at the blend anim, indeed that could do the tricks like you said to get the propeller rotate to different angle.
@Matthew
Ill take a look at the HUB for the wheel like you mention, thanks for the tips!
#6
We have done now for 4 new vehicle types. They play animation depending on the state of the controls that control the player (keyboard and mouse). We made a merge of the player and vehicle class. I don't have all the details and my programmer is convinced its flawed so he won't release but so far everything we wanted from it has worked. Somthing you can try if your that up to speed with the engine. He wasn't when he started so it can't be that hard can be time consuming though.
Matt
03/12/2003 (7:33 pm)
Also If you want more animations in and alot more freedon in your vehicle class its not a far stretch to write your own class based on flying vehicles and incorperate alot of the same stuff the player has. So you get alot of animations and the ability/physics of a vehicle. We have done now for 4 new vehicle types. They play animation depending on the state of the controls that control the player (keyboard and mouse). We made a merge of the player and vehicle class. I don't have all the details and my programmer is convinced its flawed so he won't release but so far everything we wanted from it has worked. Somthing you can try if your that up to speed with the engine. He wasn't when he started so it can't be that hard can be time consuming though.
Matt
#7
03/15/2003 (8:02 pm)
I belive the wheel HUBS use the blend animation trick. In C++ its possible to set the animation playback scale to ZERO and then just control the position (frame) manually to "play" anims from code. I do not know if that ability is exposed to script.
Torque Owner Edward Smith
Silencersoft