How to set the pitch, yaw, roll of a quaternion - c++

How to set the pitch, yaw, roll of a quaternion
What I need help with:
Hello! I have a quaternion that stores the orientation of my camera and what I would like to do is set the pitch, yaw and roll of the quaternion relative to the world.
Picture this...
What I mean my that is imagine 4 walls around you with an arrow on each wall pointing to the world up. What I want to do is no matter what the pitch, yaw and roll of the quaternion, if I'm looking at any of the arrows (any yaw) but with a little roll (so the arrow will point anywhere but up). If I use the setRoll function and pass 0*, the camera should see the arrow pointing up. If I pass 90* to the setRoll function, no matter how many times I call the function it should set the camera's rotation to 90* so the arrow will point to the left.
My code:
Here is my full camera class below. The only code that really matters are the setPitch, setYaw and setRoll functions.
Camera.hpp
#ifndef CAMERA_HPP
#define CAMERA_HPP
// GLAD
#include <glad/glad.h>
// GLM
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtc/quaternion.hpp>
class QuaternionCamera
{
public:
QuaternionCamera(glm::vec3 position, float zNear, float zFar);
QuaternionCamera(glm::vec3 position, glm::quat orientation, float zNear, float zFar);
QuaternionCamera(glm::vec3 position, glm::vec3 orientation, float zNear, float zFar);
// Set the position in world coords
void setPosition(glm::vec3 position);
// Set the orientation relative to the world
void setOrientation(glm::quat orientation);
// Set the orientation relative to the world
void setOrientation(glm::vec3 orientation);
// Set the pitch relative to the world
void setPitch(float amount);
// Set the yaw relative to the world
void setYaw(float amount);
// Set the roll relative to the world
void setRoll(float amount);
// Set the camera's near plane
void setZNear(float zNear);
// Set the camera's far plane
void setZFar(float zFar);
// Move the camera relative to it's current location
void move(glm::vec3 movement);
// Move the camera relative to it's current location on the world axis
void moveAxis(glm::vec3 translation);
// Rotate the camera relative to it's current location
void rotate(glm::quat rotation);
// Rotate the camera relative to it's current location
void rotate(glm::vec3 rotation);
// Pitch the camera relative to it's current location
void pitch(float amount);
// Yaw the camera relative to it's current location
void yaw(float amount);
// Roll the camera relative to it's current location
void roll(float amount);
// Get the camera's position in world coords
glm::vec3 getPosition() const;
// Get the camera's direction relative to the world
glm::vec3 getDirection() const;
// Get the camera's right vector
glm::vec3 getRight() const;
// Get the camera's up vector
glm::vec3 getUp() const;
// Get the camera's rotation relative to the world
glm::quat getOrientation() const;
// Get the camera's near plane
float getZNear() const;
// Get the camera's far plane
float getZFar() const;
// Get the camera's view matrix
glm::mat4 getViewMatrix() const;
// Get the camera's projection matrix
glm::mat4 getProjectionMatrix() const;
// Get the camera's view projection matrix
glm::mat4 getViewProjectionMatrix() const;
protected:
// updateProjectionMatrix is virtual because it will be defined in the two derived camera classes.
// This is because the camera class does not know if we want a perspective or orthographic viewport.
// So because the viewport is defined in a derived class, and because we change the projection matrix
// in the base camera class (zNear and zFar), we need a way to get an updated projection matrix!
virtual void updateProjectionMatrix() = 0;
void updateViewProjectionMatrix();
float zNear;
float zFar;
glm::mat4 projectionMatrix;
glm::mat4 viewProjectionMatrix;
private:
void updateCameraVectors();
void updateViewMatrix();
glm::mat4 viewMatrix;
glm::vec3 position;
glm::quat orientation;
glm::vec3 direction; // Camera Direction / Camera View Facing
glm::vec3 right;
glm::vec3 up;
};
#endif
Camera.cpp
QuaternionCamera::QuaternionCamera(glm::vec3 position, float zNear, float zFar)
{
this->position = position;
this->orientation = glm::quat(1.0f, 0.0f, 0.0f, 0.0f); // glm::quat constructor is (w, x, y, z) but it is stored as (x, y, z, w)
right = glm::vec3( 1, 0, 0);
up = glm::vec3( 0, 1, 0);
direction = glm::vec3( 0, 0, -1);
this->zNear = zNear;
this->zFar = zFar;
updateViewMatrix();
updateViewProjectionMatrix();
}
QuaternionCamera::QuaternionCamera(glm::vec3 position, glm::quat orientation, float zNear, float zFar)
{
this->position = position;
this->orientation = orientation;
right = glm::vec3( 1, 0, 0);
up = glm::vec3( 0, 1, 0);
direction = glm::vec3( 0, 0, -1);
this->zNear = zNear;
this->zFar = zFar;
updateViewMatrix();
updateViewProjectionMatrix();
}
QuaternionCamera::QuaternionCamera(glm::vec3 position, glm::vec3 orientation, float zNear, float zFar)
{
this->position = position;
this->orientation = glm::quat(glm::vec3(glm::radians(orientation.x), glm::radians(orientation.y), glm::radians(orientation.z)));
right = glm::vec3( 1, 0, 0);
up = glm::vec3( 0, 1, 0);
direction = glm::vec3( 0, 0, -1);
this->zNear = zNear;
this->zFar = zFar;
updateCameraVectors();
updateViewMatrix();
updateViewProjectionMatrix();
}
void QuaternionCamera::setPosition(glm::vec3 position)
{
this->position = position;
}
void QuaternionCamera::setOrientation(glm::quat orientation)
{
this->orientation = orientation;
}
void QuaternionCamera::setOrientation(glm::vec3 orientation)
{
glm::quat orientationQuat = glm::quat(orientation);
this->orientation = orientationQuat;
}
void QuaternionCamera::setPitch(float amount)
{
// TODO:
updateCameraVectors();
updateViewMatrix();
updateViewProjectionMatrix();
}
void QuaternionCamera::setYaw(float amount)
{
// TODO:
updateCameraVectors();
updateViewMatrix();
updateViewProjectionMatrix();
}
void QuaternionCamera::setRoll(float amount)
{
// TODO:
updateCameraVectors();
updateViewMatrix();
updateViewProjectionMatrix();
}
void QuaternionCamera::setZNear(float zNear)
{
this->zNear = zNear;
updateProjectionMatrix();
}
void QuaternionCamera::setZFar(float zFar)
{
this->zFar = zFar;
updateProjectionMatrix();
}
void QuaternionCamera::move(glm::vec3 movement)
{
position += (orientation * glm::vec3(1, 0, 0)) * movement.x + (orientation * glm::vec3(0, 1, 0)) * movement.y + (orientation * glm::vec3(0, 0, -1)) * movement.z;
updateViewMatrix();
updateViewProjectionMatrix();
}
void QuaternionCamera::moveAxis(glm::vec3 translation)
{
position += translation;
updateViewMatrix();
updateViewProjectionMatrix();
}
void QuaternionCamera::rotate(glm::quat rotation)
{
orientation *= rotation;
updateCameraVectors();
updateViewMatrix();
updateViewProjectionMatrix();
}
void QuaternionCamera::rotate(glm::vec3 rotation)
{
glm::quat rotationQuat = glm::quat(rotation);
orientation *= rotationQuat;
updateCameraVectors();
updateViewMatrix();
updateViewProjectionMatrix();
}
void QuaternionCamera::pitch(float amount)
{
glm::quat rotation = glm::angleAxis(glm::radians(amount), glm::vec3(1, 0, 0));
orientation *= rotation;
updateCameraVectors();
updateViewMatrix();
updateViewProjectionMatrix();
}
void QuaternionCamera::yaw(float amount)
{
glm::quat rotation = glm::angleAxis(glm::radians(-amount), glm::vec3(0, 1, 0));
orientation *= rotation;
updateCameraVectors();
updateViewMatrix();
updateViewProjectionMatrix();
}
void QuaternionCamera::roll(float amount)
{
glm::quat rotation = glm::angleAxis(glm::radians(amount), glm::vec3(0, 0, -1));
orientation *= rotation;
updateCameraVectors();
updateViewMatrix();
updateViewProjectionMatrix();
}
glm::vec3 QuaternionCamera::getPosition() const
{
return position;
}
glm::vec3 QuaternionCamera::getDirection() const
{
return direction;
}
glm::vec3 QuaternionCamera::getRight() const
{
return right;
}
glm::vec3 QuaternionCamera::getUp() const
{
return up;
}
glm::quat QuaternionCamera::getOrientation() const
{
return orientation;
}
float QuaternionCamera::getZNear() const
{
return zNear;
}
float QuaternionCamera::getZFar() const
{
return zFar;
}
glm::mat4 QuaternionCamera::getViewMatrix() const
{
return viewMatrix;
}
glm::mat4 QuaternionCamera::getProjectionMatrix() const
{
return projectionMatrix;
}
glm::mat4 QuaternionCamera::getViewProjectionMatrix() const
{
return viewProjectionMatrix;
}
void QuaternionCamera::updateViewProjectionMatrix()
{
viewProjectionMatrix = getProjectionMatrix() * getViewMatrix();
}
void QuaternionCamera::updateCameraVectors()
{
right = glm::normalize(orientation * glm::vec3(1, 0, 0));
up = glm::normalize(orientation * glm::vec3(0, 1, 0));
direction = glm::normalize(orientation * glm::vec3(0, 0, -1));
if (glm::dot(up, glm::cross(right, direction)) < 0)
{
up *= -1;
}
}
void QuaternionCamera::updateViewMatrix()
{
viewMatrix = glm::lookAt(position, position + direction, up/*glm::cross(right, direction)*/);
}
PerspectiveCamera::PerspectiveCamera(glm::vec3 position, float fov, float aspectRatio, float zNear, float zFar) : QuaternionCamera(position, zNear, zFar)
{
this->fov = fov;
this->aspectRatio = aspectRatio;
updateProjectionMatrix();
}
PerspectiveCamera::PerspectiveCamera(glm::vec3 position, glm::quat rotation, float fov, float aspectRatio, float zNear, float zFar) : QuaternionCamera(position, rotation, zNear, zFar)
{
this->fov = fov;
this->aspectRatio = aspectRatio;
updateProjectionMatrix();
}
PerspectiveCamera::PerspectiveCamera(glm::vec3 position, glm::vec3 rotation, float fov, float aspectRatio, float zNear, float zFar) : QuaternionCamera(position, rotation, zNear, zFar)
{
this->fov = fov;
this->aspectRatio = aspectRatio;
updateProjectionMatrix();
}
void PerspectiveCamera::setFOV(float fov)
{
this->fov = fov;
updateProjectionMatrix();
}
void PerspectiveCamera::setAspectRatio(float aspectRatio)
{
this->aspectRatio = aspectRatio;
updateProjectionMatrix();
}
void PerspectiveCamera::setAspectRatio(float width, float height)
{
this->aspectRatio = height / width;
updateProjectionMatrix();
}
float PerspectiveCamera::getFOV() const
{
return fov;
}
float PerspectiveCamera::getAspectRatio() const
{
return aspectRatio;
}
void PerspectiveCamera::updateProjectionMatrix()
{
projectionMatrix = glm::perspective(glm::radians(fov), aspectRatio, zNear, zFar);
}

