[SOLVED] Bug in quaterninon slerp (using 2.26)

Report any bugs here and we'll post fixes

Moderators: Sascha Willems, Thomas

[SOLVED] Bug in quaterninon slerp (using 2.26)

Postby JoeJ » Tue Dec 21, 2010 6:35 pm

Hi,

Im pretty sure there's a bug. With the code you should be able to reproduce this.
My first guess was that the threshold constants are too small, but it happens only at a specific angle, so i'm not sure.
But if so, the squared 1.0e-5f in CalcAverageOmega seems also very small to me (no fp expert).

So, here comes the code - hopefully i've pasted the right values at the end, otherwise tell my and i try again...

Code: Select all
   if (pickedBody)
   {
      float mix = 0.4f;
      handPos.m_x = handPos.m_x * (1-mix) + targetPos.m_x * mix;
      handPos.m_y = handPos.m_y * (1-mix) + targetPos.m_y * mix;
      handPos.m_z = handPos.m_z * (1-mix) + targetPos.m_z * mix;

dQuaternion storeInit = handOrn;
      if (1) // this generates error
      {
         handOrn = handOrn.Slerp (targetOrn, mix);
         handOrn.Normalize();
      }
      if (1) // this is ok
      {
dQuaternion storeError = handOrn;
handOrn = storeInit;

         quaternionf _handOrn (handOrn.m_q1, handOrn.m_q2, handOrn.m_q3, handOrn.m_q0);
         quaternionf _targetOrn (targetOrn.m_q1, targetOrn.m_q2, targetOrn.m_q3, targetOrn.m_q0);

         _handOrn.Slerp (&_handOrn, &_targetOrn, mix);
         _handOrn.Normalize();

         handOrn.m_q0 = _handOrn.w;
         handOrn.m_q1 = _handOrn.x;
         handOrn.m_q2 = _handOrn.y;
         handOrn.m_q3 = _handOrn.z;

float error = storeError.m_q0 - handOrn.m_q0 + storeError.m_q1 - handOrn.m_q1 +
           storeError.m_q2 - handOrn.m_q2 + storeError.m_q2 - handOrn.m_q2;
if (error > 0.5f)
{
   int breakpoint = 1;
/*
debugger output:
storeError   {m_q0=0.67136699 m_q1=0.081991978 m_q2=0.72294796 m_q3=0.14103185} // buggy
handOrn = {m_q0=0.91231567 m_q1=-0.045301240 m_q2=-0.39945686 m_q3 = -0.077860512} // ok

// reproduce with following input, slerping from storeInit to targetOrn with t = 0.4f should produce a wrong result:
storeInit = {m_q0=1.0000000 m_q1=1.9579682e-006 m_q2=-2.3370687e-012 m_q3=5.0701885e-005}
targetOrn = {m_q0=-0.49344867 m_q1=0.096223623 m_q2=0.84845477 m_q3 = 0.16545060}
*/
}
      }





Also here the code from my quat slerp:


Code: Select all
#define DELTAF 0.0001
void quaternionf::Slerp (quaternionf * from, quaternionf * to, float t)
{
    float           to1[4];
    float          omega, cosom, sinom;
    float          scale0, scale1;

    // calc cosine
    cosom = from->x * to->x + from->y * to->y + from->z * to->z
             + from->w * to->w;

    // adjust signs (if necessary)
    if ( cosom < 0.0f ) // todo: optimize like lerp
   {
      cosom = -cosom;

      to1[0] = - to->x;
      to1[1] = - to->y;
      to1[2] = - to->z;
      to1[3] = - to->w;

    } else  {

      to1[0] = to->x;
      to1[1] = to->y;
      to1[2] = to->z;
      to1[3] = to->w;

    }

    // calculate coefficients

    if ( (1.0 - cosom) > DELTAF )
   {
            // standard case (slerp)
            omega = (float)acos(cosom);
            sinom = (float)sin(omega);
            scale0 = (float)sin((1.0f - t) * omega) / sinom;
            scale1 = (float)sin(t * omega) / sinom;

    } else {       
          // "from" and "to" quaternions are very close
          //  ... so we can do a linear interpolation

            scale0 = 1.0f - t;
            scale1 = t;
    }

   // calculate final values
   x = scale0 * from->x + scale1 * to1[0];
   y = scale0 * from->y + scale1 * to1[1];
   z = scale0 * from->z + scale1 * to1[2];
   w = scale0 * from->w + scale1 * to1[3];

}
Last edited by JoeJ on Wed Dec 22, 2010 1:57 pm, edited 1 time in total.
User avatar
JoeJ
 
Posts: 1453
Joined: Tue Dec 21, 2010 6:18 pm

Re: Bug in quaterninon slerp (using 2.26)

Postby JoeJ » Tue Dec 21, 2010 7:56 pm

Found another one in matrix to quat converation:

dMatrix matrix;
NewtonBodyGetMatrix(body, &matrix[0][0]);
dQuaternion q (matrix); // produces wrong result from certain angles
// fix:
NewtonBodyGetRotation (body, &q.m_q0); // everything fine now

If both methods should give the same result, then there is a bug too.
It's more difficult to reproduce, but if youe need, i can try...



Those two things gave me a lot headache today, but it comes even worse:
I've used the tutorials and demo code to get starting, There's a big floor box (mass 0).
And some smaller moveable boxes, which fall on floor and get at rest. I pick one up, move it up and let it fall down... it falls through the floor.
I fly below the floor and hurry up to pick it again bofore it leaves world bounds, drag it back above the floor and let it fall down again...
and it collides with floor as it should!

This happens only very rarely. At the moment i've no chance to reproduce.
But if it happens, it may happen also with other boxes - but not allways.
I've no idea about it, the only difference to demo code is that i turn off autosleepeng at creation,
and maybe it happens only if i set Omega in picking-callback, instead of torque.
If I find a way to reproduce i'll try to change that and also turn on ccd, but the boxes fall very slowly.

Don't worry - I think it's my fault - new to newton.
Maybe it's a linker problem, i've Havok and Bullet too in my testbed and had to unlink LIBCMT.lib;LIBCMTD.lib;MSVCRT to get all working.
There is a linker warning "...vc90.obj...". At the moment I realize that this is not always as i thought. Currently there's no warning and everything works fine.
So forget all about this until i can reproduce, i'll let you know...

However - the quat stuff needs fixes.
User avatar
JoeJ
 
Posts: 1453
Joined: Tue Dec 21, 2010 6:18 pm

Re: Bug in quaterninon slerp (using 2.26)

Postby Julio Jerez » Tue Dec 21, 2010 8:05 pm

you would be the only person in tounsand of people, and hundred of application which has using those function verbating.
to get wrong result for those funtions. I use then in the engine, and I has used the for almost 20 years,
all I can say is that I am very sure those functions are correct.

but you do not have to use the dMatrix class if matrix, if you do not trusth it.
although I will say that, that the same class I use in the engine. and it seems to work just fine.

The only difference is that in the SDK is called dMatrix
and in the engine is called dgMatrix to avoid conflicts with people linking static libraries.

can you post two values that lead to wrong result? something like:
q0 = (a0, b0, c0, d0)
q1 = (a1, b1, c1, d1)
q = q0.Slerp(q1, t) // wrong value
Julio Jerez
Moderator
Moderator
 
Posts: 12249
Joined: Sun Sep 14, 2003 2:18 pm
Location: Los Angeles

Re: Bug in quaterninon slerp (using 2.26)

Postby JoeJ » Wed Dec 22, 2010 6:41 am

Yes, got the linking warnings again:


1>dMath.lib(dMatrix.obj) : warning LNK4204: 'c:\dev\pengII\pengII\Debug\vc90.pdb' is missing debugging information for referencing module; linking object as if no debug info
1>dMath.lib(dQuaternion.obj) : warning LNK4204: 'c:\dev\pengII\pengII\Debug\vc90.pdb' is missing debugging information for referencing module; linking object as if no debug info


So its regarding to exactly that code that caused errors. Didn't realize that yesterday - sorry for that.
Maybe I'm mixing some debug / release stuff.


The values you requested are commented at the end of the first part of code, if you still want to proof:

// reproduce with following input, slerping from storeInit to targetOrn with t = 0.4f should produce a wrong result:
storeInit = {m_q0=1.0000000 m_q1=1.9579682e-006 m_q2=-2.3370687e-012 m_q3=5.0701885e-005}
targetOrn = {m_q0=-0.49344867 m_q1=0.096223623 m_q2=0.84845477 m_q3 = 0.16545060}

Wrong and right results are:

storeError {m_q0=0.67136699 m_q1=0.081991978 m_q2=0.72294796 m_q3=0.14103185} // buggy
handOrn = {m_q0=0.91231567 m_q1=-0.045301240 m_q2=-0.39945686 m_q3 = -0.077860512} // ok


On the collission problem:
After the linking warnings the App worked.
But after the next build (no warnings), some boxes got missed by the raycast and i was able to drag other boxes through them without reaction.
So the Boxes are visible at rest on the ground, but for physics they are nonexistend - like the floor yesterday.

Can such a strange behaviour caused by wrong dll or lib? I don't know.

If you have time, please check the quat slerp. If you get the right result, we know that it must be something like that.

Thans and sorry in advance :)
User avatar
JoeJ
 
