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: matrixNeedsUpdate and matrix/orientation optimizations #28534

Draft
wants to merge 17 commits into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions docs/api/ar/core/Object3D.html
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,13 @@ <h3>[property:Boolean matrixAutoUpdate]</h3>
quaternion) والحجم في كل إطار وأيضًا يعيد حساب خصائص matrixWorld
. الافتراضي هو [page:Object3D.DEFAULT_MATRIX_AUTO_UPDATE] (true).
</p>

<h3>[property:Boolean matrixNeedsUpdate]</h3>
<p>
When this is set, it calculates the matrix of position, (rotation or
quaternion) and scale in that frame, matrixWorld for itself and descendants,
and resets this property to false. Default is `false`.
</p>

<h3>[property:Matrix4 matrixWorld]</h3>
<p>
Expand Down
7 changes: 7 additions & 0 deletions docs/api/en/core/Object3D.html
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,13 @@ <h3>[property:Boolean matrixAutoUpdate]</h3>
property. Default is [page:Object3D.DEFAULT_MATRIX_AUTO_UPDATE] (true).
</p>

<h3>[property:Boolean matrixNeedsUpdate]</h3>
<p>
When this is set, it calculates the matrix of position, (rotation or
quaternion) and scale in that frame, matrixWorld for itself and descendants,
and resets this property to false. Default is `false`.
</p>

<h3>[property:Matrix4 matrixWorld]</h3>
<p>
The global transform of the object. If the Object3D has no parent, then
Expand Down
7 changes: 7 additions & 0 deletions docs/api/it/core/Object3D.html
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,13 @@ <h3>[property:Boolean matrixAutoUpdate]</h3>
ridimensiona ogni fotogramma ed inoltre ricalcola la proprietà matrixWorld. L'impostazione predefinita è [page:Object3D.DEFAULT_MATRIX_AUTO_UPDATE] (true).
</p>

<h3>[property:Boolean matrixNeedsUpdate]</h3>
<p>
When this is set, it calculates the matrix of position, (rotation or
quaternion) and scale in that frame, matrixWorld for itself and descendants,
and resets this property to false. Default is `false`.
</p>

<h3>[property:Matrix4 matrixWorld]</h3>
<p>
La trasformazione globale dell'oggetto. Se l'Object3D non ha un genitore, è identico al [page:.matrix] della trasformazione locale.
Expand Down
7 changes: 7 additions & 0 deletions docs/api/ko/core/Object3D.html
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,13 @@ <h3>[property:Boolean matrixAutoUpdate]</h3>
기본값은 [page:Object3D.DEFAULT_MATRIX_AUTO_UPDATE] (true)입니다.
</p>

<h3>[property:Boolean matrixNeedsUpdate]</h3>
<p>
When this is set, it calculates the matrix of position, (rotation or
quaternion) and scale in that frame, matrixWorld for itself and descendants,
and resets this property to false. Default is `false`.
</p>

<h3>[property:Matrix4 matrixWorld]</h3>
<p>
객체의 글로벌 변형입니다. Object3D가 부모를 가지고 있지 않다면, 로컬 변형 [page:.matrix]와 동일합니다.
Expand Down
7 changes: 7 additions & 0 deletions docs/api/zh/core/Object3D.html
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,13 @@ <h3>[property:Boolean matrixAutoUpdate]</h3>
当这个属性设置了之后,它将计算每一帧的位移、旋转(四元变换)和缩放矩阵,并重新计算matrixWorld属性。默认值是[page:Object3D.DEFAULT_MATRIX_AUTO_UPDATE] (true)。
</p>

<h3>[property:Boolean matrixNeedsUpdate]</h3>
<p>
When this is set, it calculates the matrix of position, (rotation or
quaternion) and scale in that frame, matrixWorld for itself and descendants,
and resets this property to false. Default is `false`.
</p>

<h3>[property:Matrix4 matrixWorld]</h3>
<p>
物体的世界变换。若这个Object3D没有父级,则它将和local transform [page:.matrix](局部变换矩阵)相同。
Expand Down
127 changes: 117 additions & 10 deletions src/core/Object3D.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,59 @@ const _removedEvent = { type: 'removed' };
const _childaddedEvent = { type: 'childadded', child: null };
const _childremovedEvent = { type: 'childremoved', child: null };

