1
1
import { MathUtil , Matrix , Matrix3x3 , Quaternion , Vector3 } from "@galacean/engine-math" ;
2
2
import { BoolUpdateFlag } from "./BoolUpdateFlag" ;
3
- import { deepClone , ignoreClone } from "./clone/CloneManager" ;
4
3
import { Component } from "./Component" ;
5
4
import { Entity } from "./Entity" ;
6
5
import { UpdateFlagManager } from "./UpdateFlagManager" ;
6
+ import { assignmentClone , deepClone , ignoreClone } from "./clone/CloneManager" ;
7
7
8
8
/**
9
9
* Used to implement transformation related functions.
@@ -27,12 +27,16 @@ export class Transform extends Component {
27
27
private _rotationQuaternion : Quaternion = new Quaternion ( ) ;
28
28
@deepClone
29
29
private _scale : Vector3 = new Vector3 ( 1 , 1 , 1 ) ;
30
+ @assignmentClone
31
+ private _localUniformScaling : boolean = true ;
30
32
@deepClone
31
33
private _worldPosition : Vector3 = new Vector3 ( ) ;
32
34
@deepClone
33
35
private _worldRotation : Vector3 = new Vector3 ( ) ;
34
36
@deepClone
35
37
private _worldRotationQuaternion : Quaternion = new Quaternion ( ) ;
38
+ @assignmentClone
39
+ private _worldUniformScaling : boolean = true ;
36
40
@deepClone
37
41
private _lossyWorldScale : Vector3 = new Vector3 ( 1 , 1 , 1 ) ;
38
42
@deepClone
@@ -225,12 +229,13 @@ export class Transform extends Component {
225
229
226
230
/**
227
231
* Local lossy scaling.
228
- * @remarks The value obtained may not be correct under certain conditions(for example, the parent node has scaling,
229
- * and the child node has a rotation), the scaling will be tilted. Vector3 cannot be used to correctly represent the scaling. Must use Matrix3x3.
232
+ * @remarks The value obtained may not be correct under certain conditions(for example, the parent node has non-uniform world scaling,
233
+ * and the child node has a rotation), the scaling will be tilted.
230
234
*/
231
235
get lossyWorldScale ( ) : Vector3 {
232
236
if ( this . _isContainDirtyFlag ( TransformModifyFlags . WorldScale ) ) {
233
237
if ( this . _getParentTransform ( ) ) {
238
+ // Vector3 cannot be used to correctly represent the scaling. Must use Matrix3x3
234
239
const scaleMat = this . _getScaleMatrix ( ) ;
235
240
const e = scaleMat . elements ;
236
241
this . _lossyWorldScale . set ( e [ 0 ] , e [ 4 ] , e [ 8 ] ) ;
@@ -258,20 +263,26 @@ export class Transform extends Component {
258
263
if ( this . _localMatrix !== value ) {
259
264
this . _localMatrix . copyFrom ( value ) ;
260
265
}
261
-
266
+ const { _position : position , _rotationQuaternion : rotationQuaternion , _scale : scale } = this ;
262
267
// @ts -ignore
263
- this . _position . _onValueChanged = this . _rotationQuaternion . _onValueChanged = this . _scale . _onValueChanged = null ;
264
- this . _localMatrix . decompose ( this . _position , this . _rotationQuaternion , this . _scale ) ;
268
+ position . _onValueChanged = rotationQuaternion . _onValueChanged = scale . _onValueChanged = null ;
269
+ this . _localMatrix . decompose ( position , rotationQuaternion , scale ) ;
265
270
// @ts -ignore
266
- this . _position . _onValueChanged = this . _onPositionChanged ;
271
+ position . _onValueChanged = this . _onPositionChanged ;
267
272
// @ts -ignore
268
- this . _rotationQuaternion . _onValueChanged = this . _onRotationQuaternionChanged ;
273
+ rotationQuaternion . _onValueChanged = this . _onRotationQuaternionChanged ;
269
274
// @ts -ignore
270
- this . _scale . _onValueChanged = this . _onScaleChanged ;
275
+ scale . _onValueChanged = this . _onScaleChanged ;
271
276
272
277
this . _setDirtyFlagTrue ( TransformModifyFlags . LocalEuler ) ;
273
278
this . _setDirtyFlagFalse ( TransformModifyFlags . LocalMatrix | TransformModifyFlags . LocalQuat ) ;
274
- this . _updateAllWorldFlag ( ) ;
279
+ const localUniformScaling = scale . x === scale . y && scale . y === scale . z ;
280
+ if ( this . _localUniformScaling !== localUniformScaling ) {
281
+ this . _localUniformScaling = localUniformScaling ;
282
+ this . _updateAllWorldFlag ( TransformModifyFlags . WmWpWeWqWsWus ) ;
283
+ } else {
284
+ this . _updateAllWorldFlag ( TransformModifyFlags . WmWpWeWqWs ) ;
285
+ }
275
286
}
276
287
277
288
/**
@@ -563,7 +574,7 @@ export class Transform extends Component {
563
574
*/
564
575
_parentChange ( ) : void {
565
576
this . _isParentDirty = true ;
566
- this . _updateAllWorldFlag ( ) ;
577
+ this . _updateAllWorldFlag ( TransformModifyFlags . WmWpWeWqWsWus ) ;
567
578
}
568
579
569
580
/**
@@ -603,9 +614,9 @@ export class Transform extends Component {
603
614
private _updateWorldPositionFlag ( ) : void {
604
615
if ( ! this . _isContainDirtyFlags ( TransformModifyFlags . WmWp ) ) {
605
616
this . _worldAssociatedChange ( TransformModifyFlags . WmWp ) ;
606
- const nodeChildren = this . _entity . _children ;
607
- for ( let i : number = 0 , n : number = nodeChildren . length ; i < n ; i ++ ) {
608
- nodeChildren [ i ] . transform ?. _updateWorldPositionFlag ( ) ;
617
+ const children = this . _entity . _children ;
618
+ for ( let i = 0 , n = children . length ; i < n ; i ++ ) {
619
+ children [ i ] . transform ?. _updateWorldPositionFlag ( ) ;
609
620
}
610
621
}
611
622
}
@@ -615,14 +626,19 @@ export class Transform extends Component {
615
626
* Get worldPosition: Will trigger the worldMatrix, local position update of itself and the worldMatrix update of all parent entities.
616
627
* Get worldRotationQuaternion: Will trigger the world rotation (in quaternion) update of itself and all parent entities.
617
628
* Get worldRotation: Will trigger the world rotation(in euler and quaternion) update of itself and world rotation(in quaternion) update of all parent entities.
629
+ * Get worldScale: Will trigger the scaling update of itself and all parent entities.
618
630
* In summary, any update of related variables will cause the dirty mark of one of the full process (worldMatrix or worldRotationQuaternion) to be false.
619
631
*/
620
632
private _updateWorldRotationFlag ( ) {
621
- if ( ! this . _isContainDirtyFlags ( TransformModifyFlags . WmWeWq ) ) {
622
- this . _worldAssociatedChange ( TransformModifyFlags . WmWeWq ) ;
623
- const nodeChildren = this . _entity . _children ;
624
- for ( let i : number = 0 , n : number = nodeChildren . length ; i < n ; i ++ ) {
625
- nodeChildren [ i ] . transform ?. _updateWorldPositionAndRotationFlag ( ) ; // Rotation update of parent entity will trigger world position and rotation update of all child entity.
633
+ const parent = this . _getParentTransform ( ) ;
634
+ const parentWorldUniformScaling = parent ? parent . _getWorldUniformScaling ( ) : true ;
635
+ let flags = parentWorldUniformScaling ? TransformModifyFlags . WmWeWq : TransformModifyFlags . WmWeWqWs ;
636
+ if ( ! this . _isContainDirtyFlags ( flags ) ) {
637
+ this . _worldAssociatedChange ( flags ) ;
638
+ flags = this . _getWorldUniformScaling ( ) ? TransformModifyFlags . WmWpWeWq : TransformModifyFlags . WmWpWeWqWs ;
639
+ const children = this . _entity . _children ;
640
+ for ( let i = 0 , n = children . length ; i < n ; i ++ ) {
641
+ children [ i ] . transform ?. _updateWorldPositionAndRotationFlag ( flags ) ; // Rotation update of parent entity will trigger world position, rotation and scale update of all child entity.
626
642
}
627
643
}
628
644
}
@@ -632,14 +648,17 @@ export class Transform extends Component {
632
648
* Get worldPosition: Will trigger the worldMatrix, local position update of itself and the worldMatrix update of all parent entities.
633
649
* Get worldRotationQuaternion: Will trigger the world rotation (in quaternion) update of itself and all parent entities.
634
650
* Get worldRotation: Will trigger the world rotation(in euler and quaternion) update of itself and world rotation(in quaternion) update of all parent entities.
651
+ * Get worldScale: Will trigger the scaling update of itself and all parent entities.
635
652
* In summary, any update of related variables will cause the dirty mark of one of the full process (worldMatrix or worldRotationQuaternion) to be false.
636
- */
637
- private _updateWorldPositionAndRotationFlag ( ) {
638
- if ( ! this . _isContainDirtyFlags ( TransformModifyFlags . WmWpWeWq ) ) {
639
- this . _worldAssociatedChange ( TransformModifyFlags . WmWpWeWq ) ;
640
- const nodeChildren = this . _entity . _children ;
641
- for ( let i : number = 0 , n : number = nodeChildren . length ; i < n ; i ++ ) {
642
- nodeChildren [ i ] . transform ?. _updateWorldPositionAndRotationFlag ( ) ;
653
+ * @param flags - Dirty flag
654
+ */
655
+ private _updateWorldPositionAndRotationFlag ( flags : TransformModifyFlags ) : void {
656
+ if ( ! this . _isContainDirtyFlags ( flags ) ) {
657
+ this . _worldAssociatedChange ( flags ) ;
658
+ flags = this . _getWorldUniformScaling ( ) ? TransformModifyFlags . WmWpWeWq : TransformModifyFlags . WmWpWeWqWs ;
659
+ const children = this . _entity . _children ;
660
+ for ( let i = 0 , n = children . length ; i < n ; i ++ ) {
661
+ children [ i ] . transform ?. _updateWorldPositionAndRotationFlag ( flags ) ;
643
662
}
644
663
}
645
664
}
@@ -649,13 +668,15 @@ export class Transform extends Component {
649
668
* Get worldPosition: Will trigger the worldMatrix, local position update of itself and the worldMatrix update of all parent entities.
650
669
* Get worldScale: Will trigger the scaling update of itself and all parent entities.
651
670
* In summary, any update of related variables will cause the dirty mark of one of the full process (worldMatrix) to be false.
652
- */
653
- private _updateWorldScaleFlag ( ) {
654
- if ( ! this . _isContainDirtyFlags ( TransformModifyFlags . WmWs ) ) {
655
- this . _worldAssociatedChange ( TransformModifyFlags . WmWs ) ;
656
- const nodeChildren = this . _entity . _children ;
657
- for ( let i : number = 0 , n : number = nodeChildren . length ; i < n ; i ++ ) {
658
- nodeChildren [ i ] . transform ?. _updateWorldPositionAndScaleFlag ( ) ;
671
+ * @param flags - Dirty flag
672
+ */
673
+ private _updateWorldScaleFlag ( flags : TransformModifyFlags ) : void {
674
+ if ( ! this . _isContainDirtyFlags ( flags ) ) {
675
+ this . _worldAssociatedChange ( flags ) ;
676
+ flags |= TransformModifyFlags . WorldPosition ;
677
+ const children = this . _entity . _children ;
678
+ for ( let i = 0 , n = children . length ; i < n ; i ++ ) {
679
+ children [ i ] . transform ?. _updateWorldPositionAndScaleFlag ( flags ) ;
659
680
}
660
681
}
661
682
}
@@ -665,26 +686,28 @@ export class Transform extends Component {
665
686
* Get worldPosition: Will trigger the worldMatrix, local position update of itself and the worldMatrix update of all parent entities.
666
687
* Get worldScale: Will trigger the scaling update of itself and all parent entities.
667
688
* In summary, any update of related variables will cause the dirty mark of one of the full process (worldMatrix) to be false.
668
- */
669
- private _updateWorldPositionAndScaleFlag ( ) : void {
670
- if ( ! this . _isContainDirtyFlags ( TransformModifyFlags . WmWpWs ) ) {
671
- this . _worldAssociatedChange ( TransformModifyFlags . WmWpWs ) ;
672
- const nodeChildren = this . _entity . _children ;
673
- for ( let i : number = 0 , n : number = nodeChildren . length ; i < n ; i ++ ) {
674
- nodeChildren [ i ] . transform ?. _updateWorldPositionAndScaleFlag ( ) ;
689
+ * @param flags - Dirty flag
690
+ */
691
+ private _updateWorldPositionAndScaleFlag ( flags : TransformModifyFlags ) : void {
692
+ if ( ! this . _isContainDirtyFlags ( flags ) ) {
693
+ this . _worldAssociatedChange ( flags ) ;
694
+ const children = this . _entity . _children ;
695
+ for ( let i = 0 , n = children . length ; i < n ; i ++ ) {
696
+ children [ i ] . transform ?. _updateWorldPositionAndScaleFlag ( flags ) ;
675
697
}
676
698
}
677
699
}
678
700
679
701
/**
680
702
* Update all world transform property dirty flag, the principle is the same as above.
681
- */
682
- private _updateAllWorldFlag ( ) : void {
683
- if ( ! this . _isContainDirtyFlags ( TransformModifyFlags . WmWpWeWqWs ) ) {
684
- this . _worldAssociatedChange ( TransformModifyFlags . WmWpWeWqWs ) ;
685
- const nodeChildren = this . _entity . _children ;
686
- for ( let i : number = 0 , n : number = nodeChildren . length ; i < n ; i ++ ) {
687
- nodeChildren [ i ] . transform ?. _updateAllWorldFlag ( ) ;
703
+ * @param flags - Dirty flag
704
+ */
705
+ private _updateAllWorldFlag ( flags : TransformModifyFlags ) : void {
706
+ if ( ! this . _isContainDirtyFlags ( flags ) ) {
707
+ this . _worldAssociatedChange ( flags ) ;
708
+ const children = this . _entity . _children ;
709
+ for ( let i = 0 , n = children . length ; i < n ; i ++ ) {
710
+ children [ i ] . transform ?. _updateAllWorldFlag ( flags ) ;
688
711
}
689
712
}
690
713
}
@@ -739,7 +762,7 @@ export class Transform extends Component {
739
762
740
763
private _worldAssociatedChange ( type : number ) : void {
741
764
this . _dirtyFlag |= type ;
742
- this . _updateFlagManager . dispatch ( TransformModifyFlags . WorldMatrix ) ;
765
+ this . _updateFlagManager . dispatch ( type ) ;
743
766
}
744
767
745
768
private _rotateByQuat ( rotateQuat : Quaternion , relativeToLocal : boolean ) : void {
@@ -828,8 +851,29 @@ export class Transform extends Component {
828
851
829
852
@ignoreClone
830
853
private _onScaleChanged ( ) : void {
854
+ const { x, y, z } = this . _scale ;
831
855
this . _setDirtyFlagTrue ( TransformModifyFlags . LocalMatrix ) ;
832
- this . _updateWorldScaleFlag ( ) ;
856
+ const localUniformScaling = x == y && y == z ;
857
+ if ( this . _localUniformScaling !== localUniformScaling ) {
858
+ this . _localUniformScaling = localUniformScaling ;
859
+ this . _updateWorldScaleFlag ( TransformModifyFlags . WmWsWus ) ;
860
+ } else {
861
+ this . _updateWorldScaleFlag ( TransformModifyFlags . WmWs ) ;
862
+ }
863
+ }
864
+
865
+ private _getWorldUniformScaling ( ) : boolean {
866
+ if ( this . _isContainDirtyFlag ( TransformModifyFlags . IsWorldUniformScaling ) ) {
867
+ const localUniformScaling = this . _localUniformScaling ;
868
+ if ( localUniformScaling ) {
869
+ const parent = this . _getParentTransform ( ) ;
870
+ this . _worldUniformScaling = localUniformScaling && ( parent ? parent . _getWorldUniformScaling ( ) : true ) ;
871
+ } else {
872
+ this . _worldUniformScaling = false ;
873
+ }
874
+ this . _setDirtyFlagFalse ( TransformModifyFlags . IsWorldUniformScaling ) ;
875
+ }
876
+ return this . _worldUniformScaling ;
833
877
}
834
878
}
835
879
@@ -846,16 +890,27 @@ export enum TransformModifyFlags {
846
890
LocalMatrix = 0x40 ,
847
891
WorldMatrix = 0x80 ,
848
892
893
+ /** This is an internal flag used to assist in determining the dispatch
894
+ * of world scaling dirty flags in the case of non-uniform scaling.
895
+ */
896
+ IsWorldUniformScaling = 0x100 ,
897
+
849
898
/** WorldMatrix | WorldPosition */
850
899
WmWp = 0x84 ,
851
900
/** WorldMatrix | WorldEuler | WorldQuat */
852
901
WmWeWq = 0x98 ,
902
+ /** WorldMatrix | WorldEuler | WorldQuat | WorldScale*/
903
+ WmWeWqWs = 0xb8 ,
853
904
/** WorldMatrix | WorldPosition | WorldEuler | WorldQuat */
854
905
WmWpWeWq = 0x9c ,
855
906
/** WorldMatrix | WorldScale */
856
907
WmWs = 0xa0 ,
908
+ /** WorldMatrix | WorldScale | WorldUniformScaling */
909
+ WmWsWus = 0x1a0 ,
857
910
/** WorldMatrix | WorldPosition | WorldScale */
858
911
WmWpWs = 0xa4 ,
859
912
/** WorldMatrix | WorldPosition | WorldEuler | WorldQuat | WorldScale */
860
- WmWpWeWqWs = 0xbc
913
+ WmWpWeWqWs = 0xbc ,
914
+ /** WorldMatrix | WorldPosition | WorldEuler | WorldQuat | WorldScale | WorldUniformScaling */
915
+ WmWpWeWqWsWus = 0x1bc
861
916
}
0 commit comments