[no bug] with Quaternion and Matrix to euler angle

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.
thanhle
Posts: 325
Joined: Wed Jun 12, 2013 8:09 am

[no bug] with Quaternion and Matrix to euler angle

Post by thanhle »

Hi, there seems to be a bug relating to Quaternion to Euler or Matrix to euler.

From the math routine I can see that the return euler angle about Y axis is restrict to [-90,90].

Suppose I have a parent sceneNode with multiple childrens. If I rotated the parent node outside that angle range, and I try to rotate a children scenenode to a target vector, the rotation of the children scenenode won't be correctly update.

E.g. I'm rotating a animatted b3d character shoulder joint only to point to a target vector.

Code: Select all

 
 
 irr::scene::IBoneSceneNode *base = ((IAnimatedMeshSceneNode *)this->sceneNode)->getJointNode("Rshoulder");
         irr::scene::IBoneSceneNode *endEffector = ((IAnimatedMeshSceneNode *)this->sceneNode)->getJointNode("Relbow");
 
         vector3df p1 = endEffector->getAbsolutePosition() - base->getAbsolutePosition();
         vector3df p2 = target - base->getAbsolutePosition();
        
         quaternion q1;
         q1.rotationFromTo(p1, p2);
         q1.normalize();
         quaternion q2;
         q2.set(base->getRotation()*DEGTORAD);
         q2.normalize();
         q2 = q2*q1;                          //Right handed multiplication
 
         q2.normalize();
         vector3df anglexx;     // = q2.getMatrix().getRotationDegrees();
 
         q2.toEuler(anglexx);
         anglexx *= RADTODEG;
 
         base->setRotation(anglexx);
         base->updateAbsolutePositionOfAllChildren();
 
If the parent node is outside of [-90, 90] about y-axis, then child hand doesn't update correctly.

regards
thanh
Last edited by thanhle on Tue Feb 24, 2015 9:40 am, edited 1 time in total.
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Possible bug with Quaternion and Matrix to euler angle

Post by CuteAlien »

Thanks, I'll take a look when I work on that quaternion right-handed report you made recently. Just a few more hours/days and I should finally have my game-release behind me...
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:

Re: Possible bug with Quaternion and Matrix to euler angle

Post by CuteAlien »

OK, rotation around y in toEuler is restricted to -90, 90, but in other ranges it will add 180 to x and z and have something like 90-y (not quite sure but for positive values it's like that). Which gives the correct rotation as far as I can see.

I've looked at a few conversion function on the web, but they generally seem to restrict one axis like that. Maybe it would be better to restrict another axis as rotations around Y are the most common, but if this is a bug it would still be one. It might also be possible to simplify euler rotations somehow (so (180/89/180) would become (0,91,0)) in an own calculation. Or maybe there are other conversions from quaternions to euler which can do that automatically somehow (in theory I could calculate it 3 times with 3 different restrictions and use the rotation with the smallest sum of absolute values... but this would be too slow). Anyway this shouldn't cause an error.

I need a concrete example with shows me a situation where the result can become wrong by this. Maybe it's another function that needs to be fixed.
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
thanhle
Posts: 325
Joined: Wed Jun 12, 2013 8:09 am

Re: Possible bug with Quaternion and Matrix to euler angle

Post by thanhle »

Hi the example code I provided above is for a b3d model which has a Rshoulder and Relbow.

If you make a flying target object.

then putting those code above inside before the begin scene. You will get the elbow following the target.

Once you rotate the b3d model y-angle outside of [-90, 90], you will see the elbow doesn't rotate correctly.

I can show you a video if you want.

Regards,
thanh
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Possible bug with Quaternion and Matrix to euler angle

Post by CuteAlien »

I believe you that things are wrong, no need for a video. But I have to debug it to have a chance figuring out where/why things go wrong exactly. And I wasn't able to get a real bug in a test-case so far.

Something like my example: http://ideone.com/JO0xDD
I can reproduce there that Y doesn't got beyond 90 and it makes sense from code. And I have another solution there (which still mixes axes up, but that's not the point) which could do this specific situation better. But basically it has the same problem - just for another axis.

