From ad51416c282f234e8b08f19f31c925e642a5342c Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Tue, 11 Nov 2014 09:54:35 -0800 Subject: [PATCH] move the transform class files to the Shared library, still problem with negative scale composition --- interface/src/Application.cpp | 9 +- interface/src/gpu/Batch.h | 7 +- interface/src/gpu/GLBackend.cpp | 4 +- interface/src/gpu/Transform.cpp | 74 ----------- interface/src/renderer/Model.cpp | 3 + interface/src/renderer/Model.h | 2 +- libraries/shared/src/Transform.cpp | 118 ++++++++++++++++++ .../gpu => libraries/shared/src}/Transform.h | 22 ++-- 8 files changed, 147 insertions(+), 92 deletions(-) delete mode 100644 interface/src/gpu/Transform.cpp create mode 100644 libraries/shared/src/Transform.cpp rename {interface/src/gpu => libraries/shared/src}/Transform.h (95%) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 3487f45e1f..31115e39a3 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2890,12 +2890,15 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide()"); // transform by eye offset + gpu::Transform viewTransform; + // load the view frustum loadViewFrustum(whichCamera, _displayViewFrustum); // flip x if in mirror mode (also requires reversing winding order for backface culling) if (whichCamera.getMode() == CAMERA_MODE_MIRROR) { glScalef(-1.0f, 1.0f, 1.0f); + viewTransform.setScale(gpu::Transform::Vec3(-1.0f, 1.0f, 1.0f)); glFrontFace(GL_CW); } else { @@ -2906,7 +2909,9 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { glm::quat eyeOffsetOrient = whichCamera.getEyeOffsetOrientation(); glm::vec3 eyeOffsetAxis = glm::axis(eyeOffsetOrient); glRotatef(-glm::degrees(glm::angle(eyeOffsetOrient)), eyeOffsetAxis.x, eyeOffsetAxis.y, eyeOffsetAxis.z); - glTranslatef(-eyeOffsetPos.x, -eyeOffsetPos.y, -eyeOffsetPos.z); + viewTransform.preRotate(glm::quat(-glm::angle(eyeOffsetOrient), glm::vec3(eyeOffsetAxis.x, eyeOffsetAxis.y, eyeOffsetAxis.z))); + glTranslatef(-eyeOffsetPos.x, -eyeOffsetPos.y, -eyeOffsetPos.z); + viewTransform.preTranslate(glm::vec3(-eyeOffsetPos.x, -eyeOffsetPos.y, -eyeOffsetPos.z)); // transform view according to whichCamera // could be myCamera (if in normal mode) @@ -2915,9 +2920,11 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { glm::quat rotation = whichCamera.getRotation(); glm::vec3 axis = glm::axis(rotation); glRotatef(-glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); + viewTransform.preRotate(glm::quat(-glm::angle(rotation), axis)); // store view matrix without translation, which we'll use for precision-sensitive objects updateUntranslatedViewMatrix(-whichCamera.getPosition()); + viewTransform.preTranslate(-whichCamera.getPosition()); glTranslatef(_viewMatrixTranslation.x, _viewMatrixTranslation.y, _viewMatrixTranslation.z); diff --git a/interface/src/gpu/Batch.h b/interface/src/gpu/Batch.h index 8a9bf6f300..cbda6627d3 100644 --- a/interface/src/gpu/Batch.h +++ b/interface/src/gpu/Batch.h @@ -14,10 +14,11 @@ #include #include "InterfaceConfig.h" +#include "Transform.h" + #include #include "gpu/Stream.h" -#include "gpu/Transform.h" #if defined(NSIGHT_FOUND) #include "nvToolsExt.h" @@ -49,6 +50,10 @@ enum Primitive { NUM_PRIMITIVES, }; +typedef ::Transform Transform; +typedef QSharedPointer<::gpu::Transform> TransformPointer; +typedef std::vector< TransformPointer > Transforms; + class Batch { public: typedef Stream::Slot Slot; diff --git a/interface/src/gpu/GLBackend.cpp b/interface/src/gpu/GLBackend.cpp index f40290c8d4..115e569177 100644 --- a/interface/src/gpu/GLBackend.cpp +++ b/interface/src/gpu/GLBackend.cpp @@ -476,7 +476,9 @@ void GLBackend::updateTransform() { _transform._lastMode = GL_MODELVIEW; } if (!_transform._view.isNull()) { - Transform::Mat4 mv = _transform._view->getMatrix() * _transform._model->getMatrix(); + Transform mvx; + Transform::mult(mvx, (*_transform._view), (*_transform._model)); + Transform::Mat4 mv = mvx.getMatrix(); glLoadMatrixf((const GLfloat*) &mv[0]); } else { glLoadMatrixf((const GLfloat*) &_transform._model->getMatrix()); diff --git a/interface/src/gpu/Transform.cpp b/interface/src/gpu/Transform.cpp deleted file mode 100644 index a51dba8ce3..0000000000 --- a/interface/src/gpu/Transform.cpp +++ /dev/null @@ -1,74 +0,0 @@ -// -// 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" - - -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); -} - -Transform::Mat4& Transform::evalRelativeTransform( Mat4& result, const Vec3& origin) { - updateCache(); - result = _matrix; - result[3] = Vec4(_translation - origin, 1.f); - return result; -} - -void Transform::evalRotationScale(const Mat3& rotationScaleMatrix) { - Vec3 scale(glm::length(rotationScaleMatrix[0]), glm::length(rotationScaleMatrix[1]), glm::length(rotationScaleMatrix[2])); - if (scale.x < 0.00001f) scale.x = 0.00001f; - if (scale.y < 0.00001f) scale.y = 0.00001f; - if (scale.z < 0.00001f) scale.z = 0.00001f; - - Mat3 matRotScale( - rotationScaleMatrix[0] / scale.x, - rotationScaleMatrix[1] / scale.y, - rotationScaleMatrix[2] / scale.z); - setRotation(glm::quat_cast(matRotScale)); - - float determinant = glm::determinant(matRotScale); - if (determinant < 0.f) { - scale.x = -scale.x; - } - - setScale(scale); -} - -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])); - - evalRotationScale(Mat3(matrix)); - } -} - -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; -} - - - diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 5c8fab1118..31801922a4 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -565,7 +565,10 @@ bool Model::render(float alpha, RenderMode mode, RenderArgs* args) { _transforms[0]->evalFromRawMatrix(Application::getInstance()->getUntranslatedViewMatrix()); gpu::TransformPointer currentView(Application::getInstance()->getViewTransform()); + currentView->getMatrix(); + gpu::Transform::Mat4 glview = Application::getInstance()->getUntranslatedViewMatrix(); + _transforms[0]->setTranslation(currentView->getTranslation()); _transforms[0]->setRotation(currentView->getRotation()); _transforms[0]->setScale(currentView->getScale()); diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index ac4f6bde1b..29d4f35167 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -16,6 +16,7 @@ #include #include +#include "Transform.h" #include #include #include @@ -38,7 +39,6 @@ typedef QWeakPointer WeakAnimationHandlePointer; #include "gpu/Stream.h" -#include "gpu/Transform.h" #include "gpu/Batch.h" /// A generic 3D model displaying geometry loaded from a URL. diff --git a/libraries/shared/src/Transform.cpp b/libraries/shared/src/Transform.cpp new file mode 100644 index 0000000000..a6e9439512 --- /dev/null +++ b/libraries/shared/src/Transform.cpp @@ -0,0 +1,118 @@ +// +// Transform.cpp +// shared/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" + + +Transform::Transform() : + _translation(0), + _rotation(1.f, 0, 0, 0), + _scale(1.f), + _flags(1) // invalid cache +{ +} +Transform::Transform(const Mat4& raw) { + evalFromRawMatrix(raw); +} + +Transform::Mat4& Transform::evalRelativeTransform( Mat4& result, const Vec3& origin) { + updateCache(); + result = _matrix; + result[3] = Vec4(_translation - origin, 1.f); + return result; +} + +void Transform::evalRotationScale(const Mat3& rotationScaleMatrix) { + const float ACCURACY_THREASHOLD = 0.00001f; + + // Extract the rotation component - this is done using polar decompostion, where + // we successively average the matrix with its inverse transpose until there is + // no/a very small difference between successive averages + float norm; + int count = 0; + Mat3 rotationMat = rotationScaleMatrix; + do { + Mat3 nextRotation; + Mat3 currInvTranspose = + glm::inverse(glm::transpose(rotationMat)); + + // Go through every component in the matrices and find the next matrix + for (int i = 0; i < 3; i++) { + for (int j = 0; j <3; j++) { + nextRotation[j][i] = 0.5f * + (rotationMat[j][i] + currInvTranspose[j][i]); + } + } + + norm = 0.0; + for (int i = 0; i < 3; i++) { + float n = static_cast( + fabs(rotationMat[0][i] - nextRotation[0][i]) + + fabs(rotationMat[1][i] - nextRotation[1][i]) + + fabs(rotationMat[2][i] - nextRotation[2][i])); + norm = (norm > n ? norm : n); + } + rotationMat = nextRotation; + } while (count < 100 && norm > ACCURACY_THREASHOLD); + + + // extract scale of the matrix as the length of each axis + Mat3 scaleMat = glm::inverse(rotationMat) * rotationScaleMatrix; + + Vec3 scale2(glm::length(rotationScaleMatrix[0]), glm::length(rotationScaleMatrix[1]), glm::length(rotationScaleMatrix[2])); + Vec3 scale(scaleMat[0][0], scaleMat[1][1], scaleMat[2][2]); + if (scale.x < ACCURACY_THREASHOLD) scale.x = ACCURACY_THREASHOLD; + if (scale.y < ACCURACY_THREASHOLD) scale.y = ACCURACY_THREASHOLD; + if (scale.z < ACCURACY_THREASHOLD) scale.z = ACCURACY_THREASHOLD; + + + // Let's work on a local matrix containing rotation only + Mat3 matRot( + rotationScaleMatrix[0] / scale.x, + rotationScaleMatrix[1] / scale.y, + rotationScaleMatrix[2] / scale.z); + + // Beware!!! needs to detect for the case there is a negative scale + // Based on the determinant sign we just can flip the scale sign of one component: we choose X axis + float determinant = glm::determinant(matRot); + if (determinant < 0.f) { + scale.x = -scale.x; + // matRot[0] *= -1.f; + } + + // Beware: even though the matRot is supposed to be normalized at that point, + // glm::quat_cast doesn't always return a normalized quaternion... + setRotation(glm::normalize(glm::quat_cast(matRot))); + + // and assign the scale + setScale(scale); +} + +void Transform::evalFromRawMatrix(const Mat4& matrix) { + // for now works only in the case of TRS transformation + if ((matrix[0][3] == 0) && (matrix[1][3] == 0) && (matrix[2][3] == 0) && (matrix[3][3] == 1.f)) { + setTranslation(Vec3(matrix[3])); + evalRotationScale(Mat3(matrix)); + } +} + +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; +} + + + diff --git a/interface/src/gpu/Transform.h b/libraries/shared/src/Transform.h similarity index 95% rename from interface/src/gpu/Transform.h rename to libraries/shared/src/Transform.h index 72dc843044..c2ed99de93 100644 --- a/interface/src/gpu/Transform.h +++ b/libraries/shared/src/Transform.h @@ -1,6 +1,6 @@ // // Transform.h -// interface/src/gpu +// shared/src/gpu // // Created by Sam Gateau on 11/4/2014. // Copyright 2014 High Fidelity, Inc. @@ -12,12 +12,6 @@ #define hifi_gpu_Transform_h #include -#include "InterfaceConfig.h" - -#include "gpu/Format.h" - - -#include #include #include @@ -26,8 +20,6 @@ #include -namespace gpu { - class Transform { public: typedef glm::mat4 Mat4; @@ -113,6 +105,13 @@ public: if ( right.isTranslating()) result.postTranslate(right.getTranslation()); if ( right.isRotating()) result.postRotate(right.getRotation()); if (right.isScaling()) result.postScale(right.getScale()); + + Transform::Mat4 mv = left.getMatrix() * right.getMatrix(); + Transform::Mat4 mv2 = result.getMatrix(); + + result.evalFromRawMatrix(mv); + Transform::Mat4 mv3 = result.getMatrix(); + return result; } @@ -181,10 +180,5 @@ protected: } }; -typedef QSharedPointer< Transform > TransformPointer; -typedef std::vector< TransformPointer > Transforms; - -}; - #endif