14 #ifndef hifi_gpu_Transform_h
15 #define hifi_gpu_Transform_h
19 #include "GLMHelpers.h"
20 #include <glm/gtc/matrix_transform.hpp>
21 #include <glm/gtx/quaternion.hpp>
30 inline bool isValidScale(glm::vec3 scale) {
31 bool result = scale.x != 0.0f && scale.y != 0.0f && scale.z != 0.0f;
33 qWarning() <<
"Scale is equal to 0";
40 inline bool isValidScale(
float scale) {
41 bool result = scale != 0.0f && !glm::isnan(scale) && !glm::isinf(scale);
48 friend QDebug& operator<<(QDebug& debug,
const Transform& transform);
49 using Pointer = std::shared_ptr<Transform>;
50 typedef glm::mat4
Mat4;
51 typedef glm::mat3 Mat3;
52 typedef glm::vec4 Vec4;
53 typedef glm::vec3
Vec3;
54 typedef glm::vec2 Vec2;
55 typedef glm::quat
Quat;
58 _rotation(1.0f, 0.0f, 0.0f, 0.0f),
61 _flags(FLAG_CACHE_INVALID_BITSET)
67 _translation(translation),
70 if (!isValidScale(_scale)) {
74 Transform(
const Transform& transform) :
75 _rotation(transform._rotation),
76 _scale(transform._scale),
77 _translation(transform._translation),
78 _flags(transform._flags)
82 Transform(
const Mat4& raw) {
83 evalFromRawMatrix(raw);
87 Transform& operator=(
const Transform& transform) {
88 _rotation = transform._rotation;
89 _scale = transform._scale;
90 _translation = transform._translation;
91 _flags = transform._flags;
96 bool operator==(
const Transform& other)
const {
97 return _rotation == other._rotation && _scale == other._scale && _translation == other._translation;
100 bool operator!=(
const Transform& other)
const {
101 return _rotation != other._rotation || _scale != other._scale || _translation != other._translation;
104 Transform& setIdentity();
106 const Vec3& getTranslation()
const;
107 Transform& setTranslation(
const Vec3& translation);
108 Transform& preTranslate(
const Vec3& translation);
109 Transform& postTranslate(
const Vec3& translation);
111 const Quat& getRotation()
const;
112 Transform& setRotation(
const Quat& rotation);
113 Transform& preRotate(
const Quat& rotation);
114 Transform& postRotate(
const Quat& rotation);
116 const Vec3& getScale()
const;
117 Transform& setScale(
float scale);
118 Transform& setScale(
const Vec3& scale);
119 Transform& postScale(
float scale);
120 Transform& postScale(
const Vec3& scale);
122 bool isIdentity()
const {
return (_flags & ~Flags(FLAG_CACHE_INVALID_BITSET)).none(); }
123 bool isTranslating()
const {
return _flags[FLAG_TRANSLATION]; }
124 bool isRotating()
const {
return _flags[FLAG_ROTATION]; }
125 bool isScaling()
const {
return _flags[FLAG_SCALING]; }
126 bool isUniform()
const {
return !isNonUniform(); }
127 bool isNonUniform()
const {
return _flags[FLAG_NON_UNIFORM]; }
129 Transform& evalFromRawMatrix(
const Mat4& matrix);
130 Transform& evalFromRawMatrix(
const Mat3& rotationScalematrix);
132 Mat4 getMatrix()
const;
133 Mat4 getInverseMatrix()
const;
134 Mat4& getMatrix(
Mat4& result)
const;
135 Mat4& getInverseMatrix(
Mat4& result)
const;
136 Mat4& getInverseTransposeMatrix(
Mat4& result)
const;
138 Mat4& getRotationScaleMatrix(
Mat4& result)
const;
139 Mat4& getRotationScaleMatrixInverse(
Mat4& result)
const;
141 Transform& evalInverse(Transform& result)
const;
143 Transform relativeTransform(
const Transform& world)
const;
144 Transform worldTransform(
const Transform& relative)
const;
146 static void evalRotationScale(
Quat& rotation,
Vec3& scale,
const Mat3& rotationScaleMatrix);
148 static Transform& mult(Transform& result,
const Transform& left,
const Transform& right);
151 static Transform& inverseMult(Transform& result,
const Transform& left,
const Transform& right);
154 static Transform fromJson(
const QJsonValue& json);
155 static QJsonObject toJson(
const Transform& transform);
157 Vec4 transform(
const Vec4& pos)
const;
158 Vec3 transform(
const Vec3& pos)
const;
159 Vec3 transformDirection(
const Vec3& dir)
const;
161 bool containsNaN()
const {
return isNaN(_rotation) || isNaN(glm::dot(_scale, _translation)); }
166 FLAG_CACHE_INVALID = 0,
178 FLAG_CACHE_INVALID_BITSET = 1,
180 typedef std::bitset<NUM_FLAGS> Flags;
187 mutable Flags _flags;
190 mutable std::unique_ptr<Mat4> _matrix;
192 bool isCacheInvalid()
const {
return _flags[FLAG_CACHE_INVALID]; }
193 void validCache()
const { _flags.set(FLAG_CACHE_INVALID,
false); }
194 void invalidCache()
const { _flags.set(FLAG_CACHE_INVALID,
true); }
196 void flagTranslation() { _flags.set(FLAG_TRANSLATION,
true); }
197 void unflagTranslation() { _flags.set(FLAG_TRANSLATION,
false); }
199 void flagRotation() { _flags.set(FLAG_ROTATION,
true); }
200 void unflagRotation() { _flags.set(FLAG_ROTATION,
false); }
202 void flagScaling() { _flags.set(FLAG_SCALING,
true); }
203 void unflagScaling() { _flags.set(FLAG_SCALING,
false); }
206 void flagUniform() { _flags.set(FLAG_NON_UNIFORM,
false); }
207 void flagNonUniform() { _flags.set(FLAG_NON_UNIFORM,
true); }
209 void updateCache()
const;
210 Mat4& getCachedMatrix(
Mat4& result)
const;
213 QDebug& operator<<(QDebug& debug,
const Transform& transform);
215 inline Transform& Transform::setIdentity() {
216 _translation =
Vec3(0.0f);
217 _rotation =
Quat(1.0f, 0.0f, 0.0f, 0.0f);
219 _flags = Flags(FLAG_CACHE_INVALID_BITSET);
223 inline const Transform::Vec3& Transform::getTranslation()
const {
227 inline Transform& Transform::setTranslation(
const Vec3& translation) {
229 if (translation ==
Vec3()) {
234 _translation = translation;
238 inline Transform& Transform::preTranslate(
const Vec3& translation) {
239 if (translation ==
Vec3()) {
244 _translation += translation;
248 inline Transform& Transform::postTranslate(
const Vec3& translation) {
249 if (translation ==
Vec3()) {
255 Vec3 scaledT = translation;
261 _translation += glm::rotate(_rotation, scaledT);
263 _translation += scaledT;
268 inline const Transform::Quat& Transform::getRotation()
const {
272 inline Transform& Transform::setRotation(
const Quat& rotation) {
274 if (rotation ==
Quat()) {
279 _rotation = rotation;
283 inline Transform& Transform::preRotate(
const Quat& rotation) {
284 if (rotation ==
Quat()) {
289 _rotation = rotation * _rotation;
291 _rotation = rotation;
295 _translation = glm::rotate(rotation, _translation);
299 inline Transform& Transform::postRotate(
const Quat& rotation) {
300 if (rotation ==
Quat()) {
305 if (isNonUniform()) {
308 Mat3 scaleRot(glm::mat3_cast(rotation));
309 scaleRot[0] *= _scale;
310 scaleRot[1] *= _scale;
311 scaleRot[2] *= _scale;
312 evalRotationScale(newRot, newScale, scaleRot);
322 _rotation *= rotation;
324 _rotation = rotation;
331 inline const Transform::Vec3& Transform::getScale()
const {
335 inline Transform& Transform::setScale(
float scale) {
336 if (!isValidScale(scale)) {
347 _scale =
Vec3(scale);
351 inline Transform& Transform::setScale(
const Vec3& scale) {
352 if (!isValidScale(scale)) {
356 if ((scale.x == scale.y) && (scale.x == scale.z)) {
357 return setScale(scale.x);
367 inline Transform& Transform::postScale(
float scale) {
368 if (!isValidScale(scale) || scale == 1.0f) {
372 return setScale(scale);
380 inline Transform& Transform::postScale(
const Vec3& scale) {
381 if (!isValidScale(scale)) {
385 if ((scale.x != scale.y) || (scale.x != scale.z)) {
397 inline Transform::Mat4 Transform::getMatrix()
const {
398 Transform::Mat4 result;
403 inline Transform::Mat4 Transform::getInverseMatrix()
const {
404 Transform::Mat4 result;
405 getInverseMatrix(result);
409 inline Transform::Mat4& Transform::getMatrix(Transform::Mat4& result)
const {
411 Mat3 rot = glm::mat3_cast(_rotation);
419 result[0] = Vec4(rot[0], 0.0f);
420 result[1] = Vec4(rot[1], 0.0f);
421 result[2] = Vec4(rot[2], 0.0f);
423 result[0] = Vec4(_scale.x, 0.0f, 0.0f, 0.0f);
424 result[1] = Vec4(0.0f, _scale.y, 0.0f, 0.0f);
425 result[2] = Vec4(0.0f, 0.0f, _scale.z, 0.0f);
428 result[3] = Vec4(_translation, 1.0f);
432 inline Transform::Mat4& Transform::getInverseMatrix(Transform::Mat4& result)
const {
434 evalInverse(inverse);
435 return inverse.getMatrix(result);
438 inline Transform::Mat4& Transform::getInverseTransposeMatrix(Transform::Mat4& result)
const {
439 getInverseMatrix(result);
440 result = glm::transpose(result);
444 inline Transform::Mat4& Transform::getRotationScaleMatrix(
Mat4& result)
const {
446 result[3] = Vec4(0.0f, 0.0f, 0.0f, 1.0f);
450 inline Transform::Mat4& Transform::getRotationScaleMatrixInverse(
Mat4& result)
const {
451 getInverseMatrix(result);
452 result[3] = Vec4(0.0f, 0.0f, 0.0f, 1.0f);
456 inline Transform& Transform::evalFromRawMatrix(
const Mat4& matrix) {
458 if ((matrix[0][3] == 0.0f) && (matrix[1][3] == 0.0f) && (matrix[2][3] == 0.0f) && (matrix[3][3] == 1.0f)) {
459 setTranslation(extractTranslation(matrix));
460 evalFromRawMatrix(Mat3(matrix));
465 inline Transform& Transform::evalFromRawMatrix(
const Mat3& rotationScaleMatrix) {
468 evalRotationScale(rotation, scale, rotationScaleMatrix);
469 setRotation(rotation);
474 inline Transform& Transform::evalInverse(Transform& inverse)
const {
475 inverse.setIdentity();
477 if (isNonUniform()) {
478 inverse.setScale(
Vec3(1.0f) / _scale);
480 inverse.setScale(1.0f / _scale.x);
484 inverse.postRotate(glm::conjugate(_rotation));
486 if (isTranslating()) {
487 inverse.postTranslate(-_translation);
492 inline Transform& Transform::mult( Transform& result,
const Transform& left,
const Transform& right) {
494 if (right.isTranslating()) {
495 result.postTranslate(right.getTranslation());
497 if (right.isRotating()) {
498 result.postRotate(right.getRotation());
500 if (right.isScaling()) {
501 result.postScale(right.getScale());
512 inline Transform& Transform::inverseMult( Transform& result,
const Transform& left,
const Transform& right) {
513 result.setIdentity();
515 if (left.isScaling()) {
516 result.setScale(
Vec3(1.0f) / left.getScale());
518 if (left.isRotating()) {
519 result.postRotate(glm::conjugate(left.getRotation()));
521 if (left.isTranslating() || right.isTranslating()) {
522 result.postTranslate(right.getTranslation() - left.getTranslation());
524 if (right.isRotating()) {
525 result.postRotate(right.getRotation());
527 if (right.isScaling()) {
528 result.postScale(right.getScale());
539 inline Transform::Vec4 Transform::transform(
const Vec4& pos)
const {
545 inline Transform::Vec3 Transform::transform(
const Vec3& pos)
const {
548 Vec4 result = m * Vec4(pos, 1.0f);
549 return Vec3(result.x / result.w, result.y / result.w, result.z / result.w);
552 inline Transform::Vec3 Transform::transformDirection(
const Vec3& dir)
const {
555 Vec4 result = m * Vec4(dir, 0.0f);
556 return Vec3(result.x, result.y, result.z);
559 inline Transform::Mat4& Transform::getCachedMatrix(Transform::Mat4& result)
const {
565 inline void Transform::updateCache()
const {
566 if (isCacheInvalid()) {
567 if (!_matrix.get()) {
568 _matrix.reset(
new Mat4());
570 getMatrix((*_matrix));
Provides the Mat4 scripting interface.
Definition: Mat4.h:44
Provides the Quat scripting interface.
Definition: Quat.h:61
Provides the Vec3 scripting interface.
Definition: Vec3.h:80