In general, changing the pitch, yaw, or roll will change all the components of a quaternion. So I would just transform the quaternion into euler angles, set the appropriate angle, and transform that back into the quaternion. Something like this:
glm::vec3 eulerAngles = glm::eulerAngles(orientation);
eulerAngles.x = amount; // .y for yaw, .z for roll
orientation = glm::quat(eulerAngles);

Related

Align rotation of an object with first person camera opengl

I´m trying to implements a bullet so I have this free movement first person camera. I got this camera from learnopengl.com this is the coding:
// Default camera values
const float YAW = -90.0f;
const float PITCH = 0.0f;
const float SPEED = 2.5f;
const float SENSITIVITY = 0.1f;
const float ZOOM = 45.0f;
// An abstract camera class that processes input and calculates the corresponding Euler Angles, Vectors and Matrices for use in OpenGL
class Camera
{
public:
// Camera Attributes
glm::vec3 Position;
glm::vec3 Front;
glm::vec3 Up;
glm::vec3 Right;
glm::vec3 WorldUp;
// Euler Angles
float Yaw;
float Pitch;
// Camera options
float MovementSpeed;
float MouseSensitivity;
float Zoom;
// Constructor with vectors
Camera(glm::vec3 position = glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3 up = glm::vec3(0.0f, 1.0f, 0.0f), float yaw = YAW, float pitch = PITCH) : Front(glm::vec3(0.0f, 0.0f, -1.0f)), MovementSpeed(SPEED), MouseSensitivity(SENSITIVITY), Zoom(ZOOM)
{
Position = position;
WorldUp = up;
Yaw = yaw;
Pitch = pitch;
updateCameraVectors();
}
// Constructor with scalar values
Camera(float posX, float posY, float posZ, float upX, float upY, float upZ, float yaw, float pitch) : Front(glm::vec3(0.0f, 0.0f, -1.0f)), MovementSpeed(SPEED), MouseSensitivity(SENSITIVITY), Zoom(ZOOM)
{
Position = glm::vec3(posX, posY, posZ);
WorldUp = glm::vec3(upX, upY, upZ);
Yaw = yaw;
Pitch = pitch;
updateCameraVectors();
}
// Returns the view matrix calculated using Euler Angles and the LookAt Matrix
glm::mat4 GetViewMatrix()
{
return glm::lookAt(Position, Position + Front, Up);
}
// Processes input received from any keyboard-like input system. Accepts input parameter in the form of camera defined ENUM (to abstract it from windowing systems)
void ProcessKeyboard(Camera_Movement direction, float deltaTime)
{
float velocity = MovementSpeed * deltaTime;
if (direction == FORWARD)
Position += Front * velocity;
if (direction == BACKWARD)
Position -= Front * velocity;
if (direction == LEFT)
Position -= Right * velocity;
if (direction == RIGHT)
Position += Right * velocity;
}
// Processes input received from a mouse input system. Expects the offset value in both the x and y direction.
void ProcessMouseMovement(float xoffset, float yoffset, GLboolean constrainPitch = true)
{
xoffset *= MouseSensitivity;
yoffset *= MouseSensitivity;
Yaw += xoffset;
Pitch += yoffset;
// Make sure that when pitch is out of bounds, screen doesn't get flipped
if (constrainPitch)
{
if (Pitch > 89.0f)
Pitch = 89.0f;
if (Pitch < -89.0f)
Pitch = -89.0f;
}
// Update Front, Right and Up Vectors using the updated Euler angles
updateCameraVectors();
}
// Processes input received from a mouse scroll-wheel event. Only requires input on the vertical wheel-axis
void ProcessMouseScroll(float yoffset)
{
if (Zoom >= 1.0f && Zoom <= 45.0f)
Zoom -= yoffset;
if (Zoom <= 1.0f)
Zoom = 1.0f;
if (Zoom >= 45.0f)
Zoom = 45.0f;
}
private:
// Calculates the front vector from the Camera's (updated) Euler Angles
void updateCameraVectors()
{
// Calculate the new Front vector
glm::vec3 front;
front.x = cos(glm::radians(Yaw)) * cos(glm::radians(Pitch));
front.y = sin(glm::radians(Pitch));
front.z = sin(glm::radians(Yaw)) * cos(glm::radians(Pitch));
Front = glm::normalize(front);
// Also re-calculate the Right and Up vector
Right = glm::normalize(glm::cross(Front, WorldUp)); // Normalize the vectors, because their length gets closer to 0 the more you look up or down which results in slower movement.
Up = glm::normalize(glm::cross(Right, Front));
}
};
So now I want to create a bullet that starts from
model = glm::translate(model, camara.Position+7.0f*camara.Front);
The issue is that as I try to move the camera the object rotates with it which I know why but I don't know how to fix it, I have tried something like this:
model = glm::rotate(model, glm::radians(camara.Pitch), glm::vec3(1.0f, 0.0f, 0.0f));
model = glm::rotate(model, -glm::radians(camara.Yaw), glm::vec3(0.0f, 1.0f, 0.0f));
trying to sync the rotations but it's not working.
I want to store the position because then I want the bullets to go straight no matter where I move. Thank you.
This is how I always want it to look:
This is how it rotates as I move:

