Setting SkinnedMesh Joint positions manually plus Animations

A forum to store posts deemed exceptionally wise and useful
Post Reply
fmx

Setting SkinnedMesh Joint positions manually plus Animations

Post 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.
;)
fmx

Post 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
B@z
Posts: 876
Joined: Thu Jan 31, 2008 5:05 pm
Location: Hungary

Post 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
Image
Image
pham_ngoc_tuan
Posts: 1
Joined: Sun Apr 05, 2009 7:20 am

thaks fmx

Post by pham_ngoc_tuan »

I'm finding this.

Thanks so much. :D
dvds9999
Posts: 5
Joined: Fri Apr 03, 2009 3:53 am
Location: VietNam, HaNoi, ThanhXuan

Post by dvds9999 »

:D Helpful. Thanks.

P/S: I'm newbie. :)
B@z
Posts: 876
Joined: Thu Jan 31, 2008 5:05 pm
Location: Hungary

Post by B@z »

btw, does it work with useAnimationFrom thingy?
Image
Image
fmx

Post 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 :)
andreasky
Posts: 30
Joined: Tue Jun 09, 2009 2:36 pm

Post 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!
Nadro
Posts: 1648
Joined: Sun Feb 19, 2006 9:08 am
Location: Warsaw, Poland

Post 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
Library helping with network requests, tasks management, logger etc in desktop and mobile apps: https://github.com/GrupaPracuj/hermes
zerochen
Posts: 273
Joined: Wed Jan 07, 2009 1:17 am
Location: Germany

Re: Setting SkinnedMesh Joint positions manually plus Animat

Post 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
fmx

Re: Setting SkinnedMesh Joint positions manually plus Animat

Post 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...
Post Reply