How to use ISkinnedMesh for animation blending

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.
Post Reply
klikli234
Posts: 97
Joined: Tue Sep 07, 2010 10:52 am

How to use ISkinnedMesh for animation blending

Post by klikli234 »

node->setFrameLoop(46,81);
node->setFrameLoop(0,45);

How to let the two paragraphs different animation and play at the same time.

thx very much
mongoose7
Posts: 1227
Joined: Wed Apr 06, 2011 12:13 pm

Post by mongoose7 »

Look, I feel for you. I've been trying to animate cal3d models in Irrlicht. You have to use CSkinnedMesh. There are no tutorials. MeshViewer doesn't do much - loads the mesh, skeleton and animation using the mesh loader. The Wiki is, at best, misleading.

You cannot play two animations at the same time. If you need to blend them, you have to do it outside of Irrlicht so that you have only one blended animation. You then load this. On the other hand, if the two animations apply to different parts of the mesh, you can split the mesh in two and animate each separately. This is not good as the mesh will tear at the boundary.

You can also load the same mesh twice, the first time with the first animation and the second time with the other animation. Then, go though all the joints of the first node and point some of them ('animationFrom') to the same joint in the second node. Now animate both meshes. The two parts will have the two different animations but there will be no tearing. You have to hide the second mesh, though.

I am a beginner, too, but I hope this helps.
klikli234
Posts: 97
Joined: Tue Sep 07, 2010 10:52 am

Post by klikli234 »

thanks for your help.
but here I still have problem.
how can I get joint ratation and position from cskinnedmesh with animation. and how to casting this cskinnedmesh.
thanks again
mongoose7
Posts: 1227
Joined: Wed Apr 06, 2011 12:13 pm

Post by mongoose7 »

If you can get a joint, that is all you need. See the other thread.
klikli234
Posts: 97
Joined: Tue Sep 07, 2010 10:52 am

Post by klikli234 »

mongoose7 wrote:If you can get a joint, that is all you need. See the other thread.
Where should I get a joint. ISkinnedNode or IAnimationSenceNode
mongoose7 wrote:You can also load the same mesh twice, the first time with the first animation and the second time with the other animation. Then, go though all the joints of the first node and point some of them ('animationFrom') to the same joint in the second node. Now animate both meshes. The two parts will have the two different animations but there will be no tearing. You have to hide the second mesh, though.
by this way I need ISkinnedMesh?


there is my solution
I just want know is have better way to solution this problem

Code: Select all

#include <irrlicht.h>
using namespace irr;

using namespace core;
using namespace scene;
using namespace video;

#include <Windows.h>

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

// rotates a bone
core::vector3df matrixRotation(core::vector3df rotation, core::vector3df vec)
{
	f32 pitch=vec.X;
	f32 yaw=vec.Y;
	f32 roll=vec.Z;
	matrix4 m,t;
	m.setRotationDegrees(rotation);

	t.setRotationDegrees(core::vector3df(0,0,roll));
	m*=t;

	t.setRotationDegrees(core::vector3df(pitch,0,0));
	m*=t;

	t.setRotationDegrees(core::vector3df(0,yaw,0));
	t*=m;

	return t.getRotationDegrees();
};


//键盘状态
bool keys[irr::KEY_KEY_CODES_COUNT];
//鼠标状态
struct SMouseState
{
	core::position2di Position;
	bool LeftButtonDown;
	SMouseState() : LeftButtonDown(false) { }
} MouseState;

class MyEventReceiver : public IEventReceiver
{
public:
	MyEventReceiver()
	{

	}
	virtual bool OnEvent(const SEvent& event)
	{
		if(event.EventType == irr::EET_KEY_INPUT_EVENT)
		{
			keys[event.KeyInput.Key] = event.KeyInput.PressedDown;
		}
		if (event.EventType == irr::EET_MOUSE_INPUT_EVENT)
		{
			switch(event.MouseInput.Event)
			{
			case EMIE_LMOUSE_PRESSED_DOWN:
				MouseState.LeftButtonDown = true;
				break;

			case EMIE_LMOUSE_LEFT_UP:
				MouseState.LeftButtonDown = false;
				break;

			case EMIE_MOUSE_MOVED:
				MouseState.Position.X = event.MouseInput.X;
				MouseState.Position.Y = event.MouseInput.Y;
				break;

			default:
				// We won't use the wheel
				break;
			}
		}
		return false;
	}
private:

};