But the rotation is still correct - there are just several ways to have the same rotation. So I don't think this is the real problem here, but the bug is likely in another part.
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
thanhle
Posts: 325
Joined: Wed Jun 12, 2013 8:09 am

Re: Possible bug with Quaternion and Matrix to euler angle

Post by thanhle »

Hi too late I have made a video. I'll remove it soon. But it's clear to see the problem.

https://youtu.be/M9V6GbAXTfk

At first no rotation on y-axis gives correct angle returned. Rotate y-between (-90, 90) still ok. Anything beyond that gives frantic rotation as can be seen towards the end of the video.

The code I used is above. with below.

animSceneNode->setJointMode(E_JOINT_UPDATE_ON_RENDER::EJUOR_CONTROL);

I'll create a minimal code version for you to test soon.
Regards
thanh
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Possible bug with Quaternion and Matrix to euler angle

Post by CuteAlien »

Try adding a few more keys in between. It might try to interpolate the wrong way around.
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
thanhle
Posts: 325
Joined: Wed Jun 12, 2013 8:09 am

Re: Possible bug with Quaternion and Matrix to euler angle

Post by thanhle »

Hi CuteAlien,
There is no key. The elbow to should link is manipulated manually in real time.

I'm at work atm. I will create a simple test when I get home.
Regards
thanh
thanhle
Posts: 325
Joined: Wed Jun 12, 2013 8:09 am

Re: Possible bug with Quaternion and Matrix to euler angle

Post by thanhle »

Here is the minimal example.
It is just a single link rotation using quaternion. Could it be the skeleton matrix calculation has this error in the update transform? Don't know.

Code: Select all

#include <irrlicht.h>
using namespace irr;
using namespace irr::core;
using namespace irr::scene;
using namespace irr::video;
using namespace irr::io;
using namespace irr::gui;
 
