فهرست منبع

Object3D: granular control of matrix updates with matrixWorldAutoUpdate (#24028)

* feat(Object3D): object-level `autoUpdate`

* chore: update docs

* fix(Object3D): respect `autoUpdate` in updateMatrixWorld

* fix(renderers): respect `camera.autoUpdate` on render

* Use strict equal codestyle, respect autoUpdate with `updateParents`

* Object3D: rename autoUpdate to matrixWorldAutoUpdate

* Global: respect Object3D.matrixWorldAutoUpdate
Cody Bennett 2 سال پیش
والد
کامیت
d091564e02

+ 6 - 0
docs/api/en/core/Object3D.html

@@ -32,6 +32,12 @@
 		<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>
 

+ 0 - 6
docs/api/en/scenes/Scene.html

@@ -24,12 +24,6 @@
 
 		<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.

+ 6 - 0
docs/api/ko/core/Object3D.html

@@ -30,6 +30,12 @@
 		<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>
 

+ 6 - 0
docs/api/zh/core/Object3D.html

@@ -32,6 +32,12 @@
 	<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>
 

+ 0 - 6
docs/api/zh/scenes/Scene.html

@@ -25,12 +25,6 @@
 
 		<h2>属性</h2>
 
-		<h3>[property:Boolean autoUpdate]</h3>
-		<p>
-			默认值为true,若设置了这个值,则渲染器会检查每一帧是否需要更新场景及其中物体的矩阵。
-			当设为false时,你必须亲自手动维护场景中的矩阵。
-		</p>
-
 		<h3>[property:Object background]</h3>
 		<p>
 		若不为空,在渲染场景的时候将设置背景,且背景总是首先被渲染的。

+ 2 - 2
examples/jsm/effects/AnaglyphEffect.js

@@ -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 );
 

+ 3 - 3
examples/jsm/effects/OutlineEffect.js

@@ -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;
@@ -467,7 +467,7 @@ class OutlineEffect {
 
 			cleanupCache();
 
-			scene.autoUpdate = currentSceneAutoUpdate;
+			scene.matrixWorldAutoUpdate = currentSceneAutoUpdate;
 			scene.background = currentSceneBackground;
 			renderer.autoClear = currentAutoClear;
 			renderer.shadowMap.enabled = currentShadowMapEnabled;

+ 2 - 2
examples/jsm/effects/ParallaxBarrierEffect.js

@@ -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 );
 

+ 2 - 2
examples/jsm/effects/PeppersGhostEffect.js

@@ -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 );
 

+ 2 - 2
examples/jsm/effects/StereoEffect.js

@@ -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 );
 

+ 2 - 2
examples/jsm/renderers/CSS2DRenderer.js

@@ -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 );

+ 2 - 2
examples/jsm/renderers/CSS3DRenderer.js

@@ -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;
 

+ 2 - 2
examples/jsm/renderers/Projector.js

@@ -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 );

+ 2 - 2
examples/jsm/renderers/webgpu/WebGPURenderer.js

@@ -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();
 

+ 16 - 3
src/core/Object3D.js

@@ -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;
 
@@ -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 );
+
+			}
 
 		}
 
@@ -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 );
 
@@ -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 );
+
+				}
 
 			}
 
@@ -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;
 
@@ -923,5 +935,6 @@ class Object3D extends EventDispatcher {
 
 Object3D.DefaultUp = /*@__PURE__*/ new Vector3( 0, 1, 0 );
 Object3D.DefaultMatrixAutoUpdate = true;
+Object3D.DefaultMatrixWorldAutoUpdate = true;
 
 export { Object3D };

+ 2 - 2
src/renderers/WebGLRenderer.js

@@ -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 ) {
 

+ 0 - 3
src/scenes/Scene.js

@@ -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 } ) );
@@ -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;

+ 37 - 0
test/unit/src/core/Object3D.tests.js

@@ -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();
 
@@ -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 ) => {