int main()
{
	IrrlichtDevice* device =
		createDevice(EDT_DIRECT3D9, dimension2d<u32>(640, 480));
	if (device == 0)
		return 1;
	IVideoDriver* driver = device->getVideoDriver();
	ISceneManager* smgr = device->getSceneManager();

	smgr->loadScene("scene.irr");


	ICameraSceneNode * camera = smgr->addCameraSceneNodeFPS();
	camera->setPosition(core::vector3df(0.f, 20.f, 0.f));

	MyEventReceiver eventreceiver;
	device->setEventReceiver(&eventreceiver);




	//"Bip01_R_Thigh" "--_R_butt" "Bip01_R_Calf" "--_R_Knee" "Bip01_R_Foot" "--_R_Ankle" "Bip01_R_Toe0"
	//"Bip01_L_Thigh" "--_L_butt" "Bip01_L_Calf" "--_L_Knee" "Bip01_L_Foot" "--_L_Ankle" "Bip01_L_Toe0"
	scene::IAnimatedMeshSceneNode* node = 0,* node2 = 0;
	//ISkinnedMesh* myMesh2 = (ISkinnedMesh*)smgr->getMesh("player/run.x");

	ISkinnedMesh* myMesh = (ISkinnedMesh*)smgr->getMesh("player/urban-6.x");

	//myMesh->useAnimationFrom(myMesh2);
	node = smgr->addAnimatedMeshSceneNode(myMesh,0);
	node->setPosition(core::vector3df(0,0.f,0)); // Put its feet on the floor.
	node->setRotation(core::vector3df(0,0.f,0)); // And turn it towards the camera.
	node->setMaterialFlag(EMF_LIGHTING, false);
	node->setAnimationSpeed(30.f);
	node->setFrameLoop(0,45);
	node->setCurrentFrame(0.f);
	node->setLoopMode(true);

	node2 = smgr->addAnimatedMeshSceneNode(myMesh,0);
	node2->setPosition(core::vector3df(0,0.f,0)); // Put its feet on the floor.
	node2->setRotation(core::vector3df(0,0.f,0)); // And turn it towards the camera.
	node2->setMaterialFlag(EMF_LIGHTING, false);
	node2->setAnimationSpeed(30.f);
	node2->setFrameLoop(46,81);
	node2->setCurrentFrame(0.f);
	node2->setLoopMode(true);
	node2->setVisible(false);

	IBoneSceneNode* bonenode2_1 = node2->getJointNode("Bip01_R_Thigh");
	IBoneSceneNode* bonenode2_2 = node2->getJointNode("--_R_Butt");
	IBoneSceneNode* bonenode2_3 = node2->getJointNode("Bip01_R_Calf");
	IBoneSceneNode* bonenode2_4 = node2->getJointNode("--_R_Knee");
	IBoneSceneNode* bonenode2_5 = node2->getJointNode("Bip01_R_Foot");
	IBoneSceneNode* bonenode2_6 = node2->getJointNode("--_R_Ankle");
	IBoneSceneNode* bonenode2_7 = node2->getJointNode("Bip01_R_Toe0");
	IBoneSceneNode* bonenode2_8 = node2->getJointNode("Bip01_L_Thigh");
	IBoneSceneNode* bonenode2_9 = node2->getJointNode("--_L_butt");
	IBoneSceneNode* bonenode2_10 = node2->getJointNode("Bip01_L_Calf");
	IBoneSceneNode* bonenode2_11 = node2->getJointNode("--_L_Knee");
	IBoneSceneNode* bonenode2_12 = node2->getJointNode("Bip01_L_Foot");
	IBoneSceneNode* bonenode2_13 = node2->getJointNode("--_L_ankle");
	IBoneSceneNode* bonenode2_14 = node2->getJointNode("Bip01_L_Toe0");

	IBoneSceneNode* bonenode1 = node->getJointNode("Bip01_R_Thigh");
	IBoneSceneNode* bonenode2 = node->getJointNode("--_R_Butt");
	IBoneSceneNode* bonenode3 = node->getJointNode("Bip01_R_Calf");
	IBoneSceneNode* bonenode4 = node->getJointNode("--_R_Knee");
	IBoneSceneNode* bonenode5 = node->getJointNode("Bip01_R_Foot");
	IBoneSceneNode* bonenode6 = node->getJointNode("--_R_Ankle");
	IBoneSceneNode* bonenode7 = node->getJointNode("Bip01_R_Toe0");
	IBoneSceneNode* bonenode8 = node->getJointNode("Bip01_L_Thigh");
	IBoneSceneNode* bonenode9 = node->getJointNode("--_L_butt");
	IBoneSceneNode* bonenode10 = node->getJointNode("Bip01_L_Calf");
	IBoneSceneNode* bonenode11 = node->getJointNode("--_L_Knee");
	IBoneSceneNode* bonenode12 = node->getJointNode("Bip01_L_Foot");
	IBoneSceneNode* bonenode13 = node->getJointNode("--_L_ankle");
	IBoneSceneNode* bonenode14 = node->getJointNode("Bip01_L_Toe0");


	

	//core::array<SJoint*> joint = myMesh2->getAllJoints();

	node->setJointMode( irr::scene::EJUOR_CONTROL);

	while(device->run())
		if (device->isWindowActive())
		{
			driver->beginScene(true, true, video::SColor(0,200,200,200));

			node->animateJoints();
			node2->animateJoints();

			bonenode1->setRotation(bonenode2_1->getRotation());
			bonenode2->setRotation(bonenode2_2->getRotation());
			bonenode3->setRotation(bonenode2_3->getRotation());
			bonenode4->setRotation(bonenode2_4->getRotation());
			bonenode5->setRotation(bonenode2_5->getRotation());
			bonenode6->setRotation(bonenode2_6->getRotation());
			bonenode7->setRotation(bonenode2_7->getRotation());
			bonenode8->setRotation(bonenode2_8->getRotation());
			bonenode9->setRotation(bonenode2_9->getRotation());
			bonenode10->setRotation(bonenode2_10->getRotation());
			bonenode11->setRotation(bonenode2_11->getRotation());
			bonenode12->setRotation(bonenode2_12->getRotation());
			bonenode13->setRotation(bonenode2_13->getRotation());
			bonenode14->setRotation(bonenode2_14->getRotation());

			smgr->drawAll();
			driver->endScene();			
		}
		device->drop();
	

	return 0;
}
Last edited by klikli234 on Mon Apr 18, 2011 1:18 pm, edited 1 time in total.
Lonesome Ducky
Competition winner
Posts: 1123
Joined: Sun Jun 10, 2007 11:14 pm