function listenToProperties( object, properties, onReadCallback, onWriteCallback ) {

for ( let i = 0; i < properties.length; i ++ ) {

const property = properties[ i ];
let _value = object[ property ];

Object.defineProperty( object, property, {

get() {

if ( onReadCallback ) onReadCallback();

return _value;

},
set( value ) {

_value = value;

if ( onWriteCallback ) onWriteCallback();

}

} );

}

}

function listenToMethods( object, onChangeCallback ) {

const properties = Object.getOwnPropertyNames( object.constructor.prototype );

for ( let i = 0; i < properties.length; i ++ ) {

const property = properties[ i ];
const value = object[ property ];

if ( property === 'constructor' || typeof value !== 'function' ) continue;

object[ property ] = function () {

onChangeCallback();

return value.apply( this, arguments );

};

}

}

class Object3D extends EventDispatcher {

constructor() {
Expand All @@ -53,20 +106,68 @@ class Object3D extends EventDispatcher {
const quaternion = new Quaternion();
const scale = new Vector3( 1, 1, 1 );

function onRotationChange() {
const matrix = new Matrix4();
const matrixWorld = new Matrix4();

const self = this;
let rotationNeedsUpdate = false;
let quaternionNeedsUpdate = false;

quaternion.setFromEuler( rotation, false );
function onWrite() {

self.matrixNeedsUpdate = true;

}

function onQuaternionChange() {
function onRotationWrite() {

rotation.setFromQuaternion( quaternion, undefined, false );
self.matrixNeedsUpdate = true;
rotationNeedsUpdate = true;

}

rotation._onChange( onRotationChange );
quaternion._onChange( onQuaternionChange );
function onRotationRead() {

if ( quaternionNeedsUpdate === true ) {

quaternionNeedsUpdate = false;
rotation.setFromQuaternion( quaternion, undefined );
rotationNeedsUpdate = false;

}

}

function onQuaternionWrite() {

self.matrixNeedsUpdate = true;
quaternionNeedsUpdate = true;

}

function onQuaternionRead() {

if ( rotationNeedsUpdate === true ) {

rotationNeedsUpdate = false;
quaternion.setFromEuler( rotation );
quaternionNeedsUpdate = false;

}

}

function onMatrixChange() {

self.matrixWorldNeedsUpdate = true;

}

listenToProperties( position, [ 'x', 'y', 'z' ], undefined, onWrite );
listenToProperties( rotation, [ 'x', 'y', 'z', 'order' ], onRotationRead, onRotationWrite );
listenToProperties( quaternion, [ 'x', 'y', 'z', 'w' ], onQuaternionRead, onQuaternionWrite );
listenToProperties( scale, [ 'x', 'y', 'z' ], undefined, onWrite );
listenToMethods( matrix, onMatrixChange );
Comment on lines +166 to +170
Copy link
Contributor Author

@CodyJasonBennett CodyJasonBennett Jun 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

listenToProperties adds an on-read and on-write callback to named keys (not a deopt), which we use here to set matrixNeedsUpdate when transform properties are modified. On-read is used to convert quaternion/rotation like before, but only if their counterpart is dirty when read, preventing many unneeded conversions on mutation (which can be many times). Notably, if users stick to quaternion, they will avoid this conversion entirely. This is nice so we don't have to modify math classes like before.

listenToMethods I have as a special case for the local matrix whose members would be deopt if I just listened to all elements in its array. This is because array accessors are not named and unstable, so v8 would need to create a layer of indirection to make them stable. We want matrixWorldNeedsUpdate to be set whenever the local matrix updates to preserve existing behavior, so I instead handle the cases where local matrix is modified by its methods (which are named keys), and don't handle the case where matrix.elements is mutated directly (matrixWorldNeedsUpdate has to then be set by the user). This keeps us on the fast path for common usage without breaking APIs who expected a 1-1 relationship between local and world matrix updates.


Object.defineProperties( this, {
position: {
Expand Down Expand Up @@ -97,12 +198,13 @@ class Object3D extends EventDispatcher {
}
} );

this.matrix = new Matrix4();
this.matrixWorld = new Matrix4();
this.matrix = matrix;
this.matrixWorld = matrixWorld;

this.matrixAutoUpdate = Object3D.DEFAULT_MATRIX_AUTO_UPDATE;

this.matrixWorldAutoUpdate = Object3D.DEFAULT_MATRIX_WORLD_AUTO_UPDATE; // checked by the renderer
this.matrixNeedsUpdate = false;
this.matrixWorldNeedsUpdate = false;

this.layers = new Layers();
Expand Down Expand Up @@ -577,9 +679,13 @@ class Object3D extends EventDispatcher {

updateMatrix() {

this.matrix.compose( this.position, this.quaternion, this.scale );
if ( this.matrixNeedsUpdate === true ) {

this.matrix.compose( this.position, this.quaternion, this.scale );
this.matrixNeedsUpdate = false;
this.matrixWorldNeedsUpdate = true;

this.matrixWorldNeedsUpdate = true;
}

}

Expand Down Expand Up @@ -985,6 +1091,7 @@ class Object3D extends EventDispatcher {
this.matrixAutoUpdate = source.matrixAutoUpdate;

this.matrixWorldAutoUpdate = source.matrixWorldAutoUpdate;
this.matrixNeedsUpdate = source.matrixNeedsUpdate;
this.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate;

this.layers.mask = source.layers.mask;
Expand Down
4 changes: 2 additions & 2 deletions src/helpers/CameraHelper.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,8 @@ class CameraHelper extends LineSegments {
this.camera = camera;
if ( this.camera.updateProjectionMatrix ) this.camera.updateProjectionMatrix();

this.matrix = camera.matrixWorld;
this.matrixAutoUpdate = false;
this.matrixWorld = camera.matrixWorld;
this.matrixWorldAutoUpdate = false;
Comment on lines -110 to +111
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This relied on the fact that world matrices were always updated even transiently. Since #28533, we can do this instead.


this.pointMap = pointMap;

Expand Down
4 changes: 2 additions & 2 deletions src/helpers/DirectionalLightHelper.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ class DirectionalLightHelper extends Object3D {

this.light = light;

this.matrix = light.matrixWorld;
this.matrixAutoUpdate = false;
this.matrixWorld = light.matrixWorld;
this.matrixWorldAutoUpdate = false;

this.color = color;

Expand Down
4 changes: 2 additions & 2 deletions src/helpers/HemisphereLightHelper.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ class HemisphereLightHelper extends Object3D {

this.light = light;

this.matrix = light.matrixWorld;
this.matrixAutoUpdate = false;
this.matrixWorld = light.matrixWorld;
this.matrixWorldAutoUpdate = false;

this.color = color;

Expand Down
4 changes: 2 additions & 2 deletions src/helpers/PointLightHelper.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ class PointLightHelper extends Mesh {

this.type = 'PointLightHelper';

this.matrix = this.light.matrixWorld;
this.matrixAutoUpdate = false;
this.matrixWorld = this.light.matrixWorld;
this.matrixWorldAutoUpdate = false;

this.update();

Expand Down
4 changes: 2 additions & 2 deletions src/helpers/SkeletonHelper.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ class SkeletonHelper extends LineSegments {
this.root = object;
this.bones = bones;

this.matrix = object.matrixWorld;
this.matrixAutoUpdate = false;
this.matrixWorld = object.matrixWorld;
this.matrixWorldAutoUpdate = false;

}

Expand Down
1 change: 1 addition & 0 deletions src/loaders/ObjectLoader.js
Original file line number Diff line number Diff line change
Expand Up @@ -1015,6 +1015,7 @@ class ObjectLoader extends Loader {

if ( data.matrixAutoUpdate !== undefined ) object.matrixAutoUpdate = data.matrixAutoUpdate;
if ( object.matrixAutoUpdate ) object.matrix.decompose( object.position, object.quaternion, object.scale );
object.matrixNeedsUpdate = false;

} else {

Expand Down
Loading
Loading