OpenGL float precision makes unexpected differece

I have a function which rotates the camera around the player by yaw and pitch angles.
void Camera::updateVectors() {
GLfloat radius = glm::length(center - position);
position.x = cos(glm::radians(this->yaw)) * cos(glm::radians(this->pitch));
position.y = sin(glm::radians(this->pitch));
position.z = sin(glm::radians(this->yaw)) * cos(glm::radians(this->pitch));
position *= radius;
this->front = glm::normalize(center - position);
this->right = glm::normalize(glm::cross(this->front, this->worldUp));
this->up = glm::normalize(glm::cross(this->right, this->front));
lookAt = glm::lookAt(this->position, this->position + this->front, this->up);
}
When I move the player the camera should moves with it by adding a translation vector to both the center and position of the camera:
void Camera::Transform(glm::vec3& t) {
this->position += t;
this->center += t;
}
Vefore moving the player the camera rotation works fine and the player movement also works fine but once I try to rotate the camera after player moving it start to change position unexpected.
After making some debugging I noticed that the radius which Is calculated at first line which is the distance between center and position of the camera like 49.888889 or 50.000079 and due to the initialized values it should be 50.0, this very small difference makes the result unexpected at all.
so how could I treat this float precision or is there a bug in my code or calculations.
Edit:
position the player depends on its yaw and pitch and update the center of the camera
GLfloat velocity = this->movementSpeed * deltaTime;
if (direction == FORWARD) {
glm::vec3 t = glm::vec3(sin(glm::radians(yaw)), sin(glm::radians(pitch)), cos(glm::radians(yaw))) * velocity;
matrix = glm::translate(matrix, t);
for (GLuint i = 0; i < this->m_Entries.size(); i++) {
this->m_Entries[i].setModelMatrix(matrix);
}
glm::vec3 f(matrix[2][0], matrix[2][1], matrix[2][2]);
f *= velocity;
scene->getDefCamera()->Transform(f);
}
if (direction == BACKWARD) {
glm::vec3 t = glm::vec3(sin(glm::radians(yaw)), 0.0, cos(glm::radians(yaw))) * velocity;
matrix = glm::translate(matrix, -t);
for (GLuint i = 0; i < this->m_Entries.size(); i++) {
this->m_Entries[i].setModelMatrix(matrix);
}
glm::vec3 f(matrix[2][0], matrix[2][1], matrix[2][2]);
f *= velocity;
f = -f;
scene->getDefCamera()->Transform(f);
}
The main problem here is that you're rotating based on a position that is moving. But rotations are based on the origin of the coordinate system. So when you move the position, the rotation is still being done relative to the origin.
Instead of having Transform offset the position, it should only offset the center. Indeed, storing position makes no sense; you compute the camera's position based on its current center point, the radius, and the angles of rotation. The radius is a property that should be stored, not computed.
the solution simply is making transformations on the camera view matrix instead of making it by lookAt function
first initialize the camera
void Camera::initCamera(glm::vec3& pos, glm::vec3& center, GLfloat yaw, GLfloat pitch) {
view = glm::translate(view, center-pos);
view = glm::rotate(view, glm::radians(yaw), glm::vec3(0.0, 1.0, 0.0));
view = glm::rotate(view, glm::radians(pitch), glm::vec3(1.0, 0.0, 0.0));
view = glm::translate(view, pos-center);
}
then the rotation function:
void Camera::Rotate(GLfloat xoffset, GLfloat yoffset, glm::vec3& c) {
xoffset *= this->mouseSensitivity;
yoffset *= this->mouseSensitivity;
view = glm::translate(view, c );//c is the player position
view = glm::rotate(view, glm::radians(xoffset), glm::vec3(0.0, 1.0, 0.0));
view = glm::rotate(view, glm::radians(yoffset), glm::vec3(1.0, 0.0, 0.0));
view = glm::translate(view, - c);
}
and the camera move function:
void Camera::Translate(glm::vec3& t) {
view = glm::translate(view, -t);
}
and in the player class when the player moves it push camera to move in its direction by this code
void Mesh::Move(Move_Directions direction, GLfloat deltaTime) {
GLfloat velocity = 50.0f * this->movementSpeed * deltaTime;
if (direction == FORWARD) {
glm::vec3 t = glm::vec3(sin(glm::radians(yaw)), sin(glm::radians(pitch)), cos(glm::radians(yaw))) * velocity;
matrix = glm::translate(matrix, t);
for (GLuint i = 0; i < this->m_Entries.size(); i++) {
this->m_Entries[i].setModelMatrix(matrix);
}
glm::vec3 f(matrix[2][0], matrix[2][1], matrix[2][2]);
f *= velocity;
scene->getDefCamera()->Translate(f);
}
if (direction == BACKWARD) {
glm::vec3 t = glm::vec3(sin(glm::radians(yaw)), 0.0, cos(glm::radians(yaw))) * velocity;
matrix = glm::translate(matrix, -t);
for (GLuint i = 0; i < this->m_Entries.size(); i++) {
this->m_Entries[i].setModelMatrix(matrix);
}
glm::vec3 f(matrix[2][0], matrix[2][1], matrix[2][2]);
f *= velocity;
f = -f;
scene->getDefCamera()->Translate(f);
}
if (direction == RIGHT) {
matrix = glm::rotate(matrix, (GLfloat) -M_PI * deltaTime, glm::vec3(0.0, 1.0, 0.0));
for (GLuint i = 0; i < this->m_Entries.size(); i++) {
this->m_Entries[i].setModelMatrix(matrix);
}
}
if (direction == LEFT) {
matrix = glm::rotate(matrix, (GLfloat) M_PI * deltaTime, glm::vec3(0.0, 1.0, 0.0));
for (GLuint i = 0; i < this->m_Entries.size(); i++) {
this->m_Entries[i].setModelMatrix(matrix);
}
}
}
thanks for every body helped

