Whenever an object is scaled to 0 (scale.set(0,0,0)) or a camera and target are at position (0, 0, 0), ThreeJS stops rendering the objects and fills the console with errors:
THREE.Matrix3: .getInverse() can't invert matrix, determinant is 0
I feel like this should be handled more cleanly. It's pretty common for objects to be scaled to 0 size when doing animations and the error in the console doesn't describe what object caused the problem.
This issue was described and closed here:
https://github.com/mrdoob/three.js/issues/2361
Wouldn't it be better for ThreeJS to internally handle this like:
if scale = (0, 0, 0), scale = (1e-15, 1e-15, 1e-15). When reading the value, it can do if x==1e-15, return 0.
When this issue was last discussed in 2012, I think that negative scales were not supported.
Now that we support both positive and negative scale values, this seems like a more reasonable request. Otherwise I don't think there's any way for someone to tween from negative to positive scale.
I don't think there's any way for someone to tween from negative to positive scale
transform controls ?
any way @adevart this is perfectly solvable in user code:
scene.children[0].updateMatrix = function () {
if (this.scale.x < 0.4) this.scale.x = 0.4;
if (this.scale.y < 0.4) this.scale.y = 0.4;
if (this.scale.z < 0.4) this.scale.z = 0.4;
THREE.Object3D.prototype.updateMatrix.call(this);
}
transform controls ?
I meant tweening an animation, for example using tween.js
@mrdoob Do you want to support any of these patterns?
mesh.scale.set( 1, 1, 0 ); // squash to a plane
mesh.scale.set( 1, 0, 0 ); // squash to a line
mesh.scale.set( 0, 0, 0 ); // squash to a dot
or do you want to continue as we have been and require the components of scale
to be non-zero?
My preference is to require non-zero values.
Would a simple fix be on the Matrix classes that compute the determinant? In Matrix3.getInverse(), the values that contribute to a zero determinant can be changed to be extremely small.
If the scaling values in the transform matrix are 0, set them to be something like 1e-15 or smaller. Then you don't get a zero determinant. It shouldn't cause accuracy errors with the number being so small.
Is it just to avoid the divide by zero? Maybe if the determinant is zero, it can just be set to 1e-15 (or smaller) instead of throwing the error.
BabylonJS seems to copy a matrix into the given one and returns from the invert function without a warning:
https://github.com/BabylonJS/Babylon.js/blob/master/src/Maths/math.vector.ts#L3581
My preference is to require non-zero values.
In fact it's the only logical way.
Requiring non-zero values for the matrix calculations is fine but it's more intuitive if this is handled internally rather than by every user of the ThreeJS framework. Other game engines don't require users to avoid setting scale values to zero. Wherever possible, the ThreeJS engine should take care of things to guarantee stability and ease of use.
It can be the suggestion mentioned by @makc above:
Object3D.updateMatrix
updateMatrix: function () {
this.matrix.compose( this.position, this.quaternion, this.scale );
this.matrixWorldNeedsUpdate = true;
},
Add a check for the scale values in there and either change the values or pass a different scale object with non-zero values into the matrix call. Passing separate non-zero scale values in means that a user can still have checks like scale.x === 0.
I'm not sure this needs a fix for the calculations. It's really just the warning messages that flood the console log that cause a problem. Everything seems to run fine once the error logs are removed. These are in Matrix4.getInverse and Matrix3.getInverse.
if ( det === 0 ) {
var msg = "THREE.Matrix4: .getInverse() can't invert matrix, determinant is 0";
if ( throwOnDegenerate === true ) {
throw new Error( msg );
} else {
console.warn( msg );
}
return this.identity();
}
It can just be:
if ( det === 0 ) {
return this.identity();
}
If people want warnings or errors to show there could be a property that defaults to false for the logs and the messages can be enabled. What would be the reason someone would want these warnings? Nothing bad seems to happen turning them off.
@mrdoob Can you please respond to https://github.com/mrdoob/three.js/issues/17926#issuecomment-554135342 ?
I meant tweening an animation, for example using tween.js
I'd like to pick up this comment and highlight the importance of it. I've seen some user in the past animating the scale
property of objects and then wondering why three.js
complains with the mentioned warning. Check out this live example I've prepared that shows the problem:
https://jsfiddle.net/qz1afen9/
Like elaborated here https://github.com/mrdoob/three.js/pull/18026#issuecomment-559952681, I vote for a different implementation that does not log a warning.
@WestLangley
@mrdoob Can you please respond to #17926 (comment) ?
Sorry for the delay.
@mrdoob Do you want to support any of these patterns?
mesh.scale.set( 1, 1, 0 ); // squash to a plane mesh.scale.set( 1, 0, 0 ); // squash to a line mesh.scale.set( 0, 0, 0 ); // squash to a dot
or do you want to continue as we have been and require the components of
scale
to be non-zero?My preference is to require non-zero values.
I keep seeing users bumping into this. The common use case I see is people that want to animate a scale going fro 1 to 0, but things break when it reaches 0 and at that point their "creative flow" is gone.
I'm willing to explore what the side effects would be if we changed the behaviour.
I just bumped into this problem.
What is the correct way to scale an object from 0 to 1 and to 0 again?
I can't find any good explanation by searching the web.
@grasmachien https://jsfiddle.net/g0c68p9r/
@makc ok, so I just use 0.0001 now instead of 0 :)
Thx for the quick reply!
With the latest version of three.js
, adding the above epsilon should not be necessary anymore.
@Mugen87 was it ever really needed? here is r76 scaling to 0 just fine
ok, tats probably because s is never really 0. if you put 0 you get THREE.Matrix3.getInverse(): can't invert matrix, determinant is 0
but the visual result is still correct.
Most helpful comment
With the latest version of
three.js
, adding the above epsilon should not be necessary anymore.https://jsfiddle.net/uv8gcrd1/