Post by Lonesome Ducky »

Ok, here's the class I made to do this. Basically, it animates the upper and lower body separately. To do this, you need to have all bones in the upper body's names to start with U, and all bones in the lower body need to start with L. You create a CCharacterAnimator, provide it with the mesh with the animation, then use animateUpper or animateLower. Just remember what I said about naming the bones. You'll also have to add your animation types to the enum in CCharacterAnimator.cpp.

CCharacterAnimator.h

Code: Select all

#ifndef CCHARACTERANIMATOR_H
#define CCHARACTERANIMATOR_H
#include <irrlicht.h>

// Creates a copy of a skinned mesh
irr::scene::ISkinnedMesh* createSkinnedMeshCopy(irr::scene::ISkinnedMesh* mesh, irr::scene::ISceneManager* smgr);

// Type of animation
enum E_ANIMATION_TYPE {
	EAT_UNKNOWN = 0
};

// Class for animating characters
class CCharacterAnimator {

	// Begin and end frames
	irr::s32 mBeginFrame;
	irr::s32 mEndFrame;

	// Current frame of animation
	irr::f32 mCurrentFrame;

	// Speed of animation
	irr::f32 mAnimationSpeed;

	// Whether or not the animation loops
	bool mLooping;

	// If the animation does not loop, this stores whether or not it has been finished
	bool mDoneAnimating;

