From 67535a386c3d2e4b5843918080c0b9a578766db5 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Thu, 6 Nov 2014 09:55:34 -0800 Subject: [PATCH 01/16] first take at the Transform encapsulating a transform matrix --- interface/src/gpu/Batch.cpp | 19 ++++++++ interface/src/gpu/Batch.h | 22 +++++++-- interface/src/gpu/GLBackend.cpp | 76 ++++++++++++++++++++++++++++++-- interface/src/gpu/GLBackend.h | 46 ++++++++++++++----- interface/src/renderer/Model.cpp | 43 ++++++++++++++++-- 5 files changed, 183 insertions(+), 23 deletions(-) diff --git a/interface/src/gpu/Batch.cpp b/interface/src/gpu/Batch.cpp index e213007191..0b8f505f0f 100644 --- a/interface/src/gpu/Batch.cpp +++ b/interface/src/gpu/Batch.cpp @@ -156,3 +156,22 @@ void Batch::setIndexBuffer(Type type, const BufferPointer& buffer, Offset offset _params.push_back(_buffers.cache(buffer)); _params.push_back(type); } + +void Batch::setModelTransform(const TransformPointer& model) { + ADD_COMMAND(setModelTransform); + + _params.push_back(_transforms.cache(model)); +} + +void Batch::setViewTransform(const TransformPointer& view) { + ADD_COMMAND(setViewTransform); + + _params.push_back(_transforms.cache(view)); +} + +void Batch::setProjectionTransform(const TransformPointer& proj) { + ADD_COMMAND(setProjectionTransform); + + _params.push_back(_transforms.cache(proj)); +} + diff --git a/interface/src/gpu/Batch.h b/interface/src/gpu/Batch.h index 4149d88233..1758463a09 100644 --- a/interface/src/gpu/Batch.h +++ b/interface/src/gpu/Batch.h @@ -16,9 +16,8 @@ #include -#include "gpu/Format.h" -#include "gpu/Resource.h" #include "gpu/Stream.h" +#include "gpu/Transform.h" #if defined(NSIGHT_FOUND) #include "nvToolsExt.h" @@ -60,11 +59,16 @@ public: void clear(); + // Drawcalls void draw(Primitive primitiveType, uint32 numVertices, uint32 startVertex = 0); void drawIndexed(Primitive primitiveType, uint32 nbIndices, uint32 startIndex = 0); void drawInstanced(uint32 nbInstances, Primitive primitiveType, uint32 nbVertices, uint32 startVertex = 0, uint32 startInstance = 0); void drawIndexedInstanced(uint32 nbInstances, Primitive primitiveType, uint32 nbIndices, uint32 startIndex = 0, uint32 startInstance = 0); + // Input Stage + // InputFormat + // InputBuffers + // IndexBuffer void setInputFormat(const Stream::FormatPointer& format); void setInputStream(Slot startChannel, const BufferStream& stream); // not a command, just unroll into a loop of setInputBuffer @@ -72,6 +76,11 @@ public: void setIndexBuffer(Type type, const BufferPointer& buffer, Offset offset); + // Transform Stage + void setModelTransform(const TransformPointer& model); + void setViewTransform(const TransformPointer& view); + void setProjectionTransform(const TransformPointer& proj); + // TODO: As long as we have gl calls explicitely issued from interface // code, we need to be able to record and batch these calls. THe long @@ -138,11 +147,13 @@ public: COMMAND_drawIndexedInstanced, COMMAND_setInputFormat, - COMMAND_setInputBuffer, - COMMAND_setIndexBuffer, + COMMAND_setModelTransform, + COMMAND_setViewTransform, + COMMAND_setProjectionTransform, + // TODO: As long as we have gl calls explicitely issued from interface // code, we need to be able to record and batch these calls. THe long // term strategy is to get rid of any GL calls in favor of the HIFI GPU API @@ -265,6 +276,7 @@ public: typedef Cache::Vector BufferCaches; typedef Cache::Vector StreamFormatCaches; + typedef Cache::Vector TransformCaches; typedef unsigned char Byte; typedef std::vector Bytes; @@ -299,6 +311,8 @@ public: BufferCaches _buffers; StreamFormatCaches _streamFormats; + TransformCaches _transforms; + Bytes _data; protected: }; diff --git a/interface/src/gpu/GLBackend.cpp b/interface/src/gpu/GLBackend.cpp index 5a159d920d..452ad4ec3b 100644 --- a/interface/src/gpu/GLBackend.cpp +++ b/interface/src/gpu/GLBackend.cpp @@ -24,11 +24,13 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] = (&::gpu::GLBackend::do_drawIndexedInstanced), (&::gpu::GLBackend::do_setInputFormat), - (&::gpu::GLBackend::do_setInputBuffer), - (&::gpu::GLBackend::do_setIndexBuffer), + (&::gpu::GLBackend::do_setModelTransform), + (&::gpu::GLBackend::do_setViewTransform), + (&::gpu::GLBackend::do_setProjectionTransform), + (&::gpu::GLBackend::do_glEnable), (&::gpu::GLBackend::do_glDisable), @@ -111,7 +113,6 @@ static const GLenum _elementTypeToGLType[NUM_TYPES]= { GLBackend::GLBackend() : - _inputFormat(0), _inputAttributeActivation(0), _needInputFormatUpdate(true), @@ -122,7 +123,10 @@ GLBackend::GLBackend() : _inputBufferStrides(_inputBuffersState.size(), 0), _indexBuffer(0), - _indexBufferOffset(0) + _indexBufferOffset(0), + + _transform() + { } @@ -183,6 +187,7 @@ void GLBackend::checkGLError() { void GLBackend::do_draw(Batch& batch, uint32 paramOffset) { updateInput(); + updateTransform(); Primitive primitiveType = (Primitive)batch._params[paramOffset + 2]._uint; GLenum mode = _primitiveToGLmode[primitiveType]; @@ -195,6 +200,7 @@ void GLBackend::do_draw(Batch& batch, uint32 paramOffset) { void GLBackend::do_drawIndexed(Batch& batch, uint32 paramOffset) { updateInput(); + updateTransform(); Primitive primitiveType = (Primitive)batch._params[paramOffset + 2]._uint; GLenum mode = _primitiveToGLmode[primitiveType]; @@ -424,6 +430,68 @@ void GLBackend::do_setIndexBuffer(Batch& batch, uint32 paramOffset) { CHECK_GL_ERROR(); } +// Transform Stage + +void GLBackend::do_setModelTransform(Batch& batch, uint32 paramOffset) { + TransformPointer modelTransform = batch._transforms.get(batch._params[paramOffset]._uint); + + if (modelTransform != _transform._model) { + _transform._invalidModel = true; + } +} + +void GLBackend::do_setViewTransform(Batch& batch, uint32 paramOffset) { + TransformPointer viewTransform = batch._transforms.get(batch._params[paramOffset]._uint); + + if (viewTransform != _transform._view) { + _transform._invalidView = true; + } +} + +void GLBackend::do_setProjectionTransform(Batch& batch, uint32 paramOffset) { + TransformPointer projectionTransform = batch._transforms.get(batch._params[paramOffset]._uint); + + if (projectionTransform != _transform._projection) { + _transform._invalidProj = true; + } +} + +void GLBackend::updateTransform() { + if (_transform._invalidProj) { + if (_transform._lastMode != GL_PROJECTION) { + glMatrixMode(GL_PROJECTION); + _transform._lastMode = GL_PROJECTION; + } + CHECK_GL_ERROR(); + } + + if (_transform._invalidModel || _transform._invalidView) { + if (_transform._lastMode != GL_MODELVIEW) { + glMatrixMode(GL_MODELVIEW); + _transform._lastMode = GL_MODELVIEW; + } + + if (!_transform._model.isNull()) { + if (!_transform._view.isNull()) { + Transform::Mat4 mv = _transform._view->getMatrix() * _transform._model->getMatrix(); + glLoadMatrixf((const GLfloat*) &mv[0]); + } else { + glLoadMatrixf((const GLfloat*) &_transform._model->getMatrix()); + } + } else { + if (!_transform._view.isNull()) { + glLoadMatrixf((const GLfloat*) & _transform._view->getMatrix()); + } else { + // glLoadIdentity(); + } + } + CHECK_GL_ERROR(); + + _transform._invalidModel = false; + _transform._invalidView = false; + } +} + // TODO: As long as we have gl calls explicitely issued from interface // code, we need to be able to record and batch these calls. THe long // term strategy is to get rid of any GL calls in favor of the HIFI GPU API diff --git a/interface/src/gpu/GLBackend.h b/interface/src/gpu/GLBackend.h index 2cce6cbedc..0f58ec192d 100644 --- a/interface/src/gpu/GLBackend.h +++ b/interface/src/gpu/GLBackend.h @@ -52,11 +52,22 @@ public: protected: + // Draw Stage + void do_draw(Batch& batch, uint32 paramOffset); + void do_drawIndexed(Batch& batch, uint32 paramOffset); + void do_drawInstanced(Batch& batch, uint32 paramOffset); + void do_drawIndexedInstanced(Batch& batch, uint32 paramOffset); + + // Input Stage + void do_setInputFormat(Batch& batch, uint32 paramOffset); + void do_setInputBuffer(Batch& batch, uint32 paramOffset); + void do_setIndexBuffer(Batch& batch, uint32 paramOffset); + void updateInput(); bool _needInputFormatUpdate; Stream::FormatPointer _inputFormat; - typedef std::bitset InputBuffersState; InputBuffersState _inputBuffersState; + Buffers _inputBuffers; Offsets _inputBufferOffsets; Offsets _inputBufferStrides; @@ -68,18 +79,31 @@ protected: typedef std::bitset InputActivationCache; InputActivationCache _inputAttributeActivation; - void do_draw(Batch& batch, uint32 paramOffset); - void do_drawIndexed(Batch& batch, uint32 paramOffset); - void do_drawInstanced(Batch& batch, uint32 paramOffset); - void do_drawIndexedInstanced(Batch& batch, uint32 paramOffset); + // Transform Stage + void do_setModelTransform(Batch& batch, uint32 paramOffset); + void do_setViewTransform(Batch& batch, uint32 paramOffset); + void do_setProjectionTransform(Batch& batch, uint32 paramOffset); - void updateInput(); - void do_setInputFormat(Batch& batch, uint32 paramOffset); - - void do_setInputBuffer(Batch& batch, uint32 paramOffset); + void updateTransform(); + struct TransformStageState { + TransformPointer _model; + TransformPointer _view; + TransformPointer _projection; + bool _invalidModel; + bool _invalidView; + bool _invalidProj; - void do_setVertexBuffer(Batch& batch, uint32 paramOffset); - void do_setIndexBuffer(Batch& batch, uint32 paramOffset); + GLenum _lastMode; + + TransformStageState() : + _model(0), + _view(0), + _projection(0), + _invalidModel(true), + _invalidView(true), + _invalidProj(true), + _lastMode(GL_TEXTURE) {} + } _transform; // TODO: As long as we have gl calls explicitely issued from interface // code, we need to be able to record and batch these calls. THe long diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index a3fd3374a0..75eafcc0fb 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -556,6 +556,16 @@ bool Model::render(float alpha, RenderMode mode, RenderArgs* args) { // Let's introduce a gpu::Batch to capture all the calls to the graphics api gpu::Batch batch; + // Capture the view matrix once for the rendering of this model + gpu::TransformPointer viewTransform(new gpu::Transform()); + + glm::mat4 v = Application::getInstance()->getUntranslatedViewMatrix(); + viewTransform->evalFromRawMatrix(v); + glm::mat4 v2 = viewTransform->getMatrix(); + + viewTransform->localTranslate(Application::getInstance()->getViewMatrixTranslation()); + + // batch.setViewTransform(viewTransform); GLBATCH(glDisable)(GL_COLOR_MATERIAL); @@ -1853,17 +1863,42 @@ int Model::renderMeshes(gpu::Batch& batch, RenderMode mode, bool translucent, fl GLBATCH(glPushMatrix)(); //Application::getInstance()->loadTranslatedViewMatrix(_translation); - GLBATCH(glLoadMatrixf)((const GLfloat*)&Application::getInstance()->getUntranslatedViewMatrix()); + // GLBATCH(glLoadMatrixf)((const GLfloat*)&Application::getInstance()->getUntranslatedViewMatrix()); + + // Capture the view matrix once for the rendering of this model + glm::mat4 v = Application::getInstance()->getUntranslatedViewMatrix(); + + gpu::TransformPointer viewTransform(new gpu::Transform()); + viewTransform->evalFromRawMatrix(v); + glm::vec3 viewMatTranslation = Application::getInstance()->getViewMatrixTranslation(); - GLBATCH(glTranslatef)(_translation.x + viewMatTranslation.x, _translation.y + viewMatTranslation.y, - _translation.z + viewMatTranslation.z); + + viewTransform->localTranslate(viewMatTranslation + _translation); + glm::mat4 v2 = viewTransform->getMatrix(); + // batch.setViewTransform(viewTransform); + + // GLBATCH(glTranslatef)(_translation.x + viewMatTranslation.x, _translation.y + viewMatTranslation.y, + // _translation.z + viewMatTranslation.z); const MeshState& state = _meshStates.at(i); if (state.clusterMatrices.size() > 1) { GLBATCH(glUniformMatrix4fv)(skinLocations->clusterMatrices, state.clusterMatrices.size(), false, (const float*)state.clusterMatrices.constData()); + + // gpu::TransformPointer modelTransform(new gpu::Transform()); + // modelTransform->setTranslation(_translation); + // batch.setModelTransform(viewTransform); + + // gpu::TransformPointer mv(new gpu::Transform()); + // gpu::Transform::mult(*mv, *viewTransform, *modelTransform); + batch.setModelTransform(viewTransform); } else { - GLBATCH(glMultMatrixf)((const GLfloat*)&state.clusterMatrices[0]); + // GLBATCH(glMultMatrixf)((const GLfloat*)&state.clusterMatrices[0]); + gpu::TransformPointer modelTransform(new gpu::Transform(state.clusterMatrices[0])); + + gpu::TransformPointer mv(new gpu::Transform()); + gpu::Transform::mult(*mv, *viewTransform, *modelTransform); + batch.setModelTransform(mv); } if (mesh.blendshapes.isEmpty()) { From 4a73b0773b77d901a215fea1f8de3ab14a475597 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Thu, 6 Nov 2014 09:56:05 -0800 Subject: [PATCH 02/16] first take at the Transform encapsulating a transform matrix --- interface/src/gpu/Transform.cpp | 109 ++++++++++++++++++++++++++++++ interface/src/gpu/Transform.h | 113 ++++++++++++++++++++++++++++++++ 2 files changed, 222 insertions(+) create mode 100644 interface/src/gpu/Transform.cpp create mode 100644 interface/src/gpu/Transform.h diff --git a/interface/src/gpu/Transform.cpp b/interface/src/gpu/Transform.cpp new file mode 100644 index 0000000000..cb1607dd0b --- /dev/null +++ b/interface/src/gpu/Transform.cpp @@ -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 + +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; +} + + diff --git a/interface/src/gpu/Transform.h b/interface/src/gpu/Transform.h new file mode 100644 index 0000000000..e1e3f574e9 --- /dev/null +++ b/interface/src/gpu/Transform.h @@ -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 +#include "InterfaceConfig.h" + +#include "gpu/Format.h" + + +#include + +#include +#include +#include + +#include + +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 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 From e1a9830d9aa99ca4c6831cc1281ad097e0c62e7d Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Fri, 7 Nov 2014 09:58:32 -0800 Subject: [PATCH 03/16] mirror doesn't work with the new transform stack --- interface/src/gpu/GLBackend.cpp | 21 ++++++++----- interface/src/gpu/Transform.cpp | 11 ++++--- interface/src/gpu/Transform.h | 10 ++++-- interface/src/renderer/Model.cpp | 54 +++++++++++--------------------- 4 files changed, 46 insertions(+), 50 deletions(-) diff --git a/interface/src/gpu/GLBackend.cpp b/interface/src/gpu/GLBackend.cpp index 7572f4a5d2..f40290c8d4 100644 --- a/interface/src/gpu/GLBackend.cpp +++ b/interface/src/gpu/GLBackend.cpp @@ -436,6 +436,7 @@ void GLBackend::do_setModelTransform(Batch& batch, uint32 paramOffset) { TransformPointer modelTransform = batch._transforms.get(batch._params[paramOffset]._uint); if (modelTransform != _transform._model) { + _transform._model = modelTransform; _transform._invalidModel = true; } } @@ -444,6 +445,7 @@ void GLBackend::do_setViewTransform(Batch& batch, uint32 paramOffset) { TransformPointer viewTransform = batch._transforms.get(batch._params[paramOffset]._uint); if (viewTransform != _transform._view) { + _transform._view = viewTransform; _transform._invalidView = true; } } @@ -452,26 +454,27 @@ void GLBackend::do_setProjectionTransform(Batch& batch, uint32 paramOffset) { TransformPointer projectionTransform = batch._transforms.get(batch._params[paramOffset]._uint); if (projectionTransform != _transform._projection) { + _transform._projection = projectionTransform; _transform._invalidProj = true; } } void GLBackend::updateTransform() { if (_transform._invalidProj) { - if (_transform._lastMode != GL_PROJECTION) { + /* if (_transform._lastMode != GL_PROJECTION) { glMatrixMode(GL_PROJECTION); _transform._lastMode = GL_PROJECTION; } - CHECK_GL_ERROR(); + CHECK_GL_ERROR();*/ + _transform._invalidProj; } if (_transform._invalidModel || _transform._invalidView) { - if (_transform._lastMode != GL_MODELVIEW) { - glMatrixMode(GL_MODELVIEW); - _transform._lastMode = GL_MODELVIEW; - } - if (!_transform._model.isNull()) { + if (_transform._lastMode != GL_MODELVIEW) { + glMatrixMode(GL_MODELVIEW); + _transform._lastMode = GL_MODELVIEW; + } if (!_transform._view.isNull()) { Transform::Mat4 mv = _transform._view->getMatrix() * _transform._model->getMatrix(); glLoadMatrixf((const GLfloat*) &mv[0]); @@ -480,6 +483,10 @@ void GLBackend::updateTransform() { } } else { if (!_transform._view.isNull()) { + if (_transform._lastMode != GL_MODELVIEW) { + glMatrixMode(GL_MODELVIEW); + _transform._lastMode = GL_MODELVIEW; + } glLoadMatrixf((const GLfloat*) & _transform._view->getMatrix()); } else { // glLoadIdentity(); diff --git a/interface/src/gpu/Transform.cpp b/interface/src/gpu/Transform.cpp index cb1607dd0b..71b8b0ec92 100644 --- a/interface/src/gpu/Transform.cpp +++ b/interface/src/gpu/Transform.cpp @@ -40,21 +40,22 @@ void Transform::updateCache() const { _matrix[1] = Vec4(rot[1], 0.f); _matrix[2] = Vec4(rot[2], 0.f); - _matrix[3] = Vec4(_translation, 0.f); + _matrix[3] = Vec4(_translation, 1.f); validCache(); } } -void Transform::localTranslate( Vec3 const & translation) { - Vec3 tt = glm::rotate(_rotation, translation); - _translation += tt * _scale; +void Transform::postTranslate(const Vec3& translation) { + invalidCache(); + Vec3 tt = glm::rotate(_rotation, translation * _scale); + _translation += tt; } Transform::Mat4& Transform::evalRelativeTransform( Mat4& result, const Vec3& origin) { updateCache(); result = _matrix; - result[3] = Vec4(_translation - origin, 0.f); + result[3] = Vec4(_translation - origin, 1.f); return result; } diff --git a/interface/src/gpu/Transform.h b/interface/src/gpu/Transform.h index e1e3f574e9..2760241480 100644 --- a/interface/src/gpu/Transform.h +++ b/interface/src/gpu/Transform.h @@ -42,10 +42,11 @@ public: 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; } + void preTranslate(const Vec3& translation) { invalidCache(); _translation += translation; } + void postTranslate( Vec3 const & translation); + + void setRotation(const Quat& rotation) { invalidCache(); flagRotation(); _rotation = glm::normalize(rotation); } const Quat& getRotation() const { return _rotation; } void setNoScale() { invalidCache(); flagNoScaling(); _scale = Vec3(1.f); } @@ -63,6 +64,9 @@ public: static Transform& mult( Transform& result, const Transform& left, const Transform& right); bool isScaling() const { return _flags[FLAG_UNIFORM_SCALING] || _flags[FLAG_NON_UNIFORM_SCALING]; } + bool isUniform() const { return !isNonUniform(); } + bool isNonUniform() const { return _flags[FLAG_NON_UNIFORM_SCALING]; } + protected: enum Flag { diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 12975584d2..6627ce3e2b 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -555,17 +555,13 @@ bool Model::render(float alpha, RenderMode mode, RenderArgs* args) { // Let's introduce a gpu::Batch to capture all the calls to the graphics api gpu::Batch batch; + GLBATCH(glPushMatrix)(); // Capture the view matrix once for the rendering of this model - gpu::TransformPointer viewTransform(new gpu::Transform()); + gpu::TransformPointer viewTransform(new gpu::Transform(Application::getInstance()->getUntranslatedViewMatrix())); + viewTransform->postTranslate(Application::getInstance()->getViewMatrixTranslation()); - glm::mat4 v = Application::getInstance()->getUntranslatedViewMatrix(); - viewTransform->evalFromRawMatrix(v); - glm::mat4 v2 = viewTransform->getMatrix(); - - viewTransform->localTranslate(Application::getInstance()->getViewMatrixTranslation()); - - // batch.setViewTransform(viewTransform); + batch.setViewTransform(viewTransform); GLBATCH(glDisable)(GL_COLOR_MATERIAL); @@ -690,6 +686,8 @@ bool Model::render(float alpha, RenderMode mode, RenderArgs* args) { GLBATCH(glBindBuffer)(GL_ELEMENT_ARRAY_BUFFER, 0); GLBATCH(glBindTexture)(GL_TEXTURE_2D, 0); + GLBATCH(glPopMatrix)(); + // Render! { PROFILE_RANGE("render Batch"); @@ -1861,46 +1859,32 @@ int Model::renderMeshes(gpu::Batch& batch, RenderMode mode, bool translucent, fl } } - GLBATCH(glPushMatrix)(); - //Application::getInstance()->loadTranslatedViewMatrix(_translation); + // GLBATCH(glPushMatrix)(); + // Application::getInstance()->loadTranslatedViewMatrix(_translation); // GLBATCH(glLoadMatrixf)((const GLfloat*)&Application::getInstance()->getUntranslatedViewMatrix()); - // Capture the view matrix once for the rendering of this model - glm::mat4 v = Application::getInstance()->getUntranslatedViewMatrix(); - - gpu::TransformPointer viewTransform(new gpu::Transform()); - viewTransform->evalFromRawMatrix(v); - glm::vec3 viewMatTranslation = Application::getInstance()->getViewMatrixTranslation(); - viewTransform->localTranslate(viewMatTranslation + _translation); - glm::mat4 v2 = viewTransform->getMatrix(); - // batch.setViewTransform(viewTransform); - // GLBATCH(glTranslatef)(_translation.x + viewMatTranslation.x, _translation.y + viewMatTranslation.y, - // _translation.z + viewMatTranslation.z); + + // GLBATCH(glTranslatef)(_translation.x + viewMatTranslation.x, _translation.y + viewMatTranslation.y, _translation.z + viewMatTranslation.z); const MeshState& state = _meshStates.at(i); if (state.clusterMatrices.size() > 1) { GLBATCH(glUniformMatrix4fv)(skinLocations->clusterMatrices, state.clusterMatrices.size(), false, (const float*)state.clusterMatrices.constData()); - // gpu::TransformPointer modelTransform(new gpu::Transform()); - // modelTransform->setTranslation(_translation); - // batch.setModelTransform(viewTransform); - - // gpu::TransformPointer mv(new gpu::Transform()); - // gpu::Transform::mult(*mv, *viewTransform, *modelTransform); - batch.setModelTransform(viewTransform); + gpu::TransformPointer modelTransform(new gpu::Transform()); + modelTransform->preTranslate(_translation); + batch.setModelTransform(modelTransform); } else { - // GLBATCH(glMultMatrixf)((const GLfloat*)&state.clusterMatrices[0]); + // GLBATCH(glMultMatrixf)((const GLfloat*)&state.clusterMatrices[0]); + gpu::TransformPointer modelTransform(new gpu::Transform(state.clusterMatrices[0])); - - gpu::TransformPointer mv(new gpu::Transform()); - gpu::Transform::mult(*mv, *viewTransform, *modelTransform); - batch.setModelTransform(mv); + modelTransform->preTranslate(_translation); + batch.setModelTransform(modelTransform); } - + if (mesh.blendshapes.isEmpty()) { batch.setInputFormat(networkMesh._vertexFormat); batch.setInputStream(0, *networkMesh._vertexStream); @@ -2010,7 +1994,7 @@ int Model::renderMeshes(gpu::Batch& batch, RenderMode mode, bool translucent, fl GLBATCH(glActiveTexture)(GL_TEXTURE0); } - GLBATCH(glPopMatrix)(); + // GLBATCH(glPopMatrix)(); } From 9d146e7ea34b796e053a7c753f4bb1863b79797b Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Fri, 7 Nov 2014 14:27:22 -0800 Subject: [PATCH 04/16] improving the evalFromRawMatrix decomposition --- interface/src/gpu/Transform.cpp | 44 +++++++++++++++++--------------- interface/src/gpu/Transform.h | 2 ++ interface/src/renderer/Model.cpp | 15 ++++++----- interface/src/renderer/Model.h | 9 ++++--- 4 files changed, 38 insertions(+), 32 deletions(-) diff --git a/interface/src/gpu/Transform.cpp b/interface/src/gpu/Transform.cpp index 71b8b0ec92..88922488a4 100644 --- a/interface/src/gpu/Transform.cpp +++ b/interface/src/gpu/Transform.cpp @@ -59,20 +59,31 @@ Transform::Mat4& Transform::evalRelativeTransform( Mat4& result, const Vec3& ori 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])); - 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); + evalRotationScale(Mat3(matrix)); } } @@ -91,18 +102,9 @@ Transform& Transform::mult( Transform& result, const Transform& left, const Tran 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); + result.evalRotationScale(Mat3(mat)); return result; } diff --git a/interface/src/gpu/Transform.h b/interface/src/gpu/Transform.h index 2760241480..bcb353c578 100644 --- a/interface/src/gpu/Transform.h +++ b/interface/src/gpu/Transform.h @@ -60,6 +60,7 @@ public: Transform& evalInverseTranspose(Transform& result); void evalFromRawMatrix(const Mat4& matrix); + void evalRotationScale(const Mat3& rotationScalematrix); static Transform& mult( Transform& result, const Transform& left, const Transform& right); @@ -110,6 +111,7 @@ protected: }; typedef QSharedPointer< Transform > TransformPointer; +typedef std::vector< TransformPointer > Transforms; }; diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 6627ce3e2b..965f43acb7 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -554,14 +554,18 @@ bool Model::render(float alpha, RenderMode mode, RenderArgs* args) { } // Let's introduce a gpu::Batch to capture all the calls to the graphics api - gpu::Batch batch; + _renderBatch.clear(); + gpu::Batch& batch = _renderBatch; GLBATCH(glPushMatrix)(); // Capture the view matrix once for the rendering of this model - gpu::TransformPointer viewTransform(new gpu::Transform(Application::getInstance()->getUntranslatedViewMatrix())); - viewTransform->postTranslate(Application::getInstance()->getViewMatrixTranslation()); + if (_transforms.empty()) { + _transforms.push_back(gpu::TransformPointer(new gpu::Transform())); + } + _transforms[0]->evalFromRawMatrix(Application::getInstance()->getUntranslatedViewMatrix()); + _transforms[0]->postTranslate(Application::getInstance()->getViewMatrixTranslation() + _translation); - batch.setViewTransform(viewTransform); + batch.setViewTransform(_transforms[0]); GLBATCH(glDisable)(GL_COLOR_MATERIAL); @@ -692,7 +696,6 @@ bool Model::render(float alpha, RenderMode mode, RenderArgs* args) { { PROFILE_RANGE("render Batch"); ::gpu::GLBackend::renderBatch(batch); - batch.clear(); } // restore all the default material settings @@ -1875,13 +1878,11 @@ int Model::renderMeshes(gpu::Batch& batch, RenderMode mode, bool translucent, fl (const float*)state.clusterMatrices.constData()); gpu::TransformPointer modelTransform(new gpu::Transform()); - modelTransform->preTranslate(_translation); batch.setModelTransform(modelTransform); } else { // GLBATCH(glMultMatrixf)((const GLfloat*)&state.clusterMatrices[0]); gpu::TransformPointer modelTransform(new gpu::Transform(state.clusterMatrices[0])); - modelTransform->preTranslate(_translation); batch.setModelTransform(modelTransform); } diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 34d6a34c06..ac4f6bde1b 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -36,11 +36,10 @@ class ViewFrustum; typedef QSharedPointer AnimationHandlePointer; typedef QWeakPointer WeakAnimationHandlePointer; -namespace gpu { - class Batch; -} #include "gpu/Stream.h" +#include "gpu/Transform.h" +#include "gpu/Batch.h" /// A generic 3D model displaying geometry loaded from a URL. class Model : public QObject, public PhysicsEntity { @@ -283,7 +282,9 @@ private: QUrl _url; gpu::Buffers _blendedVertexBuffers; - + gpu::Transforms _transforms; + gpu::Batch _renderBatch; + QVector > > _dilatedTextures; QVector _attachments; From 631ed9da78350438b5c875a6d4e031ed3c15a9a0 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Mon, 10 Nov 2014 10:04:19 -0800 Subject: [PATCH 05/16] let's start reusing the Batch per model from frame to frame --- interface/src/Application.cpp | 8 ++- interface/src/Application.h | 3 + interface/src/gpu/Transform.cpp | 38 ----------- interface/src/gpu/Transform.h | 105 ++++++++++++++++++++++++++----- interface/src/renderer/Model.cpp | 12 +++- 5 files changed, 106 insertions(+), 60 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index e58f79cb5e..85ef70677e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -108,7 +108,8 @@ static unsigned STARFIELD_SEED = 1; static const int BANDWIDTH_METER_CLICK_MAX_DRAG_LENGTH = 6; // farther dragged clicks are ignored -const unsigned MAXIMUM_CACHE_SIZE = 10737418240; // 10GB +//const unsigned MAXIMUM_CACHE_SIZE = 10737418240; // 10GB +const quint64 MAXIMUM_CACHE_SIZE = 10737418240L; // 10GB static QTimer* idleTimer = NULL; @@ -186,7 +187,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : _lastNackTime(usecTimestampNow()), _lastSendDownstreamAudioStats(usecTimestampNow()), _isVSyncOn(true), - _aboutToQuit(false) + _aboutToQuit(false), + _viewTransform(new gpu::Transform()) { // read the ApplicationInfo.ini file for Name/Version/Domain information @@ -3115,6 +3117,8 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { void Application::updateUntranslatedViewMatrix(const glm::vec3& viewMatrixTranslation) { glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat*)&_untranslatedViewMatrix); _viewMatrixTranslation = viewMatrixTranslation; + _viewTransform->evalFromRawMatrix(_untranslatedViewMatrix); + _viewTransform->postTranslate(viewMatrixTranslation); } void Application::loadTranslatedViewMatrix(const glm::vec3& translation) { diff --git a/interface/src/Application.h b/interface/src/Application.h index eee2581e2e..ca8651867f 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -233,6 +233,8 @@ public: const glm::vec3& getViewMatrixTranslation() const { return _viewMatrixTranslation; } void setViewMatrixTranslation(const glm::vec3& translation) { _viewMatrixTranslation = translation; } + const gpu::TransformPointer& getViewTransform() const { return _viewTransform; } + /// if you need to access the application settings, use lockSettings()/unlockSettings() QSettings* lockSettings() { _settingsMutex.lock(); return _settings; } void unlockSettings() { _settingsMutex.unlock(); } @@ -526,6 +528,7 @@ private: QRect _mirrorViewRect; RearMirrorTools* _rearMirrorTools; + gpu::TransformPointer _viewTransform; glm::mat4 _untranslatedViewMatrix; glm::vec3 _viewMatrixTranslation; glm::mat4 _projectionMatrix; diff --git a/interface/src/gpu/Transform.cpp b/interface/src/gpu/Transform.cpp index 88922488a4..a51dba8ce3 100644 --- a/interface/src/gpu/Transform.cpp +++ b/interface/src/gpu/Transform.cpp @@ -11,7 +11,6 @@ #include "Transform.h" -#include using namespace gpu; @@ -26,32 +25,6 @@ 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, 1.f); - - validCache(); - } -} - -void Transform::postTranslate(const Vec3& translation) { - invalidCache(); - Vec3 tt = glm::rotate(_rotation, translation * _scale); - _translation += tt; -} - Transform::Mat4& Transform::evalRelativeTransform( Mat4& result, const Vec3& origin) { updateCache(); result = _matrix; @@ -97,16 +70,5 @@ Transform& Transform::evalInverseTranspose(Transform& result) { 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(); - result.evalRotationScale(Mat3(mat)); - - return result; -} diff --git a/interface/src/gpu/Transform.h b/interface/src/gpu/Transform.h index bcb353c578..72dc843044 100644 --- a/interface/src/gpu/Transform.h +++ b/interface/src/gpu/Transform.h @@ -22,6 +22,7 @@ #include #include #include +#include #include @@ -37,23 +38,68 @@ public: typedef glm::quat Quat; Transform(); + Transform(const Transform& transform) : + _translation(transform._translation), + _rotation(transform._rotation), + _scale(transform._scale), + _flags(transform._flags) + { + invalidCache(); + } Transform(const Mat4& raw); ~Transform() {} void setTranslation(const Vec3& translation) { invalidCache(); flagTranslation(); _translation = translation; } const Vec3& getTranslation() const { return _translation; } - void preTranslate(const Vec3& translation) { invalidCache(); _translation += translation; } - void postTranslate( Vec3 const & translation); + void preTranslate(const Vec3& translation) { invalidCache(); flagTranslation(); _translation += translation; } + void postTranslate(const Vec3& translation) { + invalidCache(); + flagTranslation(); + if (isRotating()) { + _translation += glm::rotate(_rotation, translation * _scale); + } else { + _translation += translation * _scale; + } + } - void setRotation(const Quat& rotation) { invalidCache(); flagRotation(); _rotation = glm::normalize(rotation); } + 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; } + void preRotate(const Quat& rotation) { + invalidCache(); + if (isRotating()) { + _rotation = rotation * _rotation; + } else { + _rotation = rotation; + } + flagRotation(); + _translation = glm::rotate(rotation, _translation); + } + void postRotate(const Quat& rotation) { + invalidCache(); + if (isRotating()) { + _rotation *= rotation; + } else { + _rotation = rotation; + } + flagRotation(); + } + + void setScale(float scale) { invalidCache(); flagScaling(); _scale = Vec3(scale); } + void setScale(const Vec3& scale) { invalidCache(); flagScaling(); _scale = scale; } const Vec3& getScale() const { return _scale; } + void postScale(const Vec3& scale) { + invalidCache(); + if (isScaling()) { + _scale *= scale; + } else { + _scale = scale; + } + flagScaling(); + } + const Mat4& getMatrix() const { updateCache(); return _matrix; } Mat4& evalRelativeTransform(Mat4& result, const Vec3& origin); @@ -62,11 +108,17 @@ public: void evalFromRawMatrix(const Mat4& matrix); void evalRotationScale(const Mat3& rotationScalematrix); - static Transform& mult( Transform& result, const Transform& left, const Transform& right); + static Transform& mult( Transform& result, const Transform& left, const Transform& right) { + result = left; + if ( right.isTranslating()) result.postTranslate(right.getTranslation()); + if ( right.isRotating()) result.postRotate(right.getRotation()); + if (right.isScaling()) result.postScale(right.getScale()); + return result; + } - bool isScaling() const { return _flags[FLAG_UNIFORM_SCALING] || _flags[FLAG_NON_UNIFORM_SCALING]; } - bool isUniform() const { return !isNonUniform(); } - bool isNonUniform() const { return _flags[FLAG_NON_UNIFORM_SCALING]; } + bool isTranslating() const { return _flags[FLAG_TRANSLATION]; } + bool isRotating() const { return _flags[FLAG_ROTATION]; } + bool isScaling() const { return _flags[FLAG_SCALING]; } protected: @@ -75,9 +127,7 @@ protected: FLAG_TRANSLATION, FLAG_ROTATION, - FLAG_UNIFORM_SCALING, - FLAG_NON_UNIFORM_SCALING, - FLAG_SHEARING, + FLAG_SCALING, FLAG_PROJECTION, @@ -103,11 +153,32 @@ protected: 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 flagScaling() { _flags.set(FLAG_SCALING, true); } - void updateCache() const; + void updateCache() const { + if (isCacheInvalid()) { + if (isRotating()) { + 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); + } else { + _matrix[0] = Vec4(_scale.x, 0.f, 0.f, 0.f); + _matrix[1] = Vec4(0.f, _scale.y, 0.f, 0.f); + _matrix[2] = Vec4(0.f, 0.f, _scale.z, 0.f); + } + + _matrix[3] = Vec4(_translation, 1.f); + validCache(); + } + } }; typedef QSharedPointer< Transform > TransformPointer; diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 965f43acb7..5c8fab1118 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -563,7 +563,13 @@ bool Model::render(float alpha, RenderMode mode, RenderArgs* args) { _transforms.push_back(gpu::TransformPointer(new gpu::Transform())); } _transforms[0]->evalFromRawMatrix(Application::getInstance()->getUntranslatedViewMatrix()); - _transforms[0]->postTranslate(Application::getInstance()->getViewMatrixTranslation() + _translation); + + gpu::TransformPointer currentView(Application::getInstance()->getViewTransform()); + + _transforms[0]->setTranslation(currentView->getTranslation()); + _transforms[0]->setRotation(currentView->getRotation()); + _transforms[0]->setScale(currentView->getScale()); + _transforms[0]->postTranslate(_translation); batch.setViewTransform(_transforms[0]); @@ -1862,7 +1868,7 @@ int Model::renderMeshes(gpu::Batch& batch, RenderMode mode, bool translucent, fl } } - // GLBATCH(glPushMatrix)(); + GLBATCH(glPushMatrix)(); // Application::getInstance()->loadTranslatedViewMatrix(_translation); // GLBATCH(glLoadMatrixf)((const GLfloat*)&Application::getInstance()->getUntranslatedViewMatrix()); @@ -1995,7 +2001,7 @@ int Model::renderMeshes(gpu::Batch& batch, RenderMode mode, bool translucent, fl GLBATCH(glActiveTexture)(GL_TEXTURE0); } - // GLBATCH(glPopMatrix)(); + GLBATCH(glPopMatrix)(); } From ad51416c282f234e8b08f19f31c925e642a5342c Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Tue, 11 Nov 2014 09:54:35 -0800 Subject: [PATCH 06/16] 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 From b716a512c69a8ae68b913c4c1a1940a0ec354fdd Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Wed, 12 Nov 2014 00:26:44 -0800 Subject: [PATCH 07/16] Stable version of the Transform and usage for Model rendering with soimilar performances and same accuracy level --- interface/src/Application.cpp | 23 ++++++++++++++++------- interface/src/Application.h | 1 + interface/src/gpu/Batch.cpp | 10 ++++++++-- interface/src/gpu/Batch.h | 3 +-- interface/src/gpu/GLBackend.cpp | 1 + interface/src/renderer/Model.cpp | 3 ++- interface/src/ui/MetavoxelEditor.cpp | 4 +++- libraries/shared/src/Transform.cpp | 9 ++++----- libraries/shared/src/Transform.h | 2 +- 9 files changed, 37 insertions(+), 19 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index c65e314cc2..923f7821d2 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2805,6 +2805,8 @@ void Application::updateShadowMap() { // store view matrix without translation, which we'll use for precision-sensitive objects updateUntranslatedViewMatrix(); + // TODO: assign an equivalent viewTransform object to the application to match the current path which uses glMatrixStack + // setViewTransform(viewTransform); glEnable(GL_POLYGON_OFFSET_FILL); glPolygonOffset(1.1f, 4.0f); // magic numbers courtesy http://www.eecs.berkeley.edu/~ravir/6160/papers/shadowmaps.ppt @@ -2883,6 +2885,7 @@ 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 @@ -2902,9 +2905,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); - 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)); + viewTransform.postRotate(glm::conjugate(eyeOffsetOrient)); + glTranslatef(-eyeOffsetPos.x, -eyeOffsetPos.y, -eyeOffsetPos.z); + viewTransform.postTranslate(-eyeOffsetPos); // transform view according to whichCamera // could be myCamera (if in normal mode) @@ -2913,11 +2916,15 @@ 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)); + viewTransform.postRotate(glm::conjugate(rotation)); // store view matrix without translation, which we'll use for precision-sensitive objects updateUntranslatedViewMatrix(-whichCamera.getPosition()); - viewTransform.preTranslate(-whichCamera.getPosition()); + + // Equivalent to what is happening with _untranslatedViewMatrix and the _viewMatrixTranslation + // the viewTransofmr object is updated with the correct value and saved, + // this is what is used for rendering the ENtities and avatars + setViewTransform(viewTransform); glTranslatef(_viewMatrixTranslation.x, _viewMatrixTranslation.y, _viewMatrixTranslation.z); @@ -3120,8 +3127,10 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { void Application::updateUntranslatedViewMatrix(const glm::vec3& viewMatrixTranslation) { glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat*)&_untranslatedViewMatrix); _viewMatrixTranslation = viewMatrixTranslation; - _viewTransform->evalFromRawMatrix(_untranslatedViewMatrix); - _viewTransform->postTranslate(viewMatrixTranslation); +} + +void Application::setViewTransform(const gpu::Transform& view) { + (*_viewTransform) = view; } void Application::loadTranslatedViewMatrix(const glm::vec3& translation) { diff --git a/interface/src/Application.h b/interface/src/Application.h index ca8651867f..b59b9c90a0 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -234,6 +234,7 @@ public: void setViewMatrixTranslation(const glm::vec3& translation) { _viewMatrixTranslation = translation; } const gpu::TransformPointer& getViewTransform() const { return _viewTransform; } + void setViewTransform(const gpu::Transform& view); /// if you need to access the application settings, use lockSettings()/unlockSettings() QSettings* lockSettings() { _settingsMutex.lock(); return _settings; } diff --git a/interface/src/gpu/Batch.cpp b/interface/src/gpu/Batch.cpp index a29e0f87a3..2bf92f43cf 100644 --- a/interface/src/gpu/Batch.cpp +++ b/interface/src/gpu/Batch.cpp @@ -21,7 +21,11 @@ Batch::Batch() : _commandOffsets(), _params(), _resources(), - _data(){ + _data(), + _buffers(), + _streamFormats(), + _transforms() +{ } Batch::~Batch() { @@ -32,8 +36,10 @@ void Batch::clear() { _commandOffsets.clear(); _params.clear(); _resources.clear(); - _buffers.clear(); _data.clear(); + _buffers.clear(); + _streamFormats.clear(); + _transforms.clear(); } uint32 Batch::cacheResource(Resource* res) { diff --git a/interface/src/gpu/Batch.h b/interface/src/gpu/Batch.h index cbda6627d3..cc838a8839 100644 --- a/interface/src/gpu/Batch.h +++ b/interface/src/gpu/Batch.h @@ -316,13 +316,12 @@ public: CommandOffsets _commandOffsets; Params _params; Resources _resources; + Bytes _data; BufferCaches _buffers; StreamFormatCaches _streamFormats; - TransformCaches _transforms; - Bytes _data; protected: }; diff --git a/interface/src/gpu/GLBackend.cpp b/interface/src/gpu/GLBackend.cpp index df62b3813c..24141cccdc 100644 --- a/interface/src/gpu/GLBackend.cpp +++ b/interface/src/gpu/GLBackend.cpp @@ -458,6 +458,7 @@ void GLBackend::do_setProjectionTransform(Batch& batch, uint32 paramOffset) { void GLBackend::updateTransform() { if (_transform._invalidProj) { + // TODO: implement the projection matrix assignment to gl state /* if (_transform._lastMode != GL_PROJECTION) { glMatrixMode(GL_PROJECTION); _transform._lastMode = GL_PROJECTION; diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index dcf70e418d..0919850f97 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -560,7 +560,8 @@ bool Model::render(float alpha, RenderMode mode, RenderArgs* args) { _transforms.push_back(gpu::TransformPointer(new gpu::Transform())); } (*_transforms[0]) = gpu::Transform((*Application::getInstance()->getViewTransform())); - _transforms[0]->postTranslate(_translation); + // apply entity translation + camera position offset to the viewTransform in one go + _transforms[0]->postTranslate(Application::getInstance()->getViewMatrixTranslation() + _translation); batch.setViewTransform(_transforms[0]); diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index e5a1f7f7a4..c0d8261427 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -919,7 +919,9 @@ void SetSpannerTool::applyEdit(const AttributePointer& attribute, const SharedOb Application::getInstance()->setupWorldLight(); Application::getInstance()->updateUntranslatedViewMatrix(); - + // TODO: assign an equivalent viewTransform object to the application to match the current path which uses glMatrixStack + // setViewTransform(viewTransform); + const glm::vec4 OPAQUE_WHITE(1.0f, 1.0f, 1.0f, 1.0f); spannerData->getRenderer()->render(OPAQUE_WHITE, SpannerRenderer::DIFFUSE_MODE, glm::vec3(), 0.0f); diff --git a/libraries/shared/src/Transform.cpp b/libraries/shared/src/Transform.cpp index c7438a058c..7e4a3724c9 100644 --- a/libraries/shared/src/Transform.cpp +++ b/libraries/shared/src/Transform.cpp @@ -25,14 +25,12 @@ void Transform::evalRotationScale(Quat& rotation, Vec3& scale, const Mat3& rotat Mat3 rotationMat = rotationScaleMatrix; do { Mat3 nextRotation; - Mat3 currInvTranspose = - glm::inverse(glm::transpose(rotationMat)); + 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]); + nextRotation[j][i] = 0.5f * (rotationMat[j][i] + currInvTranspose[j][i]); } } @@ -73,7 +71,8 @@ void Transform::evalRotationScale(Quat& rotation, Vec3& scale, const Mat3& rotat // Beware: even though the matRot is supposed to be normalized at that point, // glm::quat_cast doesn't always return a normalized quaternion... - rotation = glm::normalize(glm::quat_cast(matRot)); + // rotation = glm::normalize(glm::quat_cast(matRot)); + rotation = (glm::quat_cast(matRot)); } diff --git a/libraries/shared/src/Transform.h b/libraries/shared/src/Transform.h index 37f8eddef8..635b4924c7 100644 --- a/libraries/shared/src/Transform.h +++ b/libraries/shared/src/Transform.h @@ -296,7 +296,7 @@ inline Transform& Transform::evalInverse(Transform& inverse) const { } } if (isRotating()) { - inverse.postRotate(-_rotation); + inverse.postRotate(glm::conjugate(_rotation)); } if (isTranslating()) { inverse.postTranslate(-_translation); From 6096a61ecc496496ac5631968d6d9d5af2dbb5f4 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Wed, 12 Nov 2014 00:52:40 -0800 Subject: [PATCH 08/16] avoid for a new Transform for identity gpu::Batch::setTransformModel when rendering model part which are blend shapes --- interface/src/renderer/Model.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 0919850f97..1b723652f1 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -1866,11 +1866,8 @@ int Model::renderMeshes(gpu::Batch& batch, RenderMode mode, bool translucent, fl if (state.clusterMatrices.size() > 1) { GLBATCH(glUniformMatrix4fv)(skinLocations->clusterMatrices, state.clusterMatrices.size(), false, (const float*)state.clusterMatrices.constData()); - - gpu::TransformPointer modelTransform(new gpu::Transform()); - batch.setModelTransform(modelTransform); + batch.setModelTransform(gpu::TransformPointer()); } else { - gpu::TransformPointer modelTransform(new gpu::Transform(state.clusterMatrices[0])); batch.setModelTransform(modelTransform); } From f634b1c5cb80feea4163591f9017f0ce4d7bea3b Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Wed, 12 Nov 2014 01:03:53 -0800 Subject: [PATCH 09/16] avoid for a new Transform for identity gpu::Batch::setTransformModel when rendering model part which are blend shapes AND fix a bug in GLBackend when the ModelTransform is NULL then let's use the ViewTransform only --- interface/src/gpu/GLBackend.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/gpu/GLBackend.cpp b/interface/src/gpu/GLBackend.cpp index 24141cccdc..527739d8b0 100644 --- a/interface/src/gpu/GLBackend.cpp +++ b/interface/src/gpu/GLBackend.cpp @@ -489,7 +489,7 @@ void GLBackend::updateTransform() { _transform._lastMode = GL_MODELVIEW; } Transform::Mat4 modelView; - _transform._model->getMatrix(modelView); + _transform._view->getMatrix(modelView); glLoadMatrixf(reinterpret_cast< const GLfloat* >(&modelView)); } else { // glLoadIdentity(); From 30615f09c5d9f3f530926eccf4e616c8bb45480d Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Wed, 12 Nov 2014 01:07:28 -0800 Subject: [PATCH 10/16] fixing template syntax for linux, hope we can move to c++11 soon:) --- interface/src/gpu/Batch.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/gpu/Batch.h b/interface/src/gpu/Batch.h index cc838a8839..773b1ee6a4 100644 --- a/interface/src/gpu/Batch.h +++ b/interface/src/gpu/Batch.h @@ -51,7 +51,7 @@ enum Primitive { }; typedef ::Transform Transform; -typedef QSharedPointer<::gpu::Transform> TransformPointer; +typedef QSharedPointer< ::gpu::Transform > TransformPointer; typedef std::vector< TransformPointer > Transforms; class Batch { From e47524d70a357fc8bc5ea1e0e1ae7c83d8ae1f38 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Wed, 12 Nov 2014 10:41:50 -0800 Subject: [PATCH 11/16] fix syntax and missing constant name --- libraries/shared/src/Transform.cpp | 6 ++-- libraries/shared/src/Transform.h | 46 +++++++++++++++++++----------- 2 files changed, 32 insertions(+), 20 deletions(-) diff --git a/libraries/shared/src/Transform.cpp b/libraries/shared/src/Transform.cpp index 7e4a3724c9..4c049a8f92 100644 --- a/libraries/shared/src/Transform.cpp +++ b/libraries/shared/src/Transform.cpp @@ -24,15 +24,15 @@ void Transform::evalRotationScale(Quat& rotation, Vec3& scale, const Mat3& rotat int count = 0; Mat3 rotationMat = rotationScaleMatrix; do { - Mat3 nextRotation; Mat3 currInvTranspose = glm::inverse(glm::transpose(rotationMat)); + Mat3 nextRotation = 0.5f * (rotationMat + currInvTranspose); // Go through every component in the matrices and find the next matrix - for (int i = 0; i < 3; i++) { + /* 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++) { diff --git a/libraries/shared/src/Transform.h b/libraries/shared/src/Transform.h index 635b4924c7..13e30f6520 100644 --- a/libraries/shared/src/Transform.h +++ b/libraries/shared/src/Transform.h @@ -31,9 +31,9 @@ public: Transform() : _translation(0), - _rotation(1.f, 0, 0, 0), - _scale(1.f), - _flags(1) // invalid cache + _rotation(1.0f, 0, 0, 0), + _scale(1.0f), + _flags(FLAG_CACHE_INVALID_BITSET) // invalid cache { } Transform(const Transform& transform) : @@ -67,7 +67,7 @@ public: void postScale(float scale); void postScale(const Vec3& scale); - bool isIdentity() const { return (_flags & ~Flags(1)).none(); } + bool isIdentity() const { return (_flags & ~Flags(FLAG_CACHE_INVALID_BITSET)).none(); } bool isTranslating() const { return _flags[FLAG_TRANSLATION]; } bool isRotating() const { return _flags[FLAG_ROTATION]; } bool isScaling() const { return _flags[FLAG_SCALING]; } @@ -99,8 +99,9 @@ protected: FLAG_PROJECTION, NUM_FLAGS, - }; + FLAG_CACHE_INVALID_BITSET = 1, + }; typedef std::bitset Flags; @@ -133,9 +134,9 @@ protected: inline void Transform::setIdentity() { _translation = Vec3(0); - _rotation = Quat(1.f, 0, 0, 0); - _scale = Vec3(1.f); - _flags = Flags(1); + _rotation = Quat(1.0f, 0, 0, 0); + _scale = Vec3(1.0f); + _flags = Flags(FLAG_CACHE_INVALID_BITSET); } inline const Transform::Vec3& Transform::getTranslation() const { @@ -224,7 +225,7 @@ inline const Transform::Vec3& Transform::getScale() const { inline void Transform::setScale(float scale) { invalidCache(); flagUniform(); - if (scale == 1.f) { + if (scale == 1.0f) { unflagScaling(); } else { flagScaling(); @@ -244,7 +245,7 @@ inline void Transform::setScale(const Vec3& scale) { } inline void Transform::postScale(float scale) { - if (scale == 1.f) return; + if (scale == 1.0f) return; if (isScaling()) { // if already scaling, just invalid cache and aply uniform scale invalidCache(); @@ -289,10 +290,15 @@ inline void Transform::evalFromRawMatrix(const Mat3& rotationScaleMatrix) { inline Transform& Transform::evalInverse(Transform& inverse) const { inverse.setIdentity(); if (isScaling()) { + // TODO: At some point we will face the case when scale is 0 and so 1/0 will blow up... + // WHat should we do for this one? + assert(_scale.x != 0); + assert(_scale.y != 0); + assert(_scale.z != 0); if (isNonUniform()) { - inverse.setScale(Vec3(1.f/_scale.x, 1.f/_scale.y, 1.f/_scale.z)); + inverse.setScale(Vec3(1.0f/_scale.x, 1.0f/_scale.y, 1.0f/_scale.z)); } else { - inverse.setScale(1.f/_scale.x); + inverse.setScale(1.0f/_scale.x); } } if (isRotating()) { @@ -306,9 +312,15 @@ inline Transform& Transform::evalInverse(Transform& inverse) const { inline Transform& Transform::mult( Transform& result, const Transform& left, const Transform& right) { result = left; - if ( right.isTranslating()) result.postTranslate(right.getTranslation()); - if ( right.isRotating()) result.postRotate(right.getRotation()); - if (right.isScaling()) result.postScale(right.getScale()); + if (right.isTranslating()) { + result.postTranslate(right.getTranslation()); + } + if (right.isRotating()) { + result.postRotate(right.getRotation()); + } + if (right.isScaling()) { + result.postScale(right.getScale()); + } // HACK: In case of an issue in the Transform multiplication results, to make sure this code is // working properly uncomment the next 2 lines and compare the results, they should be the same... @@ -321,7 +333,7 @@ inline Transform& Transform::mult( Transform& result, const Transform& left, con inline void Transform::updateCache() const { if (isCacheInvalid()) { if (isRotating()) { - glm::mat3x3 rot = glm::mat3_cast(_rotation); + Mat3 rot = glm::mat3_cast(_rotation); if (isScaling()) { rot[0] *= _scale.x; @@ -338,7 +350,7 @@ inline void Transform::updateCache() const { _matrix[2] = Vec4(0.f, 0.f, _scale.z, 0.f); } - _matrix[3] = Vec4(_translation, 1.f); + _matrix[3] = Vec4(_translation, 1.0f); validCache(); } } From 7fa4ea752777b713891034972d77c09dd0290d9c Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Wed, 12 Nov 2014 15:04:52 -0800 Subject: [PATCH 12/16] commented on the else branch in the update TRansform stack doing nothing --- interface/src/gpu/GLBackend.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/interface/src/gpu/GLBackend.cpp b/interface/src/gpu/GLBackend.cpp index 527739d8b0..46020a2398 100644 --- a/interface/src/gpu/GLBackend.cpp +++ b/interface/src/gpu/GLBackend.cpp @@ -492,7 +492,8 @@ void GLBackend::updateTransform() { _transform._view->getMatrix(modelView); glLoadMatrixf(reinterpret_cast< const GLfloat* >(&modelView)); } else { - // glLoadIdentity(); + // TODO: eventually do something about the matrix when neither view nor model is specified? + // glLoadIdentity(); } } CHECK_GL_ERROR(); From 8fb04af59dfeb5e13909e627a5a218a94c121a9f Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Wed, 12 Nov 2014 16:40:45 -0800 Subject: [PATCH 13/16] defined the ViewTransform as the matrix transforming from eye space to world space (the opposite of before this commit) since it seems a better design --- interface/src/Application.cpp | 22 +++++++++++------- interface/src/gpu/Batch.h | 5 ++++ interface/src/gpu/GLBackend.cpp | 4 ++-- interface/src/renderer/Model.cpp | 4 ++-- libraries/shared/src/Transform.cpp | 6 ----- libraries/shared/src/Transform.h | 37 ++++++++++++++++++++++++++++++ 6 files changed, 60 insertions(+), 18 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 919f414c78..e7dbf1e460 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -839,12 +839,14 @@ void Application::controlledBroadcastToNodes(const QByteArray& packet, const Nod } bool Application::event(QEvent* event) { + // handle custom URL if (event->type() == QEvent::FileOpen) { QFileOpenEvent* fileEvent = static_cast(event); - if (fileEvent->url().isValid()) { - openUrl(fileEvent->url()); + + if (!fileEvent->url().isEmpty()) { + AddressManager::getInstance().handleLookupString(fileEvent->url().toLocalFile()); } return false; @@ -2899,14 +2901,16 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { glFrontFace(GL_CCW); } - glm::vec3 eyeOffsetPos = whichCamera.getEyeOffsetPosition(); +/* glm::vec3 eyeOffsetPos = whichCamera.getEyeOffsetPosition(); glm::quat eyeOffsetOrient = whichCamera.getEyeOffsetOrientation(); glm::vec3 eyeOffsetAxis = glm::axis(eyeOffsetOrient); glRotatef(-glm::degrees(glm::angle(eyeOffsetOrient)), eyeOffsetAxis.x, eyeOffsetAxis.y, eyeOffsetAxis.z); - viewTransform.postRotate(glm::conjugate(eyeOffsetOrient)); + // viewTransform.postRotate(glm::conjugate(eyeOffsetOrient)); + viewTransform.preRotate(eyeOffsetOrient); glTranslatef(-eyeOffsetPos.x, -eyeOffsetPos.y, -eyeOffsetPos.z); - viewTransform.postTranslate(-eyeOffsetPos); - + //viewTransform.postTranslate(-eyeOffsetPos); + viewTransform.preTranslate(eyeOffsetPos); +*/ // transform view according to whichCamera // could be myCamera (if in normal mode) // or could be viewFrustumOffsetCamera if in offset mode @@ -2914,14 +2918,16 @@ 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.postRotate(glm::conjugate(rotation)); + // viewTransform.postRotate(glm::conjugate(rotation)); + viewTransform.setRotation(rotation); // store view matrix without translation, which we'll use for precision-sensitive objects updateUntranslatedViewMatrix(-whichCamera.getPosition()); // Equivalent to what is happening with _untranslatedViewMatrix and the _viewMatrixTranslation - // the viewTransofmr object is updated with the correct value and saved, + // the viewTransofmr object is updatded with the correct value and saved, // this is what is used for rendering the ENtities and avatars + viewTransform.setTranslation(whichCamera.getPosition()); setViewTransform(viewTransform); glTranslatef(_viewMatrixTranslation.x, _viewMatrixTranslation.y, _viewMatrixTranslation.z); diff --git a/interface/src/gpu/Batch.h b/interface/src/gpu/Batch.h index 773b1ee6a4..3c15fef63b 100644 --- a/interface/src/gpu/Batch.h +++ b/interface/src/gpu/Batch.h @@ -82,6 +82,11 @@ public: void setIndexBuffer(Type type, const BufferPointer& buffer, Offset offset); // Transform Stage + // Vertex position is transformed by ModelTransform from object space to world space + // Then by the inverse of the ViewTransform from world space to eye space + // finaly projected into the clip space by the projection transform + // WARNING: ViewTransform transform from eye space to world space, its inverse is composed + // with the ModelTransformu to create the equivalent of the glModelViewMatrix void setModelTransform(const TransformPointer& model); void setViewTransform(const TransformPointer& view); void setProjectionTransform(const TransformPointer& proj); diff --git a/interface/src/gpu/GLBackend.cpp b/interface/src/gpu/GLBackend.cpp index 46020a2398..774aaf6ae6 100644 --- a/interface/src/gpu/GLBackend.cpp +++ b/interface/src/gpu/GLBackend.cpp @@ -476,7 +476,7 @@ void GLBackend::updateTransform() { Transform::Mat4 modelView; if (!_transform._view.isNull()) { Transform mvx; - Transform::mult(mvx, (*_transform._view), (*_transform._model)); + Transform::inverseMult(mvx, (*_transform._view), (*_transform._model)); mvx.getMatrix(modelView); } else { _transform._model->getMatrix(modelView); @@ -489,7 +489,7 @@ void GLBackend::updateTransform() { _transform._lastMode = GL_MODELVIEW; } Transform::Mat4 modelView; - _transform._view->getMatrix(modelView); + _transform._view->getInverseMatrix(modelView); glLoadMatrixf(reinterpret_cast< const GLfloat* >(&modelView)); } else { // TODO: eventually do something about the matrix when neither view nor model is specified? diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 1b723652f1..246d4abfbf 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -560,8 +560,8 @@ bool Model::render(float alpha, RenderMode mode, RenderArgs* args) { _transforms.push_back(gpu::TransformPointer(new gpu::Transform())); } (*_transforms[0]) = gpu::Transform((*Application::getInstance()->getViewTransform())); - // apply entity translation + camera position offset to the viewTransform in one go - _transforms[0]->postTranslate(Application::getInstance()->getViewMatrixTranslation() + _translation); + // apply entity translation offset to the viewTransform in one go (it's a preTranslate because viewTransform goes from world to eye space) + _transforms[0]->preTranslate(-_translation); batch.setViewTransform(_transforms[0]); diff --git a/libraries/shared/src/Transform.cpp b/libraries/shared/src/Transform.cpp index 4c049a8f92..296f0743ca 100644 --- a/libraries/shared/src/Transform.cpp +++ b/libraries/shared/src/Transform.cpp @@ -27,12 +27,6 @@ void Transform::evalRotationScale(Quat& rotation, Vec3& scale, const Mat3& rotat Mat3 currInvTranspose = glm::inverse(glm::transpose(rotationMat)); Mat3 nextRotation = 0.5f * (rotationMat + currInvTranspose); - // 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++) { diff --git a/libraries/shared/src/Transform.h b/libraries/shared/src/Transform.h index 13e30f6520..d1dd04811f 100644 --- a/libraries/shared/src/Transform.h +++ b/libraries/shared/src/Transform.h @@ -78,12 +78,17 @@ public: void evalFromRawMatrix(const Mat3& rotationScalematrix); Mat4& getMatrix(Mat4& result) const; + Mat4& getInverseMatrix(Mat4& result) const; Transform& evalInverse(Transform& result) const; static void evalRotationScale(Quat& rotation, Vec3& scale, const Mat3& rotationScaleMatrix); + static Transform& mult(Transform& result, const Transform& left, const Transform& right); + // Left will be inversed before the multiplication + static Transform& inverseMult(Transform& result, const Transform& left, const Transform& right); + protected: @@ -271,6 +276,10 @@ inline Transform::Mat4& Transform::getMatrix(Transform::Mat4& result) const { return result; } +inline Transform::Mat4& Transform::getInverseMatrix(Transform::Mat4& result) const { + return evalInverse(Transform()).getMatrix(result); +} + inline 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)) { @@ -330,6 +339,34 @@ inline Transform& Transform::mult( Transform& result, const Transform& left, con return result; } +inline Transform& Transform::inverseMult( Transform& result, const Transform& left, const Transform& right) { + result.setIdentity(); + + if (left.isScaling()) { + const Vec3& s = left.getScale(); + result.setScale(Vec3(1.0f / s.x, 1.0f / s.y, 1.0f / s.z)); + } + if (left.isRotating()) { + result.postRotate(glm::conjugate(left.getRotation())); + } + if (left.isTranslating() || right.isTranslating()) { + result.postTranslate(right.getTranslation() - left.getTranslation()); + } + if (right.isRotating()) { + result.postRotate(right.getRotation()); + } + if (right.isScaling()) { + result.postScale(right.getScale()); + } + + // HACK: In case of an issue in the Transform multiplication results, to make sure this code is + // working properly uncomment the next 2 lines and compare the results, they should be the same... + // Transform::Mat4 mv = left.getMatrix() * right.getMatrix(); + // Transform::Mat4 mv2 = result.getMatrix(); + + return result; +} + inline void Transform::updateCache() const { if (isCacheInvalid()) { if (isRotating()) { From d3a7b011bffdc0e2e280f8932e88a376264f266a Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Wed, 12 Nov 2014 16:52:11 -0800 Subject: [PATCH 14/16] defined the ViewTransform as the matrix transforming from eye space to world space (the opposite of before this commit) since it seems a better design. And cleaned the dead code in Application.cpp --- interface/src/Application.cpp | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index e7dbf1e460..d9f86d5bfc 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2885,32 +2885,24 @@ 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 { glFrontFace(GL_CCW); } -/* glm::vec3 eyeOffsetPos = whichCamera.getEyeOffsetPosition(); + glm::vec3 eyeOffsetPos = whichCamera.getEyeOffsetPosition(); glm::quat eyeOffsetOrient = whichCamera.getEyeOffsetOrientation(); glm::vec3 eyeOffsetAxis = glm::axis(eyeOffsetOrient); glRotatef(-glm::degrees(glm::angle(eyeOffsetOrient)), eyeOffsetAxis.x, eyeOffsetAxis.y, eyeOffsetAxis.z); - // viewTransform.postRotate(glm::conjugate(eyeOffsetOrient)); - viewTransform.preRotate(eyeOffsetOrient); glTranslatef(-eyeOffsetPos.x, -eyeOffsetPos.y, -eyeOffsetPos.z); - //viewTransform.postTranslate(-eyeOffsetPos); - viewTransform.preTranslate(eyeOffsetPos); -*/ + // transform view according to whichCamera // could be myCamera (if in normal mode) // or could be viewFrustumOffsetCamera if in offset mode @@ -2918,16 +2910,21 @@ 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.postRotate(glm::conjugate(rotation)); - viewTransform.setRotation(rotation); // store view matrix without translation, which we'll use for precision-sensitive objects updateUntranslatedViewMatrix(-whichCamera.getPosition()); // Equivalent to what is happening with _untranslatedViewMatrix and the _viewMatrixTranslation - // the viewTransofmr object is updatded with the correct value and saved, - // this is what is used for rendering the ENtities and avatars + // the viewTransofmr object is updatded with the correct values and saved, + // this is what is used for rendering the Entities and avatars + gpu::Transform viewTransform; viewTransform.setTranslation(whichCamera.getPosition()); + viewTransform.setRotation(rotation); + viewTransform.postTranslate(eyeOffsetPos); + viewTransform.postRotate(eyeOffsetOrient); + if (whichCamera.getMode() == CAMERA_MODE_MIRROR) { + viewTransform.setScale(gpu::Transform::Vec3(-1.0f, 1.0f, 1.0f)); + } setViewTransform(viewTransform); glTranslatef(_viewMatrixTranslation.x, _viewMatrixTranslation.y, _viewMatrixTranslation.z); From b6c004c43140d188f8ad00efe2d983f8deec5b0e Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Wed, 12 Nov 2014 17:16:43 -0800 Subject: [PATCH 15/16] Fix syntax that doesn't compile on linux and used smart glm::max instruction --- libraries/shared/src/Transform.cpp | 6 +----- libraries/shared/src/Transform.h | 4 +++- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/libraries/shared/src/Transform.cpp b/libraries/shared/src/Transform.cpp index 296f0743ca..9945091ed0 100644 --- a/libraries/shared/src/Transform.cpp +++ b/libraries/shared/src/Transform.cpp @@ -43,12 +43,8 @@ void Transform::evalRotationScale(Quat& rotation, Vec3& scale, const Mat3& rotat // extract scale of the matrix as the length of each axis Mat3 scaleMat = glm::inverse(rotationMat) * rotationScaleMatrix; - scale = Vec3(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; + scale = glm::max(Vec3(ACCURACY_THREASHOLD), Vec3(scaleMat[0][0], scaleMat[1][1], scaleMat[2][2])); - // Let's work on a local matrix containing rotation only Mat3 matRot( rotationScaleMatrix[0] / scale.x, diff --git a/libraries/shared/src/Transform.h b/libraries/shared/src/Transform.h index d1dd04811f..6ad106063f 100644 --- a/libraries/shared/src/Transform.h +++ b/libraries/shared/src/Transform.h @@ -277,7 +277,9 @@ inline Transform::Mat4& Transform::getMatrix(Transform::Mat4& result) const { } inline Transform::Mat4& Transform::getInverseMatrix(Transform::Mat4& result) const { - return evalInverse(Transform()).getMatrix(result); + Transform inverse; + evalInverse(inverse); + return inverse.getMatrix(result); } inline void Transform::evalFromRawMatrix(const Mat4& matrix) { From 859c99b9de510040c074a81c650ebb51b7e9b901 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Wed, 12 Nov 2014 18:15:35 -0800 Subject: [PATCH 16/16] Fix bug in the cache of GLBackend::TransformStage --- interface/src/gpu/GLBackend.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/src/gpu/GLBackend.cpp b/interface/src/gpu/GLBackend.cpp index 774aaf6ae6..8921dc6d1c 100644 --- a/interface/src/gpu/GLBackend.cpp +++ b/interface/src/gpu/GLBackend.cpp @@ -432,7 +432,7 @@ void GLBackend::do_setIndexBuffer(Batch& batch, uint32 paramOffset) { void GLBackend::do_setModelTransform(Batch& batch, uint32 paramOffset) { TransformPointer modelTransform = batch._transforms.get(batch._params[paramOffset]._uint); - if (modelTransform != _transform._model) { + if (_transform._model.isNull() || (modelTransform != _transform._model)) { _transform._model = modelTransform; _transform._invalidModel = true; } @@ -441,7 +441,7 @@ void GLBackend::do_setModelTransform(Batch& batch, uint32 paramOffset) { void GLBackend::do_setViewTransform(Batch& batch, uint32 paramOffset) { TransformPointer viewTransform = batch._transforms.get(batch._params[paramOffset]._uint); - if (viewTransform != _transform._view) { + if (_transform._view.isNull() || (viewTransform != _transform._view)) { _transform._view = viewTransform; _transform._invalidView = true; } @@ -450,7 +450,7 @@ void GLBackend::do_setViewTransform(Batch& batch, uint32 paramOffset) { void GLBackend::do_setProjectionTransform(Batch& batch, uint32 paramOffset) { TransformPointer projectionTransform = batch._transforms.get(batch._params[paramOffset]._uint); - if (projectionTransform != _transform._projection) { + if (_transform._projection.isNull() || (projectionTransform != _transform._projection)) { _transform._projection = projectionTransform; _transform._invalidProj = true; }