Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I have implemented a "look at" method for my screen elements and it almost works how I want it to work.

The ScreenElement class uses a R3 Vector and a Quaternion to determine the position and orientation. As a convenience function I implemented a "look at" method. I am not the biggest expert on linear algebra, so my solution was an adaption of stuff I found on forums; but it was the only solution I understood.

The current approach is as follows:

void SceneElement::look_at(const mx::Vector3f& target, const mx::Vector3f& up)
{
    mx::Vector3f forward_l = mx::normalize(target - position);
    mx::Vector3f forward_w(1, 0, 0);
    mx::Vector3f axis  = forward_l % forward_w;
    float        angle = mx::rad_to_deg(acos(forward_l * forward_w));

    mx::Vector3f third = axis % forward_w;
    if (third * forward_l < 0)
    {
        angle = - angle;
    }
    orientation = mx::axis_angle_to_quaternion(angle, axis);
}

As you can see the up vector is not used and as a result the orientation is so far correct, that it looks as the target, but the up orientation is all over the place.

I have tried different approached to integrate the up vector. The "best" (i.e. it still mostly looked at the target) was to make the same approach with a orthonormalized up vector.

Just as a note, the up vector is expected to work like gluLookAt, that is used as a baseline but it needs to be projected into the local coordinate system, this I did as:

mx::Vector3f right = mx::normalise(forward % up);
mx::Vector3f up_n  = mx::normalise(right % forward);

Just to complete the info, the math lib I use is my own mathex and the basterised modulo (%) operator is the R3 cross product.

share|improve this question
add comment

1 Answer 1

I solved it. I was on the right track... The final solution is:

void SceneElement::look_at(const mx::Vector3f& target, const mx::Vector3f& up)
{
    mx::Vector3f forward_l = mx::normalize(target - position);
    mx::Vector3f forward_w(1, 0, 0);
    mx::Vector3f axis  = forward_l % forward_w;
    float        angle = mx::rad_to_deg(acos(forward_l * forward_w));

    mx::Vector3f third = axis % forward_w;
    if (third * forward_l < 0)
    {
        angle = - angle;
    }
    mx::Quaternionf q1 = mx::axis_angle_to_quaternion(angle, axis);

    mx::Vector3f up_l  = mx::transform(q1, mx::normalize(up));
    mx::Vector3f right = mx::normalize(forward_l % up);
    mx::Vector3f up_w  = mx::normalize(right % forward_l);

    mx::Vector3f axis2  = up_l % up_w;
    float        angle2 = mx::rad_to_deg(acos(up_l * up_w));

    /*mx::Vector3f third2 = axis2 % up_w;
    if (third2 * up_l < 0)
    {
        angle2 = - angle2;
    }*/
    mx::Quaternionf q2 = mx::axis_angle_to_quaternion(angle2, axis2);

    orientation = q2 * q1;
}

The only open issue I have is I am not sure in which cases the commented out code is necessary.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.