Rotating camera Up and Left

How can I transform the camera to left and up? I have tried to do it by few examples, but nothing good. In result camera left rotates like on pic.2, that is incorrect. Also my camera up - flips + zooms out each time i press "up" button.
mat3 Transform::rotate(const float degrees, const vec3& axis) {
mat3 second_mat = glm::mat3(
glm::vec3(axis.x*axis.x, axis.x*axis.y, axis.x*axis.z),
glm::vec3(axis.x*axis.y, axis.y*axis.y, axis.y*axis.z),
glm::vec3(axis.x*axis.z, axis.y*axis.z, axis.z*axis.z));
mat3 third_mat = glm::mat3(
glm::vec3(0.0f, -axis.z, axis.y),
glm::vec3(axis.z, 0.0f, -axis.x),
glm::vec3(-axis.y, axis.x, 0.0f));
mat3 rot = mat3((glm::radians(degrees))*mat3(1.0) + (1 - cos(glm::radians(degrees))*second_mat)+ (sin(glm::radians(degrees))*third_mat));
return rot;
}
// Transforms the camera left around the "crystal ball" interface
void Transform::left(float degrees, vec3& eye, vec3& up) {
up = glm::normalize(glm::cross(up, eye));
}
// Transforms the camera up around the "crystal ball" interface
void Transform::up(float degrees, vec3& eye, vec3& up) {
eye = eye * rotate(degrees, up);
up = up * rotate(degrees, up);
}
mat4 Transform::lookAt(vec3 eye, vec3 up) {
glm::mat4 view = glm::lookAt(
glm::vec3(eye.x, eye.y, eye.z),
glm::vec3(0.0f, 0.0f, 0.0f),
glm::vec3(up.x, up.y, up.z)
);
return view;
}
You have missed "cos" in "rot".
mat3 Transform::rotate(const float degrees, const vec3& axis) {
float d = degrees *(pi / 180);
...
mat3 rot = mat3(cosf(d)*mat3(1.0) + (1 - cosf(d))*second_mat + sinf(d)*third_mat);
}
void Transform::left(float degrees, vec3& eye, vec3& up) {
eye = eye * rotate(degrees, up);
up = up * rotate(degrees, up);
}
void Transform::up(float degrees, vec3& eye, vec3& up) {
vec3 upv = glm::normalize(glm::cross(up, eye));
eye = eye * rotate(degrees, upv);
up = up * rotate(degrees, upv);
}

