🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

Reference frame with quaternions problems

Started by
4 comments, last by Sword7 2 years ago

I am trying using control movements in local frame before converting position and quaternion to global (universal) frame but, something went erratic when move around. It is only working in ecliptic frame (using quaternion identity). Look at my local/global frame conversion code.

vec3d_t Frame::fromUniversal(const vec3d_t &upos, double tjd)
{
    if (center == nullptr)
        return upos;
    
    vec3d_t opos = center->getuPosition(tjd);
    quatd_t orot = getOrientation(tjd);
    vec3d_t rpos = orot * (upos - opos);

    return rpos;
}

quatd_t Frame::fromUniversal(const quatd_t &urot, double tjd)
{
    if (center == nullptr)
        return urot;
    return urot * glm::conjugate(getOrientation(tjd));
}

vec3d_t Frame::toUniversal(const vec3d_t &lpos, double tjd)
{
    if (center == nullptr)
        return lpos;

    vec3d_t opos = center->getuPosition(tjd);
    quatd_t orot = getOrientation(tjd);
    vec3d_t rpos = opos + (glm::conjugate(orot) * lpos);

    return rpos;
}

quatd_t Frame::toUniversal(const quatd_t &lrot, double tjd)
{
    if (center == nullptr)
        return lrot;
    return lrot * getOrientation(tjd);
}


quatd_t getOrientation(double) const override
{
    return quatd_t(vec3d_t(J2000Obliquity, 0, 0));
}


    if (mode == tvFreeMode)
    {
        // free travel mode
        // Update current position and attitude in local reference frame
        // applying angular velocity to rotation quaternion in local space.
        //
        //      dq/dt = q * w * t/2
        //      where w = (0, x, y, z)
        //
        lrot += lrot * wv * (dt / 2.0);
        lrot  = glm::normalize(lrot);
        // lpos -= glm::conjugate(lrot) * tv * dt;
        lpos -= (lrot * tv) * dt;
    }

    // Updating current universal coordinates
    updateUniversal();
void Player::updateUniversal()
{
    upos = frame->toUniversal(lpos, jdTime);
    urot = frame->toUniversal(lrot, jdTime);
}

I tried to use movement controls with using equator frame (23.4 degrees tilt). It went off course when I tried move forward on a side of object but move forward in front of object correctly. When I tried to yaw left/right but it yaw at off course instead, etc… I tried many different solution but can't find correct solution so far.

I tried orbit around object but my up/down arrow works fine but my left/right arrow made object spinning around. With ecliptic plane (quaternion identity, everything works fine.

Does anyone have any solutions with local/universal (global) reference frame conversions?

Advertisement

No one replies but I now found the solution myself by swapped position/orientation and rotation global/local orientation. Everything worked fine with varying reference frames like ecliptic, equator, body fixed (geo sync), etc. I can now move around in local planetcentric frame (origin of planet) correctly.

vec3d_t Frame::fromUniversal(const vec3d_t &upos, double tjd)
{
    if (center == nullptr)
        return upos;
    
    vec3d_t opos = center->getuPosition(tjd);
    quatd_t orot = getOrientation(tjd);
    // vec3d_t rpos = orot * (upos - opos);
    vec3d_t rpos = (upos - opos) * orot;

    return rpos;
}

quatd_t Frame::fromUniversal(const quatd_t &urot, double tjd)
{
    if (center == nullptr)
        return urot;
    // return urot * glm::conjugate(getOrientation(tjd));
    return glm::conjugate(getOrientation(tjd)) * urot;
}

vec3d_t Frame::toUniversal(const vec3d_t &lpos, double tjd)
{
    if (center == nullptr)
        return lpos;

    vec3d_t opos = center->getuPosition(tjd);
    quatd_t orot = getOrientation(tjd);
    // vec3d_t rpos = opos + (glm::conjugate(orot) * lpos);
    vec3d_t rpos = opos + (lpos * glm::conjugate(orot));

    return rpos;
}

quatd_t Frame::toUniversal(const quatd_t &lrot, double tjd)
{
    if (center == nullptr)
        return lrot;
    // return lrot * getOrientation(tjd);
    return getOrientation(tjd) * lrot;
}

Well, I think that something have some issues with quaternions in GLM library. I replaced all GLM library with Eigen library. All problems went away. My reference frame and movement controls now behaves correctly.

I am now learning more about Eigen library right now.

Sword7 said:
I replaced all GLM library with Eigen library. All problems went away.

I've used both, but not the quaternion parts of it.
I assume neither is a great option for games, though. I saw glm was 10 times slower than the library i usually use when working on 3x3Matrix, vec3 and ivec3 in a fluid simulator.
I assume it's a unfortunate compiler problem related to constructors, but i have only tested this using MSVC 1 or 2 years ago. Maybe things are already better now.

Eigen on the other hand is meant to solve problems with larger matrices. I would not expect great performance for the small types we use in games for all the basic stuff.
I would still tend to prefer glm over Eigen in this regard. But it's hard to propose a faster but established library than glm. The one i personally use is Sonys Vectormath library, which was open sourced for Bullet Physics, but now is no longer part of it it seems.
I guess there are many free and nice libraries to find, but no idea which to choose.

However, i can not imagine glms quaternions to be buggy. More likely it's one of the common pitfalls on your side:

  • Multiplication order. In library A you have to write a = b x c, in lib B it's a = c x b for the same result. This is often but not exclusively tied to the Row vs. Column Major convention of the library.
  • Left / Right - Handness. If you convert matrices to quat, the matrix must respect the expected convention, otherwise you get garbage. To verify, i sometimes calculate the determinant of a manually constructed 3x3 matrix. If the value is negative, i have accidently created a flipped orientation matrix and thus the wrong handness. This still works for rendering and other stuff, so often goes unnoticed.
  • Maybe your quaternion was not normalized, and maybe Eigen did this automatically but glm did not.

Yeah. I just replaced typedefs in header file and fixed a few. All problems went away.

With GLM library, I can orbit around object vertically but can't orbit horizontally, etc…
With Eigen library, I just replaced typedefs and updated them with Eigen member function calls.

I was now able orbit around objects both vertically and horizontally (properly).

Take an example about orbiting around tracking object. It did not work with GLM library but only work with Eigen library.

void Player::orbit(quatd_t rot)
{
    // If tracking object reference not set, assign center object in local
    // reference frame as default. If center object is not available,
    // do nothing and return.
    if (trackingObject == nullptr)
    {
        if (frame != nullptr)
            trackingObject = frame->getCenter();
        if (trackingObject == nullptr)
            return;
    }

    // Determine central position of object (planet, vessel, etc)
    vec3d_t cpos = frame->fromUniversal(trackingObject->getuPosition(jdTime), jdTime);
    vec3d_t vpos = lpos - cpos;

    double vdist = vpos.norm();
    quatd_t qrot = lrot.conjugate() * rot * lrot;
    vpos = qrot.conjugate() * vpos;
    vpos = vpos.normalized() * vdist;

    lrot = lrot * qrot;
    lpos = cpos + vpos;

    updateUniversal();
}

This topic is closed to new replies.

Advertisement