Posts: 1453
Joined: Tue Dec 21, 2010 6:18 pm

Re: Bug in quaterninon slerp (using 2.26)

Postby JoeJ » Wed Dec 22, 2010 11:30 am

I've tried to clean up project with little success.
Bullet is removed now but can't get rid of Havok and other libs easily.
If I remove Newton too, there are no build warnings.
Also changed to 2.27 without changing or recompiling something inside it.

For linking i use the following steps (VC2008 32 bit Debug):

1. Create a newton folder and copy everything from lib_vs9_mt into it. Set this folder at Additional Include Directory.
2. From dll_vs9 copy newton.dll and lib to the same folder, overwriting newton.dll
3. Linker Input: newton.lib, dJointLibrary.lib, dMath.lib (also tried *_d variants)
4. post build event: xcopy "C:\dev\pengII\newton\*.dll" "C:\dev\pengII\pengII\Debug\*.*" /F /Y

This way it compiles without the need to exclude any Default Library (LIBCMT + MSVCRT).
But there are still the quat errors and those linker warnings:

1>LINK : warning LNK4098: defaultlib 'LIBCMT' conflicts with use of other libs; use /NODEFAULTLIB:library
1>dMath.lib(dMatrix.obj) : warning LNK4204: 'c:\dev\pengII\pengII\Debug\vc90.pdb' is missing debugging information for referencing module; linking object as if no debug info
1>dMath.lib(dQuaternion.obj) : warning LNK4204: 'c:\dev\pengII\pengII\Debug\vc90.pdb' is missing debugging information for referencing module; linking object as if no debug info