	// Mesh for this animator (usually only stores bones)
	irr::scene::ISkinnedMesh* mMesh;

	// Type of animation. Useful so you don't set an animation to the same thing and reset it
	E_ANIMATION_TYPE mType;

	// Priority. In a character class, animators with lower or equal priorities will be replace
	irr::s32 mPriority;

	// Copy of the scene manager, used for cloning
	irr::scene::ISceneManager* mSmgr;

	// Whether the animation is paused
	bool mPaused;

public:
	
	// Constructor
	CCharacterAnimator();
	CCharacterAnimator(irr::scene::ISceneManager* smgr, irr::scene::ISkinnedMesh* mesh, irr::s32 beginFrame, irr::s32 endFrame, irr::f32 animationSpeed, E_ANIMATION_TYPE type, irr::s32 priority, bool looping = true);

	// Destructor
	~CCharacterAnimator();

	// Create a copy of this object (clones mesh as well)
	CCharacterAnimator* clone();

	// Update animations (should be called right before animating an object)
	void update(irr::f32 frameDeltaTime);

	// Animate whole node
	void animate(irr::scene::IAnimatedMeshSceneNode* node);

	// Animate lower or upper part of node
	void animateUpper(irr::scene::IAnimatedMeshSceneNode* node);
	void animateLower(irr::scene::IAnimatedMeshSceneNode* node);

	// Getters/setters
	void setFrameLoop(irr::s32 beginFrame, irr::s32 endFrame);
	void setAnimationSpeed(irr::f32 animationSpeed);
	void setCurrentFrame(irr::f32 currentFrame);
	void setLooping(bool looping);
	void setType(E_ANIMATION_TYPE type);
	void setPriority(irr::s32 priority);
	void setMesh(irr::scene::ISkinnedMesh* mesh);

	irr::s32				   getBeginFrame();
	irr::s32				   getEndFrame();
	irr::f32				   getAnimationSpeed();
	irr::f32			 	   getCurrentFrame();
	bool					   isLooping();
	bool					   isAnimationDone();
	E_ANIMATION_TYPE		   getType();
	irr::s32				   getPriority();
	irr::scene::ISkinnedMesh*  getMesh();

};


#endif
CCharacterAnimator.cpp

Code: Select all

#include "CCharacterAnimator.h"

// Code for copying a skinned mesh, taken from cutealien
irr::scene::ISkinnedMesh* createSkinnedMeshCopy(irr::scene::ISkinnedMesh* mesh, irr::scene::ISceneManager *smgr)
{
	irr::scene::ISkinnedMesh* skinnedMesh = smgr->createSkinnedMesh();

    if ( !mesh )
        return skinnedMesh;

	for ( irr::u32 i=0; i < mesh->getMeshBuffers().size(); ++i )
    {
		irr::scene::SSkinMeshBuffer * buffer = skinnedMesh->addMeshBuffer();
        *buffer = *(mesh->getMeshBuffers()[i]);
    }

	for ( irr::u32 j=0; j < mesh->getAllJoints().size(); ++j )
    {
		irr::scene::ISkinnedMesh::SJoint *joint = skinnedMesh->addJoint();
        *joint = *(mesh->getAllJoints()[j]);
   }

    // fix children pointers (they still have old pointers)
	irr::core::array<irr::scene::ISkinnedMesh::SJoint*> & newJoints = skinnedMesh->getAllJoints();
	irr::core::array<irr::scene::ISkinnedMesh::SJoint*> & oldJoints = mesh->getAllJoints();
	for ( irr::u32 i=0; i < newJoints.size(); ++i )
    {
        irr::scene::ISkinnedMesh::SJoint * joint = newJoints[i];
		for ( irr::u32 c=0; c < joint->Children.size(); ++c )
        {
            // the child is one of the oldJoints and must be replaced by the newjoint on the same index
			for ( irr::u32 k=0; k < oldJoints.size(); ++k )
            {
                if ( joint->Children[c] == oldJoints[k] )
                {
                    joint->Children[c] = newJoints[k];
                    break;
                }
            }
        }
    }

	skinnedMesh->finalize();

    return skinnedMesh;
}