Trying to implement Camera

I am trying to implement a Camera class so I can walk and look on the world as follows:
#ifndef _CAMERA_H_
#define _CAMERA_H_
#include <glm\glm.hpp>
class Camera
{
public:
Camera();
~Camera();
void Update(const glm::vec2& newXY);
//if by = 0.0 it means, it will use the const Class speed to scale it
void MoveForward(const float by = 0.0f);
void MoveBackword(const float by = 0.0f);
void MoveLef(const float by = 0.0f);
void MoveRight(const float by = 0.0f);
void MoveUp(const float by = 0.0f);
void MoveDown(const float by = 0.0f);
void Speed(const float speed = 0.0f);
glm::vec3& GetCurrentPosition();
glm::vec3& GetCurrentDirection();
glm::mat4 GetWorldToView() const;
private:
glm::vec3 position, viewDirection, strafeDir;
glm::vec2 oldYX;
float speed;
const glm::vec3 up;
};
#endif
#include "Camera.h"
#include <glm\gtx\transform.hpp>
Camera::Camera()
:up(0.0f, 1.0f, 0.0), viewDirection(0.0f, 0.0f, -1.0f),
speed(0.1f)
{
}
Camera::~Camera()
{
}
void Camera::Update(const glm::vec2& newXY)
{
glm::vec2 delta = newXY - oldYX;
auto length = glm::length(delta);
if (glm::length(delta) < 50.f)
{
strafeDir = glm::cross(viewDirection, up);
glm::mat4 rotation = glm::rotate(-delta.x * speed, up) *
glm::rotate(-delta.y * speed, strafeDir);
viewDirection = glm::mat3(rotation) * viewDirection;
}
oldYX = newXY;
}
void Camera::Speed(const float speed)
{
this->speed = speed;
}
void Camera::MoveForward(const float by)
{
float s = by == 0.0f ? speed : by;
position += s * viewDirection;
}
void Camera::MoveBackword(const float by)
{
float s = by == 0.0f ? speed : by;
position += -s * viewDirection;
}
void Camera::MoveLef(const float by )
{
float s = by == 0.0f ? speed : by;
position += -s * strafeDir;
}
void Camera::MoveRight(const float by )
{
float s = by == 0.0f ? speed : by;
position += -s * strafeDir;
}
void Camera::MoveUp(const float by )
{
float s = by == 0.0f ? speed : by;
position += s * up;
}
void Camera::MoveDown(const float by )
{
float s = by == 0.0f ? speed : by;
position += -s * up;
}
glm::vec3& Camera::GetCurrentPosition()
{
return position;
}
glm::vec3& Camera::GetCurrentDirection()
{
return viewDirection;
}
glm::mat4 Camera::GetWorldToView() const
{
return glm::lookAt(position, position + viewDirection, up);
}
and I update and render as follow :
void Game::OnUpdate()
{
glLoadIdentity();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUniformMatrix4fv(program->GetUniformLocation("modelToViewWorld"), 1, GL_FALSE, &cam.GetWorldToView()[0][0]);
}
void Game::OnRender()
{
model->Draw();
}
Where the vertex shader looks like:
#version 410
layout (location = 0) in vec3 inVertex;
layout (location = 1) in vec2 inTexture;
layout (location = 2) in vec3 inNormal;
uniform mat4 modelToViewWorld;
void main()
{
gl_Position = vec4(mat3(modelToViewWorld) * inVertex, 1);
}
But I am moving/rotating the Model itself, not the camera around it. What am I doing wrong here?
I think the problem is that you are not inverting the view matrix. The model-view matrix is just a product of a model->world coordinates matrix transformation and a world->view coordinates matrix transformation. The first one takes the coordinates in the local model spaces and transforms them to the world space, therefore needs no invertion. However, the second one takes the coordinates of a camera in world space and transforms them to the local coordinate system of the camera and since it's the opposite of the first one it needs to be inverted.
You are not rotating the model, you are rotating the view direction.
viewDirection = glm::mat3(rotation) * viewDirection;
What you want to do is to rotate the center of the camera around the object and then set the direction of the camera towards the object.
For example:
position = vec3( radius * cos(t), radius * sin(t), 0);
direction = normalize(-position);

