diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 9ffbb86ae0..f6c9195c16 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -392,7 +392,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : // emit checkBackgroundDownloads to cause the GeometryCache to check it's queue for requested background // downloads. QSharedPointer geometryCacheP = DependencyManager::get(); - ResourceCache *geometryCache = geometryCacheP.data(); + ResourceCache* geometryCache = geometryCacheP.data(); connect(this, &Application::checkBackgroundDownloads, geometryCache, &ResourceCache::checkAsynchronousGets); // connect the DataProcessor processDatagrams slot to the QUDPSocket readyRead() signal @@ -3292,7 +3292,7 @@ void Application::displaySide(Camera& theCamera, bool selfAvatarOnly, RenderArgs gpu::Batch batch; model::Skybox::render(batch, _viewFrustum, *skybox); - gpu::GLBackend::renderBatch(batch); + gpu::GLBackend::renderBatch(batch, true); glUseProgram(0); } } diff --git a/interface/src/ui/overlays/Cube3DOverlay.cpp b/interface/src/ui/overlays/Cube3DOverlay.cpp index 329d81ff80..6fc9fe6e27 100644 --- a/interface/src/ui/overlays/Cube3DOverlay.cpp +++ b/interface/src/ui/overlays/Cube3DOverlay.cpp @@ -126,8 +126,7 @@ void Cube3DOverlay::render(RenderArgs* args) { } else { glScalef(dimensions.x, dimensions.y, dimensions.z); - // FIXME Remove non Batch version of renderWireCube once we use the render pipeline - DependencyManager::get()->renderWireCube(1.0f, cubeColor); + DependencyManager::get()->renderWireCube(1.0f, cubeColor); } } glPopMatrix(); diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 23160be045..86baacc8a8 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -510,7 +510,7 @@ void EntityTreeRenderer::render(RenderArgs::RenderMode renderMode, _tree->unlock(); glPushMatrix(); - gpu::GLBackend::renderBatch(batch); + gpu::GLBackend::renderBatch(batch, true); glPopMatrix(); // stats... diff --git a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp index 9f209e91ef..a3bfd981ec 100644 --- a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp @@ -51,9 +51,9 @@ void RenderableTextEntityItem::render(RenderArgs* args) { // TODO: Determine if we want these entities to have the deferred lighting effect? I think we do, so that the color // used for a sphere, or box have the same look as those used on a text entity. - DependencyManager::get()->bindSimpleProgram(); + //DependencyManager::get()->bindSimpleProgram(); DependencyManager::get()->renderQuad(topLeft, bottomRight, glm::vec4(toGlm(getBackgroundColorX()), alpha)); - DependencyManager::get()->releaseSimpleProgram(); + //DependencyManager::get()->releaseSimpleProgram(); glTranslatef(-(halfDimensions.x - leftMargin), halfDimensions.y - topMargin, 0.0f); glm::vec4 textColor(toGlm(getTextColorX()), alpha); diff --git a/libraries/gpu/src/gpu/GLBackend.cpp b/libraries/gpu/src/gpu/GLBackend.cpp index b0b017a826..a84af10a82 100644 --- a/libraries/gpu/src/gpu/GLBackend.cpp +++ b/libraries/gpu/src/gpu/GLBackend.cpp @@ -76,12 +76,10 @@ GLBackend::GLBackend() : _output() { initTransform(); - initInput(); } GLBackend::~GLBackend() { killTransform(); - killInput(); } void GLBackend::render(Batch& batch) { @@ -98,8 +96,11 @@ void GLBackend::render(Batch& batch) { } } -void GLBackend::renderBatch(Batch& batch) { +void GLBackend::renderBatch(Batch& batch, bool syncCache) { GLBackend backend; + if (syncCache) { + backend.syncCache(); + } backend.render(batch); } @@ -136,6 +137,13 @@ bool GLBackend::checkGLError(const char* name) { } } + +void GLBackend::syncCache() { + syncTransformStateCache(); + syncPipelineStateCache(); + syncInputStateCache(); +} + void GLBackend::do_draw(Batch& batch, uint32 paramOffset) { updateInput(); updateTransform(); @@ -549,4 +557,3 @@ void GLBackend::fetchMatrix(GLenum target, glm::mat4 & m) { } - diff --git a/libraries/gpu/src/gpu/GLBackend.h b/libraries/gpu/src/gpu/GLBackend.h index dc6c3b64ed..22266079bc 100644 --- a/libraries/gpu/src/gpu/GLBackend.h +++ b/libraries/gpu/src/gpu/GLBackend.h @@ -24,12 +24,20 @@ namespace gpu { class GLBackend : public Backend { public: + explicit GLBackend(bool syncCache); GLBackend(); ~GLBackend(); void render(Batch& batch); - static void renderBatch(Batch& batch); + // Render Batch create a local Context and execute the batch with it + // WARNING: + // if syncCache is true, then the gpu::GLBackend will synchornize + // its cache with the current gl state and it's BAD + // If you know you don't rely on any state changed by naked gl calls then + // leave to false where it belongs + // if true, the needed resync IS EXPENSIVE + static void renderBatch(Batch& batch, bool syncCache = false); static bool checkGLError(const char* name = nullptr); @@ -79,6 +87,7 @@ public: static GLShader* syncGPUObject(const Shader& shader); static GLuint getShaderID(const ShaderPointer& shader); + // FIXME: Please remove these 2 calls once the text renderer doesn't use naked gl calls anymore static void loadMatrix(GLenum target, const glm::mat4 & m); static void fetchMatrix(GLenum target, glm::mat4 & m); @@ -186,6 +195,12 @@ public: void do_setStateColorWriteMask(uint32 mask); + // This call synchronize the Full Backend cache with the current GLState + // THis is only intended to be used when mixing raw gl calls with the gpu api usage in order to sync + // the gpu::Backend state with the true gl state which has probably been messed up by these ugly naked gl calls + // Let's try to avoid to do that as much as possible! + void syncCache(); + protected: // Draw Stage @@ -201,8 +216,8 @@ protected: void do_setInputBuffer(Batch& batch, uint32 paramOffset); void do_setIndexBuffer(Batch& batch, uint32 paramOffset); - void initInput(); - void killInput(); + // Synchronize the state cache of this Backend with the actual real state of the GL Context + void syncInputStateCache(); void updateInput(); struct InputStageState { bool _invalidFormat; @@ -243,6 +258,8 @@ protected: void initTransform(); void killTransform(); + // Synchronize the state cache of this Backend with the actual real state of the GL Context + void syncTransformStateCache(); void updateTransform(); struct TransformStageState { TransformObject _transformObject; @@ -299,7 +316,6 @@ protected: GLState* _state; bool _invalidState = false; - bool _needStateSync = true; PipelineStageState() : _pipeline(), @@ -308,8 +324,7 @@ protected: _stateCache(State::DEFAULT), _stateSignatureCache(0), _state(nullptr), - _invalidState(false), - _needStateSync(true) + _invalidState(false) {} } _pipeline; diff --git a/libraries/gpu/src/gpu/GLBackendInput.cpp b/libraries/gpu/src/gpu/GLBackendInput.cpp index 6646ae3f64..fde6ac40d0 100755 --- a/libraries/gpu/src/gpu/GLBackendInput.cpp +++ b/libraries/gpu/src/gpu/GLBackendInput.cpp @@ -46,24 +46,12 @@ static const GLenum attributeSlotToClassicAttribName[NUM_CLASSIC_ATTRIBS] = { }; #endif -void GLBackend::initInput() { - glPushClientAttrib(GL_VERTEX_ARRAY); - glPushClientAttrib(GL_NORMAL_ARRAY); - glPushClientAttrib(GL_COLOR_ARRAY); - glPushClientAttrib(GL_TEXTURE_COORD_ARRAY); - +void GLBackend::syncInputStateCache() { for (int i = 0; i < NUM_CLASSIC_ATTRIBS; i++) { _input._attributeActivation[i] = glIsEnabled(attributeSlotToClassicAttribName[i]); } } -void GLBackend::killInput() { - glPopClientAttrib(); // GL_VERTEX_ARRAY - glPopClientAttrib(); // GL_NORMAL_ARRAY - glPopClientAttrib(); // GL_COLOR_ARRAY - glPopClientAttrib(); // GL_TEXTURE_COORD_ARRAY -} - void GLBackend::updateInput() { if (_input._invalidFormat || _input._buffersState.any()) { @@ -164,9 +152,6 @@ void GLBackend::updateInput() { } } } - } else { - glBindBuffer(GL_ARRAY_BUFFER, 0); - (void) CHECK_GL_ERROR(); } // everything format related should be in sync now _input._invalidFormat = false; diff --git a/libraries/gpu/src/gpu/GLBackendPipeline.cpp b/libraries/gpu/src/gpu/GLBackendPipeline.cpp index 938ed77730..ec9be957ae 100755 --- a/libraries/gpu/src/gpu/GLBackendPipeline.cpp +++ b/libraries/gpu/src/gpu/GLBackendPipeline.cpp @@ -63,11 +63,6 @@ void GLBackend::do_setPipeline(Batch& batch, uint32 paramOffset) { if (_pipeline._pipeline == pipeline) { return; } - - if (_pipeline._needStateSync) { - syncPipelineStateCache(); - _pipeline._needStateSync = false; - } // null pipeline == reset if (!pipeline) { @@ -108,17 +103,7 @@ void GLBackend::do_setPipeline(Batch& batch, uint32 paramOffset) { } } -#define DEBUG_GLSTATE void GLBackend::updatePipeline() { -#ifdef DEBUG_GLSTATE - if (_pipeline._needStateSync) { - State::Data state; - getCurrentGLState(state); - State::Signature signature = State::evalSignature(state); - (void) signature; // quiet compiler - } -#endif - if (_pipeline._invalidProgram) { // doing it here is aproblem for calls to glUniform.... so will do it on assing... glUseProgram(_pipeline._program); diff --git a/libraries/gpu/src/gpu/GLBackendTransform.cpp b/libraries/gpu/src/gpu/GLBackendTransform.cpp index d619d0afee..3f760e4cc8 100755 --- a/libraries/gpu/src/gpu/GLBackendTransform.cpp +++ b/libraries/gpu/src/gpu/GLBackendTransform.cpp @@ -55,6 +55,25 @@ void GLBackend::killTransform() { #else #endif } + +void GLBackend::syncTransformStateCache() { + _transform._invalidProj = true; + _transform._invalidView = true; + _transform._invalidModel = true; + + GLint currentMode; + glGetIntegerv(GL_MATRIX_MODE, ¤tMode); + _transform._lastMode = currentMode; + + glGetFloatv(GL_PROJECTION_MATRIX, (float*) &_transform._projection); + + Mat4 modelView; + glGetFloatv(GL_MODELVIEW_MATRIX, (float*) &modelView); + auto modelViewInv = glm::inverse(modelView); + _transform._view.evalFromRawMatrix(modelViewInv); + _transform._model.setIdentity(); +} + void GLBackend::updateTransform() { // Check all the dirty flags and update the state accordingly if (_transform._invalidProj) { diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 2f23773bc1..8a9ee4bf6d 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -12,7 +12,6 @@ // include this before QOpenGLFramebufferObject, which includes an earlier version of OpenGL #include - #include #include #include @@ -48,16 +47,26 @@ #include "point_light_frag.h" #include "spot_light_frag.h" +static const std::string glowIntensityShaderHandle = "glowIntensity"; + void DeferredLightingEffect::init(AbstractViewStateInterface* viewState) { + auto vertexShader = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(simple_vert))); + auto pixelShader = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(simple_frag))); + gpu::Shader::BindingSet slotBindings; + slotBindings.insert(gpu::Shader::Binding(glowIntensityShaderHandle, 0)); + + gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vertexShader, pixelShader)); + gpu::Shader::makeProgram(*program, slotBindings); + + gpu::StatePointer state = gpu::StatePointer(new gpu::State()); + state->setCullMode(gpu::State::CULL_BACK); + state->setDepthTest(true, true, gpu::LESS_EQUAL); + state->setBlendFunction(false, + gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, + gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); + _simpleProgram = gpu::PipelinePointer(gpu::Pipeline::create(program, state)); + _viewState = viewState; - _simpleProgram.addShaderFromSourceCode(QGLShader::Vertex, simple_vert); - _simpleProgram.addShaderFromSourceCode(QGLShader::Fragment, simple_frag); - _simpleProgram.link(); - - _simpleProgram.bind(); - _glowIntensityLocation = _simpleProgram.uniformLocation("glowIntensity"); - _simpleProgram.release(); - loadLightProgram(directional_light_frag, false, _directionalLight, _directionalLightLocations); loadLightProgram(directional_light_shadow_map_frag, false, _directionalLightShadowMap, _directionalLightShadowMapLocations); @@ -92,29 +101,12 @@ void DeferredLightingEffect::init(AbstractViewStateInterface* viewState) { lp->setAmbientSpherePreset(gpu::SphericalHarmonics::Preset(_ambientLightMode % gpu::SphericalHarmonics::NUM_PRESET)); } -void DeferredLightingEffect::bindSimpleProgram() { - DependencyManager::get()->setPrimaryDrawBuffers(true, true, true); - _simpleProgram.bind(); - _simpleProgram.setUniformValue(_glowIntensityLocation, DependencyManager::get()->getIntensity()); - glDisable(GL_BLEND); -} - void DeferredLightingEffect::bindSimpleProgram(gpu::Batch& batch) { DependencyManager::get()->setPrimaryDrawBuffers(batch, true, true, true); - batch._glUseProgram(_simpleProgram.programId()); - batch._glUniform1f(_glowIntensityLocation, DependencyManager::get()->getIntensity()); - batch._glDisable(GL_BLEND); -} - -void DeferredLightingEffect::releaseSimpleProgram() { - glEnable(GL_BLEND); - _simpleProgram.release(); - DependencyManager::get()->setPrimaryDrawBuffers(true, false, false); + batch.setPipeline(_simpleProgram); } void DeferredLightingEffect::releaseSimpleProgram(gpu::Batch& batch) { - batch._glEnable(GL_BLEND); - batch._glUseProgram(0); DependencyManager::get()->setPrimaryDrawBuffers(batch, true, false, false); } @@ -136,12 +128,6 @@ void DeferredLightingEffect::renderSolidCube(gpu::Batch& batch, float size, cons releaseSimpleProgram(batch); } -void DeferredLightingEffect::renderWireCube(float size, const glm::vec4& color) { - gpu::Batch batch; - renderWireCube(batch, size, color); - gpu::GLBackend::renderBatch(batch); -} - void DeferredLightingEffect::renderWireCube(gpu::Batch& batch, float size, const glm::vec4& color) { bindSimpleProgram(batch); DependencyManager::get()->renderWireCube(batch, size, color); diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index 22a26dfbc7..33728ab15a 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -33,15 +33,10 @@ public: void init(AbstractViewStateInterface* viewState); - /// Returns a reference to a simple program suitable for rendering static untextured geometry - ProgramObject& getSimpleProgram() { return _simpleProgram; } - /// Sets up the state necessary to render static untextured geometry with the simple program. - void bindSimpleProgram(); void bindSimpleProgram(gpu::Batch& batch); /// Tears down the state necessary to render static untextured geometry with the simple program. - void releaseSimpleProgram(); void releaseSimpleProgram(gpu::Batch& batch); //// Renders a solid sphere with the simple program. @@ -54,8 +49,6 @@ public: void renderSolidCube(gpu::Batch& batch, float size, const glm::vec4& color); //// Renders a wireframe cube with the simple program. - // FIXME Remove non Batch version once Cube3DOverlay uses the render pipeline - void renderWireCube(float size, const glm::vec4& color); void renderWireCube(gpu::Batch& batch, float size, const glm::vec4& color); //// Renders a quad with the simple program. @@ -105,10 +98,9 @@ private: }; static void loadLightProgram(const char* fragSource, bool limited, ProgramObject& program, LightLocations& locations); - - ProgramObject _simpleProgram; - int _glowIntensityLocation; + gpu::PipelinePointer _simpleProgram; + ProgramObject _directionalSkyboxLight; LightLocations _directionalSkyboxLightLocations; ProgramObject _directionalSkyboxLightShadowMap; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 483ea6177e..44cc2b735b 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -946,8 +946,8 @@ bool Model::renderCore(float alpha, RenderMode mode, RenderArgs* args) { glPushMatrix(); #endif - ::gpu::GLBackend::renderBatch(batch); - + ::gpu::GLBackend::renderBatch(batch, true); // force sync with gl state here + #if defined(ANDROID) #else glPopMatrix(); @@ -1859,6 +1859,7 @@ void Model::endScene(RenderMode mode, RenderArgs* args) { } gpu::GLBackend backend; + backend.syncCache(); // force sync with gl state here if (args) { glm::mat4 proj; diff --git a/libraries/render-utils/src/simple.slv b/libraries/render-utils/src/simple.slv index 9ad47a3e66..1460058892 100644 --- a/libraries/render-utils/src/simple.slv +++ b/libraries/render-utils/src/simple.slv @@ -12,16 +12,22 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +<@include gpu/Transform.slh@> + +<$declareStandardTransform()$> + // the interpolated normal varying vec4 interpolatedNormal; void main(void) { - // transform and store the normal for interpolation - interpolatedNormal = normalize(gl_ModelViewMatrix * vec4(gl_Normal, 0.0)); - // pass along the diffuse color gl_FrontColor = gl_Color; - // use standard pipeline transform - gl_Position = ftransform(); -} + // standard transform + TransformCamera cam = getTransformCamera(); + TransformObject obj = getTransformObject(); + <$transformModelToClipPos(cam, obj, gl_Vertex, gl_Position)$> + <$transformModelToEyeDir(cam, obj, gl_Normal, interpolatedNormal.xyz)$> + + interpolatedNormal = vec4(normalize(interpolatedNormal.xyz), 0.0); +} \ No newline at end of file diff --git a/libraries/shared/src/Transform.h b/libraries/shared/src/Transform.h index fd6a4bda4b..f3b5b14385 100644 --- a/libraries/shared/src/Transform.h +++ b/libraries/shared/src/Transform.h @@ -22,6 +22,18 @@ #include +inline bool isValidScale(glm::vec3 scale) { + bool result = scale.x != 0.0f && scale.y != 0.0f && scale.z != 0.0f; + assert(result); + return result; +} + +inline bool isValidScale(float scale) { + bool result = scale != 0.0f; + assert(result); + return result; +} + class Transform { public: typedef glm::mat4 Mat4; @@ -32,7 +44,7 @@ public: typedef glm::quat Quat; Transform() : - _rotation(1.0f, 0, 0, 0), + _rotation(1.0f, 0.0f, 0.0f, 0.0f), _scale(1.0f), _translation(0.0f), _flags(FLAG_CACHE_INVALID_BITSET) // invalid cache @@ -44,6 +56,9 @@ public: _translation(translation), _flags(FLAG_CACHE_INVALID_BITSET) // invalid cache { + if (!isValidScale(_scale)) { + _scale = Vec3(1.0f); + } } Transform(const Transform& transform) : _rotation(transform._rotation), @@ -166,8 +181,8 @@ protected: }; inline void Transform::setIdentity() { - _translation = Vec3(0); - _rotation = Quat(1.0f, 0, 0, 0); + _translation = Vec3(0.0f); + _rotation = Quat(1.0f, 0.0f, 0.0f, 0.0f); _scale = Vec3(1.0f); _flags = Flags(FLAG_CACHE_INVALID_BITSET); } @@ -187,19 +202,25 @@ inline void Transform::setTranslation(const Vec3& translation) { } inline void Transform::preTranslate(const Vec3& translation) { - if (translation == Vec3() ) return; + if (translation == Vec3()) { + return; + } invalidCache(); flagTranslation(); _translation += translation; } inline void Transform::postTranslate(const Vec3& translation) { - if (translation == Vec3() ) return; + if (translation == Vec3()) { + return; + } invalidCache(); flagTranslation(); Vec3 scaledT = translation; - if (isScaling()) scaledT *= _scale; + if (isScaling()) { + scaledT *= _scale; + } if (isRotating()) { _translation += glm::rotate(_rotation, scaledT); @@ -223,7 +244,9 @@ inline void Transform::setRotation(const Quat& rotation) { } inline void Transform::preRotate(const Quat& rotation) { - if (rotation == Quat()) return; + if (rotation == Quat()) { + return; + } invalidCache(); if (isRotating()) { _rotation = rotation * _rotation; @@ -236,7 +259,9 @@ inline void Transform::preRotate(const Quat& rotation) { } inline void Transform::postRotate(const Quat& rotation) { - if (rotation == Quat()) return; + if (rotation == Quat()) { + return; + } invalidCache(); if (isNonUniform()) { @@ -269,8 +294,12 @@ inline const Transform::Vec3& Transform::getScale() const { } inline void Transform::setScale(float scale) { + if (!isValidScale(scale)) { + return; + } invalidCache(); flagUniform(); + if (scale == 1.0f) { unflagScaling(); } else { @@ -280,6 +309,9 @@ inline void Transform::setScale(float scale) { } inline void Transform::setScale(const Vec3& scale) { + if (!isValidScale(scale)) { + return; + } if ((scale.x == scale.y) && (scale.x == scale.z)) { setScale(scale.x); } else { @@ -291,9 +323,11 @@ inline void Transform::setScale(const Vec3& scale) { } inline void Transform::postScale(float scale) { - if (scale == 1.0f) return; + if (isValidScale(scale) || scale == 1.0f) { + return; + } if (isScaling()) { - // if already scaling, just invalid cache and aply uniform scale + // if already scaling, just invalid cache and apply uniform scale invalidCache(); _scale *= scale; } else { @@ -302,6 +336,9 @@ inline void Transform::postScale(float scale) { } inline void Transform::postScale(const Vec3& scale) { + if (!isValidScale(scale)) { + return; + } invalidCache(); if (isScaling()) { _scale *= scale; @@ -360,7 +397,7 @@ inline Transform::Mat4& Transform::getRotationScaleMatrixInverse(Mat4& result) c 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.0f)) { + if ((matrix[0][3] == 0.0f) && (matrix[1][3] == 0.0f) && (matrix[2][3] == 0.0f) && (matrix[3][3] == 1.0f)) { setTranslation(Vec3(matrix[3])); evalFromRawMatrix(Mat3(matrix)); } @@ -377,15 +414,10 @@ 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.0f/_scale.x, 1.0f/_scale.y, 1.0f/_scale.z)); + inverse.setScale(Vec3(1.0f) / _scale); } else { - inverse.setScale(1.0f/_scale.x); + inverse.setScale(1.0f / _scale.x); } } if (isRotating()) { @@ -421,8 +453,7 @@ inline Transform& Transform::inverseMult( Transform& result, const Transform& le 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)); + result.setScale(Vec3(1.0f) / left.getScale()); } if (left.isRotating()) { result.postRotate(glm::conjugate(left.getRotation()));