first take at the Transform encapsulating a transform matrix

This commit is contained in:
Sam Gateau 2014-11-06 09:56:05 -08:00
parent 67535a386c
commit 4a73b0773b
2 changed files with 222 additions and 0 deletions

View file

@ -0,0 +1,109 @@
//
// Transform.cpp
// interface/src/gpu
//
// Created by Sam Gateau on 11/4/2014.
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "Transform.h"
#include <glm/gtx/quaternion.hpp>
using namespace gpu;
Transform::Transform() :
_translation(0),
_rotation(1.f, 0, 0, 0),
_scale(1.f),
_flags(1) // invalid cache
{
}
Transform::Transform(const Mat4& raw) {
evalFromRawMatrix(raw);
}
void Transform::updateCache() const {
if (isCacheInvalid()) {
glm::mat3x3 rot = glm::mat3_cast(_rotation);
if ((_scale.x != 1.f) || (_scale.y != 1.f) || (_scale.z != 1.f)) {
rot[0] *= _scale.x;
rot[1] *= _scale.y;
rot[2] *= _scale.z;
}
_matrix[0] = Vec4(rot[0], 0.f);
_matrix[1] = Vec4(rot[1], 0.f);
_matrix[2] = Vec4(rot[2], 0.f);
_matrix[3] = Vec4(_translation, 0.f);
validCache();
}
}
void Transform::localTranslate( Vec3 const & translation) {
Vec3 tt = glm::rotate(_rotation, translation);
_translation += tt * _scale;
}
Transform::Mat4& Transform::evalRelativeTransform( Mat4& result, const Vec3& origin) {
updateCache();
result = _matrix;
result[3] = Vec4(_translation - origin, 0.f);
return result;
}
void Transform::evalFromRawMatrix(const Mat4& matrix) {
if ((matrix[0][3] == 0) && (matrix[1][3] == 0) && (matrix[2][3] == 0) && (matrix[3][3] == 1.f)) {
setTranslation(Vec3(matrix[3]));
Mat3 matRS = Mat3(matrix);
Vec3 scale(glm::length(matRS[0]), glm::length(matRS[1]), glm::length(matRS[2]));
matRS[0] *= 1/scale.x;
matRS[1] *= 1/scale.y;
matRS[2] *= 1/scale.z;
setRotation(glm::quat_cast(matRS));
setScale(scale);
}
}
Transform& Transform::evalInverseTranspose(Transform& result) {
result.setTranslation(-_translation);
result.setRotation(-_rotation);
if (isScaling()) {
result.setScale(Vec3(1.f/_scale.x, 1.f/_scale.y, 1.f/_scale.z));
}
return result;
}
Transform& Transform::mult( Transform& result, const Transform& left, const Transform& right) {
right.updateCache();
left.updateCache();
result.setTranslation(Vec3(left.getMatrix() * Vec4(right.getTranslation(), 1.f)));
Mat4 mat = left.getMatrix() * right.getMatrix();
Mat3 matRS = Mat3(mat);
Vec3 scale(glm::length(matRS[0]), glm::length(matRS[1]), glm::length(matRS[2]));
matRS[0] *= 1/scale.x;
matRS[1] *= 1/scale.y;
matRS[2] *= 1/scale.z;
result.setRotation(glm::quat_cast(matRS));
result.setScale(scale);
return result;
}

View file

@ -0,0 +1,113 @@
//
// Transform.h
// interface/src/gpu
//
// Created by Sam Gateau on 11/4/2014.
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_gpu_Transform_h
#define hifi_gpu_Transform_h
#include <assert.h>
#include "InterfaceConfig.h"
#include "gpu/Format.h"
#include <QSharedPointer>
#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <bitset>
namespace gpu {
class Transform {
public:
typedef glm::mat4 Mat4;
typedef glm::mat3 Mat3;
typedef glm::vec4 Vec4;
typedef glm::vec3 Vec3;
typedef glm::vec2 Vec2;
typedef glm::quat Quat;
Transform();
Transform(const Mat4& raw);
~Transform() {}
void setTranslation(const Vec3& translation) { invalidCache(); flagTranslation(); _translation = translation; }
const Vec3& getTranslation() const { return _translation; }
void parentTranslate(const Vec3& translation) { _translation += translation; }
void localTranslate( Vec3 const & translation);
void setRotation(const Quat& rotation) { invalidCache(); flagRotation(); _rotation = rotation; }
const Quat& getRotation() const { return _rotation; }
void setNoScale() { invalidCache(); flagNoScaling(); _scale = Vec3(1.f); }
void setScale(float scale) { invalidCache(); flagUniformScaling(); _scale = Vec3(scale); }
void setScale(const Vec3& scale) { invalidCache(); flagNonUniformScaling(); _scale = scale; }
const Vec3& getScale() const { return _scale; }
const Mat4& getMatrix() const { updateCache(); return _matrix; }
Mat4& evalRelativeTransform(Mat4& result, const Vec3& origin);
Transform& evalInverseTranspose(Transform& result);
void evalFromRawMatrix(const Mat4& matrix);
static Transform& mult( Transform& result, const Transform& left, const Transform& right);
bool isScaling() const { return _flags[FLAG_UNIFORM_SCALING] || _flags[FLAG_NON_UNIFORM_SCALING]; }
protected:
enum Flag {
FLAG_CACHE_INVALID = 0,
FLAG_TRANSLATION,
FLAG_ROTATION,
FLAG_UNIFORM_SCALING,
FLAG_NON_UNIFORM_SCALING,
FLAG_SHEARING,
FLAG_PROJECTION,
NUM_FLAGS,
};
typedef std::bitset<NUM_FLAGS> Flags;
// TRS
Vec3 _translation;
Quat _rotation;
Vec3 _scale;
mutable Flags _flags;
// Cached transform
mutable Mat4 _matrix;
bool isCacheInvalid() const { return _flags[FLAG_CACHE_INVALID]; }
void validCache() const { _flags.set(FLAG_CACHE_INVALID, false); }
void invalidCache() const { _flags.set(FLAG_CACHE_INVALID, true); }
void flagTranslation() { _flags.set(FLAG_TRANSLATION, true); }
void flagRotation() { _flags.set(FLAG_ROTATION, true); }
void flagNoScaling() { _flags.set(FLAG_UNIFORM_SCALING, false); _flags.set(FLAG_NON_UNIFORM_SCALING, false); }
void flagUniformScaling() { _flags.set(FLAG_UNIFORM_SCALING, true); _flags.set(FLAG_NON_UNIFORM_SCALING, false); }
void flagNonUniformScaling() { _flags.set(FLAG_UNIFORM_SCALING, false); _flags.set(FLAG_NON_UNIFORM_SCALING, true); }
void updateCache() const;
};
typedef QSharedPointer< Transform > TransformPointer;
};
#endif