@babylonjs/core 9.3.1 → 9.3.2
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/Engines/abstractEngine.js +2 -2
- package/Engines/abstractEngine.js.map +1 -1
- package/Lights/Clustered/clusteredLightContainer.d.ts +1 -0
- package/Lights/Clustered/clusteredLightContainer.js +19 -0
- package/Lights/Clustered/clusteredLightContainer.js.map +1 -1
- package/Lights/light.d.ts +6 -0
- package/Lights/light.js +8 -0
- package/Lights/light.js.map +1 -1
- package/Lights/spotLight.d.ts +2 -0
- package/Lights/spotLight.js +10 -0
- package/Lights/spotLight.js.map +1 -1
- package/Materials/Background/backgroundMaterial.js +4 -1
- package/Materials/Background/backgroundMaterial.js.map +1 -1
- package/Materials/GaussianSplatting/gaussianSplattingMaterial.js +6 -2
- package/Materials/GaussianSplatting/gaussianSplattingMaterial.js.map +1 -1
- package/Materials/Node/Blocks/Dual/lightBlock.d.ts +8 -0
- package/Materials/Node/Blocks/Dual/lightBlock.js +16 -0
- package/Materials/Node/Blocks/Dual/lightBlock.js.map +1 -1
- package/Materials/Node/Blocks/PBR/pbrMetallicRoughnessBlock.js +3 -0
- package/Materials/Node/Blocks/PBR/pbrMetallicRoughnessBlock.js.map +1 -1
- package/Materials/Node/nodeMaterial.js +4 -1
- package/Materials/Node/nodeMaterial.js.map +1 -1
- package/Materials/PBR/openpbrMaterial.js +4 -1
- package/Materials/PBR/openpbrMaterial.js.map +1 -1
- package/Materials/PBR/pbrBaseMaterial.js +4 -1
- package/Materials/PBR/pbrBaseMaterial.js.map +1 -1
- package/Materials/materialHelper.functions.d.ts +12 -0
- package/Materials/materialHelper.functions.js +24 -0
- package/Materials/materialHelper.functions.js.map +1 -1
- package/Materials/standardMaterial.js +4 -1
- package/Materials/standardMaterial.js.map +1 -1
- package/Meshes/GaussianSplatting/gaussianSplattingMesh.d.ts +13 -0
- package/Meshes/GaussianSplatting/gaussianSplattingMesh.js +26 -0
- package/Meshes/GaussianSplatting/gaussianSplattingMesh.js.map +1 -1
- package/Meshes/GaussianSplatting/gaussianSplattingMeshBase.d.ts +3 -0
- package/Meshes/GaussianSplatting/gaussianSplattingMeshBase.js +113 -10
- package/Meshes/GaussianSplatting/gaussianSplattingMeshBase.js.map +1 -1
- package/Misc/tools.js +1 -1
- package/Misc/tools.js.map +1 -1
- package/Rendering/depthRenderer.d.ts +8 -0
- package/Rendering/depthRenderer.js +48 -13
- package/Rendering/depthRenderer.js.map +1 -1
- package/Rendering/depthRendererSceneComponent.d.ts +1 -0
- package/Rendering/depthRendererSceneComponent.js +26 -0
- package/Rendering/depthRendererSceneComponent.js.map +1 -1
- package/XR/features/WebXRBodyTracking.d.ts +952 -0
- package/XR/features/WebXRBodyTracking.js +2221 -0
- package/XR/features/WebXRBodyTracking.js.map +1 -0
- package/XR/features/index.d.ts +1 -0
- package/XR/features/index.js +1 -0
- package/XR/features/index.js.map +1 -1
- package/XR/webXRFeaturesManager.d.ts +7 -0
- package/XR/webXRFeaturesManager.js +4 -0
- package/XR/webXRFeaturesManager.js.map +1 -1
- package/package.json +1 -1
- package/sceneComponent.d.ts +1 -0
- package/sceneComponent.js +1 -0
- package/sceneComponent.js.map +1 -1
|
@@ -0,0 +1,952 @@
|
|
|
1
|
+
import { WebXRAbstractFeature } from "./WebXRAbstractFeature.js";
|
|
2
|
+
import { type WebXRSessionManager } from "../webXRSessionManager.js";
|
|
3
|
+
import { type AbstractMesh } from "../../Meshes/abstractMesh.js";
|
|
4
|
+
import { Quaternion } from "../../Maths/math.vector.js";
|
|
5
|
+
import { type Nullable } from "../../types.js";
|
|
6
|
+
import { type IDisposable, type Scene } from "../../scene.js";
|
|
7
|
+
import { Observable } from "../../Misc/observable.js";
|
|
8
|
+
import { TransformNode } from "../../Meshes/transformNode.js";
|
|
9
|
+
import { type Node } from "../../node.js";
|
|
10
|
+
/**
|
|
11
|
+
* All 83 body joint names as defined by the WebXR Body Tracking specification.
|
|
12
|
+
* @see https://immersive-web.github.io/body-tracking/#xrbody-interface
|
|
13
|
+
*/
|
|
14
|
+
export declare enum WebXRBodyJoint {
|
|
15
|
+
/** The center of the hips / pelvis */
|
|
16
|
+
HIPS = "hips",
|
|
17
|
+
/** Lower spine (lumbar) */
|
|
18
|
+
SPINE_LOWER = "spine-lower",
|
|
19
|
+
/** Middle spine (thoracic) */
|
|
20
|
+
SPINE_MIDDLE = "spine-middle",
|
|
21
|
+
/** Upper spine */
|
|
22
|
+
SPINE_UPPER = "spine-upper",
|
|
23
|
+
/** Chest */
|
|
24
|
+
CHEST = "chest",
|
|
25
|
+
/** Neck */
|
|
26
|
+
NECK = "neck",
|
|
27
|
+
/** Head */
|
|
28
|
+
HEAD = "head",
|
|
29
|
+
/** Left shoulder */
|
|
30
|
+
LEFT_SHOULDER = "left-shoulder",
|
|
31
|
+
/** Left scapula */
|
|
32
|
+
LEFT_SCAPULA = "left-scapula",
|
|
33
|
+
/** Left upper arm */
|
|
34
|
+
LEFT_ARM_UPPER = "left-arm-upper",
|
|
35
|
+
/** Left forearm (lower arm) */
|
|
36
|
+
LEFT_ARM_LOWER = "left-arm-lower",
|
|
37
|
+
/** Left hand wrist twist (forearm twist) */
|
|
38
|
+
LEFT_HAND_WRIST_TWIST = "left-hand-wrist-twist",
|
|
39
|
+
/** Right shoulder */
|
|
40
|
+
RIGHT_SHOULDER = "right-shoulder",
|
|
41
|
+
/** Right scapula */
|
|
42
|
+
RIGHT_SCAPULA = "right-scapula",
|
|
43
|
+
/** Right upper arm */
|
|
44
|
+
RIGHT_ARM_UPPER = "right-arm-upper",
|
|
45
|
+
/** Right forearm (lower arm) */
|
|
46
|
+
RIGHT_ARM_LOWER = "right-arm-lower",
|
|
47
|
+
/** Right hand wrist twist (forearm twist) */
|
|
48
|
+
RIGHT_HAND_WRIST_TWIST = "right-hand-wrist-twist",
|
|
49
|
+
/** Left palm center */
|
|
50
|
+
LEFT_HAND_PALM = "left-hand-palm",
|
|
51
|
+
/** Left wrist */
|
|
52
|
+
LEFT_HAND_WRIST = "left-hand-wrist",
|
|
53
|
+
/** Left thumb metacarpal */
|
|
54
|
+
LEFT_HAND_THUMB_METACARPAL = "left-hand-thumb-metacarpal",
|
|
55
|
+
/** Left thumb proximal phalanx */
|
|
56
|
+
LEFT_HAND_THUMB_PHALANX_PROXIMAL = "left-hand-thumb-phalanx-proximal",
|
|
57
|
+
/** Left thumb distal phalanx */
|
|
58
|
+
LEFT_HAND_THUMB_PHALANX_DISTAL = "left-hand-thumb-phalanx-distal",
|
|
59
|
+
/** Left thumb tip */
|
|
60
|
+
LEFT_HAND_THUMB_TIP = "left-hand-thumb-tip",
|
|
61
|
+
/** Left index finger metacarpal */
|
|
62
|
+
LEFT_HAND_INDEX_METACARPAL = "left-hand-index-metacarpal",
|
|
63
|
+
/** Left index finger proximal phalanx */
|
|
64
|
+
LEFT_HAND_INDEX_PHALANX_PROXIMAL = "left-hand-index-phalanx-proximal",
|
|
65
|
+
/** Left index finger intermediate phalanx */
|
|
66
|
+
LEFT_HAND_INDEX_PHALANX_INTERMEDIATE = "left-hand-index-phalanx-intermediate",
|
|
67
|
+
/** Left index finger distal phalanx */
|
|
68
|
+
LEFT_HAND_INDEX_PHALANX_DISTAL = "left-hand-index-phalanx-distal",
|
|
69
|
+
/** Left index finger tip */
|
|
70
|
+
LEFT_HAND_INDEX_TIP = "left-hand-index-tip",
|
|
71
|
+
/** Left middle finger metacarpal */
|
|
72
|
+
LEFT_HAND_MIDDLE_METACARPAL = "left-hand-middle-metacarpal",
|
|
73
|
+
/** Left middle finger proximal phalanx */
|
|
74
|
+
LEFT_HAND_MIDDLE_PHALANX_PROXIMAL = "left-hand-middle-phalanx-proximal",
|
|
75
|
+
/** Left middle finger intermediate phalanx */
|
|
76
|
+
LEFT_HAND_MIDDLE_PHALANX_INTERMEDIATE = "left-hand-middle-phalanx-intermediate",
|
|
77
|
+
/** Left middle finger distal phalanx */
|
|
78
|
+
LEFT_HAND_MIDDLE_PHALANX_DISTAL = "left-hand-middle-phalanx-distal",
|
|
79
|
+
/** Left middle finger tip */
|
|
80
|
+
LEFT_HAND_MIDDLE_TIP = "left-hand-middle-tip",
|
|
81
|
+
/** Left ring finger metacarpal */
|
|
82
|
+
LEFT_HAND_RING_METACARPAL = "left-hand-ring-metacarpal",
|
|
83
|
+
/** Left ring finger proximal phalanx */
|
|
84
|
+
LEFT_HAND_RING_PHALANX_PROXIMAL = "left-hand-ring-phalanx-proximal",
|
|
85
|
+
/** Left ring finger intermediate phalanx */
|
|
86
|
+
LEFT_HAND_RING_PHALANX_INTERMEDIATE = "left-hand-ring-phalanx-intermediate",
|
|
87
|
+
/** Left ring finger distal phalanx */
|
|
88
|
+
LEFT_HAND_RING_PHALANX_DISTAL = "left-hand-ring-phalanx-distal",
|
|
89
|
+
/** Left ring finger tip */
|
|
90
|
+
LEFT_HAND_RING_TIP = "left-hand-ring-tip",
|
|
91
|
+
/** Left little finger metacarpal */
|
|
92
|
+
LEFT_HAND_LITTLE_METACARPAL = "left-hand-little-metacarpal",
|
|
93
|
+
/** Left little finger proximal phalanx */
|
|
94
|
+
LEFT_HAND_LITTLE_PHALANX_PROXIMAL = "left-hand-little-phalanx-proximal",
|
|
95
|
+
/** Left little finger intermediate phalanx */
|
|
96
|
+
LEFT_HAND_LITTLE_PHALANX_INTERMEDIATE = "left-hand-little-phalanx-intermediate",
|
|
97
|
+
/** Left little finger distal phalanx */
|
|
98
|
+
LEFT_HAND_LITTLE_PHALANX_DISTAL = "left-hand-little-phalanx-distal",
|
|
99
|
+
/** Left little finger tip */
|
|
100
|
+
LEFT_HAND_LITTLE_TIP = "left-hand-little-tip",
|
|
101
|
+
/** Right palm center */
|
|
102
|
+
RIGHT_HAND_PALM = "right-hand-palm",
|
|
103
|
+
/** Right wrist */
|
|
104
|
+
RIGHT_HAND_WRIST = "right-hand-wrist",
|
|
105
|
+
/** Right thumb metacarpal */
|
|
106
|
+
RIGHT_HAND_THUMB_METACARPAL = "right-hand-thumb-metacarpal",
|
|
107
|
+
/** Right thumb proximal phalanx */
|
|
108
|
+
RIGHT_HAND_THUMB_PHALANX_PROXIMAL = "right-hand-thumb-phalanx-proximal",
|
|
109
|
+
/** Right thumb distal phalanx */
|
|
110
|
+
RIGHT_HAND_THUMB_PHALANX_DISTAL = "right-hand-thumb-phalanx-distal",
|
|
111
|
+
/** Right thumb tip */
|
|
112
|
+
RIGHT_HAND_THUMB_TIP = "right-hand-thumb-tip",
|
|
113
|
+
/** Right index finger metacarpal */
|
|
114
|
+
RIGHT_HAND_INDEX_METACARPAL = "right-hand-index-metacarpal",
|
|
115
|
+
/** Right index finger proximal phalanx */
|
|
116
|
+
RIGHT_HAND_INDEX_PHALANX_PROXIMAL = "right-hand-index-phalanx-proximal",
|
|
117
|
+
/** Right index finger intermediate phalanx */
|
|
118
|
+
RIGHT_HAND_INDEX_PHALANX_INTERMEDIATE = "right-hand-index-phalanx-intermediate",
|
|
119
|
+
/** Right index finger distal phalanx */
|
|
120
|
+
RIGHT_HAND_INDEX_PHALANX_DISTAL = "right-hand-index-phalanx-distal",
|
|
121
|
+
/** Right index finger tip */
|
|
122
|
+
RIGHT_HAND_INDEX_TIP = "right-hand-index-tip",
|
|
123
|
+
/** Right middle finger metacarpal */
|
|
124
|
+
RIGHT_HAND_MIDDLE_METACARPAL = "right-hand-middle-metacarpal",
|
|
125
|
+
/** Right middle finger proximal phalanx */
|
|
126
|
+
RIGHT_HAND_MIDDLE_PHALANX_PROXIMAL = "right-hand-middle-phalanx-proximal",
|
|
127
|
+
/** Right middle finger intermediate phalanx */
|
|
128
|
+
RIGHT_HAND_MIDDLE_PHALANX_INTERMEDIATE = "right-hand-middle-phalanx-intermediate",
|
|
129
|
+
/** Right middle finger distal phalanx */
|
|
130
|
+
RIGHT_HAND_MIDDLE_PHALANX_DISTAL = "right-hand-middle-phalanx-distal",
|
|
131
|
+
/** Right middle finger tip */
|
|
132
|
+
RIGHT_HAND_MIDDLE_TIP = "right-hand-middle-tip",
|
|
133
|
+
/** Right ring finger metacarpal */
|
|
134
|
+
RIGHT_HAND_RING_METACARPAL = "right-hand-ring-metacarpal",
|
|
135
|
+
/** Right ring finger proximal phalanx */
|
|
136
|
+
RIGHT_HAND_RING_PHALANX_PROXIMAL = "right-hand-ring-phalanx-proximal",
|
|
137
|
+
/** Right ring finger intermediate phalanx */
|
|
138
|
+
RIGHT_HAND_RING_PHALANX_INTERMEDIATE = "right-hand-ring-phalanx-intermediate",
|
|
139
|
+
/** Right ring finger distal phalanx */
|
|
140
|
+
RIGHT_HAND_RING_PHALANX_DISTAL = "right-hand-ring-phalanx-distal",
|
|
141
|
+
/** Right ring finger tip */
|
|
142
|
+
RIGHT_HAND_RING_TIP = "right-hand-ring-tip",
|
|
143
|
+
/** Right little finger metacarpal */
|
|
144
|
+
RIGHT_HAND_LITTLE_METACARPAL = "right-hand-little-metacarpal",
|
|
145
|
+
/** Right little finger proximal phalanx */
|
|
146
|
+
RIGHT_HAND_LITTLE_PHALANX_PROXIMAL = "right-hand-little-phalanx-proximal",
|
|
147
|
+
/** Right little finger intermediate phalanx */
|
|
148
|
+
RIGHT_HAND_LITTLE_PHALANX_INTERMEDIATE = "right-hand-little-phalanx-intermediate",
|
|
149
|
+
/** Right little finger distal phalanx */
|
|
150
|
+
RIGHT_HAND_LITTLE_PHALANX_DISTAL = "right-hand-little-phalanx-distal",
|
|
151
|
+
/** Right little finger tip */
|
|
152
|
+
RIGHT_HAND_LITTLE_TIP = "right-hand-little-tip",
|
|
153
|
+
/** Left upper leg (thigh) */
|
|
154
|
+
LEFT_UPPER_LEG = "left-upper-leg",
|
|
155
|
+
/** Left lower leg (shin) */
|
|
156
|
+
LEFT_LOWER_LEG = "left-lower-leg",
|
|
157
|
+
/** Left foot ankle twist */
|
|
158
|
+
LEFT_FOOT_ANKLE_TWIST = "left-foot-ankle-twist",
|
|
159
|
+
/** Left foot ankle */
|
|
160
|
+
LEFT_FOOT_ANKLE = "left-foot-ankle",
|
|
161
|
+
/** Left foot subtalar */
|
|
162
|
+
LEFT_FOOT_SUBTALAR = "left-foot-subtalar",
|
|
163
|
+
/** Left foot transverse */
|
|
164
|
+
LEFT_FOOT_TRANSVERSE = "left-foot-transverse",
|
|
165
|
+
/** Left foot ball */
|
|
166
|
+
LEFT_FOOT_BALL = "left-foot-ball",
|
|
167
|
+
/** Right upper leg (thigh) */
|
|
168
|
+
RIGHT_UPPER_LEG = "right-upper-leg",
|
|
169
|
+
/** Right lower leg (shin) */
|
|
170
|
+
RIGHT_LOWER_LEG = "right-lower-leg",
|
|
171
|
+
/** Right foot ankle twist */
|
|
172
|
+
RIGHT_FOOT_ANKLE_TWIST = "right-foot-ankle-twist",
|
|
173
|
+
/** Right foot ankle */
|
|
174
|
+
RIGHT_FOOT_ANKLE = "right-foot-ankle",
|
|
175
|
+
/** Right foot subtalar */
|
|
176
|
+
RIGHT_FOOT_SUBTALAR = "right-foot-subtalar",
|
|
177
|
+
/** Right foot transverse */
|
|
178
|
+
RIGHT_FOOT_TRANSVERSE = "right-foot-transverse",
|
|
179
|
+
/** Right foot ball */
|
|
180
|
+
RIGHT_FOOT_BALL = "right-foot-ball"
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Parent index for each joint in {@link BodyJointReferenceArray} order.
|
|
184
|
+
* -1 means "root" (no parent). Used to convert world-space XR poses to
|
|
185
|
+
* local-space transforms suitable for skeleton bones.
|
|
186
|
+
*
|
|
187
|
+
* Hierarchy follows the WebXR Body Tracking specification and standard
|
|
188
|
+
* humanoid anatomy.
|
|
189
|
+
*/
|
|
190
|
+
export declare const BodyJointParentIndex: number[];
|
|
191
|
+
/**
|
|
192
|
+
* Logical body parts for convenient grouping of joints.
|
|
193
|
+
*/
|
|
194
|
+
export declare enum BodyPart {
|
|
195
|
+
/** Torso / spine (hips through head) */
|
|
196
|
+
TORSO = "torso",
|
|
197
|
+
/** Left arm (shoulder through wrist twist) */
|
|
198
|
+
LEFT_ARM = "left-arm",
|
|
199
|
+
/** Right arm (shoulder through wrist twist) */
|
|
200
|
+
RIGHT_ARM = "right-arm",
|
|
201
|
+
/** Left hand (palm through finger tips) */
|
|
202
|
+
LEFT_HAND = "left-hand",
|
|
203
|
+
/** Right hand (palm through finger tips) */
|
|
204
|
+
RIGHT_HAND = "right-hand",
|
|
205
|
+
/** Left leg (upper leg through foot ball) */
|
|
206
|
+
LEFT_LEG = "left-leg",
|
|
207
|
+
/** Right leg (upper leg through foot ball) */
|
|
208
|
+
RIGHT_LEG = "right-leg"
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* A dictionary mapping each {@link WebXRBodyJoint} to a bone name in a rigged body mesh.
|
|
212
|
+
*
|
|
213
|
+
* When you supply a rigged mesh to {@link WebXRTrackedBody.setBodyMesh}, provide
|
|
214
|
+
* a mapping so the feature knows which skeleton bone to drive for each joint.
|
|
215
|
+
*
|
|
216
|
+
* @example
|
|
217
|
+
* ```typescript
|
|
218
|
+
* const rigMapping: XRBodyMeshRigMapping = {
|
|
219
|
+
* "hips": "Bip01_Pelvis",
|
|
220
|
+
* "spine-lower": "Bip01_Spine",
|
|
221
|
+
* "head": "Bip01_Head",
|
|
222
|
+
* // …remaining joints…
|
|
223
|
+
* };
|
|
224
|
+
* ```
|
|
225
|
+
*/
|
|
226
|
+
export type XRBodyMeshRigMapping = {
|
|
227
|
+
[jointName in WebXRBodyJoint]?: string;
|
|
228
|
+
};
|
|
229
|
+
/**
|
|
230
|
+
* Represents the XRBodySpace native interface as defined by the spec.
|
|
231
|
+
* An XRBodySpace is an XRSpace that additionally exposes a jointName.
|
|
232
|
+
* @see https://immersive-web.github.io/body-tracking/#xrjointspace-interface
|
|
233
|
+
*/
|
|
234
|
+
interface XRBodySpace extends XRSpace {
|
|
235
|
+
readonly jointName: string;
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Represents the native XRBody interface as defined by the spec.
|
|
239
|
+
* An XRBody is an iterable map of XRBodyJoint → XRBodySpace.
|
|
240
|
+
* @see https://immersive-web.github.io/body-tracking/#xrbody-interface
|
|
241
|
+
*/
|
|
242
|
+
interface XRBody {
|
|
243
|
+
readonly size: number;
|
|
244
|
+
get(key: string): XRBodySpace | undefined;
|
|
245
|
+
forEach(callbackfn: (value: XRBodySpace, key: string, map: XRBody) => void): void;
|
|
246
|
+
[Symbol.iterator](): IterableIterator<[string, XRBodySpace]>;
|
|
247
|
+
entries(): IterableIterator<[string, XRBodySpace]>;
|
|
248
|
+
keys(): IterableIterator<string>;
|
|
249
|
+
values(): IterableIterator<XRBodySpace>;
|
|
250
|
+
}
|
|
251
|
+
declare global {
|
|
252
|
+
interface XRFrame {
|
|
253
|
+
body?: XRBody;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Configuration options for the WebXR body tracking feature.
|
|
258
|
+
*/
|
|
259
|
+
export interface IWebXRBodyTrackingOptions {
|
|
260
|
+
/**
|
|
261
|
+
* A pre-existing rigged body mesh to drive with tracked joint poses.
|
|
262
|
+
* If provided, skeleton bones will be linked to tracked joints automatically.
|
|
263
|
+
* The mesh should contain a skeleton whose bones can be mapped via `rigMapping`.
|
|
264
|
+
*/
|
|
265
|
+
bodyMesh?: AbstractMesh;
|
|
266
|
+
/**
|
|
267
|
+
* A mapping from {@link WebXRBodyJoint} names to skeleton bone names.
|
|
268
|
+
* Required when the skeleton's bone names do not match the WebXR joint names.
|
|
269
|
+
* If omitted and a body mesh is provided, the feature assumes bones are
|
|
270
|
+
* named identically to the WebXR joint names (e.g. `"hips"`, `"left-arm-upper"`, etc.).
|
|
271
|
+
*/
|
|
272
|
+
rigMapping?: XRBodyMeshRigMapping;
|
|
273
|
+
/**
|
|
274
|
+
* Scale factor applied to the local-space position of every joint.
|
|
275
|
+
*
|
|
276
|
+
* This uniformly scales the distances between parent and child joints,
|
|
277
|
+
* allowing you to fit XR body tracking data to meshes that are larger or
|
|
278
|
+
* smaller than the tracked user.
|
|
279
|
+
*
|
|
280
|
+
* - `1.0` (default): no scaling — real-world proportions.
|
|
281
|
+
* - `> 1.0`: stretches the skeleton (makes it taller / wider).
|
|
282
|
+
* - `< 1.0`: compresses the skeleton.
|
|
283
|
+
*
|
|
284
|
+
* Only affects local joint offsets, not the root (hips) position.
|
|
285
|
+
*/
|
|
286
|
+
jointScaleFactor?: number;
|
|
287
|
+
/**
|
|
288
|
+
* Preserve bind-pose local translations for mapped bones and only retarget rotations.
|
|
289
|
+
*
|
|
290
|
+
* When `false` (default), mapped bones are translated directly to the tracked joint
|
|
291
|
+
* positions. This reproduces the tracked skeleton exactly, but can distort avatars whose
|
|
292
|
+
* proportions differ from the tracked user.
|
|
293
|
+
*
|
|
294
|
+
* When `true`, mapped child bones keep their bind-pose local translation offsets while
|
|
295
|
+
* still using the tracked joint rotations. This is the typical retargeting mode for
|
|
296
|
+
* driving arbitrary skinned characters without forcing them to the tracked skeleton's
|
|
297
|
+
* segment lengths.
|
|
298
|
+
*/
|
|
299
|
+
preserveBindPoseBonePositions?: boolean;
|
|
300
|
+
/**
|
|
301
|
+
* Apply a per-bone orientation offset so the avatar bone basis matches the XR joint basis.
|
|
302
|
+
*
|
|
303
|
+
* When enabled, WebXR joint rotations are corrected using the bone's bind-space child axis.
|
|
304
|
+
* This is useful for rigs whose bone local axes do not match the anatomical axes used by
|
|
305
|
+
* the WebXR body-tracking joint orientations.
|
|
306
|
+
*/
|
|
307
|
+
useBoneOrientationOffsets?: boolean;
|
|
308
|
+
/**
|
|
309
|
+
* Rotation applied in each tracked joint's local frame to re-base the
|
|
310
|
+
* XR joint axes. Some runtimes (e.g., some Meta Quest builds) emit body
|
|
311
|
+
* joint poses whose +Z axis points along the bone (parent → child), while
|
|
312
|
+
* most avatar rigs expect +Y along the bone. Setting this to
|
|
313
|
+
* `Quaternion.RotationAxis(Vector3.Right(), -Math.PI / 2)` converts
|
|
314
|
+
* "+Z-along-bone" joint data to "+Y-along-bone" before retargeting.
|
|
315
|
+
*
|
|
316
|
+
* Applied as a pre-multiply on each joint's world matrix:
|
|
317
|
+
* `M' = R × M`, which, under Babylon's row-vector convention
|
|
318
|
+
* (`v_world = v_local × M`), effectively re-bases the joint-local axes.
|
|
319
|
+
*
|
|
320
|
+
* Default `undefined` = identity (no re-basing).
|
|
321
|
+
*/
|
|
322
|
+
jointLocalRotationOffset?: Quaternion;
|
|
323
|
+
/**
|
|
324
|
+
* Per–XR-joint override for the "aim child" joint used when
|
|
325
|
+
* {@link useBoneOrientationOffsets} is enabled.
|
|
326
|
+
*
|
|
327
|
+
* By default the aim direction for a mapped bone is computed against its
|
|
328
|
+
* nearest mapped descendant in the skeleton. For rigs whose XR-mapped
|
|
329
|
+
* spine chain has very short segments (e.g. WebXR's `hips`→`spine-lower`
|
|
330
|
+
* is typically only ~1 cm), the aim direction becomes noise-dominated and
|
|
331
|
+
* can produce a large incorrect rotation for the parent bone.
|
|
332
|
+
*
|
|
333
|
+
* Use this map to redirect a specific XR joint's aim target to a farther
|
|
334
|
+
* XR joint whose relative position is stable. Both the source and target
|
|
335
|
+
* joint must be present in {@link rigMapping} (i.e. mapped to a bone on the
|
|
336
|
+
* skeleton).
|
|
337
|
+
*
|
|
338
|
+
* Example for a Mixamo-style rig where hips, spine, spine1, spine2 and
|
|
339
|
+
* neck are all mapped:
|
|
340
|
+
* ```ts
|
|
341
|
+
* aimChildOverrides: {
|
|
342
|
+
* [WebXRBodyJoint.HIPS]: WebXRBodyJoint.SPINE_UPPER, // skip spine-lower/middle
|
|
343
|
+
* [WebXRBodyJoint.SPINE_LOWER]: WebXRBodyJoint.NECK, // long stable segment
|
|
344
|
+
* [WebXRBodyJoint.SPINE_MIDDLE]: WebXRBodyJoint.NECK,
|
|
345
|
+
* }
|
|
346
|
+
* ```
|
|
347
|
+
*/
|
|
348
|
+
aimChildOverrides?: Partial<Record<WebXRBodyJoint, WebXRBodyJoint>>;
|
|
349
|
+
/**
|
|
350
|
+
* Convenience flag for Mixamo-rigged characters.
|
|
351
|
+
*
|
|
352
|
+
* When set to `true`, the feature automatically applies:
|
|
353
|
+
* - {@link MixamoRigMapping} as the `rigMapping` (skipping any explicit
|
|
354
|
+
* `rigMapping` you provide).
|
|
355
|
+
* - {@link MixamoAimChildOverrides} as `aimChildOverrides` (skipping any
|
|
356
|
+
* explicit `aimChildOverrides` you provide).
|
|
357
|
+
* - Turns on {@link useBoneOrientationOffsets} by default (you can still
|
|
358
|
+
* override to `false`).
|
|
359
|
+
*
|
|
360
|
+
* The Mixamo `mixamorig:` bone-name prefix is detected automatically by
|
|
361
|
+
* inspecting the skeleton, so the same mapping works regardless of whether
|
|
362
|
+
* the bones have been renamed to strip the prefix (common when re-exporting).
|
|
363
|
+
*/
|
|
364
|
+
isMixamoModel?: boolean;
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* Default rig mapping for Mixamo-rigged humanoid characters.
|
|
368
|
+
*
|
|
369
|
+
* Maps each supported {@link WebXRBodyJoint} to the corresponding Mixamo bone
|
|
370
|
+
* name, **without** the `mixamorig:` prefix. When the feature applies this
|
|
371
|
+
* mapping, it auto-detects whether the skeleton uses the `mixamorig:` prefix
|
|
372
|
+
* and prepends it as needed, so the same table works for both prefixed and
|
|
373
|
+
* unprefixed exports.
|
|
374
|
+
*
|
|
375
|
+
* @example
|
|
376
|
+
* ```ts
|
|
377
|
+
* xr.featuresManager.enableFeature(WebXRFeatureName.BODY_TRACKING, "latest", {
|
|
378
|
+
* bodyMesh: myMixamoMesh,
|
|
379
|
+
* isMixamoModel: true,
|
|
380
|
+
* });
|
|
381
|
+
* ```
|
|
382
|
+
*
|
|
383
|
+
* Or, if you want to extend or customize it:
|
|
384
|
+
* ```ts
|
|
385
|
+
* import { MixamoRigMapping } from "@babylonjs/core";
|
|
386
|
+
* const rigMapping: XRBodyMeshRigMapping = { ...MixamoRigMapping, [WebXRBodyJoint.NECK]: "MyNeckBone" };
|
|
387
|
+
* ```
|
|
388
|
+
*/
|
|
389
|
+
export declare const MixamoRigMapping: XRBodyMeshRigMapping;
|
|
390
|
+
/**
|
|
391
|
+
* Default aim-child overrides for Mixamo-rigged humanoids.
|
|
392
|
+
*
|
|
393
|
+
* Redirects the short / noisy XR spine segments to longer, stable ones so that
|
|
394
|
+
* {@link IWebXRBodyTrackingOptions.useBoneOrientationOffsets} produces clean
|
|
395
|
+
* torso rotations. In WebXR data, `hips`→`spine-lower` is typically only ~1 cm
|
|
396
|
+
* apart — too short to give a stable aim direction — so we reroute Mixamo's
|
|
397
|
+
* Hips/Spine/Spine1 bones to aim at `spine-upper` / `neck` instead.
|
|
398
|
+
*/
|
|
399
|
+
export declare const MixamoAimChildOverrides: Partial<Record<WebXRBodyJoint, WebXRBodyJoint>>;
|
|
400
|
+
/**
|
|
401
|
+
* Resolve the Mixamo rig mapping for a given body mesh, auto-detecting the
|
|
402
|
+
* `mixamorig:` bone-name prefix. Falls back to the unprefixed names.
|
|
403
|
+
* @param bodyMesh The rigged Mixamo body mesh.
|
|
404
|
+
* @returns An {@link XRBodyMeshRigMapping} whose bone names include the
|
|
405
|
+
* detected prefix (if any).
|
|
406
|
+
* @internal
|
|
407
|
+
*/
|
|
408
|
+
export declare function _ResolveMixamoRigMapping(bodyMesh: AbstractMesh): XRBodyMeshRigMapping;
|
|
409
|
+
/**
|
|
410
|
+
* Represents a tracked body during a WebXR session.
|
|
411
|
+
*
|
|
412
|
+
* This class manages the bridge between the WebXR body pose data and the
|
|
413
|
+
* Babylon.js scene graph. It creates a set of {@link TransformNode}s — one per
|
|
414
|
+
* body joint — whose transforms are updated every frame from the XR runtime.
|
|
415
|
+
* When a rigged body mesh is attached, its skeleton bones are linked to these
|
|
416
|
+
* transform nodes, causing the mesh to follow the user's body automatically.
|
|
417
|
+
*
|
|
418
|
+
* Coordinate-system handling:
|
|
419
|
+
* - WebXR delivers poses in a right-handed system.
|
|
420
|
+
* - By default, Babylon.js uses a left-handed system.
|
|
421
|
+
* - The class converts the data in-place (negating the Z components of every
|
|
422
|
+
* 4 × 4 joint matrix) before decomposing into Babylon transforms.
|
|
423
|
+
* - If the mesh was authored in a right-handed tool (the common case for glTF),
|
|
424
|
+
* the bone transforms are un-flipped so the skeleton interprets them correctly.
|
|
425
|
+
*/
|
|
426
|
+
export declare class WebXRTrackedBody implements IDisposable {
|
|
427
|
+
/**
|
|
428
|
+
* Fired when the body mesh is changed via {@link setBodyMesh}.
|
|
429
|
+
*/
|
|
430
|
+
readonly onBodyMeshSetObservable: Observable<WebXRTrackedBody>;
|
|
431
|
+
private _scene;
|
|
432
|
+
/**
|
|
433
|
+
* One {@link TransformNode} per joint. These receive the WebXR matrix data
|
|
434
|
+
* every frame and serve as link targets for skeleton bones.
|
|
435
|
+
*/
|
|
436
|
+
private _jointTransforms;
|
|
437
|
+
/**
|
|
438
|
+
* Flat Float32Array that receives transform matrices directly from the
|
|
439
|
+
* WebXR API (via `fillPoses`). 16 floats per joint × 83 joints = 1 328 floats.
|
|
440
|
+
*/
|
|
441
|
+
private _jointTransformMatrices;
|
|
442
|
+
/**
|
|
443
|
+
* Copy of the raw RHS XR matrices (before LHS conversion).
|
|
444
|
+
* Used to compute bone-local transforms for glTF skeletons that
|
|
445
|
+
* operate in RHS space.
|
|
446
|
+
*/
|
|
447
|
+
private _jointTransformMatricesRHS;
|
|
448
|
+
/**
|
|
449
|
+
* Cached array of XRBodySpace objects extracted from the XRBody, kept in the
|
|
450
|
+
* same order as {@link BodyJointReferenceArray}.
|
|
451
|
+
*/
|
|
452
|
+
private _jointSpaces;
|
|
453
|
+
/** Temporary matrix: this joint's XR world-space matrix. */
|
|
454
|
+
private _tempJointMatrix;
|
|
455
|
+
/** Temporary matrix: parent joint's XR world-space matrix. */
|
|
456
|
+
private _tempParentMatrix;
|
|
457
|
+
/** Temporary matrix: computed bone-local matrix. */
|
|
458
|
+
private _tempLocalMatrix;
|
|
459
|
+
/** Temporary vector for scale extracted from decompose. */
|
|
460
|
+
private _tempScaleVector;
|
|
461
|
+
/** Temporary quaternion for decompose. */
|
|
462
|
+
private _tempRotQuat;
|
|
463
|
+
/** Temporary position vector for decompose. */
|
|
464
|
+
private _tempPosVec;
|
|
465
|
+
/** Temporary quaternion for alternate rotation calculations. */
|
|
466
|
+
private _tempRotQuat2;
|
|
467
|
+
/** Temporary vector for desired child direction. */
|
|
468
|
+
private _tempDirection;
|
|
469
|
+
/** Temporary vector for joint-local child direction. */
|
|
470
|
+
private _tempLocalDirection;
|
|
471
|
+
/** Cached desired final positions for mapped joints. */
|
|
472
|
+
private _desiredFinalPositions;
|
|
473
|
+
/**
|
|
474
|
+
* For each joint index, the joint index of the nearest mapped SKELETON
|
|
475
|
+
* ancestor bone. -1 when the bone has no mapped ancestor (root level).
|
|
476
|
+
* Precomputed in {@link setBodyMesh} by walking the skeleton hierarchy.
|
|
477
|
+
*/
|
|
478
|
+
private _jointParentJointIdx;
|
|
479
|
+
/** Tracks which joint indices have a linked bone (for step 4b). */
|
|
480
|
+
private _jointHasBone;
|
|
481
|
+
/** Bone → XR joint index lookup, built in {@link setBodyMesh}. */
|
|
482
|
+
private _boneToJointIdx;
|
|
483
|
+
/** Original bind-pose local matrices for mapped bones. */
|
|
484
|
+
private _mappedBoneBindLocals;
|
|
485
|
+
/** Nearest mapped child bone for each mapped bone. */
|
|
486
|
+
private _mappedChildBones;
|
|
487
|
+
/** Bind-space local child direction for each mapped bone. */
|
|
488
|
+
private _bindLocalAimDirections;
|
|
489
|
+
/**
|
|
490
|
+
* XR joint index to aim each mapped bone at. This can be a mapped joint
|
|
491
|
+
* (same as `_boneToJointIdx.get(aimChildBone)`) or an **unmapped** XR
|
|
492
|
+
* joint whose tracked position is nonetheless useful for aim correction —
|
|
493
|
+
* e.g. `LEFT_HAND_MIDDLE_METACARPAL` for `mixamorig:LeftHand`, which has
|
|
494
|
+
* no mapped finger descendant but whose tracked position still defines
|
|
495
|
+
* "where the hand is pointing".
|
|
496
|
+
*/
|
|
497
|
+
private _boneAimTargetJointIdx;
|
|
498
|
+
/**
|
|
499
|
+
* Per-mapped-bone bind-pose world rotation in mesh-local space
|
|
500
|
+
* (decomposed from `bone.getFinalMatrix()` at bind time). Used by the
|
|
501
|
+
* delta-from-bind retarget path (axis-convention-invariant).
|
|
502
|
+
*/
|
|
503
|
+
private _bindBoneWorldRotMeshLocal;
|
|
504
|
+
/**
|
|
505
|
+
* Bind-pose tracked joint rotation in mesh-local space per mapped joint.
|
|
506
|
+
* Captured on the first tracked frame (or on demand via
|
|
507
|
+
* {@link captureTrackedBind}). `null` until captured.
|
|
508
|
+
*/
|
|
509
|
+
private _trackedBindDesiredFinalRot;
|
|
510
|
+
/** Bind-pose tracked joint position (mesh-local), captured alongside rotation. */
|
|
511
|
+
private _trackedBindDesiredFinalPos;
|
|
512
|
+
/** True once a tracked-bind snapshot has been taken. */
|
|
513
|
+
private _hasTrackedBind;
|
|
514
|
+
/**
|
|
515
|
+
* When `true` (default), the first tracked frame after the feature
|
|
516
|
+
* attaches is used as the "rest" pose for delta-from-bind retargeting.
|
|
517
|
+
* Set to `false` to require an explicit {@link captureTrackedBind} call.
|
|
518
|
+
*/
|
|
519
|
+
autoCaptureBindOnFirstFrame: boolean;
|
|
520
|
+
/** Scratch quaternion for retarget delta composition. */
|
|
521
|
+
private _tempDeltaQuat;
|
|
522
|
+
private _tempBoneWorldRot;
|
|
523
|
+
private _tempParentNewWorldRotInv;
|
|
524
|
+
private _tempTrackedCurRot;
|
|
525
|
+
private _tempTrackedCurPos;
|
|
526
|
+
private _tempBindLocalScale;
|
|
527
|
+
private _tempBindLocalPos;
|
|
528
|
+
/**
|
|
529
|
+
* Per-bone cache of the current frame's computed world rotation.
|
|
530
|
+
* Entries are pooled across frames (values are reused via `copyFrom`)
|
|
531
|
+
* to avoid allocating a fresh Quaternion per mapped bone per frame.
|
|
532
|
+
* A bone is considered "populated this frame" iff it has been visited
|
|
533
|
+
* by the current retarget pass (tracked via `_computedBoneNewWorldRotFrameId`).
|
|
534
|
+
*/
|
|
535
|
+
private _computedBoneNewWorldRot;
|
|
536
|
+
/** Per-bone marker: frame id at which the pooled rotation above was last set. */
|
|
537
|
+
private _computedBoneNewWorldRotFrameId;
|
|
538
|
+
private _currentRetargetFrameId;
|
|
539
|
+
/** Scratch quaternion reused for the parent-world accumulation loop. */
|
|
540
|
+
private _tempParentAccumRot;
|
|
541
|
+
/** Scratch quaternion reused for the parent-world intermediate product. */
|
|
542
|
+
private _tempParentAccumTmp;
|
|
543
|
+
/** The skeleton reference for iterating bones in parent-first order. */
|
|
544
|
+
private _skeleton;
|
|
545
|
+
/** Cached inverse of the skeleton mesh's world matrix. */
|
|
546
|
+
private _meshWorldMatrixInverse;
|
|
547
|
+
/** Cached inverse of the skeleton mesh pose matrix when initial skinning is used. */
|
|
548
|
+
private _initialSkinMatrixInverse;
|
|
549
|
+
/**
|
|
550
|
+
* Pre-allocated desiredFinal matrices (one per joint slot).
|
|
551
|
+
* `desiredFinal[i] = strip(xrWorld[i] × inv(meshWorld))` — the bone's
|
|
552
|
+
* target skeleton-space final matrix with parasitic scale removed.
|
|
553
|
+
*/
|
|
554
|
+
private _desiredFinals;
|
|
555
|
+
/**
|
|
556
|
+
* Standalone TransformNodes created for unmapped skinned bones.
|
|
557
|
+
* These TNs are initialized to the bone's bind-pose local and linked
|
|
558
|
+
* so that `prepare()` reads deterministic values rather than the
|
|
559
|
+
* original glTF scene-graph TNs (which we don't control).
|
|
560
|
+
*/
|
|
561
|
+
private _unmappedBoneNodes;
|
|
562
|
+
/** The mesh that owns the skeleton (used for world-matrix inverse). */
|
|
563
|
+
private _skeletonMesh;
|
|
564
|
+
/** The body mesh root (topmost parent), used to parent the mesh to the camera. */
|
|
565
|
+
private _bodyMeshRoot;
|
|
566
|
+
/** The rigged body mesh, if any. */
|
|
567
|
+
private _bodyMesh;
|
|
568
|
+
/** Scale factor for local joint offsets. */
|
|
569
|
+
private _jointScaleFactor;
|
|
570
|
+
/** Whether mapped bones should keep their bind-pose local translations. */
|
|
571
|
+
private readonly _preserveBindPoseBonePositions;
|
|
572
|
+
/** Whether mapped bones should correct WebXR joint rotations using bind-space orientation offsets. */
|
|
573
|
+
private readonly _useBoneOrientationOffsets;
|
|
574
|
+
/** Per–XR-joint override mapping for aim children (used with _useBoneOrientationOffsets). */
|
|
575
|
+
private _aimChildOverrides;
|
|
576
|
+
/**
|
|
577
|
+
* Runtime-mutable rotation applied in each tracked joint's local frame to
|
|
578
|
+
* re-base XR joint axes (e.g., "+Z-along-bone" → "+Y-along-bone").
|
|
579
|
+
* `null` = identity / disabled.
|
|
580
|
+
*/
|
|
581
|
+
jointLocalRotationOffset: Nullable<Quaternion>;
|
|
582
|
+
/** Cached 4×4 matrix form of {@link jointLocalRotationOffset} for the fast path. */
|
|
583
|
+
private _jointLocalRotationOffsetMatrix;
|
|
584
|
+
/** Temporary matrix used when applying {@link jointLocalRotationOffset}. */
|
|
585
|
+
private _tempOffsetAppliedMatrix;
|
|
586
|
+
/**
|
|
587
|
+
* When true, bypass skeleton.prepare() and write skin matrices directly.
|
|
588
|
+
* This is a diagnostic flag to help isolate rendering issues. When the
|
|
589
|
+
* standard pipeline (TN → bone → prepare → skin matrices) produces
|
|
590
|
+
* unexpected results, enabling this writes `absInvBind × final` directly
|
|
591
|
+
* into the skeleton's transform matrix buffer.
|
|
592
|
+
* @internal
|
|
593
|
+
*/
|
|
594
|
+
_directSkinWrite: boolean;
|
|
595
|
+
/**
|
|
596
|
+
* Debug info string from the last `updateFromXRFrame` call.
|
|
597
|
+
* Useful for diagnosing tracking failures on-device.
|
|
598
|
+
* @internal
|
|
599
|
+
*/
|
|
600
|
+
_lastDebugInfo: string;
|
|
601
|
+
/**
|
|
602
|
+
* Get the current body mesh (if any).
|
|
603
|
+
*/
|
|
604
|
+
get bodyMesh(): Nullable<AbstractMesh>;
|
|
605
|
+
/**
|
|
606
|
+
* Get or set the scale factor for local joint offsets.
|
|
607
|
+
* @see {@link IWebXRBodyTrackingOptions.jointScaleFactor}
|
|
608
|
+
*/
|
|
609
|
+
get jointScaleFactor(): number;
|
|
610
|
+
set jointScaleFactor(value: number);
|
|
611
|
+
/**
|
|
612
|
+
* Returns the array of transform nodes representing each body joint.
|
|
613
|
+
* The order matches {@link WebXRBodyTracking.AllBodyJoints}; use
|
|
614
|
+
* {@link getJointTransform} or {@link getBodyPartTransforms} for
|
|
615
|
+
* name-based lookup.
|
|
616
|
+
*
|
|
617
|
+
* Note: when a body mesh is attached, these transform nodes are also
|
|
618
|
+
* used as the skeleton's link targets for mapped joints. In that case
|
|
619
|
+
* the values held by mapped-joint nodes are skeleton-local (parent bone's
|
|
620
|
+
* frame), not XR world-space. Unmapped-joint nodes always hold world-space
|
|
621
|
+
* pose. If you need world-space poses for every joint regardless of
|
|
622
|
+
* mapping, sample the bone matrices directly via the attached skeleton.
|
|
623
|
+
*/
|
|
624
|
+
get jointTransforms(): readonly TransformNode[];
|
|
625
|
+
/**
|
|
626
|
+
* Get the transform node for a specific body joint.
|
|
627
|
+
* @param jointName The name of the body joint (from {@link WebXRBodyJoint}).
|
|
628
|
+
* @returns The transform node corresponding to that joint, or `undefined` if not found.
|
|
629
|
+
*/
|
|
630
|
+
getJointTransform(jointName: WebXRBodyJoint): TransformNode | undefined;
|
|
631
|
+
/**
|
|
632
|
+
* Get all joint transform nodes that belong to a given body part.
|
|
633
|
+
* @param part The body part to query.
|
|
634
|
+
* @param result Optional pre-allocated array to fill (avoids per-call allocation).
|
|
635
|
+
* The array is cleared and populated with the results.
|
|
636
|
+
* @returns An array of TransformNodes for that body part.
|
|
637
|
+
*/
|
|
638
|
+
getBodyPartTransforms(part: BodyPart, result?: TransformNode[]): TransformNode[];
|
|
639
|
+
/**
|
|
640
|
+
* Construct a new tracked body instance.
|
|
641
|
+
* @param scene The Babylon.js scene.
|
|
642
|
+
* @param bodyMesh Optional rigged body mesh to attach immediately.
|
|
643
|
+
* @param rigMapping Optional mapping from WebXR joint names to skeleton bone names.
|
|
644
|
+
* @param jointScaleFactor Scale factor for local joint offsets (default 1.0).
|
|
645
|
+
* @param preserveBindPoseBonePositions Whether mapped bones should keep bind-pose local translations.
|
|
646
|
+
* @param useBoneOrientationOffsets Whether mapped bones should correct XR joint rotations using bind-space offsets.
|
|
647
|
+
* @param aimChildOverrides Per–XR-joint override for the aim child used with `useBoneOrientationOffsets`.
|
|
648
|
+
* @param jointLocalRotationOffset Optional rotation re-basing each XR joint's local frame (e.g. Z-along-bone → Y-along-bone).
|
|
649
|
+
*/
|
|
650
|
+
constructor(scene: Scene, bodyMesh?: AbstractMesh, rigMapping?: XRBodyMeshRigMapping, jointScaleFactor?: number, preserveBindPoseBonePositions?: boolean, useBoneOrientationOffsets?: boolean, aimChildOverrides?: Partial<Record<WebXRBodyJoint, WebXRBodyJoint>>, jointLocalRotationOffset?: Quaternion);
|
|
651
|
+
/**
|
|
652
|
+
* Attach (or replace) a rigged body mesh.
|
|
653
|
+
*
|
|
654
|
+
* The mesh's skeleton bones are linked to the internal transform nodes
|
|
655
|
+
* that receive WebXR tracking data each frame. If the mesh has a skeleton,
|
|
656
|
+
* the `rigMapping` (or a direct name match) is used to bind each bone.
|
|
657
|
+
*
|
|
658
|
+
* @param bodyMesh The rigged mesh to drive.
|
|
659
|
+
* @param rigMapping An optional mapping from {@link WebXRBodyJoint} to bone name.
|
|
660
|
+
* If omitted, bones are expected to be named after the WebXR joint names.
|
|
661
|
+
*/
|
|
662
|
+
setBodyMesh(bodyMesh: AbstractMesh, rigMapping?: XRBodyMeshRigMapping): void;
|
|
663
|
+
/**
|
|
664
|
+
* Update joint transforms from the current XR frame.
|
|
665
|
+
*
|
|
666
|
+
* This method is called once per frame by the feature class. Internally it:
|
|
667
|
+
* 1. Extracts all XRBodySpaces from the XRBody.
|
|
668
|
+
* 2. Fills the transform-matrix buffer via `fillPoses()` (or per-joint fallback).
|
|
669
|
+
* 3. Converts from WebXR right-handed to Babylon left-handed coordinates.
|
|
670
|
+
* 4. Decomposes each matrix into the corresponding TransformNode.
|
|
671
|
+
* 5. Parents the body mesh root to the XR camera so it tracks correctly.
|
|
672
|
+
*
|
|
673
|
+
* @param xrFrame The current XRFrame.
|
|
674
|
+
* @param referenceSpace The XRReferenceSpace to resolve poses against.
|
|
675
|
+
* @param xrCameraParent The parent node of the XR camera (used for parenting).
|
|
676
|
+
* @returns `true` if valid tracking data was processed, `false` otherwise.
|
|
677
|
+
*/
|
|
678
|
+
updateFromXRFrame(xrFrame: XRFrame, referenceSpace: XRReferenceSpace, xrCameraParent: Nullable<Node>): boolean;
|
|
679
|
+
/**
|
|
680
|
+
* Replay a pre-captured joint matrix set through the retargeting
|
|
681
|
+
* pipeline as if it had just been delivered by an XR frame.
|
|
682
|
+
*
|
|
683
|
+
* Useful for headset-less testing: call with a snapshot captured via
|
|
684
|
+
* {@link snapshotFrame} (the `jointMatricesRHS` array, or `jointMatricesLHS`
|
|
685
|
+
* already flipped). The matrices are assumed to be RHS unless
|
|
686
|
+
* `isAlreadyLhs=true`, in which case the RHS→LHS flip step is skipped.
|
|
687
|
+
*
|
|
688
|
+
* @param rawMatrices Float32Array of BODY_JOINT_COUNT × 16 (= 1328) floats.
|
|
689
|
+
* @param isAlreadyLhs Set to `true` if matrices are already LHS-converted.
|
|
690
|
+
*/
|
|
691
|
+
replayRawJointMatrices(rawMatrices: Float32Array | number[], isAlreadyLhs?: boolean): void;
|
|
692
|
+
/**
|
|
693
|
+
* Run steps 2.5 → 5 of the retargeting pipeline using whatever is
|
|
694
|
+
* currently in `_jointTransformMatrices` (as if the WebXR API just
|
|
695
|
+
* filled it for the current frame).
|
|
696
|
+
* @param xrCameraParent Parent node of the XR camera (used to parent the body mesh root during live XR).
|
|
697
|
+
* @param skipRhsToLhs If true, skip the RHS→LHS flip (matrices are already in the scene's handedness).
|
|
698
|
+
*/
|
|
699
|
+
private _processTrackedJointMatrices;
|
|
700
|
+
/**
|
|
701
|
+
* Capture the current tracked-joint desired-final rotations and positions
|
|
702
|
+
* as the "rest pose" for delta-from-bind retargeting.
|
|
703
|
+
*
|
|
704
|
+
* Delta-from-bind is the production retarget path: every subsequent
|
|
705
|
+
* frame is interpreted as a rotation delta from this snapshot, which
|
|
706
|
+
* makes retargeting invariant to the XR-joint axis convention and to
|
|
707
|
+
* any skeletal-proportion differences between the tracked user and the
|
|
708
|
+
* avatar.
|
|
709
|
+
*
|
|
710
|
+
* Call this after the user assumes a known rest pose (e.g. T-pose,
|
|
711
|
+
* A-pose, arms-at-sides). By default the feature auto-captures on the
|
|
712
|
+
* first tracked frame — disable via {@link autoCaptureBindOnFirstFrame}.
|
|
713
|
+
*/
|
|
714
|
+
captureTrackedBind(): void;
|
|
715
|
+
/**
|
|
716
|
+
* Clear any captured bind, reverting subsequent frames to the fallback
|
|
717
|
+
* direct-retarget path (or re-triggering auto-capture on the next frame).
|
|
718
|
+
*/
|
|
719
|
+
clearTrackedBind(): void;
|
|
720
|
+
/** Internal: copy current desiredFinals into the tracked-bind slots. */
|
|
721
|
+
private _captureTrackedBindFromDesiredFinals;
|
|
722
|
+
/**
|
|
723
|
+
* Delta-from-bind retarget: axis-convention-invariant.
|
|
724
|
+
*
|
|
725
|
+
* For each mapped bone in skeleton order (parents first):
|
|
726
|
+
* let j = joint mapped to this bone
|
|
727
|
+
* deltaMeshLocalRot = bindTracked[j]⁻¹ × currentTracked[j] (right-side in row-vector)
|
|
728
|
+
* newBoneWorldRot = bindBoneWorldRot × deltaMeshLocalRot
|
|
729
|
+
* newBoneLocalRot = newBoneWorldRot × parentNewBoneWorldRot⁻¹
|
|
730
|
+
*
|
|
731
|
+
* Positions: root bone receives tracked world delta (so the avatar
|
|
732
|
+
* translates with the user). All other mapped bones keep their rig's
|
|
733
|
+
* bind-pose local translation to preserve segment lengths.
|
|
734
|
+
* @param scaleFactor Additional scale applied to joint local positions.
|
|
735
|
+
*/
|
|
736
|
+
private _retargetDeltaFromBind;
|
|
737
|
+
/**
|
|
738
|
+
* Legacy direct-retarget path (pre-bind-capture). Kept as fallback.
|
|
739
|
+
* @param useInitialSkinMatrix Skeleton needs initial-skin-matrix chaining for the root.
|
|
740
|
+
* @param useBoneOrientationOffsets Apply aim-direction correction per mapped bone.
|
|
741
|
+
* @param scaleFactor Additional scale applied to joint local positions.
|
|
742
|
+
* @param computedWorldRotations Optional map used by the aim-correction path for parent lookups.
|
|
743
|
+
*/
|
|
744
|
+
private _retargetDirect;
|
|
745
|
+
/**
|
|
746
|
+
* Capture a snapshot of the current frame's raw XR joint matrices and
|
|
747
|
+
* skeleton metadata. Returns a JSON string that can be used offline to
|
|
748
|
+
* replay / debug bone-local computation without a headset.
|
|
749
|
+
*
|
|
750
|
+
* The snapshot includes:
|
|
751
|
+
* - `jointMatricesRHS` – 83 × 16 raw RHS matrices (before LHS conversion)
|
|
752
|
+
* - `jointMatricesLHS` – 83 × 16 LHS-converted matrices (after step 3)
|
|
753
|
+
* - `meshWorldMatrix` – 16 floats, the skeleton mesh's world matrix (if any)
|
|
754
|
+
* - `jointHasBone` – boolean[83], which joints are mapped to bones
|
|
755
|
+
* - `jointParentJointIdx` – number[83], mapped ancestor for each joint
|
|
756
|
+
* - `useRightHandedSystem` – scene handedness setting
|
|
757
|
+
* - `jointNames` – the 83 joint names in order
|
|
758
|
+
*
|
|
759
|
+
* @returns A JSON string with the snapshot data.
|
|
760
|
+
*/
|
|
761
|
+
snapshotFrame(): string;
|
|
762
|
+
/**
|
|
763
|
+
* Capture a snapshot and copy it to the system clipboard.
|
|
764
|
+
* Logs to the console on success or failure.
|
|
765
|
+
* @returns A promise that resolves when the copy completes.
|
|
766
|
+
*/
|
|
767
|
+
snapshotFrameToClipboardAsync(): Promise<void>;
|
|
768
|
+
/**
|
|
769
|
+
* Dispose of this tracked body and its resources.
|
|
770
|
+
* @param disposeMesh If `true`, the body mesh and its skeleton are disposed as well.
|
|
771
|
+
*/
|
|
772
|
+
dispose(disposeMesh?: boolean): void;
|
|
773
|
+
}
|
|
774
|
+
/**
|
|
775
|
+
* WebXR Body Tracking feature.
|
|
776
|
+
*
|
|
777
|
+
* This feature tracks the user's full-body pose using the
|
|
778
|
+
* [WebXR Body Tracking Module](https://immersive-web.github.io/body-tracking/),
|
|
779
|
+
* which exposes 83 articulated joints covering the torso, arms, hands, legs and feet.
|
|
780
|
+
*
|
|
781
|
+
* ## Quick Start
|
|
782
|
+
*
|
|
783
|
+
* ```typescript
|
|
784
|
+
* // Enable body tracking when creating the default XR experience:
|
|
785
|
+
* const xr = await scene.createDefaultXRExperienceAsync();
|
|
786
|
+
* const bodyTracking = xr.baseExperience.featuresManager.enableFeature(
|
|
787
|
+
* WebXRFeatureName.BODY_TRACKING,
|
|
788
|
+
* "latest",
|
|
789
|
+
* {
|
|
790
|
+
* bodyMesh: myRiggedBodyMesh,
|
|
791
|
+
* rigMapping: {
|
|
792
|
+
* "hips": "Bip01_Pelvis",
|
|
793
|
+
* "spine-lower": "Bip01_Spine",
|
|
794
|
+
* // … one entry per joint you want to drive …
|
|
795
|
+
* },
|
|
796
|
+
* } as IWebXRBodyTrackingOptions,
|
|
797
|
+
* );
|
|
798
|
+
*
|
|
799
|
+
* // React to tracking changes:
|
|
800
|
+
* bodyTracking.onBodyTrackingStartedObservable.add((trackedBody) => {
|
|
801
|
+
* console.log("Body tracking started");
|
|
802
|
+
* });
|
|
803
|
+
* bodyTracking.onBodyTrackingFrameUpdateObservable.add((trackedBody) => {
|
|
804
|
+
* // The tracked body's joint transforms are already up-to-date.
|
|
805
|
+
* });
|
|
806
|
+
* ```
|
|
807
|
+
*
|
|
808
|
+
* ## How It Works
|
|
809
|
+
*
|
|
810
|
+
* 1. The feature requests the `"body-tracking"` native WebXR feature at session start.
|
|
811
|
+
* 2. Each frame, if `XRFrame.body` is available, joint poses are filled into a
|
|
812
|
+
* flat Float32Array via the batch `fillPoses()` API (with a per-joint fallback).
|
|
813
|
+
* 3. The 4 × 4 matrices are converted from WebXR right-handed coordinates to
|
|
814
|
+
* Babylon.js left-handed coordinates in-place (unless the scene is RHS).
|
|
815
|
+
* 4. Each matrix is decomposed and written to a TransformNode; skeleton bones
|
|
816
|
+
* linked to those nodes animate the rigged mesh automatically.
|
|
817
|
+
*
|
|
818
|
+
* ## Coordinate System
|
|
819
|
+
*
|
|
820
|
+
* WebXR data arrives in a **right-handed** coordinate system. Babylon.js
|
|
821
|
+
* defaults to **left-handed**. The conversion is handled automatically:
|
|
822
|
+
* - Joint matrices are flipped in-place (Z-negation of specific matrix elements).
|
|
823
|
+
* - For meshes authored in a right-handed tool (glTF, Blender, etc.), the bone
|
|
824
|
+
* data is un-flipped so the skeleton interprets poses correctly.
|
|
825
|
+
* - If you use `scene.useRightHandedSystem = true`, no conversion is applied.
|
|
826
|
+
*
|
|
827
|
+
* @see https://immersive-web.github.io/body-tracking/
|
|
828
|
+
*/
|
|
829
|
+
export declare class WebXRBodyTracking extends WebXRAbstractFeature {
|
|
830
|
+
/** Configuration options for the body tracking feature. */
|
|
831
|
+
readonly options: IWebXRBodyTrackingOptions;
|
|
832
|
+
/**
|
|
833
|
+
* The module's name, used when enabling the feature on the features manager.
|
|
834
|
+
* Value: `"xr-body-tracking"`.
|
|
835
|
+
*/
|
|
836
|
+
static readonly Name: "xr-body-tracking";
|
|
837
|
+
/**
|
|
838
|
+
* The (Babylon) version of this module.
|
|
839
|
+
* This is an integer representing the implementation version.
|
|
840
|
+
* This number does not correspond to the WebXR specs version.
|
|
841
|
+
*/
|
|
842
|
+
static readonly Version = 1;
|
|
843
|
+
/**
|
|
844
|
+
* Observable fired when body tracking starts (i.e. the first frame where
|
|
845
|
+
* `XRFrame.body` returns valid data).
|
|
846
|
+
*/
|
|
847
|
+
readonly onBodyTrackingStartedObservable: Observable<WebXRTrackedBody>;
|
|
848
|
+
/**
|
|
849
|
+
* Observable fired when body tracking is lost (i.e. `XRFrame.body` becomes
|
|
850
|
+
* `null` or returns no valid poses after previously tracking).
|
|
851
|
+
*/
|
|
852
|
+
readonly onBodyTrackingEndedObservable: Observable<void>;
|
|
853
|
+
/**
|
|
854
|
+
* Observable fired every frame that has valid body tracking data.
|
|
855
|
+
* At the point of notification, all joint transforms are up-to-date.
|
|
856
|
+
*/
|
|
857
|
+
readonly onBodyTrackingFrameUpdateObservable: Observable<WebXRTrackedBody>;
|
|
858
|
+
/**
|
|
859
|
+
* Observable fired when the body mesh has been set via {@link setBodyMesh}
|
|
860
|
+
* or during initial configuration.
|
|
861
|
+
*/
|
|
862
|
+
readonly onBodyMeshSetObservable: Observable<WebXRTrackedBody>;
|
|
863
|
+
/** The current tracked body, or null when not tracking. */
|
|
864
|
+
private _trackedBody;
|
|
865
|
+
/** True while we have an active body tracking session. */
|
|
866
|
+
private _isTracking;
|
|
867
|
+
/** Observer for world scale changes, so the body mesh can be rescaled. */
|
|
868
|
+
private _worldScaleObserver;
|
|
869
|
+
/**
|
|
870
|
+
* Debug info from the feature-level frame loop.
|
|
871
|
+
* Shows why `_onXRFrame` did or did not call `updateFromXRFrame`.
|
|
872
|
+
* @internal
|
|
873
|
+
*/
|
|
874
|
+
_lastFrameDebugInfo: string;
|
|
875
|
+
/**
|
|
876
|
+
* Get the currently tracked body, if any.
|
|
877
|
+
*/
|
|
878
|
+
get trackedBody(): Nullable<WebXRTrackedBody>;
|
|
879
|
+
/**
|
|
880
|
+
* Returns `true` while body tracking data is actively being received.
|
|
881
|
+
*/
|
|
882
|
+
get isTracking(): boolean;
|
|
883
|
+
/**
|
|
884
|
+
* Construct a new WebXRBodyTracking feature.
|
|
885
|
+
* @param _xrSessionManager The XR session manager.
|
|
886
|
+
* @param options Configuration options.
|
|
887
|
+
*/
|
|
888
|
+
constructor(_xrSessionManager: WebXRSessionManager,
|
|
889
|
+
/** Configuration options for the body tracking feature. */
|
|
890
|
+
options?: IWebXRBodyTrackingOptions);
|
|
891
|
+
/**
|
|
892
|
+
* Attach a rigged body mesh (or replace the current one) at any time.
|
|
893
|
+
*
|
|
894
|
+
* This is a convenience method that forwards to the underlying
|
|
895
|
+
* {@link WebXRTrackedBody.setBodyMesh}. The body does not need to be
|
|
896
|
+
* already tracking for this to work — the mesh will be applied once
|
|
897
|
+
* tracking begins.
|
|
898
|
+
*
|
|
899
|
+
* @param bodyMesh The rigged mesh to drive.
|
|
900
|
+
* @param rigMapping Optional mapping from {@link WebXRBodyJoint} names to bone names.
|
|
901
|
+
*/
|
|
902
|
+
setBodyMesh(bodyMesh: AbstractMesh, rigMapping?: XRBodyMeshRigMapping): void;
|
|
903
|
+
/**
|
|
904
|
+
* Attach the feature.
|
|
905
|
+
* Called by the features manager when the XR session initialises.
|
|
906
|
+
*
|
|
907
|
+
* Body tracking is a draft WebXR spec. Some UAs (e.g. Meta Quest) provide
|
|
908
|
+
* body data on `XRFrame.body` but do not list `"body-tracking"` in
|
|
909
|
+
* `session.enabledFeatures`. To handle this, we temporarily clear
|
|
910
|
+
* {@link xrNativeFeatureName} before calling the base `attach()` so the
|
|
911
|
+
* enabled-features check is skipped, then restore it afterwards.
|
|
912
|
+
* @returns `true` if attachment succeeded.
|
|
913
|
+
*/
|
|
914
|
+
attach(): boolean;
|
|
915
|
+
/**
|
|
916
|
+
* Detach the feature.
|
|
917
|
+
* Called by the features manager when the XR session ends.
|
|
918
|
+
* @returns `true` if detachment succeeded.
|
|
919
|
+
*/
|
|
920
|
+
detach(): boolean;
|
|
921
|
+
/**
|
|
922
|
+
* Dispose this feature and all resources.
|
|
923
|
+
*/
|
|
924
|
+
dispose(): void;
|
|
925
|
+
/**
|
|
926
|
+
* Called every XR frame by the base class.
|
|
927
|
+
* Reads body joint data from the XR runtime and updates transforms.
|
|
928
|
+
* @param xrFrame The current XRFrame.
|
|
929
|
+
*/
|
|
930
|
+
protected _onXRFrame(xrFrame: XRFrame): void;
|
|
931
|
+
/**
|
|
932
|
+
* Returns the complete ordered list of body joint names tracked by this feature.
|
|
933
|
+
* Useful for iterating over all joints or building UI.
|
|
934
|
+
*/
|
|
935
|
+
static get AllBodyJoints(): readonly WebXRBodyJoint[];
|
|
936
|
+
/**
|
|
937
|
+
* Capture a single-frame snapshot of all 83 joints and copy it to the
|
|
938
|
+
* clipboard. Call this from a playground button or the console while
|
|
939
|
+
* wearing the headset:
|
|
940
|
+
*
|
|
941
|
+
* ```typescript
|
|
942
|
+
* bodyTracking.snapshotFrameToClipboard();
|
|
943
|
+
* ```
|
|
944
|
+
*
|
|
945
|
+
* The JSON can later be loaded offline to replay the bone-local
|
|
946
|
+
* computation without a headset.
|
|
947
|
+
* @returns A promise that resolves when the copy completes, or rejects
|
|
948
|
+
* if no body is currently tracked.
|
|
949
|
+
*/
|
|
950
|
+
snapshotFrameToClipboardAsync(): Promise<void>;
|
|
951
|
+
}
|
|
952
|
+
export {};
|