🎉 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!

360 degrees rotation around x axis

Started by
4 comments, last by dud3 6 years, 9 months ago

How do we rotate the camera around x axis 360 degrees, without having the strange effect as in my video below? 

Mine behaves exactly the same way spherical coordinates would, I'm using euler angles.

Tried googling, but couldn't find a proper answer, guessing I don't know what exactly to google for, googled 'rotate 360 around x axis', got no proper answers.

 

References:

Code: https://pastebin.com/Hcshj3FQ

The video shows the difference between blender and my rotation:

 

Advertisement

I would suggest using a parametrization of rotations that doesn't have a region where things get wacky. Either orthogonal matrices or quaternions would do.

 

I think I'm stuck, I'm just trying to achieve the same rotation around the x axis as in blender.

The video shows the difference between blender and my rotation:

 

You should have a notion of what the current attitude of your object is (i.e., the rotation that brings it from its initial position to its current position). When the mouse is clicked you create a new rotation, which depends only on the point where the mouse was initially clicked and its current position (perhaps just depends on the vector between those). While the mouse button is down, you display the object as having attitude (current_attitude * mouse_rotation). When the mouse button is released, you bake the mouse rotation into the attitude (`current_attitude *= mouse_rotation').

In the paragraph above I have used multiplicative notation to represent composition of rotations. Composition of rotations is hard if you are using Euler angles. But if you are using matrices or quaternions, it literally is a multiplication (be careful to get the order right, because it matters).

 

This is the current code, under dragTPSInput(...):
 


#pragma once

#include <glm.hpp>
#include <gtc/matrix_transform.hpp>
#include <gtc/type_ptr.hpp>

#include "InputHandler.h"
#include "Vector2D.h"

class Camera 
{
public:

	glm::vec3 m_position;
	
	glm::vec3 m_front;
	glm::vec3 m_up;
	glm::vec3 m_right;

	glm::vec3 m_worldup;

	float m_yaw;
	float m_pitch;

	float m_zoom;

	bool m_enableInput;

	// Mouse
	float m_mouseSensitivity;

	enum class direction { in, out, right, left };

	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 = -90.0f,
		float pitch = 0.0,
		float zoom = 1.0f,
		float mouseSensitivity = 0.05f) :
		m_front(glm::vec3(0.0f, 0.0f, -1.0f)), 
		m_enableInput(false)
	{
		m_position = position;

		m_yaw = yaw;
		m_pitch = pitch;

		m_worldup = up;

		m_zoom = zoom;
		m_mouseSensitivity = mouseSensitivity;

		updateCameraVectors();
	}

	void lookAt()
	{
	}

	void move(direction d)
	{
		if (d == direction::in)
			m_position -= m_front;
		
		if (d == direction::out)
			m_position += m_front;

		if(d == direction::right)
			m_position += glm::normalize(glm::cross(m_front, m_up)) * m_mouseSensitivity;

		if(d == direction::left)
			m_position -= glm::normalize(glm::cross(m_front, m_up)) * m_mouseSensitivity;
	}
	
	void rotate()
	{
	}

	void zoom()
	{
	}

	void scrollInput()
	{
	}

	void keyboardInput()
	{
		// todo: give the user ability to adjust input keys

		if (_inHandler->onKeyDown(SDL_SCANCODE_W)) {
			move(direction::in);
		}
		if (_inHandler->onKeyDown(SDL_SCANCODE_S)) {
			move(direction::out);
		}
		if (_inHandler->onKeyDown(SDL_SCANCODE_D)) {
			move(direction::right);
		}
		if (_inHandler->onKeyDown(SDL_SCANCODE_A)) {
			move(direction::left);
		}
	}

	void dragFPSInput(Vector2D* mouseMoveDiff, bool constrainPitch = true)
	{
		m_yaw += mouseMoveDiff->getX(); // offsetx
		m_pitch += -(mouseMoveDiff->getY()); // offsety

		// Make sure that when pitch is out of bounds, screen doesn't get flipped
		if (constrainPitch)
		{
			if (m_pitch > 89.0f)
				m_pitch = 89.0f;
			if (m_pitch < -89.0f)
				m_pitch = -89.0f;
		}

		// Update Front, Right and Up Vectors using the updated Eular angles
		updateCameraVectors();
	}

	void dragTPSInput(Vector2D* mouseMoveDiff)
	{
		// m_position = glm::rotate(m_position, -mouseMoveDiff->getY() * m_mouseSensitivity, glm::vec3(1, 0, 0));
		// m_position = glm::rotate(m_position, -mouseMoveDiff->getX() * m_mouseSensitivity, glm::vec3(0, 1, 0));

		glm::quat rot = glm::angleAxis(glm::radians(-mouseMoveDiff->getY()), glm::vec3(1, 0, 0));
		rot = rot * glm::angleAxis(glm::radians(-mouseMoveDiff->getX()), glm::vec3(0, 1, 0));

		glm::mat4 rotMatrix = glm::mat4_cast(rot);

		glm::vec4 pos = glm::vec4(m_position.x, m_position.y, m_position.z, 1.0f);

		pos = rotMatrix * pos;

		m_position.x = pos.x;
		m_position.y = pos.y;
		m_position.z = pos.z;

		updateCameraVectors();
	}

	void onInput(bool drag = true, bool scroll = true, bool keyboard = false)
	{
		if (drag)
			if (_inHandler->getMouseButtonState(_inHandler->mouse_buttons::LEFT))
				if(_inHandler->isMouseMovig())
					dragTPSInput(_inHandler->getMouseMoveDiff());

		if (scroll)
			scrollInput();

		if (keyboard)
			keyboardInput();
	}

	// Returns the view matrix calculated using Eular Angles and the LookAt Matrix
	glm::mat4 getViewMatrix()
	{
		glm::vec3 pos = glm::vec3(m_position.x, m_position.y, m_position.z);
		return glm::lookAt(pos, m_front, m_up);
	}

private:
	void updateCameraVectors()
	{
		// Calculate the new Front vector
		glm::vec3 front;
		front.x = cos(glm::radians(m_yaw)) * cos(glm::radians(m_pitch));
		front.y = sin(glm::radians(m_pitch));
		front.z = sin(glm::radians(m_yaw)) * cos(glm::radians(m_pitch));

		m_front = glm::normalize(front);

		// Also re-calculate the Right and Up vector
		// Normalize the vectors, because their length gets closer to 0 the more you look up or down which results in slower movement.
		m_right = glm::normalize(glm::cross(m_front, m_worldup)); 
		
		m_up = glm::normalize(glm::cross(m_right, m_front));
	}

	InputHandler* _inHandler = TheInputHandler::Instance();
};

 

This topic is closed to new replies.

Advertisement