#ifdef _IRR_WINDOWS_
#pragma comment(lib, "Irrlicht.lib")
#pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")
#endif
int main()
{
 
    IrrlichtDevice *device = createDevice(video::EDT_OPENGL, dimension2d<u32>(640, 480), 16, false, false, false, 0);
 
    if (!device)
        return 1;
 
    device->setWindowCaption(L"Hello World! - Irrlicht Engine Demo");
    IVideoDriver* driver = device->getVideoDriver();
    ISceneManager* smgr = device->getSceneManager();
    IGUIEnvironment* guienv = device->getGUIEnvironment();
    guienv->addStaticText(L"Hello World! This is the Irrlicht Software renderer!",
        rect<s32>(10, 10, 260, 22), true);
 
    IAnimatedMesh* mesh = smgr->getMesh("media/jgSally.b3d");
 
 
    if (!mesh)
    {
        device->drop();
        return 1;
    }
    IAnimatedMeshSceneNode* node = smgr->addAnimatedMeshSceneNode(mesh);
 
    if (node)
    {
        node->setMaterialFlag(EMF_LIGHTING, false);
        //node->setScale(vector3df( 0.1f));
        node->setFrameLoop(1, 24);
        node->setJointMode(E_JOINT_UPDATE_ON_RENDER::EJUOR_CONTROL);
        node->setMaterialTexture(0, driver->getTexture("media/jgSally2.jpg"));
    }
 
    
 
 
 
    ISceneNode *vNode = device->getSceneManager()->addSphereSceneNode(0.5f);
    vNode->setPosition(vector3df(0.f, 15.f, 5.f));
    vNode->setName("Flyer");
 
    scene::ISceneNodeAnimator * flyCircleAnimator = device->getSceneManager()->createFlyCircleAnimator(core::vector3df(0.f, 15.f, 5.f), 5.0f, 0.002f, vector3df(0, 0, 1));
    vNode->addAnimator(flyCircleAnimator);
 
 
    vNode->setMaterialFlag(E_MATERIAL_FLAG::EMF_LIGHTING, true);
 
 
    smgr->addCameraSceneNode(0, vector3df(0, 20, 20), vector3df(0, 8, 0));
 
    irr::scene::IBoneSceneNode *base = ((IAnimatedMeshSceneNode *)node)->getJointNode("Rshoulder");
    irr::scene::IBoneSceneNode *endEffector = ((IAnimatedMeshSceneNode *)node)->getJointNode("Relbow");
 
    while (device->run())
    {
 
        driver->beginScene(true, true, SColor(255, 100, 101, 140));
 
        smgr->drawAll();
        guienv->drawAll();
 
        driver->endScene();
 
        
        vector3df rot = node->getRotation();
        rot.Y += 0.01f;
        rot.Y = rot.Y > 360 ? rot.Y - 360 : rot.Y;
        node->setRotation(rot);
        node->updateAbsolutePosition();
 
        //((IBoneSceneNode *)*node->getChildren().begin())->updateAbsolutePositionOfAllChildren();
 
 
        vector3df basePos = base->getAbsolutePosition();
        vector3df target = vNode->getAbsolutePosition();
 
        vector3df endEffPos = endEffector->getAbsolutePosition();
        vector3df p1 = endEffPos - basePos;
        vector3df p2 = target - basePos;
        p1.normalize();
        p2.normalize();
        vector3df axis = p1.crossProduct(p2);
        axis.normalize();
 
        float dot = p1.dotProduct(p2);
        float angle = acosf(dot);
 
 
        if (abs(angle) > 0.0001)
        {
            //printf("%f,%f\n", dot, angle);
 
            quaternion q1;
            //q1.rotationFromTo(p1, p2);
            q1.fromAngleAxis(angle, axis);
            q1.normalize();
 
            quaternion q2;
            q2.set(base->getRotation()*DEGTORAD);
            q2.normalize();
            q2 = q2*q1;
 
            q2.normalize();
            vector3df anglexx;
 
            q2.toEuler(anglexx);
            anglexx *= RADTODEG;
 
            base->setRotation(q2.getMatrix().getRotationDegrees());
            base->updateAbsolutePosition();
            endEffector->updateAbsolutePosition();
 
        }
 
 
    }
 
    device->drop();
    return 0;
}
b3dFile: http://s000.tinyupload.com/index.php?fi ... 1653798266
Last edited by thanhle on Fri Apr 10, 2015 5:37 pm, edited 1 time in total.
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Possible bug with Quaternion and Matrix to euler angle

Post by CuteAlien »

Thanks. But is really all that code needed? Including a flycircleanimator and another node? And node itself also rotation it seems. Please do a quick check if you need all those lines - because for someone else (aka me) reading someone else's code it's always harder to figure out which parts can be dropped or have to stay.

edit: Also a few comments what the math is supposed to do might help a little. I think it's something about rotating elbow somehow...
Something like "angle is that angle between..."
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
thanhle
Posts: 325
Joined: Wed Jun 12, 2013 8:09 am

Re: Possible bug with Quaternion and Matrix to euler angle

Post by thanhle »

That code is Irrlicht tutorial 1 code with 2 more additions. It's not my fault that the code is long : ). I just want to stick to base so that it is easier to see what's wrong.

You can drop the flying circle.
Just make the b3D character statically rotate > 90 degree or less than -90 degree.

You will see the arm rotate incorrectly.

Regards
thanh
thanhle
Posts: 325
Joined: Wed Jun 12, 2013 8:09 am

Re: Possible bug with Quaternion and Matrix to euler angle

Post by thanhle »

Oki, here's the shorter version : ). No rotation animation.

Code: Select all

 
 
#include <irrlicht.h>
using namespace irr;
using namespace irr::core;
using namespace irr::scene;
using namespace irr::video;
using namespace irr::io;
using namespace irr::gui;
 
