useAnimationFrom problem

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.
Valmond
Posts: 308
Joined: Thu Apr 12, 2007 3:26 pm

useAnimationFrom problem

Post by Valmond »

Hi!

Thinking I was smart I tried to mix animations and skinned meshes together using useAnimationFrom().

Basically I load up Meshes containing characters (ie. Human, Skeleton, Orc...) at startup,
then I load up animations (ie. Idle, Run, Attack...), also at startup.

Both are B3D files and scene::ISkinnedMesh:es (Meshes contains a Mesh + Bones, Animations contains Bones+Animation).


At runtime when I want to draw a running orc I add a node created with :
node[m_PlayerID]=smgr->addAnimatedMeshSceneNode(NewMesh,RootNode,m_PlayerID);
(m_PlayerID here is an exclusive ID for this "Orc-Player")

where NewMesh points on the preloaded Orc ISkinnedMesh.

I then use
scene::ISkinnedMesh* SkinMesh=(scene::ISkinnedMesh*)node[m_PlayerID]->getMesh();
SkinMesh->useAnimationFrom(NewAnimationMesh);
node[m_PlayerID]->setFrameLoop(0, 60);

where NewAnimationMesh is the preloaded ISkinnedMesh containing the run animation.




This all works well except when I want to draw another Orc (Attacking) at the same time...
(A running Orc + an attacking Human works Okay).

They're getting the same animation!
(ie. both are attacking).


I use:
node[m_PlayerID]->setCurrentFrame(frame);
node[m_PlayerID]->animateJoints(true);

for each node too, but they're ending up with the same frame too.



What I got is that I'm doing all bone-manipulation on like 'one set of bones' and all meshes (of one type) uses it, but how can I get around that?

Do I need to clone the animation mesh each time I want to use one (or the Orc mesh?) of them or have I missed something here?
hayate
Posts: 43
Joined: Mon Feb 16, 2009 9:38 pm
Location: Brescia, Italy

Re: useAnimationFrom problem

Post by hayate »

Valmond wrote:...
...
At runtime when I want to draw a running orc I add a node created with :
node[m_PlayerID]=smgr->addAnimatedMeshSceneNode(NewMesh,RootNode,m_PlayerID);

where NewMesh points on the preloaded Orc ISkinnedMesh.

I then use
scene::ISkinnedMesh* SkinMesh=(scene::ISkinnedMesh*)node[m_PlayerID]->getMesh();
SkinMesh->useAnimationFrom(NewAnimationMesh);
node[m_PlayerID]->setFrameLoop(0, 60);
...
...
Do I need to clone the animation mesh each time I want to use one (or the Orc mesh?) of them or have I missed something here?
I think that SkinMesh pointer points at the same Iskinnedmesh you use for all Orcs (the NewMesh from the addAnimatedMeshSceneNode), changing that mesh animations changes the animations for all nodes using it as animations are stored in mesh, not in nodes

I thought only 3 workarounds (2 of them are similar) for this:
1)(less flexible but probably requires less memory) put all the animations in a single skinnedmesh with different frames (0-60 run, 61-120 attack and so on) instead of one skinnedmesh for every animation
2)(faster and easier to implement but don't use this if you need many nodes in this way or it will fill all your memory) for every node clone the NewMesh into a new skinnedMesh (remember to delete it when you delete the node)
3)for every animation of your Orcs create a skinned mesh and apply the animation, then change the mesh of your node with the one you need, you could also do this on runtime (create the runningorc skinned mesh the first time you need to make an orc run, then use it for every orc that need to run)

I don't know but there is probably a simple way to chain 2 or more meshes togheter (if there is you can combine it with the third method to create a single mesh containing all of your orc animations and use it for all the orcs like method 1 but keeping the flexibility to add new animations easily)
Sorry for my awful english ^_^'
Image
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Post by CuteAlien »

I seem to have the same problem. Actually I missed that so far - it seems I accidentally tested all the time animations by selecting different meshes :-)

Well, anyway - right now there seems no way to actually copy a skinnedmesh or am I missing something? I guess I'm adding a copy function to the meshmanipulator tomorrow in my version, but maybe someone has a better solution?
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Valmond
Posts: 308
Joined: Thu Apr 12, 2007 3:26 pm

Post by Valmond »

Thanks Hayate, there are lot of fixes but all of them needs more memory / loading time etc. and for 1) that is exactly what I'm trying to code away :)


It seems like this code

node[m_PlayerID]->setCurrentFrame(frame);
node[m_PlayerID]->animateJoints(true);

is actually executed instantly and not on a per-node basis at render time and
it is executed on the original mesh (and not on cloned bones, which seems normal after all)...


Maybe a CustomSceneNode that does the setCurrentFrame() + animateJoints() at rendertime might do it?


@CuteAlien
If you find a solution them I'm interested ;)
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Post by CuteAlien »

OK, can't promise my solution is perfect as I'm still struggling to understand how that stuff is done in Irrlicht, but at least it works.

