Re: pfMakeRotOntoMat()

New Message Reply Date view Thread view Subject view Author view

Don Hatch (hatch++at++hell.asd.sgi.com)
Wed, 17 Jul 1996 19:18:07 -0700


On Jul 17, 4:43pm, tidrowd++at++cc.tacom.army.mil wrote:
> Subject: pfMakeRotOntoMat()
> I know this changed into pfMakeVecRotVecMat() in 2.0, but I'm seeing
> some problems with the old version (legacy code - will convert it
> eventually) in that when the two vectors are nearly parallel, the
> rotations in the resulting matrix suddenly disappears. I'm guessing
> that it's due to precision issues (using pfSinCos internally, etc.)
> but was wondering if perhaps there was some known problem with it.
> Did it get any better with 2.0? Or should I roll my own for this
> case? (if so, anybody have a code fragment? ;)

Discontinuous behavior is unavoidable when the vectors are parallel or nearly
parallel; the best we can do is guarantee that the returned
matrix does rotate vec0 onto vec1.
If the vectors are pointing in the same direction, then the
identity matrix is a correct answer and is as good as any.

The buggy case was when the vectors are in opposite
directions (or nearly opposite); we were returning a matrix representing
a uniform scale of -1 (which is not even a rotation).
This bug exists even in Performer 2.0 and 2.0.1,
but it is fixed in 2.0.2, 2.1, and future versions.
(if you install 2.0.2 libraries, your dynamically linked 2.0 programs
will automatically get the fix at runtime).

Here is the fixed version from libpr:

    // rotate v0 onto v1, assumes v0 and v1 are normalized
    void
    pfMatrix::makeVecRotVec(const pfVec3 & v0, const pfVec3 & v1)
    {
        pfVec3 axis;
        float x, y, z, sinTheta, cosTheta, t;

        cosTheta = PFDOT_VEC3(v0, v1);
        axis.cross(v0, v1);
        sinTheta = PFLENGTH_VEC3(axis);

        // Check for colinear vectors
        if (!PF_ABSLT(sinTheta, pfEta))
        {
            t = 1.0f / sinTheta;
            PFSCALE_VEC3(axis, t, axis);
        }
        else if (cosTheta < 0.0f)
        {
            // v0 = -v1 -- rotate about an arbitrary axis
            // perpendicular to v0.
            pfVec3 absv0(PF_ABS(v0[0]), PF_ABS(v0[1]), PF_ABS(v0[2]));
            pfVec3 leastCoordAxis(0.f,0.f,0.f);
            leastCoordAxis[absv0[0]<=absv0[1] ? absv0[0]<=absv0[2] ? 0 : 2
                                              : absv0[1]<=absv0[2] ? 1 : 2] = 1.f;
            axis.cross(v0, leastCoordAxis);
            axis.normalize();
        }
        else
        {
            makeIdent();
            return;
        }

        x = axis[0];
        y = axis[1];
        z = axis[2];

        t = 1.0f - cosTheta;

        mat[2][3] = 0.0f;
        mat[3][0] = 0.0f;
        mat[3][1] = 0.0f;
        mat[3][2] = 0.0f;
        mat[3][3] = 1.0f;
        mat[0][0] = t * x * x + cosTheta;
        mat[0][1] = t * x * y + sinTheta * z;
        mat[0][2] = t * x * z - sinTheta * y;
        mat[0][3] = 0.0f;
        mat[1][0] = t * y * x - sinTheta * z;
        mat[1][1] = t * y * y + cosTheta;
        mat[1][2] = t * y * z + sinTheta * x;
        mat[1][3] = 0.0f;
        mat[2][0] = t * z * x + sinTheta * y;
        mat[2][1] = t * z * y - sinTheta * x;
        mat[2][2] = t * z * z + cosTheta;
    }

Don

-- 
Don Hatch  hatch++at++sgi.com  (415) 933-5150  Silicon Graphics, Inc.

======================================================================= List Archives, FAQ, FTP: http://www.sgi.com/Technology/Performer/ Submissions: info-performer++at++sgi.com Admin. requests: info-performer-request++at++sgi.com


New Message Reply Date view Thread view Subject view Author view

This archive was generated by hypermail 2.0b2 on Mon Aug 10 1998 - 17:53:11 PDT

This message has been cleansed for anti-spam protection. Replace '++at++' in any mail addresses with the '@' symbol.