#ifdef _IRR_WINDOWS_
#pragma comment(lib, "Irrlicht.lib")
#pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")
#endif
int main()
{
 
    IrrlichtDevice *device = createDevice(video::EDT_OPENGL, dimension2d<u32>(640, 480), 16, false, false, false, 0);
 
    if (!device)
        return 1;
 
    device->setWindowCaption(L"Hello World! - Irrlicht Engine Demo");
    IVideoDriver* driver = device->getVideoDriver();
    ISceneManager* smgr = device->getSceneManager();
    IGUIEnvironment* guienv = device->getGUIEnvironment();
    guienv->addStaticText(L"Hello World! This is the Irrlicht Software renderer!",
        rect<s32>(10, 10, 260, 22), true);
 
    IAnimatedMesh* mesh = smgr->getMesh("media/jgSally.b3d");
 
 
    if (!mesh)
    {
        device->drop();
        return 1;
    }
    IAnimatedMeshSceneNode* node = smgr->addAnimatedMeshSceneNode(mesh);
 
    if (node)
    {
        node->setMaterialFlag(EMF_LIGHTING, false);
        //node->setScale(vector3df( 0.1f));
        node->setFrameLoop(1, 24);
        node->setJointMode(E_JOINT_UPDATE_ON_RENDER::EJUOR_CONTROL);
        node->setMaterialTexture(0, driver->getTexture("media/jgSally2.jpg"));
    }
 
vector3df rot = node->getRotation();
    rot.Y = 100.0f; // 0.01f;
    node->setRotation(rot);
    node->updateAbsolutePosition();
 
 
    ISceneNode *vNode = device->getSceneManager()->addSphereSceneNode(0.5f);
    vNode->setPosition(vector3df(0.f, 15.f, 5.f));
    vNode->setName("Flyer");
    
    vNode->setMaterialFlag(E_MATERIAL_FLAG::EMF_LIGHTING, true);
 
    smgr->addCameraSceneNode(0, vector3df(0, 20, 20), vector3df(0, 8, 0));
 
    irr::scene::IBoneSceneNode *base = ((IAnimatedMeshSceneNode *)node)->getJointNode("Rshoulder");
    irr::scene::IBoneSceneNode *endEffector = ((IAnimatedMeshSceneNode *)node)->getJointNode("Relbow");
 
    while (device->run())
    {
 
        vector3df basePos = base->getAbsolutePosition();
        vector3df target = vNode->getAbsolutePosition();
 
        vector3df endEffPos = endEffector->getAbsolutePosition();
        vector3df p1 = endEffPos - basePos;
        vector3df p2 = target - basePos;
        p1.normalize();
        p2.normalize();
        vector3df axis = p1.crossProduct(p2);
        axis.normalize();
 
        float dot = p1.dotProduct(p2);
        float angle = acosf(dot);
 
 
        if (abs(angle) > 0.0001)
        {
            //printf("%f,%f\n", dot, angle);
 
            quaternion q1;
            //q1.rotationFromTo(p1, p2);
            q1.fromAngleAxis(angle, axis);
            q1.normalize();
 
            quaternion q2;
            q2.set(base->getRotation()*DEGTORAD);
            q2.normalize();
            q2 = q2*q1;
 
            q2.normalize();
            vector3df anglexx;
 
            q2.toEuler(anglexx);
            anglexx *= RADTODEG;
 
            base->setRotation(q2.getMatrix().getRotationDegrees());
            base->updateAbsolutePosition();
            endEffector->updateAbsolutePosition();
 
        }
 
 
        driver->beginScene(true, true, SColor(255, 100, 101, 140));
 
        smgr->drawAll();
        guienv->drawAll();
 
        driver->endScene();
    
 
    }
 
    device->drop();
    return 0;
 
}
 
 
 
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Possible bug with Quaternion and Matrix to euler angle

Post by CuteAlien »

Thanks, I try if I can find some time to get through it (but not today). Generally when posting bugreports please try always to kick out every line which has nothing to do with the bug. It's always far (very far!) easier for the poster to do that than for anyone trying to read & understand it.
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:

Re: Possible bug with Quaternion and Matrix to euler angle

Post by CuteAlien »

edit: Hehe - I see - the rotation of the parent has to stay in to see the problem.

Sorry, not getting it. I 've modified the code a little to make it easier to see what's going on. And you control exactly one bone and it follows throughout the target without problems here (svn trunk):

Code: Select all

 
#include <irrlicht.h>
using namespace irr;
using namespace irr::core;
using namespace irr::scene;
using namespace irr::video;
 
