Page 1 of 1

Setting SkinnedMesh Joint positions manually plus Animations

Posted: Thu Mar 05, 2009 1:22 pm
by fmx
I had a LOT of trouble figuring this out, even though Luke's "new" animation system has been around for a while, the not-so-obvious tutorial in the wiki, and I've seen LOTS of questions asked about this kind of stuff when i searched through the forums.

Here's the low-down:

Let's say you want to load a Skinned Animated character into Irrlicht.

> You want to animate it using the standard keyframe data from the file (ie, Irrlicht does all the dirty-work as it's supposed to).

> But you also want to be able to move certain Joints around, make them look at something or position them to a particular place, or for ragdolling, etc, etc.


How to do it?

Simply transform the Joint's desired position and rotation values by its Parent's INVERSE Absolute Transformation!


A demonstration:

Code: Select all


// Irrlicht
	#include <irrlicht.h>

	using namespace irr;

	using namespace core;
	using namespace scene;
	using namespace video;
	using namespace io;
	using namespace gui;


	#ifdef _IRR_WINDOWS_
		#pragma comment(lib, "Irrlicht.lib")
		#pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")
	#endif


// MAIN

int main()
{
	// create Irrlicht device
		IrrlichtDevice* device = createDevice( video::EDT_OPENGL, dimension2d<s32>(800, 600), 32,
				false, false);

		if (device == 0)
			return 1; // could not create selected driver.

		video::IVideoDriver* driver = device->getVideoDriver();
		scene::ISceneManager* smgr = device->getSceneManager();

	// create camera
		smgr->addCameraSceneNodeFPS(0, 100.0f, .1f);

	// Load Char
		IAnimatedMesh* CharMesh = smgr->getMesh("../../media/dwarf.X");
		if (!CharMesh) return 1;

		IAnimatedMeshSceneNode* CharNode = smgr->addAnimatedMeshSceneNode( CharMesh );
		if (!CharNode) return 1;

	// Initilise
		CharNode->setMaterialFlag(EMF_LIGHTING, false);
		CharNode->setAnimationSpeed(10);

	// Prepare for Joint Control
		CharNode->setJointMode(EJUOR_CONTROL); //To write positions to the mesh on render



	int lastFPS = -1;


	f32 headRotation = 0;
	f32 headPosition = 0;


	while(device->run())
	{

	// Animate character manually
		CharNode->animateJoints();


	// Get the Joint you want to MANIPULATE, and its Parent
		IBoneSceneNode* thisJoint = CharNode->getJointNode("head");

		if( thisJoint )
		{
			ISceneNode* parentJoint = thisJoint->getParent();

			if( parentJoint )
			{
			// Get the default (animated) Joint's position and rotation
				vector3df jointPos = thisJoint->getAbsolutePosition();
				vector3df jointRot = thisJoint->getAbsoluteTransformation().getRotationDegrees();

			// Get the absolute INVERSE Transformation matrix of the parent
				matrix4 iparentTransform = parentJoint->getAbsoluteTransformation();
					iparentTransform.makeInverse();

			// Set the Absolute Position or Rotation of the Joint without fear!
				vector3df newJointPos = jointPos + vector3df( 0, 1+(sin(headPosition)*2), 0 );
				vector3df newJointRot = vector3df( 0, headRotation, 0 );

			// Transform the Position by the Parent's Inverse matrix before applying it
				iparentTransform.transformVect( newJointPos );	

			// APPLY
				thisJoint->setPosition( newJointPos );
				thisJoint->setRotation( newJointRot );
			}
		}


	// funny
		headPosition += 0.01f;
		if( headPosition > 2*PI ){ headPosition -= 0; }

		headRotation += 0.5f;
		if( headRotation > 360 ){ headRotation -= 360; }


	// do Irrlicht stuff

		driver->beginScene(true, true, video::SColor(255,113,113,133));

		smgr->drawAll(); // draw the 3d scene
		device->getGUIEnvironment()->drawAll(); // draw the gui environment (the logo)

		driver->endScene();

		int fps = driver->getFPS();

		if (lastFPS != fps)
		{
			core::stringw tmp(L"fmx's funny dwarf head joint manipulation demo! [");
			tmp += driver->getName();
			tmp += L"] fps: ";
			tmp += fps;

			device->setWindowCaption(tmp.c_str());
			lastFPS = fps;
		}
	}


	// show cursor
	//	device->getCursorControl()->setVisible(true);



	device->drop();
	
	return 0;
}
Sorry for the lack of "tuition material" but I've got things to be getting on with, and the code should be self-explanatory.

Just copy and paste this into the HelloWorld example or something.

Binary and source to quickly see what it does:
http://www.mediafire.com/?lmazmtzzzur

I assure you that you wont be dissapointed.
;)

Posted: Fri Mar 06, 2009 2:22 pm
by fmx
Just added a binary example and source-file to demonstrate this in action.
Also edited the name to try make it more obvious it deals with SKINNED AnimatedMeshes
(some people might not realise that joints only work with skinned meshes)
:P

Posted: Fri Mar 06, 2009 6:57 pm
by B@z
so is it good for example, making a model move like the other model? cool :P
i have been waiting for it :P

thaks fmx

Posted: Sun Apr 05, 2009 7:22 am
by pham_ngoc_tuan
I'm finding this.

Thanks so much. :D

Posted: Thu Apr 16, 2009 3:50 pm
by dvds9999
:D Helpful. Thanks.

P/S: I'm newbie. :)

Posted: Thu Apr 16, 2009 5:47 pm
by B@z
btw, does it work with useAnimationFrom thingy?

Posted: Sat Apr 18, 2009 3:44 pm
by fmx
it should do, because the actual joint manipulation occurs after irrlicht finishes animating it (by using the "animateJoints" command) so theoretically you could add the useAnimationFrom (thingy) before that line.

But I've never tested it, good luck :)

Posted: Fri Jun 12, 2009 10:42 am
by andreasky
Hi,

I tried to run your demo and it works well.
I also changed some parameters in the source file to see how the animation would change.

I created a 3D model with joints wthout animation. I called a joint "head", as in our demo. Then, I exported the model as ".X" file and loaded into the source code of your demo, instead "dwarf.X".
However, after running the demo, the node I called "head" does not animate.

Do you know what I am missing?

Thank you!

Posted: Sat Jun 27, 2009 3:46 pm
by Nadro
Hi, If You manual update Node (parent of each bones) position (eg. setPosition) between drawAll() it's very important to updateAbsolutePosition() each parents of current bone, because without it we calculate bone position bassed on her parent position from last frame. More infos in this thread:
http://irrlicht.sourceforge.net/phpBB2/ ... hp?t=33981

Re: Setting SkinnedMesh Joint positions manually plus Animat

Posted: Mon Aug 06, 2012 8:36 am
by zerochen
hi,

this code has a little error in the line

Code: Select all

if( headPosition > 2*PI ){ headPosition -= 0; }
because it doesnt do anything

regards
zerochen

Re: Setting SkinnedMesh Joint positions manually plus Animat

Posted: Mon Aug 06, 2012 3:26 pm
by fmx
Yeah you're right :P
that line wasn't important anyway, i think

This code snippet is so old and outdated I dont even remember writing it...