Implements turn left function in openGL

Basically, I need to change the eye and up vectors correctly when pressing the left key (turning the view to right). My implementation is as follows but it does not seem to pass the tests. Anyone can help?
// Transforms the camera left around the "crystal ball" interface
void Transform::left(float degrees, vec3& eye, vec3& up) {
// YOUR CODE FOR HW1 HERE
eye = rotate(degrees, vec3(0, 1, 0)) * eye;
up = rotate(degrees, vec3(0, 1, 0)) * up;
}
The rotation function takes two arguments degree and axis, and returns the rotation matrix which is a 3 by 3 matrix:
mat3 Transform::rotate(const float degrees, const vec3& axis) {
// YOUR CODE FOR HW1 HERE
mat3 rot, I(1.0);
mat3 a_x;
a_x[0][0] = 0;
a_x[0][1] = -axis[2];
a_x[0][2] = axis[1];
a_x[1][0] = axis[2];
a_x[1][1] = 0;
a_x[1][2] = -axis[0];
a_x[2][0] = -axis[1];
a_x[2][1] = axis[0];
a_x[2][2] = 0;
float theta = degrees / 180 * pi;
rot = I * cos(theta) + glm::outerProduct(axis, axis) *(1-cos(theta)) + a_x*sin(theta);
return rot;
}
Try if something like this fixes it:
glm::mat3 Transform::rotate(float angle, const glm::vec3& axis) {
glm::mat3 a_x( 0.0f, axis.z, -axis.y,
-axis.z, 0.0f, axis.x,
axis.y, -axis.x, 0.0f);
angle = glm::radians(angle);
return glm::mat3() * cos(angle) + sin(angle) * a_x
+ (1.0f - cos(angle)) * glm::outerProduct(axis, axis);
}
I googled around and find a solution:
// Transforms the camera left around the "crystal ball" interface
void Transform::left(float degrees, vec3& eye, vec3& up) {
// YOUR CODE FOR HW1 HERE
eye = eye * rotate(degrees, up);
}
The rotation function is correct.