#ifdef _IRR_WINDOWS_
#pragma comment(lib, "Irrlicht.lib")
#pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")
#endif
 
int main()
{
    IrrlichtDevice *device = createDevice(video::EDT_OPENGL, dimension2d<u32>(640, 480), 16, false, false, false, 0);
    if (!device)
        return 1;
 
    IVideoDriver* driver = device->getVideoDriver();
    ISceneManager* smgr = device->getSceneManager();
 
    IAnimatedMesh* mesh = smgr->getMesh("media/jgSally.b3d");
    if (!mesh)
    {
        device->drop();
        return 1;
    }
 
    IAnimatedMeshSceneNode* node = smgr->addAnimatedMeshSceneNode(mesh);
    if (node)
    {
        node->setMaterialFlag(EMF_LIGHTING, false);
        //node->setFrameLoop(1, 24);
        node->setJointMode(EJUOR_CONTROL);
        node->setMaterialTexture(0, driver->getTexture("media/jgSally2.jpg"));
    }
 
    ISceneNode *vNode = device->getSceneManager()->addSphereSceneNode(0.5f);
    vNode->setPosition(vector3df(0.f, 15.f, 5.f));
    vNode->setName("Flyer");
 
    scene::ISceneNodeAnimator * flyCircleAnimator = device->getSceneManager()->createFlyCircleAnimator(core::vector3df(0.f, 15.f, 5.f), 5.0f, 0.002f, vector3df(0, 0, 1));
    vNode->addAnimator(flyCircleAnimator);
 
    ICameraSceneNode* camera = smgr->addCameraSceneNodeFPS(0, 10.0f, 0.1f);
    camera->setPosition(vector3df(0, 20, 20));
    camera->updateAbsolutePosition();
    camera->setTarget(vector3df(0, 8, 0));
 
    IBoneSceneNode *base = ((IAnimatedMeshSceneNode *)node)->getJointNode("Rshoulder");
    IBoneSceneNode *endEffector = ((IAnimatedMeshSceneNode *)node)->getJointNode("Relbow");
 
    while (device->run())
    {
        vector3df basePos = base->getAbsolutePosition();
        vector3df target = vNode->getAbsolutePosition();
 
        vector3df endEffPos = endEffector->getAbsolutePosition();
        vector3df p1 = endEffPos - basePos;
        vector3df p2 = target - basePos;
        p1.normalize();
        p2.normalize();
        vector3df axis = p1.crossProduct(p2);
        axis.normalize();
 
        float dot = p1.dotProduct(p2);
        float angle = acosf(dot);
        if (abs(angle) > 0.0001)
        {
            quaternion q1;
            q1.fromAngleAxis(angle, axis);
            q1.normalize();
 
            quaternion q2;
            q2.set(base->getRotation()*DEGTORAD);
            q2.normalize();
            q2 = q2*q1;
 
            q2.normalize();
            vector3df anglexx;
 
            q2.toEuler(anglexx);
            anglexx *= RADTODEG;
 
            base->setRotation(q2.getMatrix().getRotationDegrees());
            base->updateAbsolutePosition();
            endEffector->updateAbsolutePosition();
        }
 
        driver->beginScene(true, true, SColor(255, 100, 101, 140));
        smgr->drawAll();
 
        SMaterial someMaterial;
        someMaterial.Lighting = false;
        driver->setMaterial(someMaterial);
        driver->setTransform(video::ETS_WORLD, core::IdentityMatrix);
        driver->draw3DLine(basePos, target);
 
        driver->endScene();
    }
 
    device->drop();
    return 0;
}
 
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
thanhle
Posts: 325
Joined: Wed Jun 12, 2013 8:09 am

Re: Possible bug with Quaternion and Matrix to euler angle

Post by thanhle »

You need to rotate the parent y-angle > 90 degree or <-90 degree, then you will see the problem.
Just add the bit below before the while loop.

vector3df rot = node->getRotation();
rot.Y = 100.0f; // 0.01f;
node->setRotation(rot);
node->updateAbsolutePosition();

Let me check trunk if it has fix this issue.

Regards
thanh
Post Reply