// Constructors
CCharacterAnimator::CCharacterAnimator() : mBeginFrame(0), mEndFrame(0), mCurrentFrame(0), mAnimationSpeed(0.0f), mLooping(true), mDoneAnimating(false), mMesh(0), mType(EAT_UNKNOWN), mPriority(-1), mSmgr(0) {

}
CCharacterAnimator::CCharacterAnimator(irr::scene::ISceneManager* smgr, irr::scene::ISkinnedMesh* mesh, irr::s32 beginFrame, irr::s32 endFrame, irr::f32 animationSpeed, E_ANIMATION_TYPE type, irr::s32 priority, bool looping)
: mBeginFrame(beginFrame), mEndFrame(endFrame), mAnimationSpeed(animationSpeed), mType(type), mPriority(priority), mLooping(looping), mDoneAnimating(false), mCurrentFrame(0) {

	// Create a copy of the mesh (not necessary)
	//mMesh = createSkinnedMeshCopy(mesh,smgr);
	
	mMesh = mesh;

	// Store the scene manager
	mSmgr = smgr;

}
// Destructor
CCharacterAnimator::~CCharacterAnimator() {
	/*if (mMesh != 0) {
		delete mMesh;
		mMesh = 0;
	}*/
}

// Clones this node
CCharacterAnimator* CCharacterAnimator::clone() {
	
	if (mSmgr != 0 && mMesh != 0) {
		CCharacterAnimator* clone = new CCharacterAnimator(mSmgr,mMesh,mBeginFrame,mEndFrame,mAnimationSpeed,mType,mPriority,mLooping);
	}
	else
		return 0;

}

// Animate a node
void CCharacterAnimator::animate(irr::scene::IAnimatedMeshSceneNode *node) {

	if (mMesh != 0 && node != 0) {

		node->setJointMode(irr::scene::EJUOR_CONTROL);

		// Loop through all the joints, and if their name starts with u, Animate them
		for (int i = 0; i < mMesh->getJointCount(); i++) {
				// Commented out because .ms3d files exported from misfit have problems
				//node->getJointNode(i)->setPosition(mMesh->getAllJoints()[i]->LocalAnimatedMatrix.getTranslation());
				node->getJointNode(i)->setRotation(mMesh->getAllJoints()[i]->LocalAnimatedMatrix.getRotationDegrees());
				node->getJointNode(i)->setScale(mMesh->getAllJoints()[i]->LocalAnimatedMatrix.getScale());
		}

	}

}

// Animate the upper part of a node
void CCharacterAnimator::animateUpper(irr::scene::IAnimatedMeshSceneNode *node) {

	if (mMesh != 0 && node != 0) {

		node->setJointMode(irr::scene::EJUOR_CONTROL);

		// Loop through all the joints, and if their name starts with u, Animate them
		for (int i = 0; i < mMesh->getJointCount(); i++) {

			if (node->getJointNode(i)->getName()[0] == 'U') {
				// Commented out because .ms3d files exported from misfit have problems
				//node->getJointNode(i)->setPosition(mMesh->getAllJoints()[i]->LocalAnimatedMatrix.getTranslation());
				node->getJointNode(i)->setRotation(mMesh->getAllJoints()[i]->LocalAnimatedMatrix.getRotationDegrees());
				node->getJointNode(i)->setScale(mMesh->getAllJoints()[i]->LocalAnimatedMatrix.getScale());
			}

		}

	}

}