If i use lib_vs9_md instead of lib_vs9_mt, those warnings become errors.
I've also tried: Exclude step 2 and instead set _NEWTON_USE_LIB in preprocessor.
But the troubles stay the same no matter what i try.

Questions:
What's wrong with my method?
What's the difference between lib_vs9_md and lib_vs9_mt?
Are *_d variants debug versions and must i use them for debug and the others for release?
newton.* from dll_vs9 is for dynamic linking and lib_vs9_** is for static lib only, right?
Should I try to copy source from math stuff into my project and compile it directly, instead of using dMath.lib? I don't have any other idea.


Something different:
Looking at at the math stuff i can't find any 16 byte alignemt.
If Linux compiler does this by default and Windows not, this could cause the linux speedup you mentioned.
I'm sure you thought on that, just trying to be helpful :)
User avatar
JoeJ
 
Posts: 1453
Joined: Tue Dec 21, 2010 6:18 pm

Re: Bug in quaterninon slerp (using 2.26)

Postby Julio Jerez » Wed Dec 22, 2010 12:45 pm

Ok I see what you cofusion wi the quaterion slet funtion is

you called like this:

Code: Select all
dQuaternion q0 (1.0000000f, 1.9579682e-006f, -2.3370687e-012f, 5.0701885e-005f);
dQuaternion q1 (-0.49344867f, 0.096223623f, 0.84845477f, 0.16545060f);
dQuaternion q2 (q0.Slerp(q1, 0.4f));

