IMeshManipulator::transform fails to work on rigged meshes

You discovered a bug in the engine, and you are sure that it is not a problem of your code? Just post it in here. Please read the bug posting guidelines first.
Post Reply
Vandar_Vegawan
Posts: 3
Joined: Wed Mar 28, 2012 10:50 pm

IMeshManipulator::transform fails to work on rigged meshes

Post by Vandar_Vegawan »

If a mesh uses skeletal animation, a call to IMeshManipulator.transform() will transform the vertices of that mesh but not the skeleton. This causes animations using the mesh to revert to their original positions. As a demonstration, I created two simple meshes and animated one of them by making one of its faces move up and down using skeletal animation. I then used the IMeshManipulator to rotate both meshes 90 degrees. The static mesh behaved appropriately, but the points on the animated mesh affected by the bone did not.

Image
The static mesh on the left behaves properly. The animated mesh on the right should have its top moving up and down, but the animated portion is set back to its original rotation instead.

The code I used is below. I don't know how to upload my test meshes, so you'll need to provide your own.

Code: Select all

 
#include <irrlicht.h>
 
// Quick test to show how IMeshManipulator::transform fails to transform animated .b3d meshes
 
using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;
 
int main()
{
        IrrlichtDevice *device = createDevice( video::EDT_SOFTWARE,
          dimension2d<u32>(640, 480), 16, false, false, false, 0);
        if (!device) {return 1;}
 
        device->setWindowCaption(L"IMeshManipulator Bug Demonstration");
 
        IVideoDriver* driver = device->getVideoDriver();
        ISceneManager* smgr = device->getSceneManager();
 
        // Non-animated node, with mesh manip
        IAnimatedMesh* mesh = smgr->getMesh("NonAnim.b3d");
        if (!mesh)
        {
                device->drop();
                return 1;
        }
        matrix4 rotateMatrix;
        rotateMatrix.buildRotateFromTo(vector3df(0,1,0), vector3df(0,0,1));
        smgr->getMeshManipulator()->transform(mesh, rotateMatrix);
        IAnimatedMeshSceneNode* node = smgr->addAnimatedMeshSceneNode(mesh, 0,
          -1, vector3df(-5, 0, 0));
        if (node) { node->setMaterialFlag(EMF_LIGHTING, false); }
 
        // Animated node, with mesh manip. This fails to be properly manipulated.
        mesh = smgr->getMesh("Animated.b3d");
        if (!mesh)
        {
                device->drop();
                return 1;
        }
        smgr->getMeshManipulator()->transform(mesh, rotateMatrix);
        node = smgr->addAnimatedMeshSceneNode(mesh, 0, -1, vector3df(5, 0, 0));
        if (node)
        {
            node->setMaterialFlag(EMF_LIGHTING, false);
            node->setFrameLoop (0, 20);
        }
 
        ICameraSceneNode* cam = smgr->addCameraSceneNode(0, vector3df(0,15,5), vector3df(0,5,0));
        cam->setUpVector(vector3df(0,0,1));
 
        while(device->run())
        {
                driver->beginScene(true, true, SColor(255,100,101,140));
                smgr->drawAll();
                driver->endScene();
        }
        device->drop();
 
        return 0;
}
 
Irrlicht Engine Version 1.7.3
Microsoft Windows 7 Home Premium Edition Service Pack 1 (Build 7601)
mongoose7
Posts: 1227
Joined: Wed Apr 06, 2011 12:13 pm

Re: IMeshManipulator::transform fails to work on rigged mesh

Post by mongoose7 »

In the rendering loop, call the animateMesh function and then apply the transform. You have no code in the rendering loop and yet the animation system will keep transforming your mesh every time round the loop, so there is no way you can do what you want to do in the way you want to do it. You may need to look at EJUOR_CONTROL as well.
Vandar_Vegawan
Posts: 3
Joined: Wed Mar 28, 2012 10:50 pm

Re: IMeshManipulator::transform fails to work on rigged mesh

Post by Vandar_Vegawan »

The lack of code in the rendering loop is intentional. The IMeshManipulator class documentation specifies that it is intended to be called once to fix wrongly imported meshes during load time and not run time, so I wanted to be able to set the transform once and not worry during the game loop. If both transform functions are commented out of my code, everything animates and displays fine in its original position.

I don't understand what you mean when you say the animation system keeps transforming the mesh each time it is looped. If you mean it is being transformed by the joints back to its original coordinates, then that is the problem. I expected these coordinates to be updated along with the vertices when the transform function is called, and the result to be used by the animating system.

A bit of diving into the joints system, followed by a quick test, shows that simply applying the transform to the local matrix of each joint seems to work. To see on my previous test code, add the following after loading the animated mesh.

Code: Select all

// Transform the joints
if (mesh && mesh->getMeshType() == EAMT_SKINNED)
{
    array<ISkinnedMesh::SJoint*> &joints = ((ISkinnedMesh*)mesh)->getAllJoints();
 
    for(unsigned int i = 0; i < joints.size(); i++)
    {
        joints[i]->LocalMatrix *= rotateMatrix;
    }
}
Unfortunately, the MeshManipulator works on IMesh, while the getMeshType() function is in IAnimatedMesh class, so we'll need to create an overload of the transform function taking IAnimatedMesh* if we want to implement this fix.

Finally, Here are some screenshots I took with and without the fix.
Image

The Left side is the old code, the right side has the fix inserted. I added an extra joint to the top of the animated mesh to see if I needed to adjust for child joints transforming multiple times, but it appears to work fine. That said, I didn't test it very thoroughly, so there might be problems down the road with not adjusting the joint's other data members, etc.
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Re: IMeshManipulator::transform fails to work on rigged mesh

Post by hybrid »

Yes, mesh manipulation is intentionally devised for static meshes. The handling of animated meshes is not yet that standardized that we can easily apply mesh manipulations of any kind to animated meshes.
Post Reply