// Animate the lower part of a node
void CCharacterAnimator::animateLower(irr::scene::IAnimatedMeshSceneNode *node) {

	if (mMesh != 0 && node != 0) {

		node->setJointMode(irr::scene::EJUOR_CONTROL);

		// Loop through all the joints, and if their name starts with l, Animate them
		for (int i = 0; i < mMesh->getJointCount(); i++) {

			if (node->getJointNode(i)->getName()[0] == 'L') {
				// Commented out because .ms3d files exported from misfit have problems
				//node->getJointNode(i)->setPosition(mMesh->getAllJoints()[i]->LocalAnimatedMatrix.getTranslation());
				node->getJointNode(i)->setRotation(mMesh->getAllJoints()[i]->LocalAnimatedMatrix.getRotationDegrees());
				node->getJointNode(i)->setScale(mMesh->getAllJoints()[i]->LocalAnimatedMatrix.getScale());
			}
		
		}

	}

}

// Update the animation
void CCharacterAnimator::update(irr::f32 frameDeltaTime) {
	
	// Find new frame
	mCurrentFrame += frameDeltaTime*mAnimationSpeed;
	irr::f32 nextFrame = mCurrentFrame + (mAnimationSpeed/abs(mAnimationSpeed));

	// Make sure it doesn't go over
	// If looping, reset animation
	if (mLooping) {
	
		while (mCurrentFrame > mEndFrame)
			mCurrentFrame -= (mEndFrame-mBeginFrame);
		while (mCurrentFrame < mBeginFrame)
			mCurrentFrame += (mEndFrame-mBeginFrame);

		while (nextFrame > mEndFrame)
			nextFrame -= (mEndFrame-mBeginFrame);
		while (nextFrame < mBeginFrame)
			nextFrame += (mEndFrame-mBeginFrame);

	}
	
	// If not looping, stop animation if it goes over
	else {

		if (mCurrentFrame > mEndFrame) {
			mCurrentFrame = mEndFrame;
			mDoneAnimating = true;
		}
		else if (mCurrentFrame < mBeginFrame) {
			mCurrentFrame = mBeginFrame;
			mDoneAnimating = true;
		}

		if (nextFrame > mEndFrame)
			nextFrame = mEndFrame;
		else if (nextFrame < mBeginFrame)
			nextFrame = mBeginFrame;
	
	}

	// Find actual current frame
	irr::s32 wholeFrame = floor(mCurrentFrame);
	irr::f32 blend = mCurrentFrame - wholeFrame;


	// Move mesh first to the current frame, and then blend with the next frame
	mMesh->animateMesh(wholeFrame,1.0f);
	mMesh->animateMesh(floor(nextFrame),blend);

}



// Getters/setters
// Set frame loop
void CCharacterAnimator::setFrameLoop(irr::s32 beginFrame, irr::s32 endFrame) {
	mBeginFrame = beginFrame;
	mEndFrame = endFrame;
}

// Set animation speed
void CCharacterAnimator::setAnimationSpeed(irr::f32 animationSpeed) {
	mAnimationSpeed = animationSpeed;
}

// Set current frame
void CCharacterAnimator::setCurrentFrame(irr::f32 currentFrame) {
	mCurrentFrame = currentFrame;
}

// Set whether or not the animation is looping
void CCharacterAnimator::setLooping(bool looping) {
	mLooping = looping;
}

// Set type of animation
void CCharacterAnimator::setType(E_ANIMATION_TYPE type) {
	mType = type;
}

// Set priority of this object (determines whether an animation should override another)
void CCharacterAnimator::setPriority(irr::s32 priority) {
	mPriority = priority;
}

// Set mesh of this object
void CCharacterAnimator::setMesh(irr::scene::ISkinnedMesh *mesh) {
	if (mMesh)
		delete mMesh;
	mMesh = mesh;
}

