Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Object3D: granular control of matrix updates with matrixWorldAutoUpdate #24028

Merged
merged 8 commits into from
Aug 23, 2022
6 changes: 6 additions & 0 deletions docs/api/en/core/Object3D.html
Expand Up @@ -32,6 +32,12 @@ <h2>Properties</h2>
<h3>[property:AnimationClip animations]</h3>
<p>Array with object's animation clips.</p>

<h3>[property:Boolean matrixWorldAutoUpdate]</h3>
<p>
Default is true. If set, then the renderer checks every frame if the object and its children need matrix updates.
When it isn't, then you have to maintain all matrices in the object and its children yourself.
</p>

<h3>[property:Boolean castShadow]</h3>
<p>Whether the object gets rendered into shadow map. Default is `false`.</p>

Expand Down
6 changes: 0 additions & 6 deletions docs/api/en/scenes/Scene.html
Expand Up @@ -24,12 +24,6 @@ <h3>[name]()</h3>

<h2>Properties</h2>

<h3>[property:Boolean autoUpdate]</h3>
<p>
Default is true. If set, then the renderer checks every frame if the scene and its objects needs matrix updates.
When it isn't, then you have to maintain all matrices in the scene yourself.
</p>

<h3>[property:Object background]</h3>
<p>
If not null, sets the background used when rendering the scene, and is always rendered first.
Expand Down
6 changes: 6 additions & 0 deletions docs/api/ko/core/Object3D.html
Expand Up @@ -30,6 +30,12 @@ <h2>프로퍼티</h2>
<h3>[property:AnimationClip animations]</h3>
<p>객체의 애니메이션 클립 배열입니다.</p>

<h3>[property:Boolean matrixWorldAutoUpdate]</h3>
<p>
Default is true. If set, then the renderer checks every frame if the object and its children need matrix updates.
When it isn't, then you have to maintain all matrices in the object and its children yourself.
</p>

<h3>[property:Boolean castShadow]</h3>
<p>객체가 섀도우 맵으로 렌더링 되는지의 여부입니다. 기본값은 *false*입니다.</p>

Expand Down
6 changes: 6 additions & 0 deletions docs/api/zh/core/Object3D.html
Expand Up @@ -32,6 +32,12 @@ <h2>属性</h2>
<h3>[property:AnimationClip animations]</h3>
<p>Array with object's animation clips.</p>

<h3>[property:Boolean matrixWorldAutoUpdate]</h3>
<p>
Default is true. If set, then the renderer checks every frame if the object and its children need matrix updates.
When it isn't, then you have to maintain all matrices in the object and its children yourself.
</p>

<h3>[property:Boolean castShadow]</h3>
<p>对象是否被渲染到阴影贴图中。默认值为*false*。</p>

Expand Down
6 changes: 0 additions & 6 deletions docs/api/zh/scenes/Scene.html
Expand Up @@ -25,12 +25,6 @@ <h3>[name]()</h3>

<h2>属性</h2>

<h3>[property:Boolean autoUpdate]</h3>
<p>
默认值为true,若设置了这个值,则渲染器会检查每一帧是否需要更新场景及其中物体的矩阵。
当设为false时,你必须亲自手动维护场景中的矩阵。
</p>

