I'm having trouble implementing a non-origin point rotation. I have a class Transform
that stores each component separately in three 3D vectors for position
, scale
, and rotation
. This is fine for local rotations based on the center of the object.
The issue is how do I determine/concatenate non-origin rotations in addition to origin rotations. Normally this would be achieved as a Transform-Rotate-Transform for the center rotation followed by a Transform-Rotate-Transform for the non-origin point.
The problem is because I am storing the individual components, the final Transform matrix is not calculated until needed by using the individual components to fill an appropriate Matrix. (See GetLocalTransform()
)
Do I need to store an additional rotation (and radius) for world rotations as well or is there a method of implementation that works while only using the single rotation value?
Transform.h
#ifndef A2DE_CTRANSFORM_H
#define A2DE_CTRANSFORM_H
#include "../a2de_vals.h"
#include "CMatrix4x4.h"
#include "CVector3D.h"
#include <vector>
A2DE_BEGIN
class Transform {
public:
Transform();
Transform(Transform* parent);
Transform(const Transform& other);
Transform& operator=(const Transform& rhs);
virtual ~Transform();
void SetParent(Transform* parent);
void AddChild(Transform* child);
void RemoveChild(Transform* child);
Transform* FirstChild();
Transform* LastChild();
Transform* NextChild();
Transform* PreviousChild();
Transform* GetChild(std::size_t index);
std::size_t GetChildCount() const;
std::size_t GetChildCount();
void SetPosition(const a2de::Vector3D& position);
const a2de::Vector3D& GetPosition() const;
a2de::Vector3D& GetPosition();
void SetRotation(const a2de::Vector3D& rotation);
const a2de::Vector3D& GetRotation() const;
a2de::Vector3D& GetRotation();
void SetScale(const a2de::Vector3D& scale);
const a2de::Vector3D& GetScale() const;
a2de::Vector3D& GetScale();
a2de::Matrix4x4 GetLocalTransform() const;
a2de::Matrix4x4 GetLocalTransform();
protected:
private:
a2de::Vector3D _position;
a2de::Vector3D _scale;
a2de::Vector3D _rotation;
std::size_t _curChildIndex;
Transform* _parent;
std::vector<Transform*> _children;
};
A2DE_END
#endif
Transform.cpp
#include "CTransform.h"
#include "CVector2D.h"
#include "CVector4D.h"
A2DE_BEGIN
Transform::Transform() :
_position(),
_scale(1.0, 1.0),
_rotation(),
_curChildIndex(0),
_parent(nullptr),
_children()
{
/* DO NOTHING */
}
Transform::Transform(Transform* parent) :
_position(),
_scale(1.0, 1.0),
_rotation(),
_curChildIndex(0),
_parent(parent),
_children()
{
/* DO NOTHING */
}
Transform::Transform(const Transform& other) :
_position(other._position),
_scale(other._scale),
_rotation(other._rotation),
_curChildIndex(0),
_parent(other._parent),
_children(other._children)
{
/* DO NOTHING */
}
Transform& Transform::operator=(const Transform& rhs) {
if(this == &rhs) return *this;
this->_position = rhs._position;
this->_scale = rhs._scale;
this->_rotation = rhs._rotation;
this->_curChildIndex = 0;
this->_parent = rhs._parent;
this->_children = rhs._children;
return *this;
}
Transform::~Transform() {
_children.clear();
_parent = nullptr;
}
void Transform::SetParent(Transform* parent) {
_parent = parent;
}
void Transform::AddChild(Transform* child) {
if(child == nullptr) return;
_children.push_back(child);
}
void Transform::RemoveChild(Transform* child) {
if(_children.empty()) return;
_children.erase(std::remove(_children.begin(), _children.end(), child), _children.end());
}
Transform* Transform::FirstChild() {
if(_children.empty()) return nullptr;
return *(_children.begin());
}
Transform* Transform::LastChild() {
if(_children.empty()) return nullptr;
return *(_children.end());
}
Transform* Transform::NextChild() {
if(_children.empty()) return nullptr;
std::size_t s(_children.size());
if(_curChildIndex >= s) {
_curChildIndex = s;
return nullptr;
}
return _children[_curChildIndex++];
}
Transform* Transform::PreviousChild() {
if(_children.empty()) return nullptr;
if(_curChildIndex == 0) {
return nullptr;
}
return _children[_curChildIndex--];
}
Transform* Transform::GetChild(std::size_t index) {
if(_children.empty()) return nullptr;
if(index > _children.size()) return nullptr;
return _children[index];
}
std::size_t Transform::GetChildCount() const {
if(_children.empty()) return 0;
return _children.size();
}
std::size_t Transform::GetChildCount() {
return static_cast<const Transform&>(*this).GetChildCount();
}
void Transform::SetPosition(const a2de::Vector3D& position) {
_position = position;
}
const a2de::Vector3D& Transform::GetPosition() const {
return _position;
}
a2de::Vector3D& Transform::GetPosition() {
return const_cast<a2de::Vector3D&>(static_cast<const Transform&>(*this).GetPosition());
}
void Transform::SetRotation(const a2de::Vector3D& rotation) {
_rotation = rotation;
}
const a2de::Vector3D& Transform::GetRotation() const {
return _rotation;
}
a2de::Vector3D& Transform::GetRotation() {
return const_cast<a2de::Vector3D&>(static_cast<const Transform&>(*this).GetRotation());
}
void Transform::SetScale(const a2de::Vector3D& scale) {
_scale = scale;
}
const a2de::Vector3D& Transform::GetScale() const {
return _scale;
}
a2de::Vector3D& Transform::GetScale() {
return const_cast<a2de::Vector3D&>(static_cast<const Transform&>(*this).GetScale());
}
a2de::Matrix4x4 Transform::GetLocalTransform() const {
Matrix4x4 p((_parent ? _parent->GetLocalTransform() : a2de::Matrix4x4::GetIdentity()));
Matrix4x4 t(a2de::Matrix4x4::GetTranslationMatrix(_position));
Matrix4x4 r(a2de::Matrix4x4::GetRotationMatrix(_rotation));
Matrix4x4 s(a2de::Matrix4x4::GetScaleMatrix(_scale));
return (p * t * r * s);
}
a2de::Matrix4x4 Transform::GetLocalTransform() {
return static_cast<const Transform&>(*this).GetLocalTransform();
}
A2DE_END