It needs some patch to Irrlicht - (my Irrlicht version is around revision 1981 - which means shortly after Irrlicht 1.5 release). That adds a function to the meshmanipulator that creates a new ISkinnedMesh with the meshbuffers and joints of another ISkinnedMesh:

Code: Select all

diff -r 8ecc8dc21f86 lib/irrlicht/include/IMeshManipulator.h
--- a/lib/irrlicht/include/IMeshManipulator.h	Fri Mar 06 17:24:47 2009 +0100
+++ b/lib/irrlicht/include/IMeshManipulator.h	Wed Mar 11 03:04:11 2009 +0100
@@ -20,6 +20,7 @@
 	class IMesh;
 	class IMeshBuffer;
 	struct SMesh;
+	class ISkinnedMesh;
 
 	//! An interface for easy manipulation of meshes.
 	/** Scale, set alpha value, flip surfaces, and so on. This exists for
@@ -180,6 +181,13 @@
 		IReferenceCounted::drop() for more information. */
 		virtual IAnimatedMesh * createAnimatedMesh(IMesh* mesh,
 			scene::E_ANIMATED_MESH_TYPE type = scene::EAMT_UNKNOWN) const = 0;
+
+        //! Create a skinned mesh which has copied all meshbuffers and joints of the original mesh
+        /** 
+        \param mesh Original mesh
+        \return Newly created skinned mesh. You should call drop() wehn you don't need it anymore.
+        See	IReferenceCounted::drop() for more information. */
+		virtual ISkinnedMesh* createSkinnedMesh(ISkinnedMesh* mesh) const = 0;
 	};
 
 } // end namespace scene
diff -r 8ecc8dc21f86 lib/irrlicht/source/Irrlicht/CMeshManipulator.cpp
--- a/lib/irrlicht/source/Irrlicht/CMeshManipulator.cpp	Fri Mar 06 17:24:47 2009 +0100
+++ b/lib/irrlicht/source/Irrlicht/CMeshManipulator.cpp	Wed Mar 11 03:04:11 2009 +0100
@@ -6,6 +6,7 @@
 #include "SMesh.h"
 #include "CMeshBuffer.h"
 #include "SAnimatedMesh.h"
+#include "CSkinnedMesh.h"
 #include "os.h"
 
 namespace irr
@@ -1140,6 +1141,50 @@
 	return new SAnimatedMesh(mesh, type);
 }
 
+//! Create a skinned mesh which has copied all meshbuffers and joints of the original mesh
+ISkinnedMesh* CMeshManipulator::createSkinnedMesh(ISkinnedMesh* mesh) const
+{
+    CSkinnedMesh * skinnedMesh = new CSkinnedMesh();
+
+    if ( !mesh )
+        return skinnedMesh;
+
+    for ( u32 i=0; i < mesh->getMeshBuffers().size(); ++i )
+    {
+        SSkinMeshBuffer * buffer = skinnedMesh->createBuffer();
+        *buffer = *(mesh->getMeshBuffers()[i]);
+    }
+
+    for ( u32 j=0; j < mesh->getAllJoints().size(); ++j )
+    {
+        CSkinnedMesh::SJoint *joint = skinnedMesh->createJoint();
+        *joint = *(mesh->getAllJoints()[j]);
+    }
+
+    // fix children pointers (they still have old pointers)
+    core::array<CSkinnedMesh::SJoint*> & newJoints = skinnedMesh->getAllJoints();
+    core::array<CSkinnedMesh::SJoint*> & oldJoints = mesh->getAllJoints();
+    for ( u32 i=0; i < newJoints.size(); ++i )
+    {
+        CSkinnedMesh::SJoint * joint = newJoints[i];
+        for ( 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 ( u32 k=0; k < oldJoints.size(); ++k )
+            {
+                if ( joint->Children[c] == oldJoints[k] )
+                {
+                    joint->Children[c] = newJoints[k];
+                    break;
+                }
+            }
+        }
+    }
+
+    skinnedMesh->finalize();
+
+    return skinnedMesh;
+}
 
 } // end namespace scene
 } // end namespace irr
diff -r 8ecc8dc21f86 lib/irrlicht/source/Irrlicht/CMeshManipulator.h
--- a/lib/irrlicht/source/Irrlicht/CMeshManipulator.h	Fri Mar 06 17:24:47 2009 +0100
+++ b/lib/irrlicht/source/Irrlicht/CMeshManipulator.h	Wed Mar 11 03:04:11 2009 +0100
@@ -106,6 +106,9 @@
 	//! create a new AnimatedMesh and adds the mesh to it
 	virtual IAnimatedMesh * createAnimatedMesh(scene::IMesh* mesh,scene::E_ANIMATED_MESH_TYPE type) const;
 
