0
votes

I've been trying to emulate gluLookAt functionality, but with Quaternions. Each of my game object have a TranslationComponent. This component stores the object's position (glm::vec3), rotation (glm::quat) and scale (glm::vec3). The camera calculates its position each tick doing the following:

// UP = glm::vec3(0,1,0); 
//FORWARD = glm::vec3(0,0,1);
cameraPosition = playerPosition - (UP * distanceUP) - (FORWARD * distanceAway);

This position code works as expexted, the camera is place 3 metres behind the player and 1 metre up. Now, the camera's Quaternion is set to the follow:

//Looking at the player's feet  
cameraRotation = quatFromToRotation(FORWARD, playerPosition); 

The rendering engine now takes these values and generates the ViewMatrix (camera) and the ModelMatrix (player) and then renders the scene. The code looks like this:

 glm::mat4 viewTranslationMatrix = 
         glm::translate(glm::mat4(1.0f), cameraTransform->getPosition());
 glm::mat4 viewScaleMatrix = 
         glm::scale(glm::mat4(1.0f), cameraTransform->getScale());
 glm::mat4 viewRotationMatrix = 
         glm::mat4_cast(cameraTransform->getRotation());

 viewMatrix = viewTranslationMatrix * viewRotationMatrix * viewScaleMatrix;

quatFromToRotation(glm::vec3 from, glm::vec3 to) is defined as the following:

glm::quat quatFromToRotation(glm::vec3 from, glm::vec3 to)
{
    from = glm::normalize(from); to = glm::normalize(to);

    float cosTheta = glm::dot(from, to);
    glm::vec3 rotationAxis;

    if (cosTheta < -1 + 0.001f)
    {
        rotationAxis = glm::cross(glm::vec3(0.0f, 0.0f, 1.0f), from);
        if (glm::length2(rotationAxis) < 0.01f)
            rotationAxis = glm::cross(glm::vec3(1.0f, 0.0f, 0.0f), from);

        rotationAxis = glm::normalize(rotationAxis);
        return glm::angleAxis(180.0f, rotationAxis);
    }

    rotationAxis = glm::cross(from, to);

    float s = sqrt((1.0f + cosTheta) * 2.0f);
    float invis = 1.0f / s;

    return glm::quat(
            s * 0.5f,
            rotationAxis.x * invis,
            rotationAxis.y * invis,
            rotationAxis.z * invis
        );
}

What I'm having troubles with is the fact the cameraRotation isn't being set correctly. No matter where the player is, the camera's forward is always (0,0,-1)

1
Where / how do you compute the camera's forward?Floris
Assuming FORWARD is a direction and not a position, I do not think this is quite what you want... what about quatToFromRotation (playerPosition + FORWARD, playerPosition);?Andon M. Coleman
Also, the function you listed in your code is quatFromToRotation (...), which is different from what you discussed in the body of your text.Andon M. Coleman
Ah, yes, that was a typo. I edited it.Brett
Just to note, glm has a function equivalent to gluLookAt() in functionality, named glm::lookAt() and defined in <glm/gtc/matrix_transform.hpp>. For more info, check the glm manual and search for "lookAt". You'll find the function documentation there.chbaker0

1 Answers

1
votes

Your problem is in the line

//Looking at the player's feet  
cameraRotation = quatToFromRotation(FORWARD, playerPosition);

You need to look from the camera position to the player's feet - not from "one meter above the player" (assuming the player is at (0,0,0) when you initially do this). Replace FORWARD with cameraPosition:

cameraRotation = quatToFromRotation(cameraPosition, playerPosition);

EDIT I believe you have an error in your quatToFromRotation function as well. See https://stackoverflow.com/a/11741520/1967396 for a very nice explanation (and some pseudo code) of quaternion rotation.