and you got this result?
q2 (0.67136699, 0.081991978, 0.72294796, 0.14103185)
which is correct, tha is teh angle betenn q0 and q1,

the problem is that you want the shotest angle betwen q0 and q1, and tah is givene whne teh angel between q0 and q1 is possitive
I newtion all function are general porpuse I do not add any sanity check or data validation.

if you want the short angle bewtest q0 and q1, you soudl call it like this

Code: Select all
dQuaternion q0 (1.0000000f, 1.9579682e-006f, -2.3370687e-012f, 5.0701885e-005f);
dQuaternion q1 (-0.49344867f, 0.096223623f, 0.84845477f, 0.16545060f);
if (q0.DotProduct(q1) < 0.0f)
   q1.Scale (-1.0);
dQuaternion q2 (q0.Slerp(q1, 0.4f));

which generate this result, and I beleive it is what you have.
q2 (0.91231555, -0.045301236, -0.39945680, -0.077860504);


basically you verify that is the cos of the angle is negative and if it is you multiply the destination quaternion by -1

in case you wander why I did no add that funtionality to teh math library, the answer is that it will slow it down, for most calculation.
in general the interpoltion is bewteen quaternion that are close already, for example and animation must kepframe are close, and if not teh animation can be preprocesed
adding that check uncoditinally just make it a waste when the rotation are already close.

when you know that there is a possiblity of the angle being larger than 180 degree, they it is to end application to do the check.
basically you can derive a class from the dquaterion like this

Code: Select all
class myquat: public dquaternion
{
    ...

  dquaternion SlerpWitLimit (dquation& q1, dfloat t)
 {
     if (q1.DotProdut(*this) <0.0) {
          dQuaterion tmp (q1)
         q1.Scale (-1.0)
         return Slerp (tmp, t)
     } else {
        return Slepr (q1, t);
   }
 }
}



On the linking problem has you try using the DLL first to see if you can get a project going first?
you may be having problems with the mt and md libraries.
Julio Jerez
Moderator
Moderator
 
Posts: 12249
Joined: Sun Sep 14, 2003 2:18 pm
Location: Los Angeles

Re: Bug in quaterninon slerp (using 2.26)

Postby JoeJ » Wed Dec 22, 2010 1:33 pm

Ah yes, that slerp thing is clear now. And i can remember i've had exact the same problem years ago with someone else slerp routine.
I've forgotten that.
Interesting is how i found the problem: The target orientation is aligned with the camera, and the source orientation is slerped towards it every timestep by the value of 0.4 for smoothing. No reseting in between.
And the problem happens when i rotate the camere slowly and only 1-2 degrees left and right about a certain angle. So the relative angle can't exceed 180 deg.
Same with my code if i remove the check.
However - no need for explantations. For now i'm one of those who are lucky about quaternions applications, but don't understand how they work :)

Maybe something similar explains the matrix to quat conversation issue (2nd. post)
I'll see if i can reproduce this with numbers...

And i'll try to compile your math myself to get rid of dMath.lib.
If that does not help, i'll try a new project.

Thanks.

EDIT:
dQuaternion q (matrix) gave the sign reversed quaternion than a call to NewtonBodyGetRotation().
So also this is no bug. :oops:
User avatar
JoeJ
 
Posts: 1453
Joined: Tue Dec 21, 2010 6:18 pm


Return to Bugs and Fixes

Who is online

Users browsing this forum: No registered users and 3 guests

cron