@onerjs/core 8.42.3 → 8.42.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Animations/animatorAvatar.d.ts +31 -16
- package/Animations/animatorAvatar.js +138 -86
- package/Animations/animatorAvatar.js.map +1 -1
- package/AudioV2/abstractAudio/abstractSound.js +3 -4
- package/AudioV2/abstractAudio/abstractSound.js.map +1 -1
- package/AudioV2/abstractAudio/audioBus.js +3 -0
- package/AudioV2/abstractAudio/audioBus.js.map +1 -1
- package/AudioV2/abstractAudio/streamingSoundInstance.d.ts +1 -1
- package/AudioV2/abstractAudio/streamingSoundInstance.js +2 -2
- package/AudioV2/abstractAudio/streamingSoundInstance.js.map +1 -1
- package/AudioV2/webAudio/components/spatialWebAudioUpdaterComponent.d.ts +4 -1
- package/AudioV2/webAudio/components/spatialWebAudioUpdaterComponent.js +5 -2
- package/AudioV2/webAudio/components/spatialWebAudioUpdaterComponent.js.map +1 -1
- package/AudioV2/webAudio/webAudioStaticSound.js +3 -3
- package/AudioV2/webAudio/webAudioStaticSound.js.map +1 -1
- package/AudioV2/webAudio/webAudioStreamingSound.js +2 -4
- package/AudioV2/webAudio/webAudioStreamingSound.js.map +1 -1
- package/Cameras/Inputs/geospatialCameraKeyboardInput.js +6 -3
- package/Cameras/Inputs/geospatialCameraKeyboardInput.js.map +1 -1
- package/Cameras/geospatialCamera.d.ts +4 -2
- package/Cameras/geospatialCamera.js +10 -8
- package/Cameras/geospatialCamera.js.map +1 -1
- package/Cameras/geospatialCameraMovement.d.ts +11 -1
- package/Cameras/geospatialCameraMovement.js +26 -6
- package/Cameras/geospatialCameraMovement.js.map +1 -1
- package/Debug/physicsViewer.d.ts +1 -0
- package/Debug/physicsViewer.js +1 -0
- package/Debug/physicsViewer.js.map +1 -1
- package/Engines/WebGPU/webgpuBufferManager.js +3 -1
- package/Engines/WebGPU/webgpuBufferManager.js.map +1 -1
- package/Engines/abstractEngine.js +2 -2
- package/Engines/abstractEngine.js.map +1 -1
- package/Engines/nullEngine.js +4 -0
- package/Engines/nullEngine.js.map +1 -1
- package/Engines/webgpuEngine.js +2 -2
- package/Engines/webgpuEngine.js.map +1 -1
- package/FrameGraph/frameGraph.d.ts +21 -1
- package/FrameGraph/frameGraph.js +49 -0
- package/FrameGraph/frameGraph.js.map +1 -1
- package/FrameGraph/frameGraphUtils.d.ts +1 -2
- package/FrameGraph/frameGraphUtils.js +2 -27
- package/FrameGraph/frameGraphUtils.js.map +1 -1
- package/Helpers/environmentHelper.js +7 -0
- package/Helpers/environmentHelper.js.map +1 -1
- package/Layers/highlightLayer.d.ts +14 -0
- package/Layers/highlightLayer.js +20 -0
- package/Layers/highlightLayer.js.map +1 -1
- package/Layers/selectionOutlineLayer.d.ts +1 -0
- package/Layers/selectionOutlineLayer.js +1 -0
- package/Layers/selectionOutlineLayer.js.map +1 -1
- package/Layers/thinEffectLayer.js +25 -1
- package/Layers/thinEffectLayer.js.map +1 -1
- package/Layers/thinHighlightLayer.d.ts +9 -0
- package/Layers/thinHighlightLayer.js +19 -3
- package/Layers/thinHighlightLayer.js.map +1 -1
- package/Lights/Clustered/clusteredLightContainer.js +10 -8
- package/Lights/Clustered/clusteredLightContainer.js.map +1 -1
- package/Loading/Plugins/babylonFileLoader.d.ts +2 -0
- package/Loading/Plugins/babylonFileLoader.js +2 -0
- package/Loading/Plugins/babylonFileLoader.js.map +1 -1
- package/Materials/Node/Blocks/Dual/depthSourceBlock.d.ts +1 -0
- package/Materials/Node/Blocks/Dual/depthSourceBlock.js +1 -0
- package/Materials/Node/Blocks/Dual/depthSourceBlock.js.map +1 -1
- package/Materials/Node/Blocks/Dual/sceneDepthBlock.d.ts +1 -0
- package/Materials/Node/Blocks/Dual/sceneDepthBlock.js +1 -0
- package/Materials/Node/Blocks/Dual/sceneDepthBlock.js.map +1 -1
- package/Materials/Node/Blocks/Teleport/teleportOutBlock.js +10 -4
- package/Materials/Node/Blocks/Teleport/teleportOutBlock.js.map +1 -1
- package/Materials/Textures/renderTargetTexture.js +6 -4
- package/Materials/Textures/renderTargetTexture.js.map +1 -1
- package/Meshes/abstractMesh.d.ts +9 -0
- package/Meshes/abstractMesh.js +16 -0
- package/Meshes/abstractMesh.js.map +1 -1
- package/Meshes/mesh.js +2 -0
- package/Meshes/mesh.js.map +1 -1
- package/Meshes/thinInstanceMesh.d.ts +7 -3
- package/Meshes/thinInstanceMesh.js +15 -3
- package/Meshes/thinInstanceMesh.js.map +1 -1
- package/Misc/index.d.ts +1 -0
- package/Misc/index.js +1 -0
- package/Misc/index.js.map +1 -1
- package/Misc/snapshotRenderingHelper.d.ts +5 -3
- package/Misc/snapshotRenderingHelper.js +9 -5
- package/Misc/snapshotRenderingHelper.js.map +1 -1
- package/Particles/EmitterTypes/coneParticleEmitter.js +3 -3
- package/Particles/EmitterTypes/coneParticleEmitter.js.map +1 -1
- package/Particles/EmitterTypes/sphereParticleEmitter.js +2 -2
- package/Particles/EmitterTypes/sphereParticleEmitter.js.map +1 -1
- package/Particles/Node/Blocks/index.d.ts +0 -2
- package/Particles/Node/Blocks/index.js +0 -2
- package/Particles/Node/Blocks/index.js.map +1 -1
- package/Particles/Node/Blocks/particleNumberMathBlock.js +16 -0
- package/Particles/Node/Blocks/particleNumberMathBlock.js.map +1 -1
- package/Particles/Node/Blocks/systemBlock.d.ts +0 -4
- package/Particles/Node/Blocks/systemBlock.js +1 -32
- package/Particles/Node/Blocks/systemBlock.js.map +1 -1
- package/Particles/Node/nodeParticleSystemSet.helper.js +2 -89
- package/Particles/Node/nodeParticleSystemSet.helper.js.map +1 -1
- package/PostProcesses/RenderPipeline/Pipelines/defaultRenderingPipeline.d.ts +1 -0
- package/PostProcesses/RenderPipeline/Pipelines/defaultRenderingPipeline.js +1 -0
- package/PostProcesses/RenderPipeline/Pipelines/defaultRenderingPipeline.js.map +1 -1
- package/PostProcesses/RenderPipeline/Pipelines/lensRenderingPipeline.d.ts +1 -0
- package/PostProcesses/RenderPipeline/Pipelines/lensRenderingPipeline.js +1 -0
- package/PostProcesses/RenderPipeline/Pipelines/lensRenderingPipeline.js.map +1 -1
- package/PostProcesses/RenderPipeline/Pipelines/ssao2RenderingPipeline.d.ts +6 -0
- package/PostProcesses/RenderPipeline/Pipelines/ssao2RenderingPipeline.js +8 -0
- package/PostProcesses/RenderPipeline/Pipelines/ssao2RenderingPipeline.js.map +1 -1
- package/PostProcesses/RenderPipeline/Pipelines/ssaoRenderingPipeline.d.ts +1 -0
- package/PostProcesses/RenderPipeline/Pipelines/ssaoRenderingPipeline.js +1 -0
- package/PostProcesses/RenderPipeline/Pipelines/ssaoRenderingPipeline.js.map +1 -1
- package/PostProcesses/RenderPipeline/Pipelines/ssrRenderingPipeline.d.ts +6 -0
- package/PostProcesses/RenderPipeline/Pipelines/ssrRenderingPipeline.js +8 -0
- package/PostProcesses/RenderPipeline/Pipelines/ssrRenderingPipeline.js.map +1 -1
- package/PostProcesses/RenderPipeline/Pipelines/standardRenderingPipeline.d.ts +1 -0
- package/PostProcesses/RenderPipeline/Pipelines/standardRenderingPipeline.js +1 -0
- package/PostProcesses/RenderPipeline/Pipelines/standardRenderingPipeline.js.map +1 -1
- package/PostProcesses/screenSpaceReflectionPostProcess.d.ts +1 -0
- package/PostProcesses/screenSpaceReflectionPostProcess.js +1 -0
- package/PostProcesses/screenSpaceReflectionPostProcess.js.map +1 -1
- package/Rendering/GlobalIllumination/giRSMManager.d.ts +1 -0
- package/Rendering/GlobalIllumination/giRSMManager.js +1 -0
- package/Rendering/GlobalIllumination/giRSMManager.js.map +1 -1
- package/Rendering/IBLShadows/iblShadowsAccumulationPass.js +7 -3
- package/Rendering/IBLShadows/iblShadowsAccumulationPass.js.map +1 -1
- package/Rendering/IBLShadows/iblShadowsSpatialBlurPass.js +3 -1
- package/Rendering/IBLShadows/iblShadowsSpatialBlurPass.js.map +1 -1
- package/Rendering/IBLShadows/iblShadowsVoxelTracingPass.js +3 -1
- package/Rendering/IBLShadows/iblShadowsVoxelTracingPass.js.map +1 -1
- package/Rendering/geometryBufferRenderer.js +3 -0
- package/Rendering/geometryBufferRenderer.js.map +1 -1
- package/Rendering/prePassRenderer.d.ts +1 -0
- package/Rendering/prePassRenderer.js +1 -0
- package/Rendering/prePassRenderer.js.map +1 -1
- package/Shaders/gpuUpdateParticles.vertex.js +1 -1
- package/Shaders/gpuUpdateParticles.vertex.js.map +1 -1
- package/ShadersWGSL/ShadersInclude/depthPrePass.js +4 -1
- package/ShadersWGSL/ShadersInclude/depthPrePass.js.map +1 -1
- package/ShadersWGSL/background.fragment.js +1 -1
- package/ShadersWGSL/background.fragment.js.map +1 -1
- package/ShadersWGSL/default.fragment.js +1 -1
- package/ShadersWGSL/default.fragment.js.map +1 -1
- package/ShadersWGSL/gpuUpdateParticles.compute.js +1 -1
- package/ShadersWGSL/gpuUpdateParticles.compute.js.map +1 -1
- package/XR/features/WebXRControllerPhysics.d.ts +1 -0
- package/XR/features/WebXRControllerPhysics.js +1 -0
- package/XR/features/WebXRControllerPhysics.js.map +1 -1
- package/XR/features/WebXRHandTracking.d.ts +1 -0
- package/XR/features/WebXRHandTracking.js +1 -0
- package/XR/features/WebXRHandTracking.js.map +1 -1
- package/package.json +1 -1
- package/scene.js +19 -1
- package/scene.js.map +1 -1
- package/Particles/Node/Blocks/Update/updateRemapBlock.d.ts +0 -39
- package/Particles/Node/Blocks/Update/updateRemapBlock.js +0 -93
- package/Particles/Node/Blocks/Update/updateRemapBlock.js.map +0 -1
- package/Particles/Node/Blocks/particleFresnelBlock.d.ts +0 -34
- package/Particles/Node/Blocks/particleFresnelBlock.js +0 -74
- package/Particles/Node/Blocks/particleFresnelBlock.js.map +0 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { AbstractMesh, MorphTargetManager, Immutable, Bone, Nullable, MorphTarget, AnimationGroup, Skeleton } from "../index.js";
|
|
2
|
+
import { TransformNode } from "../Meshes/transformNode.js";
|
|
2
3
|
/**
|
|
3
4
|
* Options for retargeting an animation group to an avatar.
|
|
4
5
|
*/
|
|
@@ -10,13 +11,13 @@ export interface IRetargetOptions {
|
|
|
10
11
|
animationGroupName?: string;
|
|
11
12
|
/**
|
|
12
13
|
* If true, the retargeted animations will be fixed to correct common issues like orthogonal quaternions.
|
|
13
|
-
* Default is
|
|
14
|
+
* Default is false.
|
|
14
15
|
*/
|
|
15
16
|
fixAnimations?: boolean;
|
|
16
17
|
/**
|
|
17
18
|
* If true, the parent hierarchy of bones and transform nodes will be checked during retargeting.
|
|
18
19
|
* Animations will be removed if the hierarchies don't match.
|
|
19
|
-
* Default is
|
|
20
|
+
* Default is false.
|
|
20
21
|
*/
|
|
21
22
|
checkHierarchy?: boolean;
|
|
22
23
|
/**
|
|
@@ -34,9 +35,17 @@ export interface IRetargetOptions {
|
|
|
34
35
|
/**
|
|
35
36
|
* If true, adjusts the root position animation to correct for ground reference height differences between the source and target avatars.
|
|
36
37
|
* This ensures that the animated character maintains proper contact with the ground during retargeting.
|
|
37
|
-
*
|
|
38
|
+
* Requires groundReferenceNodeName to be specified to determine the ground reference point in the source animation.
|
|
39
|
+
* Default is false.
|
|
38
40
|
*/
|
|
39
41
|
fixGroundReference?: boolean;
|
|
42
|
+
/**
|
|
43
|
+
* If true, adjusts the ground reference dynamically during retargeting. fixGroundReference must be true for this to work.
|
|
44
|
+
* When enabled, the system will continuously adjust the ground reference point throughout the retargeting process to make sure it's the lowest point of the character.
|
|
45
|
+
* This allows for more accurate ground contact correction, especially in animations where groundReferenceNodeName is not always the lowest point (e.g., walking, running).
|
|
46
|
+
* Default is false.
|
|
47
|
+
*/
|
|
48
|
+
fixGroundReferenceDynamicRefNode?: boolean;
|
|
40
49
|
/**
|
|
41
50
|
* The name of the root transform node in the source animation group (typically "Hips" or similar).
|
|
42
51
|
* If not specified, the system will attempt to automatically find the first bone without a parent.
|
|
@@ -66,16 +75,19 @@ export interface IRetargetOptions {
|
|
|
66
75
|
mapNodeNames?: Map<string, string>;
|
|
67
76
|
}
|
|
68
77
|
/**
|
|
69
|
-
* Represents an animator avatar that manages skeletons and morph target managers for a hierarchical transform node and mesh structure.
|
|
70
|
-
* This class is used to group and manage animation-related resources (skeletons and morph targets) associated with a root transform node and its descendants.
|
|
78
|
+
* Represents an animator avatar that manages meshes, skeletons and morph target managers for a hierarchical transform node and mesh structure.
|
|
79
|
+
* This class is used to group and manage animation-related resources (meshes, skeletons and morph targets) associated with a root transform node and its descendants.
|
|
71
80
|
*/
|
|
72
81
|
export declare class AnimatorAvatar {
|
|
73
82
|
readonly name: string;
|
|
74
83
|
readonly rootNode?: TransformNode | undefined;
|
|
75
84
|
private _disposeResources;
|
|
85
|
+
/**
|
|
86
|
+
* List of meshes found in the hierarchy of the root node. Only meshes with at least one vertex are included.
|
|
87
|
+
*/
|
|
88
|
+
meshes: AbstractMesh[];
|
|
76
89
|
/**
|
|
77
90
|
* Set of skeletons found in the mesh hierarchy.
|
|
78
|
-
* Each skeleton in this set has its bones linked to corresponding transform nodes.
|
|
79
91
|
*/
|
|
80
92
|
skeletons: Set<Skeleton>;
|
|
81
93
|
/**
|
|
@@ -96,8 +108,8 @@ export declare class AnimatorAvatar {
|
|
|
96
108
|
/**
|
|
97
109
|
* Creates an instance of AnimatorAvatar.
|
|
98
110
|
* @param name - The name to assign to this avatar and its root node
|
|
99
|
-
* @param rootNode - The root node of the avatar hierarchy. This node and its descendants will be scanned for skeletons and morph target managers. If not provided, you are expected to manually manage skeletons and morph target managers.
|
|
100
|
-
* @param _disposeResources - Indicates whether to dispose of resources (skeletons, morph target managers, root node and descendants + materials and textures) when the avatar is disposed (true by default)
|
|
111
|
+
* @param rootNode - The root node of the avatar hierarchy. This node and its descendants will be scanned for meshes, skeletons and morph target managers. If not provided, you are expected to manually manage meshes, skeletons and morph target managers.
|
|
112
|
+
* @param _disposeResources - Indicates whether to dispose of resources (meshes, skeletons, morph target managers, root node and descendants + materials and textures) when the avatar is disposed (true by default)
|
|
101
113
|
*/
|
|
102
114
|
constructor(name: string, rootNode?: TransformNode | undefined, _disposeResources?: boolean);
|
|
103
115
|
/**
|
|
@@ -105,7 +117,13 @@ export declare class AnimatorAvatar {
|
|
|
105
117
|
* @param nameOrTransformNode The linked transform node or the name of the linked transform node
|
|
106
118
|
* @returns The found bone or null if not found
|
|
107
119
|
*/
|
|
108
|
-
|
|
120
|
+
findBoneByTransformNode(nameOrTransformNode: string | TransformNode): Nullable<Bone>;
|
|
121
|
+
/**
|
|
122
|
+
* Finds a bone in the avatar's skeletons by its name.
|
|
123
|
+
* @param name The name of the bone
|
|
124
|
+
* @returns The found bone or null if not found
|
|
125
|
+
*/
|
|
126
|
+
findBoneByName(name: string): Nullable<Bone>;
|
|
109
127
|
/**
|
|
110
128
|
* Make sures that the animation group passed as the first parameter will animate the bones in the skeleton(s) / the morphs in the morph target manager(s) of the avatar.
|
|
111
129
|
* Retargeting is based on the names of the targets (TransformNode or MorphTarget) in the animation and the names of the bones in the skeleton / morph targets in the morph target manager.
|
|
@@ -132,16 +150,13 @@ export declare class AnimatorAvatar {
|
|
|
132
150
|
private _retargetTransformNodeToBone;
|
|
133
151
|
private _retargetAnimationKeys;
|
|
134
152
|
/**
|
|
135
|
-
* This method
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
* in the animation data, as two consecutive rotations should normally be close to each other and not have a large gap.
|
|
139
|
-
* The fix is to copy the first quaternion into the second.
|
|
153
|
+
* This method corrects quaternion animations when two consecutive quaternions are orthogonal to each other. When this happens, in 99.99% of
|
|
154
|
+
* cases it's an error in the animation data, as two consecutive rotations should normally be close to each other and not have a large gap.
|
|
155
|
+
* The fix is to copy the first quaternion into the second.
|
|
140
156
|
* @param animationGroup The animation group to fix
|
|
141
157
|
* @internal
|
|
142
158
|
*/
|
|
143
159
|
private _fixAnimationGroup;
|
|
144
|
-
private _fixAnimationQuaternion;
|
|
145
160
|
private _getRootNode;
|
|
146
161
|
/**
|
|
147
162
|
* Checks whether the parent hierarchy of a bone matches that of a given transform node. Checks are performed by name.
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { Vector3, Quaternion, TmpVectors, Matrix } from "../Maths/math.vector.js";
|
|
2
2
|
import { Logger } from "../Misc/logger.js";
|
|
3
|
+
import { TransformNode } from "../Meshes/transformNode.js";
|
|
3
4
|
/**
|
|
4
|
-
* Represents an animator avatar that manages skeletons and morph target managers for a hierarchical transform node and mesh structure.
|
|
5
|
-
* This class is used to group and manage animation-related resources (skeletons and morph targets) associated with a root transform node and its descendants.
|
|
5
|
+
* Represents an animator avatar that manages meshes, skeletons and morph target managers for a hierarchical transform node and mesh structure.
|
|
6
|
+
* This class is used to group and manage animation-related resources (meshes, skeletons and morph targets) associated with a root transform node and its descendants.
|
|
6
7
|
*/
|
|
7
8
|
export class AnimatorAvatar {
|
|
8
9
|
/**
|
|
@@ -18,8 +19,8 @@ export class AnimatorAvatar {
|
|
|
18
19
|
/**
|
|
19
20
|
* Creates an instance of AnimatorAvatar.
|
|
20
21
|
* @param name - The name to assign to this avatar and its root node
|
|
21
|
-
* @param rootNode - The root node of the avatar hierarchy. This node and its descendants will be scanned for skeletons and morph target managers. If not provided, you are expected to manually manage skeletons and morph target managers.
|
|
22
|
-
* @param _disposeResources - Indicates whether to dispose of resources (skeletons, morph target managers, root node and descendants + materials and textures) when the avatar is disposed (true by default)
|
|
22
|
+
* @param rootNode - The root node of the avatar hierarchy. This node and its descendants will be scanned for meshes, skeletons and morph target managers. If not provided, you are expected to manually manage meshes, skeletons and morph target managers.
|
|
23
|
+
* @param _disposeResources - Indicates whether to dispose of resources (meshes, skeletons, morph target managers, root node and descendants + materials and textures) when the avatar is disposed (true by default)
|
|
23
24
|
*/
|
|
24
25
|
constructor(name, rootNode, _disposeResources = true) {
|
|
25
26
|
this.name = name;
|
|
@@ -29,21 +30,20 @@ export class AnimatorAvatar {
|
|
|
29
30
|
* Indicates whether to show warnings during retargeting operations.
|
|
30
31
|
*/
|
|
31
32
|
this.showWarnings = true;
|
|
33
|
+
this.meshes = [];
|
|
32
34
|
this.skeletons = new Set();
|
|
33
35
|
this.morphTargetManagers = new Set();
|
|
34
36
|
if (!rootNode) {
|
|
35
37
|
return;
|
|
36
38
|
}
|
|
37
39
|
rootNode.name = name;
|
|
38
|
-
if (!rootNode.rotationQuaternion) {
|
|
39
|
-
rootNode.rotationQuaternion = new Quaternion();
|
|
40
|
-
}
|
|
41
40
|
rootNode
|
|
42
41
|
.getChildMeshes(false, (node) => {
|
|
43
42
|
const mesh = node;
|
|
44
43
|
return mesh.getTotalVertices && mesh.getTotalVertices() > 0;
|
|
45
44
|
})
|
|
46
45
|
.forEach((mesh) => {
|
|
46
|
+
this.meshes.push(mesh);
|
|
47
47
|
if (mesh.skeleton) {
|
|
48
48
|
this.skeletons.add(mesh.skeleton);
|
|
49
49
|
}
|
|
@@ -60,7 +60,7 @@ export class AnimatorAvatar {
|
|
|
60
60
|
* @param nameOrTransformNode The linked transform node or the name of the linked transform node
|
|
61
61
|
* @returns The found bone or null if not found
|
|
62
62
|
*/
|
|
63
|
-
|
|
63
|
+
findBoneByTransformNode(nameOrTransformNode) {
|
|
64
64
|
const isName = !this._isTransformNode(nameOrTransformNode);
|
|
65
65
|
const iterator = this.skeletons.keys();
|
|
66
66
|
let bone = null;
|
|
@@ -78,6 +78,22 @@ export class AnimatorAvatar {
|
|
|
78
78
|
}
|
|
79
79
|
return null;
|
|
80
80
|
}
|
|
81
|
+
/**
|
|
82
|
+
* Finds a bone in the avatar's skeletons by its name.
|
|
83
|
+
* @param name The name of the bone
|
|
84
|
+
* @returns The found bone or null if not found
|
|
85
|
+
*/
|
|
86
|
+
findBoneByName(name) {
|
|
87
|
+
const iterator = this.skeletons.keys();
|
|
88
|
+
for (let key = iterator.next(); key.done !== true; key = iterator.next()) {
|
|
89
|
+
const skeleton = key.value;
|
|
90
|
+
const index = skeleton.getBoneIndexByName(name);
|
|
91
|
+
if (index !== -1) {
|
|
92
|
+
return skeleton.bones[index];
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
81
97
|
/**
|
|
82
98
|
* Make sures that the animation group passed as the first parameter will animate the bones in the skeleton(s) / the morphs in the morph target manager(s) of the avatar.
|
|
83
99
|
* Retargeting is based on the names of the targets (TransformNode or MorphTarget) in the animation and the names of the bones in the skeleton / morph targets in the morph target manager.
|
|
@@ -93,23 +109,24 @@ export class AnimatorAvatar {
|
|
|
93
109
|
retargetAnimationGroup(sourceAnimationGroup, options) {
|
|
94
110
|
const localOptions = {
|
|
95
111
|
animationGroupName: sourceAnimationGroup.name,
|
|
96
|
-
fixAnimations:
|
|
97
|
-
checkHierarchy:
|
|
112
|
+
fixAnimations: false,
|
|
113
|
+
checkHierarchy: false,
|
|
98
114
|
retargetAnimationKeys: true,
|
|
99
|
-
fixGroundReference:
|
|
115
|
+
fixGroundReference: false,
|
|
116
|
+
fixGroundReferenceDynamicRefNode: false,
|
|
100
117
|
fixRootPosition: true,
|
|
101
118
|
...options,
|
|
102
119
|
};
|
|
103
120
|
// Make sure that all world matrices are up to date, both in the bone hierarchy and in the animation transform node hierarchy
|
|
104
121
|
this._computeBoneWorldMatrices();
|
|
105
122
|
const mapNodeNames = localOptions.mapNodeNames ?? new Map();
|
|
106
|
-
const
|
|
123
|
+
const lstSourceTransformNodes = new Set();
|
|
107
124
|
const sourceTransformNodeNameToNode = new Map();
|
|
108
125
|
for (let i = 0; i < sourceAnimationGroup.targetedAnimations.length; ++i) {
|
|
109
126
|
const ta = sourceAnimationGroup.targetedAnimations[i];
|
|
110
|
-
if (ta.target.getClassName?.() === "TransformNode" && !
|
|
127
|
+
if (ta.target.getClassName?.() === "TransformNode" && !lstSourceTransformNodes.has(ta.target)) {
|
|
111
128
|
const tn = ta.target;
|
|
112
|
-
|
|
129
|
+
lstSourceTransformNodes.add(tn);
|
|
113
130
|
if (!tn.rotationQuaternion) {
|
|
114
131
|
tn.rotationQuaternion = Quaternion.FromEulerAngles(tn.rotation.x, tn.rotation.y, tn.rotation.z);
|
|
115
132
|
tn.rotation.setAll(0);
|
|
@@ -124,7 +141,7 @@ export class AnimatorAvatar {
|
|
|
124
141
|
});
|
|
125
142
|
}
|
|
126
143
|
}
|
|
127
|
-
|
|
144
|
+
lstSourceTransformNodes.forEach((node) => {
|
|
128
145
|
node.computeWorldMatrix(true);
|
|
129
146
|
});
|
|
130
147
|
// Clone the source animation and retarget it
|
|
@@ -156,7 +173,10 @@ export class AnimatorAvatar {
|
|
|
156
173
|
}
|
|
157
174
|
const sourceTransformNode = ta.target;
|
|
158
175
|
const sourceTransformNodeName = mapNodeNames.get(sourceTransformNode.name) ?? sourceTransformNode.name;
|
|
159
|
-
|
|
176
|
+
let targetBone = this.findBoneByTransformNode(sourceTransformNodeName);
|
|
177
|
+
if (!targetBone) {
|
|
178
|
+
targetBone = this.findBoneByName(sourceTransformNodeName);
|
|
179
|
+
}
|
|
160
180
|
if (!targetBone) {
|
|
161
181
|
if (this.showWarnings) {
|
|
162
182
|
Logger.Warn(`RetargetAnimationGroup - Avatar '${this.name}', AnimationGroup '${animationGroup.name}': "${sourceTransformNodeName}" bone not found in any skeleton of avatar: animation removed.`);
|
|
@@ -165,12 +185,6 @@ export class AnimatorAvatar {
|
|
|
165
185
|
}
|
|
166
186
|
break;
|
|
167
187
|
}
|
|
168
|
-
if (!targetBone._linkedTransformNode) {
|
|
169
|
-
if (this.showWarnings) {
|
|
170
|
-
Logger.Warn(`RetargetAnimationGroup - Avatar '${this.name}', AnimationGroup '${animationGroup.name}': bone "${targetBone.name}" has no linked transform node: skipping retargeting.`);
|
|
171
|
-
}
|
|
172
|
-
break;
|
|
173
|
-
}
|
|
174
188
|
if (!this._retargetTransformNodeToBone(ta, sourceTransformNode, targetBone, animationGroup.name, mapTransformNodeToRootNode, mapNodeNames, !!localOptions.checkHierarchy)) {
|
|
175
189
|
animationGroup.targetedAnimations.splice(i, 1);
|
|
176
190
|
i--;
|
|
@@ -193,15 +207,21 @@ export class AnimatorAvatar {
|
|
|
193
207
|
: "Root position fixing process skipped.";
|
|
194
208
|
const res = this._findVerticalAxis(msg, animationGroup, mapNodeNames.get(localOptions.rootNodeName) ?? localOptions.rootNodeName, sourceTransformNodeNameToNode, mapNodeNames.get(localOptions.groundReferenceNodeName) ?? localOptions.groundReferenceNodeName, localOptions.groundReferenceVerticalAxis);
|
|
195
209
|
if (res) {
|
|
196
|
-
const { verticalAxis, sourceRootTransformNode,
|
|
210
|
+
const { verticalAxis, sourceRootTransformNode, targetRootTransformNodeOrBone, targetRootPositionAnimation, sourceGroundReferenceTransformNode, targetGroundReferenceTransformNodeOrBone, proportionRatio, } = res;
|
|
197
211
|
if (localOptions.fixRootPosition) {
|
|
198
|
-
this._fixRootPosition(sourceAnimationGroup, animationGroup, sourceRootTransformNode,
|
|
212
|
+
this._fixRootPosition(sourceAnimationGroup, animationGroup, sourceRootTransformNode, targetRootTransformNodeOrBone, targetRootPositionAnimation, proportionRatio);
|
|
199
213
|
this._resetStates(sourceTransformNodeNameToNode);
|
|
200
214
|
}
|
|
215
|
+
const fixGroundReferenceDynamicRefNode = !!localOptions.fixGroundReferenceDynamicRefNode;
|
|
201
216
|
if (localOptions.fixGroundReference) {
|
|
202
|
-
this._fixGroundReference(sourceAnimationGroup, animationGroup, verticalAxis,
|
|
217
|
+
this._fixGroundReference(sourceAnimationGroup, animationGroup, verticalAxis, targetRootTransformNodeOrBone, targetRootPositionAnimation, sourceGroundReferenceTransformNode, targetGroundReferenceTransformNodeOrBone, lstSourceTransformNodes, mapNodeNames, fixGroundReferenceDynamicRefNode);
|
|
203
218
|
this._resetStates(sourceTransformNodeNameToNode);
|
|
204
219
|
}
|
|
220
|
+
else if (fixGroundReferenceDynamicRefNode) {
|
|
221
|
+
if (this.showWarnings) {
|
|
222
|
+
Logger.Warn(`RetargetAnimationGroup - Avatar '${this.name}', AnimationGroup '${animationGroup.name}': fixGroundReferenceDynamicRefNode option is set to true but fixGroundReference is false: dynamic ground reference node fixing process skipped.`);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
205
225
|
}
|
|
206
226
|
}
|
|
207
227
|
return animationGroup;
|
|
@@ -227,6 +247,7 @@ export class AnimatorAvatar {
|
|
|
227
247
|
}
|
|
228
248
|
_computeBoneWorldMatrices() {
|
|
229
249
|
this.skeletons.forEach((skeleton) => {
|
|
250
|
+
skeleton.prepare(true);
|
|
230
251
|
skeleton.bones.forEach((bone) => {
|
|
231
252
|
bone._linkedTransformNode?.computeWorldMatrix(true);
|
|
232
253
|
});
|
|
@@ -267,19 +288,27 @@ export class AnimatorAvatar {
|
|
|
267
288
|
}
|
|
268
289
|
if (!this._checkParentHierarchy(targetBone, rootNode, mapNodeNames)) {
|
|
269
290
|
if (this.showWarnings) {
|
|
270
|
-
Logger.Warn(`RetargetAnimationGroup - Avatar '${this.name}', AnimationGroup '${animationGroupName}': parent hierarchy mismatch between bone "${targetBone.name}" and transform node "${sourceTransformNode.name}": animation removed`);
|
|
291
|
+
Logger.Warn(`RetargetAnimationGroup - Avatar '${this.name}', AnimationGroup '${animationGroupName}': parent hierarchy mismatch between bone "${targetBone._linkedTransformNode?.name ?? targetBone.name}" and transform node "${sourceTransformNode.name}": animation removed`);
|
|
271
292
|
}
|
|
272
293
|
return false;
|
|
273
294
|
}
|
|
274
295
|
}
|
|
275
|
-
ta.target = targetBone._linkedTransformNode;
|
|
296
|
+
ta.target = targetBone._linkedTransformNode ?? targetBone;
|
|
276
297
|
return true;
|
|
277
298
|
}
|
|
278
299
|
_retargetAnimationKeys(animation, sourceTransformNode, targetBone) {
|
|
279
300
|
const keys = animation.getKeys();
|
|
280
301
|
const targetTransformNode = targetBone._linkedTransformNode;
|
|
281
|
-
|
|
282
|
-
|
|
302
|
+
let targetWorldMatrix;
|
|
303
|
+
let targetParentWorldMatrix;
|
|
304
|
+
if (targetTransformNode) {
|
|
305
|
+
targetWorldMatrix = targetTransformNode.getWorldMatrix();
|
|
306
|
+
targetParentWorldMatrix = targetTransformNode.parent ? targetTransformNode.parent.getWorldMatrix() : Matrix.IdentityReadOnly;
|
|
307
|
+
}
|
|
308
|
+
else {
|
|
309
|
+
targetWorldMatrix = targetBone.getFinalMatrix();
|
|
310
|
+
targetParentWorldMatrix = targetBone.parent ? targetBone.parent.getFinalMatrix() : Matrix.IdentityReadOnly;
|
|
311
|
+
}
|
|
283
312
|
const targetParentInverseWorldMatrix = targetParentWorldMatrix.invertToRef(TmpVectors.Matrix[0]);
|
|
284
313
|
const sourceInverseWorld = sourceTransformNode.getWorldMatrix().invertToRef(TmpVectors.Matrix[1]);
|
|
285
314
|
const sourceParentWorld = sourceTransformNode.parent ? sourceTransformNode.parent.getWorldMatrix() : Matrix.IdentityReadOnly;
|
|
@@ -314,11 +343,9 @@ export class AnimatorAvatar {
|
|
|
314
343
|
}
|
|
315
344
|
}
|
|
316
345
|
/**
|
|
317
|
-
* This method
|
|
318
|
-
*
|
|
319
|
-
*
|
|
320
|
-
* in the animation data, as two consecutive rotations should normally be close to each other and not have a large gap.
|
|
321
|
-
* The fix is to copy the first quaternion into the second.
|
|
346
|
+
* This method corrects quaternion animations when two consecutive quaternions are orthogonal to each other. When this happens, in 99.99% of
|
|
347
|
+
* cases it's an error in the animation data, as two consecutive rotations should normally be close to each other and not have a large gap.
|
|
348
|
+
* The fix is to copy the first quaternion into the second.
|
|
322
349
|
* @param animationGroup The animation group to fix
|
|
323
350
|
* @internal
|
|
324
351
|
*/
|
|
@@ -326,41 +353,21 @@ export class AnimatorAvatar {
|
|
|
326
353
|
for (let i = 0; i < animationGroup.targetedAnimations.length; ++i) {
|
|
327
354
|
const ta = animationGroup.targetedAnimations[i];
|
|
328
355
|
switch (ta.animation.targetProperty) {
|
|
329
|
-
case "
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
if (!bone) {
|
|
338
|
-
if (this.showWarnings) {
|
|
339
|
-
Logger.Warn(`FixAnimationGroup - Avatar '${this.name}', AnimationGroup '${animationGroup.name}': no bone in any skeleton of the avatar ${this.name} animates the transform node ${transformNode.name}: animation removed`);
|
|
356
|
+
case "rotationQuaternion": {
|
|
357
|
+
const keys = ta.animation.getKeys();
|
|
358
|
+
for (let i = 0; i < keys.length - 1; ++i) {
|
|
359
|
+
const curQuat = keys[i].value;
|
|
360
|
+
const nextQuat = keys[i + 1].value;
|
|
361
|
+
if (Math.abs(Quaternion.Dot(curQuat, nextQuat)) < 0.001) {
|
|
362
|
+
keys[i + 1].value = curQuat.clone();
|
|
363
|
+
i += 1;
|
|
340
364
|
}
|
|
341
|
-
animationGroup.targetedAnimations.splice(i, 1);
|
|
342
|
-
i--;
|
|
343
|
-
continue;
|
|
344
|
-
}
|
|
345
|
-
ta.target = bone._linkedTransformNode;
|
|
346
|
-
if (ta.animation.targetProperty === "rotationQuaternion") {
|
|
347
|
-
this._fixAnimationQuaternion(ta.animation);
|
|
348
365
|
}
|
|
366
|
+
break;
|
|
349
367
|
}
|
|
350
368
|
}
|
|
351
369
|
}
|
|
352
370
|
}
|
|
353
|
-
_fixAnimationQuaternion(animation, epsilon = 0.001) {
|
|
354
|
-
const keys = animation.getKeys();
|
|
355
|
-
for (let i = 0; i < keys.length - 1; ++i) {
|
|
356
|
-
const curQuat = keys[i].value;
|
|
357
|
-
const nextQuat = keys[i + 1].value;
|
|
358
|
-
if (Math.abs(Quaternion.Dot(curQuat, nextQuat)) < epsilon) {
|
|
359
|
-
keys[i + 1].value = curQuat.clone();
|
|
360
|
-
i += 1;
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
371
|
_getRootNode(node) {
|
|
365
372
|
let current = node;
|
|
366
373
|
while (current.parent) {
|
|
@@ -378,19 +385,20 @@ export class AnimatorAvatar {
|
|
|
378
385
|
* @internal
|
|
379
386
|
*/
|
|
380
387
|
_checkParentHierarchy(bone, rootTransformNode, mapNodeNames) {
|
|
381
|
-
const children = rootTransformNode.getDescendants(false, (node) => (mapNodeNames.get(node.name) ?? node.name) === bone._linkedTransformNode.name);
|
|
388
|
+
const children = rootTransformNode.getDescendants(false, (node) => (mapNodeNames.get(node.name) ?? node.name) === (bone._linkedTransformNode?.name ?? bone.name));
|
|
382
389
|
if (!children || children.length !== 1) {
|
|
383
390
|
if (this.showWarnings) {
|
|
384
|
-
Logger.Warn(`RetargetAnimationGroup - Avatar '${this.name}', CheckParentHierarchy: unable to find a corresponding transform node to bone name ${bone._linkedTransformNode.name} in the source animation.`);
|
|
391
|
+
Logger.Warn(`RetargetAnimationGroup - Avatar '${this.name}', CheckParentHierarchy: unable to find a corresponding transform node to bone name "${bone._linkedTransformNode?.name ?? bone.name}" in the source animation.`);
|
|
385
392
|
}
|
|
386
393
|
return false;
|
|
387
394
|
}
|
|
388
395
|
let transformNode = children[0];
|
|
389
396
|
while (bone) {
|
|
390
397
|
const name = mapNodeNames.get(transformNode?.name ?? "") ?? transformNode?.name;
|
|
391
|
-
|
|
398
|
+
const boneName = bone._linkedTransformNode?.name ?? bone.name;
|
|
399
|
+
if (boneName !== name) {
|
|
392
400
|
if (this.showWarnings) {
|
|
393
|
-
Logger.Warn(`RetargetAnimationGroup - Avatar '${this.name}', CheckParentHierarchy: bone name ${
|
|
401
|
+
Logger.Warn(`RetargetAnimationGroup - Avatar '${this.name}', CheckParentHierarchy: bone name "${boneName}" is different from transform node name "${name}".`);
|
|
394
402
|
}
|
|
395
403
|
return false;
|
|
396
404
|
}
|
|
@@ -448,27 +456,33 @@ export class AnimatorAvatar {
|
|
|
448
456
|
}
|
|
449
457
|
// Look for the position animation + target node of the root node name (generally the hips) in the retargeted animation
|
|
450
458
|
let targetRootPositionAnimation;
|
|
451
|
-
let
|
|
459
|
+
let targetRootTransformNodeOrBone;
|
|
452
460
|
for (let i = 0; i < animationGroup.targetedAnimations.length; ++i) {
|
|
453
461
|
const ta = animationGroup.targetedAnimations[i];
|
|
454
462
|
const target = ta.target;
|
|
455
463
|
const animation = ta.animation;
|
|
456
464
|
if (target.name === remappedRootNodeName && animation.targetProperty === "position") {
|
|
457
465
|
targetRootPositionAnimation = animation;
|
|
458
|
-
|
|
466
|
+
targetRootTransformNodeOrBone = ta.target;
|
|
459
467
|
break;
|
|
460
468
|
}
|
|
461
469
|
}
|
|
462
|
-
if (!targetRootPositionAnimation || !
|
|
470
|
+
if (!targetRootPositionAnimation || !targetRootTransformNodeOrBone) {
|
|
463
471
|
if (this.showWarnings) {
|
|
464
472
|
Logger.Warn(`RetargetAnimationGroup - Avatar '${this.name}', AnimationGroup '${animationGroup.name}': unable to find a "position" animation for the node "${remappedRootNodeName}". ${msg}`);
|
|
465
473
|
}
|
|
466
474
|
return null;
|
|
467
475
|
}
|
|
468
|
-
|
|
469
|
-
if (
|
|
476
|
+
let targetGroundReferenceTransformNodeOrBone = null;
|
|
477
|
+
if (targetRootTransformNodeOrBone instanceof TransformNode) {
|
|
478
|
+
targetGroundReferenceTransformNodeOrBone = this.findBoneByTransformNode(remappedGroundReferenceNodeName)?._linkedTransformNode;
|
|
479
|
+
}
|
|
480
|
+
else {
|
|
481
|
+
targetGroundReferenceTransformNodeOrBone = this.findBoneByName(remappedGroundReferenceNodeName);
|
|
482
|
+
}
|
|
483
|
+
if (!targetGroundReferenceTransformNodeOrBone) {
|
|
470
484
|
if (this.showWarnings) {
|
|
471
|
-
Logger.Warn(`RetargetAnimationGroup - Avatar '${this.name}', AnimationGroup '${animationGroup.name}': unable to find the transform node corresponding
|
|
485
|
+
Logger.Warn(`RetargetAnimationGroup - Avatar '${this.name}', AnimationGroup '${animationGroup.name}': unable to find the bone/transform node corresponding with name "${remappedGroundReferenceNodeName}" in the avatar skeleton. Ensure that this bone exists. ${msg}`);
|
|
472
486
|
}
|
|
473
487
|
return null;
|
|
474
488
|
}
|
|
@@ -496,14 +510,14 @@ export class AnimatorAvatar {
|
|
|
496
510
|
verticalAxis = 2;
|
|
497
511
|
}
|
|
498
512
|
}
|
|
499
|
-
const targetRootGroundReferenceDiff =
|
|
513
|
+
const targetRootGroundReferenceDiff = targetRootTransformNodeOrBone.getAbsolutePosition().subtract(targetGroundReferenceTransformNodeOrBone.getAbsolutePosition());
|
|
500
514
|
return {
|
|
501
515
|
verticalAxis,
|
|
502
516
|
sourceRootTransformNode,
|
|
503
517
|
sourceGroundReferenceTransformNode,
|
|
504
|
-
|
|
518
|
+
targetRootTransformNodeOrBone,
|
|
505
519
|
targetRootPositionAnimation,
|
|
506
|
-
|
|
520
|
+
targetGroundReferenceTransformNodeOrBone,
|
|
507
521
|
proportionRatio: verticalAxis === 0
|
|
508
522
|
? targetRootGroundReferenceDiff.x / sourceRootGroundReferenceDiff.x
|
|
509
523
|
: verticalAxis === 1
|
|
@@ -521,12 +535,14 @@ export class AnimatorAvatar {
|
|
|
521
535
|
node.computeWorldMatrix(true);
|
|
522
536
|
});
|
|
523
537
|
}
|
|
524
|
-
_fixRootPosition(sourceAnimationGroup, animationGroup, sourceRootTransformNode,
|
|
525
|
-
const targetNodeInverseParentWorldMatrix =
|
|
538
|
+
_fixRootPosition(sourceAnimationGroup, animationGroup, sourceRootTransformNode, targetRootTransformNodeOrBone, targetRootPositionAnimation, proportionRatio) {
|
|
539
|
+
const targetNodeInverseParentWorldMatrix = targetRootTransformNodeOrBone instanceof TransformNode
|
|
540
|
+
? (targetRootTransformNodeOrBone.parent?.getWorldMatrix().invertToRef(TmpVectors.Matrix[0]) ?? Matrix.IdentityReadOnly)
|
|
541
|
+
: (targetRootTransformNodeOrBone.parent?.getFinalMatrix().invertToRef(TmpVectors.Matrix[0]) ?? Matrix.IdentityReadOnly);
|
|
526
542
|
sourceRootTransformNode.computeWorldMatrix(true);
|
|
527
|
-
|
|
543
|
+
targetRootTransformNodeOrBone.computeWorldMatrix(true);
|
|
528
544
|
const sourceWorldPosition = sourceRootTransformNode.absolutePosition.clone();
|
|
529
|
-
const targetWorldPosition =
|
|
545
|
+
const targetWorldPosition = targetRootTransformNodeOrBone.getAbsolutePosition().clone();
|
|
530
546
|
sourceAnimationGroup.play(false);
|
|
531
547
|
animationGroup.play(false);
|
|
532
548
|
// Loop over the position animation of the root transform node
|
|
@@ -546,8 +562,10 @@ export class AnimatorAvatar {
|
|
|
546
562
|
sourceAnimationGroup.stop();
|
|
547
563
|
animationGroup.stop();
|
|
548
564
|
}
|
|
549
|
-
_fixGroundReference(sourceAnimationGroup, animationGroup, verticalAxis,
|
|
550
|
-
const targetNodeInverseParentWorldMatrix =
|
|
565
|
+
_fixGroundReference(sourceAnimationGroup, animationGroup, verticalAxis, targetRootTransformNodeOrBone, targetRootPositionAnimation, sourceGroundReferenceTransformNode, targetGroundReferenceTransformNodeOrBone, sourceListTransformNodes, mapNodeNames, fixGroundReferenceDynamicRefNode) {
|
|
566
|
+
const targetNodeInverseParentWorldMatrix = targetRootTransformNodeOrBone instanceof TransformNode
|
|
567
|
+
? (targetRootTransformNodeOrBone.parent?.getWorldMatrix().invertToRef(TmpVectors.Matrix[0]) ?? Matrix.IdentityReadOnly)
|
|
568
|
+
: (targetRootTransformNodeOrBone.parent?.getFinalMatrix().invertToRef(TmpVectors.Matrix[0]) ?? Matrix.IdentityReadOnly);
|
|
551
569
|
sourceAnimationGroup.play(false);
|
|
552
570
|
animationGroup.play(false);
|
|
553
571
|
// Loop over the position animation of the root transform node
|
|
@@ -559,11 +577,45 @@ export class AnimatorAvatar {
|
|
|
559
577
|
animationGroup.goToFrame(frame);
|
|
560
578
|
animationGroup.pause();
|
|
561
579
|
sourceGroundReferenceTransformNode.computeWorldMatrix(true);
|
|
562
|
-
|
|
580
|
+
targetGroundReferenceTransformNodeOrBone.computeWorldMatrix(true);
|
|
563
581
|
// Calculate the offset to apply to the root position in the target to have the ground reference at the same height in the source and target animations
|
|
564
|
-
const diffGroundReferences =
|
|
565
|
-
|
|
566
|
-
|
|
582
|
+
const diffGroundReferences = targetGroundReferenceTransformNodeOrBone
|
|
583
|
+
.getAbsolutePosition()
|
|
584
|
+
.subtractToRef(sourceGroundReferenceTransformNode.absolutePosition, TmpVectors.Vector3[0]);
|
|
585
|
+
let groundReferenceOffset = verticalAxis === 0 ? diffGroundReferences.x : verticalAxis === 1 ? diffGroundReferences.y : diffGroundReferences.z;
|
|
586
|
+
if (fixGroundReferenceDynamicRefNode) {
|
|
587
|
+
// Try to find a bone in this frame that has a greater offset than the ground reference, to use it instead of the ground reference.
|
|
588
|
+
const targetRootToGroundReferenceDiff = targetRootTransformNodeOrBone
|
|
589
|
+
.getAbsolutePosition()
|
|
590
|
+
.subtractToRef(targetGroundReferenceTransformNodeOrBone.getAbsolutePosition(), TmpVectors.Vector3[0]);
|
|
591
|
+
const targetRootToGroundReferenceOffset = verticalAxis === 0 ? targetRootToGroundReferenceDiff.x : verticalAxis === 1 ? targetRootToGroundReferenceDiff.y : targetRootToGroundReferenceDiff.z;
|
|
592
|
+
const iterator = sourceListTransformNodes.keys();
|
|
593
|
+
for (let key = iterator.next(); key.done !== true; key = iterator.next()) {
|
|
594
|
+
const sourceTransformNode = key.value;
|
|
595
|
+
if (sourceTransformNode === sourceGroundReferenceTransformNode) {
|
|
596
|
+
continue;
|
|
597
|
+
}
|
|
598
|
+
const targetNodeName = mapNodeNames.get(sourceTransformNode.name) ?? sourceTransformNode.name;
|
|
599
|
+
let targetBone = this.findBoneByTransformNode(targetNodeName);
|
|
600
|
+
if (!targetBone) {
|
|
601
|
+
targetBone = this.findBoneByName(targetNodeName);
|
|
602
|
+
}
|
|
603
|
+
if (!targetBone) {
|
|
604
|
+
continue;
|
|
605
|
+
}
|
|
606
|
+
sourceTransformNode.computeWorldMatrix();
|
|
607
|
+
targetBone.computeWorldMatrix();
|
|
608
|
+
const targetBoneWorldPosition = targetBone._linkedTransformNode?.getAbsolutePosition() ?? targetBone.getAbsolutePosition();
|
|
609
|
+
const targetRootToBoneDiff = targetRootTransformNodeOrBone.getAbsolutePosition().subtractToRef(targetBoneWorldPosition, TmpVectors.Vector3[0]);
|
|
610
|
+
const rootToBoneOffset = verticalAxis === 0 ? targetRootToBoneDiff.x : verticalAxis === 1 ? targetRootToBoneDiff.y : targetRootToBoneDiff.z;
|
|
611
|
+
if (Math.abs(rootToBoneOffset) > Math.abs(targetRootToGroundReferenceOffset) && Math.sign(rootToBoneOffset) === Math.sign(targetRootToGroundReferenceOffset)) {
|
|
612
|
+
const diff = targetBoneWorldPosition.subtractToRef(sourceTransformNode.getAbsolutePosition(), TmpVectors.Vector3[0]);
|
|
613
|
+
const offset = verticalAxis === 0 ? diff.x : verticalAxis === 1 ? diff.y : diff.z;
|
|
614
|
+
groundReferenceOffset = offset;
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
const localOffset = Vector3.TransformNormalToRef(new Vector3(verticalAxis === 0 ? groundReferenceOffset : 0, verticalAxis === 1 ? groundReferenceOffset : 0, verticalAxis === 2 ? groundReferenceOffset : 0), targetNodeInverseParentWorldMatrix, TmpVectors.Vector3[1]);
|
|
567
619
|
key.value.subtractInPlace(localOffset);
|
|
568
620
|
}
|
|
569
621
|
sourceAnimationGroup.stop();
|