+    //! Create a skinned mesh which has copied all meshbuffersand joints of the original mesh
+    virtual ISkinnedMesh* createSkinnedMesh(ISkinnedMesh* mesh) const;
+
 private:
 
 	static void calculateTangents(core::vector3df& normal, 

Now when I create Animation nodes I make sure skinned meshes are copied first:

Code: Select all

irr::scene::IAnimatedMesh * mesh = .... // whereever you get it from - probably from loading.
irr::scene::IAnimatedMeshSceneNode * node = 0;
if ( mesh->getMeshType() == scene::EAMT_SKINNED )
{
	scene::IMeshManipulator * meshManip = sceneManager.getMeshManipulator();
	scene::ISkinnedMesh * meshCopy = meshManip->createSkinnedMesh( static_cast<scene::ISkinnedMesh*>(mesh));
	node = sceneManager.addAnimatedMeshSceneNode(meshCopy);
	meshCopy->drop();
}
else
{
	node = sceneManager.addAnimatedMeshSceneNode(mesh);
}
That's basically it.

If you use Blender you might also be interested in my patch to gandalfs exporter: http://www.michaelzeilfelder.de/irrlicht.htm#Scripts
This patch allows to export meshes and animations separately, so I load just the mesh with bones into my scenenode. And then with useAnimationFrom I use meshes which only contain bones and animations.
Last edited by CuteAlien on Wed Mar 11, 2009 2:47 pm, edited 1 time in total.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Post by CuteAlien »

edit: *redface*
Last edited by CuteAlien on Wed Mar 11, 2009 2:48 pm, edited 1 time in total.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

Then just take it out :D You can simply remove the text and leave the comment start there, which wouldn't require any other change to the patch file.
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Post by CuteAlien »

hybrid wrote:Then just take it out :D You can simply remove the text and leave the comment start there, which wouldn't require any other change to the patch file.
Guess that was too obvious for me ;-) Fixed now.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Valmond
Posts: 308
Joined: Thu Apr 12, 2007 3:26 pm

Post by Valmond »

Oh yes it works!

After some cut and paste and forgotten copies of the .dll (+relinking etc) my skeletons doesn't do the same animation Thank you!
Valmond
Posts: 308
Joined: Thu Apr 12, 2007 3:26 pm

Post by Valmond »

Came to think of it, shouldn't this patch be a candidate for a future release?

It's deadly useful!
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Post by CuteAlien »

I'm not 100% happy with it so far. A create-function with a parameter that only uses part of that parameter (just enough to make this work). I'm not sure if this is intuitive to use (without reading this thread first). Also I'm not deep enough in the animation system to know if this covers all such problem or if it just works for my (and your) models or if any further data of CSkinnedMesh should be copied here.

I think Bitplane would prefer having the animationscenenodes handling the mesh-copies, which would be the easier-to-use solution. I avoided that as it would have made for patch that is more fused with other code and that sort of patches makes it in my experience harder for me to update my patches to newer engine versions.

Then again maybe a working solution is better than no solution at all. Anyway, the Irrlicht team is aware of the thread, so if they ever come around to handling this they have at least some basis to start.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
B@z
Posts: 876
Joined: Thu Jan 31, 2008 5:05 pm
Location: Hungary

Post by B@z »

hi
sorry for hijacking your topic, but dun wanna open a new xD


I just dont understand why it doesn't animate joints what can't be found in the boneMesh?
it just doesn't make any sense...
If there is no matching joint in the boneMesh, then it should use the original animation from the skinMesh.
and of course, if no animation in the skinMesh, then it won't animate.
For example, for a cloak, in your boneMesh there is just the bones for the human, and in the cloak, there should be the cloak animation.
Its just cant be customized enough in this way..
and yeah we can put all the joints in the same mesh, but then it would be a great chaos xD
so i suggest it should copy animations when same bone has found, and use the original bone animation when not found.
Image
Image
B@z
Posts: 876
Joined: Thu Jan 31, 2008 5:05 pm
Location: Hungary

Post by B@z »

any idea how could i modify that it copyes the animation when found same joint, and use the original animation when didn't find
Image
Image
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Post by CuteAlien »

I suppose in your example you should rather give the cloak it's own animation which is independent of the human animation.

I would not like to see parts of an old animation messing with a new animation which I have set. I guess there are situation where you might want to have several animations operating the same time at the same bones - and the second one having priority over the first is in that case one of the things you could wish for, but I don't think that is supported right now. I guess you could try animating a mesh twice with both animations and somehow checking first which bones are used by both animatios and then removing those for the first animation. But I think at the moment you would have to change Irrlicht itself for that.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
B@z
Posts: 876
Joined: Thu Jan 31, 2008 5:05 pm
Location: Hungary

Post by B@z »

nope, because it would only use the original animation when the same joint name couldnt be found.

so the human animation would be loaded from the boneMesh, and the cloak animation from my skinMesh.
and i dont want to have several animations the same time at the same bones..
i cant even imagine it, whats that? O_o
Image
Image
Post Reply