// Getters
// Get begin frame of animation
irr::s32 CCharacterAnimator::getBeginFrame() {
	return mBeginFrame;
}

// Get end frame of animation
irr::s32 CCharacterAnimator::getEndFrame() {
	return mEndFrame;
}

// Get current frame of animation
irr::f32 CCharacterAnimator::getCurrentFrame() {
	return mCurrentFrame;
}

// Get animation speed
irr::f32 CCharacterAnimator::getAnimationSpeed() {
	return mAnimationSpeed;
}

// Get whether or not this animation loops
bool CCharacterAnimator::isLooping() {
	return mLooping;
}

// Whether or not this animation has finished
bool CCharacterAnimator::isAnimationDone() {
	return mDoneAnimating;
}

// Get type of animation
E_ANIMATION_TYPE CCharacterAnimator::getType() {
	return mType;
}

// Get priority of animation (whether or not this animation should override another)
irr::s32 CCharacterAnimator::getPriority() {
	return mPriority;
}

// Get mesh of animation
irr::scene::ISkinnedMesh* CCharacterAnimator::getMesh() {
	return mMesh;
}
mongoose7
Posts: 1227
Joined: Wed Apr 06, 2011 12:13 pm

Post by mongoose7 »

When you wrote

Code: Select all

IBoneSceneNode* bonenode1 = node->getJointNode((irr::c8*)"Bip01_Spine");
in the other thread, I thought this was working code. If this code works, it is all you need. Though I would be surprised if IAnimatedMeshSceneNode can give you access to the joints. I think it is only for AnimatedMeshes not for SkinnedMeshes. (These aren't my names :x ). So you might have to look at other scene nodes. I don't think there are any examples of this, so you are on your own. I'm still working on the loader so I can offer no further help. I think I'd look at CBoneSceneNode.

If you haven't really got a joint, you have to go from a scene manager to the mesh. You need to extract a CSkinnedMesh object. I haven't done it yet - still working on the loader.
klikli234
Posts: 97
Joined: Tue Sep 07, 2010 10:52 am

Post by klikli234 »

thanks Lonesome Ducky and mongoose7 very much
mongoose7
Posts: 1227
Joined: Wed Apr 06, 2011 12:13 pm

Post by mongoose7 »

Yes, Lonesome Ducky, a really generous act. 8)

This is not my problem, but reading your code I notice two things.

1. You use EJUOR_CONTROL;
2. You copy the rotations and translations from one node to another.

I would have thought (ahem) that you could just point UseAnimationFrom at the node. Although I guess this means you have to animate it first. But then Irrlicht would control the animation?

Just my thoughts. As I said, your effort in this matter has been heroic.
Lonesome Ducky
Competition winner
Posts: 1123
Joined: Sun Jun 10, 2007 11:14 pm

Post by Lonesome Ducky »

Well, he was looking for a way to play two animations at once (or that's the way I read it). useAnimationFrom allows only one animation. Hopefully that's what he was asking at least :lol: . But if not, I didn't waste too much time as this is some code I had laying around from another project.

The reason I used EJUOR_CONTROL is so I could manually move the bones of the target mesh. I'm also only copying the joint transformations to specific joints, so you can use more than one animation at once. Basically with this code, you'd create two CCharacterAnimators. One for the top, one for the bottom. Then you'd just do:

Code: Select all

bottom->animateLower(node);
top->animateUpper(node);
And you'd have two animations playing on the same mesh.
mongoose7
Posts: 1227
Joined: Wed Apr 06, 2011 12:13 pm

Post by mongoose7 »

OK, I can see that. But my point was that you can set useAnimationFrom on specific nodes. And then you can let Irrlicht do the animation.

I'm thinking of blending two animations by multiplying their rotation matrices together. It is not really possible to multiple the translation matrices as this would just make the skeleton twice as large as the mesh, which wouldn't play out too well.

Anyway, food for thought. Not much skinned mesh animation going on here so it was good to see your contribution.
Post Reply