I am building a Unity-like Transform class.
This is my header file:
#include "Common.h"
struct Transform
{
public:
Transform();
void Translate(float x, float y, float z);
void Translate(const glm::vec3 &dir);
void SetPosition(const glm::vec3 &pos);
void SetYPosition(const float &pos);
void Rotate(float x, float y, float z, bool world = true);
void Rotate(const glm::vec3 &dir, bool world = true);
void SetRotation(const glm::vec3 &rot);
void Scale(const glm::vec3 &scale);
void Scale(float x, float y, float z);
const glm::vec3& GetScale();
const glm::vec3& GetPosition();
const glm::vec3& GetRotation();
void LookAt(glm::vec3 targetPosition);
glm::mat4 GetWorldMatrix();
glm::vec3 Up();
glm::vec3 Right();
glm::vec3 Forward();
glm::mat4 GetOrientation();
glm::mat4 GetTranslation();
glm::mat4 GetScaling();
void NormalizeAngles();
private:
glm::vec3 m_Position, m_Rotation, m_Scale;
glm::mat4 m_Translation, m_Orientation, m_Scaling;
bool m_NeedUpdate;
};
inline Transform::Transform()
{
m_Scale = glm::vec3(1,1,1);
m_NeedUpdate = true;
}
...
inline void Transform::Translate(float x, float y, float z)
{
m_Position += glm::vec3(x,y,z);
m_NeedUpdate = true;
}
inline void Transform::Translate(const glm::vec3 &dir)
{
m_Position += dir;
m_NeedUpdate = true;
}
inline void Transform::SetRotation(const glm::vec3 &rot)
{
m_Rotation = rot;
m_NeedUpdate = true;
}
inline void Transform::Rotate(float x, float y, float z,bool world)
{
if(world)
m_Rotation += glm::vec3(x,y,z);
else
{
//TODO
m_Rotation += glm::vec3(x,y,z);
}
m_NeedUpdate = true;
}
inline void Transform::Rotate(const glm::vec3 &rot,bool world)
{
if(world)
m_Rotation += rot;
else
{
//TODO
}
m_NeedUpdate = true;
}
...
inline const glm::vec3& Transform::GetRotation()
{
return m_Rotation;
}
...
And this is my C++ file:
#include "Transform.h"
static const float MaxVerticalAngle = 89.0f; //must be less than 90 to avoid gimbal lock
void Transform::NormalizeAngles()
{
m_Rotation.y = fmodf(m_Rotation.y, 360.0f);
//fmodf can return negative values, but this will make them all positive
if(m_Rotation.y < 0.0f)
m_Rotation.y += 360.0f;
if(m_Rotation.x > MaxVerticalAngle)
m_Rotation.x = MaxVerticalAngle;
else if(m_Rotation.x < -MaxVerticalAngle)
m_Rotation.x = -MaxVerticalAngle;
}
void Transform::LookAt(glm::vec3 targetPosition)
{
if((targetPosition - m_Position) == glm::vec3(0,0,0)) return;
glm::vec3 direction = glm::normalize(targetPosition - m_Position);
m_Rotation.x = asinf(-direction.y)* RadToDeg;
m_Rotation.y = -atan2f(-direction.x, -direction.z)*RadToDeg;
NormalizeAngles();
m_NeedUpdate = true;
}
glm::mat4 Transform::GetOrientation()
{
if(m_NeedUpdate)
{
m_Orientation = glm::rotate(m_Rotation.x, glm::vec3(1,0,0));
m_Orientation = glm::rotate(m_Orientation, m_Rotation.y, glm::vec3(0,1,0));
m_Orientation = glm::rotate(m_Orientation, m_Rotation.z, glm::vec3(0,0,1));
}
return m_Orientation;
}
glm::mat4 Transform::GetTranslation()
{
if(m_NeedUpdate)
{
m_Translation = glm::translate(m_Position);
}
return m_Translation;
}
...
I have problems implementing the rotation correctly (the //TODO commented part). Currently rotation is only working in world orientation, but I would like to select whether orientation should be in world or in local orientation. Also translation currently works in world space, it also should be selectable whether to translate in local orientation or in world orientation.
How can I make my translation and rotation operations operate on local coordinates?