<h3>[property:Object background]</h3>
<p>
若不为空,在渲染场景的时候将设置背景,且背景总是首先被渲染的。
Expand Down
4 changes: 2 additions & 2 deletions examples/jsm/effects/AnaglyphEffect.js
Expand Up @@ -131,9 +131,9 @@ class AnaglyphEffect {

const currentRenderTarget = renderer.getRenderTarget();

scene.updateMatrixWorld();
if ( scene.matrixWorldAutoUpdate === true ) scene.updateMatrixWorld();

if ( camera.parent === null ) camera.updateMatrixWorld();
if ( camera.parent === null && camera.matrixWorldAutoUpdate === true ) camera.updateMatrixWorld();

_stereo.update( camera );

Expand Down
6 changes: 3 additions & 3 deletions examples/jsm/effects/OutlineEffect.js
Expand Up @@ -450,11 +450,11 @@ class OutlineEffect {
this.renderOutline = function ( scene, camera ) {

const currentAutoClear = renderer.autoClear;
const currentSceneAutoUpdate = scene.autoUpdate;
const currentSceneAutoUpdate = scene.matrixWorldAutoUpdate;
const currentSceneBackground = scene.background;
const currentShadowMapEnabled = renderer.shadowMap.enabled;

scene.autoUpdate = false;
scene.matrixWorldAutoUpdate = false;
scene.background = null;
renderer.autoClear = false;
renderer.shadowMap.enabled = false;
Expand All @@ -467,7 +467,7 @@ class OutlineEffect {

cleanupCache();

scene.autoUpdate = currentSceneAutoUpdate;
scene.matrixWorldAutoUpdate = currentSceneAutoUpdate;
scene.background = currentSceneBackground;
renderer.autoClear = currentAutoClear;
renderer.shadowMap.enabled = currentShadowMapEnabled;
Expand Down
4 changes: 2 additions & 2 deletions examples/jsm/effects/ParallaxBarrierEffect.js
Expand Up @@ -90,9 +90,9 @@ class ParallaxBarrierEffect {

this.render = function ( scene, camera ) {

scene.updateMatrixWorld();
if ( scene.matrixWorldAutoUpdate === true ) scene.updateMatrixWorld();

if ( camera.parent === null ) camera.updateMatrixWorld();
if ( camera.parent === null && camera.matrixWorldAutoUpdate === true ) camera.updateMatrixWorld();

_stereo.update( camera );

Expand Down
4 changes: 2 additions & 2 deletions examples/jsm/effects/PeppersGhostEffect.js
Expand Up @@ -53,9 +53,9 @@ class PeppersGhostEffect {

this.render = function ( scene, camera ) {

scene.updateMatrixWorld();
if ( scene.matrixWorldAutoUpdate === true ) scene.updateMatrixWorld();

if ( camera.parent === null ) camera.updateMatrixWorld();
if ( camera.parent === null && camera.matrixWorldAutoUpdate === true ) camera.updateMatrixWorld();

camera.matrixWorld.decompose( _position, _quaternion, _scale );

Expand Down
4 changes: 2 additions & 2 deletions examples/jsm/effects/StereoEffect.js
Expand Up @@ -25,9 +25,9 @@ class StereoEffect {

this.render = function ( scene, camera ) {

scene.updateMatrixWorld();
if ( scene.matrixWorldAutoUpdate === true ) scene.updateMatrixWorld();

if ( camera.parent === null ) camera.updateMatrixWorld();
if ( camera.parent === null && camera.matrixWorldAutoUpdate === true ) camera.updateMatrixWorld();

_stereo.update( camera );

Expand Down
4 changes: 2 additions & 2 deletions examples/jsm/renderers/CSS2DRenderer.js
Expand Up @@ -85,8 +85,8 @@ class CSS2DRenderer {

this.render = function ( scene, camera ) {

if ( scene.autoUpdate === true ) scene.updateMatrixWorld();
if ( camera.parent === null ) camera.updateMatrixWorld();
if ( scene.matrixWorldAutoUpdate === true ) scene.updateMatrixWorld();
if ( camera.parent === null && camera.matrixWorldAutoUpdate === true ) camera.updateMatrixWorld();

_viewMatrix.copy( camera.matrixWorldInverse );
_viewProjectionMatrix.multiplyMatrices( camera.projectionMatrix, _viewMatrix );
Expand Down
4 changes: 2 additions & 2 deletions examples/jsm/renderers/CSS3DRenderer.js
Expand Up @@ -132,8 +132,8 @@ class CSS3DRenderer {

}

if ( scene.autoUpdate === true ) scene.updateMatrixWorld();
if ( camera.parent === null ) camera.updateMatrixWorld();
if ( scene.matrixWorldAutoUpdate === true ) scene.updateMatrixWorld();
if ( camera.parent === null && camera.matrixWorldAutoUpdate === true ) camera.updateMatrixWorld();

let tx, ty;

Expand Down
4 changes: 2 additions & 2 deletions examples/jsm/renderers/Projector.js
Expand Up @@ -411,8 +411,8 @@ class Projector {

_renderData.elements.length = 0;

if ( scene.autoUpdate === true ) scene.updateMatrixWorld();
if ( camera.parent === null ) camera.updateMatrixWorld();
if ( scene.matrixWorldAutoUpdate === true ) scene.updateMatrixWorld();
if ( camera.parent === null && camera.matrixWorldAutoUpdate === true ) camera.updateMatrixWorld();

_viewMatrix.copy( camera.matrixWorldInverse );
_viewProjectionMatrix.multiplyMatrices( camera.projectionMatrix, _viewMatrix );
Expand Down
4 changes: 2 additions & 2 deletions examples/jsm/renderers/webgpu/WebGPURenderer.js
Expand Up @@ -242,9 +242,9 @@ class WebGPURenderer {

//

if ( scene.autoUpdate === true ) scene.updateMatrixWorld();
if ( scene.matrixWorldAutoUpdate === true ) scene.updateMatrixWorld();

if ( camera.parent === null ) camera.updateMatrixWorld();
if ( camera.parent === null && camera.matrixWorldAutoUpdate === true ) camera.updateMatrixWorld();

if ( this._info.autoReset === true ) this._info.reset();

Expand Down
19 changes: 16 additions & 3 deletions src/core/Object3D.js
Expand Up @@ -100,6 +100,8 @@ class Object3D extends EventDispatcher {
this.matrixAutoUpdate = Object3D.DefaultMatrixAutoUpdate;
this.matrixWorldNeedsUpdate = false;

this.matrixWorldAutoUpdate = Object3D.DefaultMatrixWorldAutoUpdate; // checked by the renderer

this.layers = new Layers();
this.visible = true;

Expand Down Expand Up @@ -584,7 +586,11 @@ class Object3D extends EventDispatcher {

for ( let i = 0, l = children.length; i < l; i ++ ) {

children[ i ].updateMatrixWorld( force );
if ( children[ i ].matrixWorldAutoUpdate === true || force === true ) {

children[ i ].updateMatrixWorld( force );

}

}

Expand All @@ -594,7 +600,7 @@ class Object3D extends EventDispatcher {

const parent = this.parent;

if ( updateParents === true && parent !== null ) {
if ( updateParents === true && parent !== null && parent.matrixWorldAutoUpdate === true ) {

parent.updateWorldMatrix( true, false );

Expand All @@ -620,7 +626,11 @@ class Object3D extends EventDispatcher {

for ( let i = 0, l = children.length; i < l; i ++ ) {

children[ i ].updateWorldMatrix( false, true );
if ( children[ i ].matrixWorldAutoUpdate === true ) {

children[ i ].updateWorldMatrix( false, true );

}

}

Expand Down Expand Up @@ -893,6 +903,8 @@ class Object3D extends EventDispatcher {
this.matrixAutoUpdate = source.matrixAutoUpdate;
this.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate;

this.matrixWorldAutoUpdate = source.matrixWorldAutoUpdate;

this.layers.mask = source.layers.mask;
this.visible = source.visible;

Expand Down Expand Up @@ -923,5 +935,6 @@ class Object3D extends EventDispatcher {

Object3D.DefaultUp = /*@__PURE__*/ new Vector3( 0, 1, 0 );
Object3D.DefaultMatrixAutoUpdate = true;
Object3D.DefaultMatrixWorldAutoUpdate = true;

export { Object3D };
4 changes: 2 additions & 2 deletions src/renderers/WebGLRenderer.js
Expand Up @@ -955,11 +955,11 @@ function WebGLRenderer( parameters = {} ) {

// update scene graph

if ( scene.autoUpdate === true ) scene.updateMatrixWorld();
if ( scene.matrixWorldAutoUpdate === true ) scene.updateMatrixWorld();

// update camera matrices and frustum

if ( camera.parent === null ) camera.updateMatrixWorld();
if ( camera.parent === null && camera.matrixWorldAutoUpdate === true ) camera.updateMatrixWorld();

if ( xr.enabled === true && xr.isPresenting === true ) {

Expand Down
3 changes: 0 additions & 3 deletions src/scenes/Scene.js
Expand Up @@ -16,8 +16,6 @@ class Scene extends Object3D {

this.overrideMaterial = null;

this.autoUpdate = true; // checked by the renderer

if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) {

__THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'observe', { detail: this } ) );
Expand All @@ -36,7 +34,6 @@ class Scene extends Object3D {

if ( source.overrideMaterial !== null ) this.overrideMaterial = source.overrideMaterial.clone();

this.autoUpdate = source.autoUpdate;
this.matrixAutoUpdate = source.matrixAutoUpdate;

return this;
Expand Down
37 changes: 37 additions & 0 deletions test/unit/src/core/Object3D.tests.js
Expand Up @@ -786,8 +786,27 @@ export default QUnit.module( 'Core', () => {
0, 0, 0, 1
], 'No effect to child world matrix if parent local and world matrices and child local matrix are not updated' );

// -- matrixWorldAutoUpdate = false test

parent.position.set( 3, 2, 1 );
parent.updateMatrix();
parent.matrixWorldNeedsUpdate = false;

child.matrixWorldAutoUpdate = false;
parent.updateMatrixWorld();

assert.deepEqual( child.matrixWorld.elements, [
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
], 'No effect to child world matrix when matrixWorldAutoUpdate is set to false' );

// -- Propagation to children world matrices test

child.position.set( 0, 0, 0 );
parent.position.set( 1, 2, 3 );
child.matrixWorldAutoUpdate = true;
parent.matrixAutoUpdate = true;
parent.updateMatrixWorld();

Expand Down Expand Up @@ -1013,6 +1032,24 @@ export default QUnit.module( 'Core', () => {
m.setPosition( parent.position ).elements,
'object\'s world matrix is updated even if matrixAutoUpdate is false' );

// object.matrixWorldAutoUpdate = false test

parent.matrixWorldAutoUpdate = false;
child.matrixWorldAutoUpdate = false;

child.matrixWorld.identity();
parent.matrixWorld.identity();

object.updateWorldMatrix( true, true );

assert.deepEqual( child.matrixWorld.elements,
m.identity().elements,
'No effect to child\'s world matrix if matrixWorldAutoUpdate is false' );

assert.deepEqual( parent.matrixWorld.elements,
m.identity().elements,
'No effect to parent\'s world matrix if matrixWorldAutoUpdate is false' );

} );

QUnit.test( 'toJSON', ( assert ) => {
Expand Down