xrblocks 0.5.1 → 0.7.0
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/README.md +2 -2
- package/build/ai/AI.d.ts +1 -1
- package/build/camera/CameraUtils.d.ts +20 -4
- package/build/core/components/ScriptsManager.d.ts +8 -1
- package/build/depth/Depth.d.ts +8 -5
- package/build/depth/DepthTextures.d.ts +4 -4
- package/build/simulator/SimulatorDepth.d.ts +16 -5
- package/build/xrblocks.js +288 -128
- package/build/xrblocks.js.map +1 -1
- package/build/xrblocks.min.js +1 -1
- package/build/xrblocks.min.js.map +1 -1
- package/package.json +6 -6
package/build/xrblocks.js
CHANGED
|
@@ -14,15 +14,15 @@
|
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*
|
|
16
16
|
* @file xrblocks.js
|
|
17
|
-
* @version v0.
|
|
18
|
-
* @commitid
|
|
19
|
-
* @builddate
|
|
17
|
+
* @version v0.7.0
|
|
18
|
+
* @commitid 950b1e5
|
|
19
|
+
* @builddate 2026-01-03T00:05:55.605Z
|
|
20
20
|
* @description XR Blocks SDK, built from source with the above commit ID.
|
|
21
21
|
* @agent When using with Gemini to create XR apps, use **Gemini Canvas** mode,
|
|
22
22
|
* and follow rules below:
|
|
23
23
|
* 1. Include the following importmap for maximum compatibility:
|
|
24
|
-
"three": "https://cdn.jsdelivr.net/npm/three@0.
|
|
25
|
-
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.
|
|
24
|
+
"three": "https://cdn.jsdelivr.net/npm/three@0.182.0/build/three.module.js",
|
|
25
|
+
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.182.0/examples/jsm/",
|
|
26
26
|
"troika-three-text": "https://cdn.jsdelivr.net/gh/protectwise/troika@028b81cf308f0f22e5aa8e78196be56ec1997af5/packages/troika-three-text/src/index.js",
|
|
27
27
|
"troika-three-utils": "https://cdn.jsdelivr.net/gh/protectwise/troika@v0.52.4/packages/troika-three-utils/src/index.js",
|
|
28
28
|
"troika-worker-utils": "https://cdn.jsdelivr.net/gh/protectwise/troika@v0.52.4/packages/troika-worker-utils/src/index.js",
|
|
@@ -286,7 +286,7 @@ class GenerateSkyboxTool extends Tool {
|
|
|
286
286
|
async execute(args) {
|
|
287
287
|
try {
|
|
288
288
|
const image = await this.ai.generate('Generate a 360 equirectangular skybox image for the prompt of:' +
|
|
289
|
-
args.prompt, 'image', 'Generate a 360 equirectangular skybox image for the prompt'
|
|
289
|
+
args.prompt, 'image', 'Generate a 360 equirectangular skybox image for the prompt');
|
|
290
290
|
if (image) {
|
|
291
291
|
console.log('Applying texture...');
|
|
292
292
|
this.scene.background = new THREE.TextureLoader().load(image);
|
|
@@ -1365,7 +1365,7 @@ class Gemini extends BaseAIModel {
|
|
|
1365
1365
|
}
|
|
1366
1366
|
return { text: response.text || null };
|
|
1367
1367
|
}
|
|
1368
|
-
async generate(prompt, type = 'image', systemInstruction = 'Generate an image', model = 'gemini-2.5-flash-image
|
|
1368
|
+
async generate(prompt, type = 'image', systemInstruction = 'Generate an image', model = 'gemini-2.5-flash-image') {
|
|
1369
1369
|
if (!this.isAvailable())
|
|
1370
1370
|
return;
|
|
1371
1371
|
let contents;
|
|
@@ -1674,7 +1674,7 @@ class AI extends Script {
|
|
|
1674
1674
|
* In XR mode, show a 3D UI to instruct users to get an API key.
|
|
1675
1675
|
*/
|
|
1676
1676
|
triggerKeyPopup() { }
|
|
1677
|
-
async generate(prompt, type = 'image', systemInstruction = 'Generate an image', model =
|
|
1677
|
+
async generate(prompt, type = 'image', systemInstruction = 'Generate an image', model = undefined) {
|
|
1678
1678
|
return this.model.generate(prompt, type, systemInstruction, model);
|
|
1679
1679
|
}
|
|
1680
1680
|
/**
|
|
@@ -2255,10 +2255,6 @@ class DepthMesh extends MeshScript {
|
|
|
2255
2255
|
const depthY = Math.round(clamp((1.0 - v) * height, 0, height - 1));
|
|
2256
2256
|
const rawDepth = depthArray[depthY * width + depthX];
|
|
2257
2257
|
let depth = depthData.rawValueToMeters * rawDepth;
|
|
2258
|
-
// Workaround for b/382679381.
|
|
2259
|
-
if (this.depthOptions.useFloat32) {
|
|
2260
|
-
depth = rawDepth;
|
|
2261
|
-
}
|
|
2262
2258
|
// Finds global min/max.
|
|
2263
2259
|
if (depth > 0) {
|
|
2264
2260
|
if (depth < this.minDepth) {
|
|
@@ -2502,68 +2498,63 @@ const xrDepthMeshPhysicsOptions = deepFreeze(new DepthOptions({
|
|
|
2502
2498
|
class DepthTextures {
|
|
2503
2499
|
constructor(options) {
|
|
2504
2500
|
this.options = options;
|
|
2505
|
-
this.
|
|
2501
|
+
this.float32Arrays = [];
|
|
2506
2502
|
this.uint8Arrays = [];
|
|
2507
2503
|
this.dataTextures = [];
|
|
2508
2504
|
this.nativeTextures = [];
|
|
2509
2505
|
this.depthData = [];
|
|
2510
2506
|
}
|
|
2511
|
-
createDataDepthTextures(depthData,
|
|
2512
|
-
if (this.dataTextures[
|
|
2513
|
-
this.dataTextures[
|
|
2507
|
+
createDataDepthTextures(depthData, viewId) {
|
|
2508
|
+
if (this.dataTextures[viewId]) {
|
|
2509
|
+
this.dataTextures[viewId].dispose();
|
|
2514
2510
|
}
|
|
2515
2511
|
if (this.options.useFloat32) {
|
|
2516
|
-
const typedArray = new
|
|
2512
|
+
const typedArray = new Float32Array(depthData.width * depthData.height);
|
|
2517
2513
|
const format = THREE.RedFormat;
|
|
2518
|
-
const type = THREE.
|
|
2519
|
-
this.
|
|
2520
|
-
this.dataTextures[
|
|
2514
|
+
const type = THREE.FloatType;
|
|
2515
|
+
this.float32Arrays[viewId] = typedArray;
|
|
2516
|
+
this.dataTextures[viewId] = new THREE.DataTexture(typedArray, depthData.width, depthData.height, format, type);
|
|
2521
2517
|
}
|
|
2522
2518
|
else {
|
|
2523
2519
|
const typedArray = new Uint8Array(depthData.width * depthData.height * 2);
|
|
2524
2520
|
const format = THREE.RGFormat;
|
|
2525
2521
|
const type = THREE.UnsignedByteType;
|
|
2526
|
-
this.uint8Arrays[
|
|
2527
|
-
this.dataTextures[
|
|
2522
|
+
this.uint8Arrays[viewId] = typedArray;
|
|
2523
|
+
this.dataTextures[viewId] = new THREE.DataTexture(typedArray, depthData.width, depthData.height, format, type);
|
|
2528
2524
|
}
|
|
2529
2525
|
}
|
|
2530
|
-
updateData(depthData,
|
|
2531
|
-
if (this.dataTextures.length <
|
|
2532
|
-
this.dataTextures[
|
|
2533
|
-
this.dataTextures[
|
|
2534
|
-
this.createDataDepthTextures(depthData,
|
|
2526
|
+
updateData(depthData, viewId) {
|
|
2527
|
+
if (this.dataTextures.length < viewId + 1 ||
|
|
2528
|
+
this.dataTextures[viewId].image.width !== depthData.width ||
|
|
2529
|
+
this.dataTextures[viewId].image.height !== depthData.height) {
|
|
2530
|
+
this.createDataDepthTextures(depthData, viewId);
|
|
2535
2531
|
}
|
|
2536
2532
|
if (this.options.useFloat32) {
|
|
2537
|
-
|
|
2538
|
-
const float16Data = new Uint16Array(float32Data.length);
|
|
2539
|
-
for (let i = 0; i < float16Data.length; i++) {
|
|
2540
|
-
float16Data[i] = THREE.DataUtils.toHalfFloat(float32Data[i]);
|
|
2541
|
-
}
|
|
2542
|
-
this.uint16Arrays[view_id].set(float16Data);
|
|
2533
|
+
this.float32Arrays[viewId].set(new Float32Array(depthData.data));
|
|
2543
2534
|
}
|
|
2544
2535
|
else {
|
|
2545
|
-
this.uint8Arrays[
|
|
2536
|
+
this.uint8Arrays[viewId].set(new Uint8Array(depthData.data));
|
|
2546
2537
|
}
|
|
2547
|
-
this.dataTextures[
|
|
2548
|
-
this.depthData[
|
|
2538
|
+
this.dataTextures[viewId].needsUpdate = true;
|
|
2539
|
+
this.depthData[viewId] = depthData;
|
|
2549
2540
|
}
|
|
2550
|
-
updateNativeTexture(depthData, renderer,
|
|
2551
|
-
if (this.dataTextures.length <
|
|
2552
|
-
this.nativeTextures[
|
|
2541
|
+
updateNativeTexture(depthData, renderer, viewId) {
|
|
2542
|
+
if (this.dataTextures.length < viewId + 1) {
|
|
2543
|
+
this.nativeTextures[viewId] = new THREE.ExternalTexture(depthData.texture);
|
|
2553
2544
|
}
|
|
2554
2545
|
else {
|
|
2555
|
-
this.nativeTextures[
|
|
2546
|
+
this.nativeTextures[viewId].sourceTexture = depthData.texture;
|
|
2556
2547
|
}
|
|
2557
2548
|
// fixed in newer revision of three
|
|
2558
|
-
const textureProperties = renderer.properties.get(this.nativeTextures[
|
|
2549
|
+
const textureProperties = renderer.properties.get(this.nativeTextures[viewId]);
|
|
2559
2550
|
textureProperties.__webglTexture = depthData.texture;
|
|
2560
2551
|
textureProperties.__version = 1;
|
|
2561
2552
|
}
|
|
2562
|
-
get(
|
|
2553
|
+
get(viewId) {
|
|
2563
2554
|
if (this.dataTextures.length > 0) {
|
|
2564
|
-
return this.dataTextures[
|
|
2555
|
+
return this.dataTextures[viewId];
|
|
2565
2556
|
}
|
|
2566
|
-
return this.nativeTextures[
|
|
2557
|
+
return this.nativeTextures[viewId];
|
|
2567
2558
|
}
|
|
2568
2559
|
}
|
|
2569
2560
|
|
|
@@ -3057,6 +3048,15 @@ const DEFAULT_DEPTH_WIDTH = 160;
|
|
|
3057
3048
|
const DEFAULT_DEPTH_HEIGHT = DEFAULT_DEPTH_WIDTH;
|
|
3058
3049
|
const clipSpacePosition = new THREE.Vector3();
|
|
3059
3050
|
class Depth {
|
|
3051
|
+
get rawValueToMeters() {
|
|
3052
|
+
if (this.cpuDepthData.length) {
|
|
3053
|
+
return this.cpuDepthData[0].rawValueToMeters;
|
|
3054
|
+
}
|
|
3055
|
+
else if (this.gpuDepthData.length) {
|
|
3056
|
+
return this.gpuDepthData[0].rawValueToMeters;
|
|
3057
|
+
}
|
|
3058
|
+
return 0;
|
|
3059
|
+
}
|
|
3060
3060
|
/**
|
|
3061
3061
|
* Depth is a lightweight manager based on three.js to simply prototyping
|
|
3062
3062
|
* with Depth in WebXR.
|
|
@@ -3070,11 +3070,13 @@ class Depth {
|
|
|
3070
3070
|
this.options = new DepthOptions();
|
|
3071
3071
|
this.width = DEFAULT_DEPTH_WIDTH;
|
|
3072
3072
|
this.height = DEFAULT_DEPTH_HEIGHT;
|
|
3073
|
-
this.rawValueToMeters = 0.0010000000474974513;
|
|
3074
3073
|
this.occludableShaders = new Set();
|
|
3075
3074
|
// Whether we're counting the number of depth clients.
|
|
3076
3075
|
this.depthClientsInitialized = false;
|
|
3077
3076
|
this.depthClients = new Set();
|
|
3077
|
+
this.depthProjectionMatrices = [];
|
|
3078
|
+
this.depthViewMatrices = [];
|
|
3079
|
+
this.depthViewProjectionMatrices = [];
|
|
3078
3080
|
if (Depth.instance) {
|
|
3079
3081
|
return Depth.instance;
|
|
3080
3082
|
}
|
|
@@ -3157,16 +3159,29 @@ class Depth {
|
|
|
3157
3159
|
vertexPosition.multiplyScalar(-depth / vertexPosition.z);
|
|
3158
3160
|
return vertexPosition;
|
|
3159
3161
|
}
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
this.
|
|
3162
|
+
updateDepthMatrices(depthData, viewId) {
|
|
3163
|
+
// Populate depth view and projection matrices.
|
|
3164
|
+
while (viewId >= this.depthViewMatrices.length) {
|
|
3165
|
+
this.depthViewMatrices.push(new THREE.Matrix4());
|
|
3166
|
+
this.depthViewProjectionMatrices.push(new THREE.Matrix4());
|
|
3167
|
+
this.depthProjectionMatrices.push(new THREE.Matrix4());
|
|
3166
3168
|
}
|
|
3169
|
+
if (depthData.projectionMatrix && depthData.transform) {
|
|
3170
|
+
this.depthProjectionMatrices[viewId].fromArray(depthData.projectionMatrix);
|
|
3171
|
+
this.depthViewMatrices[viewId].fromArray(depthData.transform.inverse.matrix);
|
|
3172
|
+
}
|
|
3173
|
+
else {
|
|
3174
|
+
const camera = this.renderer.xr?.getCamera()?.cameras?.[viewId] ?? this.camera;
|
|
3175
|
+
this.depthProjectionMatrices[viewId].copy(camera.projectionMatrix);
|
|
3176
|
+
this.depthViewMatrices[viewId].copy(camera.matrixWorldInverse);
|
|
3177
|
+
}
|
|
3178
|
+
this.depthViewProjectionMatrices[viewId].multiplyMatrices(this.depthProjectionMatrices[viewId], this.depthViewMatrices[viewId]);
|
|
3179
|
+
}
|
|
3180
|
+
updateCPUDepthData(depthData, viewId = 0) {
|
|
3181
|
+
this.cpuDepthData[viewId] = depthData;
|
|
3167
3182
|
// Updates Depth Array.
|
|
3168
|
-
if (this.depthArray[
|
|
3169
|
-
this.depthArray[
|
|
3183
|
+
if (this.depthArray[viewId] == null) {
|
|
3184
|
+
this.depthArray[viewId] = this.options.useFloat32
|
|
3170
3185
|
? new Float32Array(depthData.data)
|
|
3171
3186
|
: new Uint16Array(depthData.data);
|
|
3172
3187
|
this.width = depthData.width;
|
|
@@ -3174,25 +3189,21 @@ class Depth {
|
|
|
3174
3189
|
}
|
|
3175
3190
|
else {
|
|
3176
3191
|
// Copies the data from an ArrayBuffer to the existing TypedArray.
|
|
3177
|
-
this.depthArray[
|
|
3192
|
+
this.depthArray[viewId].set(this.options.useFloat32
|
|
3178
3193
|
? new Float32Array(depthData.data)
|
|
3179
3194
|
: new Uint16Array(depthData.data));
|
|
3180
3195
|
}
|
|
3181
3196
|
// Updates Depth Texture.
|
|
3182
3197
|
if (this.options.depthTexture.enabled && this.depthTextures) {
|
|
3183
|
-
this.depthTextures.updateData(depthData,
|
|
3198
|
+
this.depthTextures.updateData(depthData, viewId);
|
|
3184
3199
|
}
|
|
3185
|
-
if (this.options.depthMesh.enabled && this.depthMesh &&
|
|
3200
|
+
if (this.options.depthMesh.enabled && this.depthMesh && viewId == 0) {
|
|
3186
3201
|
this.depthMesh.updateDepth(depthData);
|
|
3187
3202
|
}
|
|
3203
|
+
this.updateDepthMatrices(depthData, viewId);
|
|
3188
3204
|
}
|
|
3189
|
-
updateGPUDepthData(depthData,
|
|
3190
|
-
this.gpuDepthData[
|
|
3191
|
-
// Workaround for b/382679381.
|
|
3192
|
-
this.rawValueToMeters = depthData.rawValueToMeters;
|
|
3193
|
-
if (this.options.useFloat32) {
|
|
3194
|
-
this.rawValueToMeters = 1.0;
|
|
3195
|
-
}
|
|
3205
|
+
updateGPUDepthData(depthData, viewId = 0) {
|
|
3206
|
+
this.gpuDepthData[viewId] = depthData;
|
|
3196
3207
|
// For now, assume that we need cpu depth only if depth mesh is enabled.
|
|
3197
3208
|
// In the future, add a separate option.
|
|
3198
3209
|
const needCpuDepth = this.options.depthMesh.enabled;
|
|
@@ -3200,8 +3211,8 @@ class Depth {
|
|
|
3200
3211
|
? this.depthMesh.convertGPUToGPU(depthData)
|
|
3201
3212
|
: null;
|
|
3202
3213
|
if (cpuDepth) {
|
|
3203
|
-
if (this.depthArray[
|
|
3204
|
-
this.depthArray[
|
|
3214
|
+
if (this.depthArray[viewId] == null) {
|
|
3215
|
+
this.depthArray[viewId] = this.options.useFloat32
|
|
3205
3216
|
? new Float32Array(cpuDepth.data)
|
|
3206
3217
|
: new Uint16Array(cpuDepth.data);
|
|
3207
3218
|
this.width = cpuDepth.width;
|
|
@@ -3209,16 +3220,16 @@ class Depth {
|
|
|
3209
3220
|
}
|
|
3210
3221
|
else {
|
|
3211
3222
|
// Copies the data from an ArrayBuffer to the existing TypedArray.
|
|
3212
|
-
this.depthArray[
|
|
3223
|
+
this.depthArray[viewId].set(this.options.useFloat32
|
|
3213
3224
|
? new Float32Array(cpuDepth.data)
|
|
3214
3225
|
: new Uint16Array(cpuDepth.data));
|
|
3215
3226
|
}
|
|
3216
3227
|
}
|
|
3217
3228
|
// Updates Depth Texture.
|
|
3218
3229
|
if (this.options.depthTexture.enabled && this.depthTextures) {
|
|
3219
|
-
this.depthTextures.updateNativeTexture(depthData, this.renderer,
|
|
3230
|
+
this.depthTextures.updateNativeTexture(depthData, this.renderer, viewId);
|
|
3220
3231
|
}
|
|
3221
|
-
if (this.options.depthMesh.enabled && this.depthMesh &&
|
|
3232
|
+
if (this.options.depthMesh.enabled && this.depthMesh && viewId == 0) {
|
|
3222
3233
|
if (cpuDepth) {
|
|
3223
3234
|
this.depthMesh.updateDepth(cpuDepth);
|
|
3224
3235
|
}
|
|
@@ -3226,11 +3237,12 @@ class Depth {
|
|
|
3226
3237
|
this.depthMesh.updateGPUDepth(depthData);
|
|
3227
3238
|
}
|
|
3228
3239
|
}
|
|
3240
|
+
this.updateDepthMatrices(depthData, viewId);
|
|
3229
3241
|
}
|
|
3230
|
-
getTexture(
|
|
3242
|
+
getTexture(viewId) {
|
|
3231
3243
|
if (!this.options.depthTexture.enabled)
|
|
3232
3244
|
return undefined;
|
|
3233
|
-
return this.depthTextures?.get(
|
|
3245
|
+
return this.depthTextures?.get(viewId);
|
|
3234
3246
|
}
|
|
3235
3247
|
update(frame) {
|
|
3236
3248
|
if (!this.options.enabled)
|
|
@@ -3264,33 +3276,26 @@ class Depth {
|
|
|
3264
3276
|
return;
|
|
3265
3277
|
}
|
|
3266
3278
|
}
|
|
3267
|
-
|
|
3268
|
-
|
|
3269
|
-
|
|
3270
|
-
});
|
|
3271
|
-
session.addEventListener('end', () => {
|
|
3272
|
-
this.xrRefSpace = undefined;
|
|
3273
|
-
});
|
|
3274
|
-
}
|
|
3275
|
-
else {
|
|
3276
|
-
const pose = frame.getViewerPose(this.xrRefSpace);
|
|
3279
|
+
const xrRefSpace = this.renderer.xr.getReferenceSpace();
|
|
3280
|
+
if (xrRefSpace) {
|
|
3281
|
+
const pose = frame.getViewerPose(xrRefSpace);
|
|
3277
3282
|
if (pose) {
|
|
3278
|
-
for (let
|
|
3279
|
-
const view = pose.views[
|
|
3280
|
-
this.view[
|
|
3283
|
+
for (let viewId = 0; viewId < pose.views.length; ++viewId) {
|
|
3284
|
+
const view = pose.views[viewId];
|
|
3285
|
+
this.view[viewId] = view;
|
|
3281
3286
|
if (session.depthUsage === 'gpu-optimized') {
|
|
3282
3287
|
const depthData = binding.getDepthInformation(view);
|
|
3283
3288
|
if (!depthData) {
|
|
3284
3289
|
return;
|
|
3285
3290
|
}
|
|
3286
|
-
this.updateGPUDepthData(depthData,
|
|
3291
|
+
this.updateGPUDepthData(depthData, viewId);
|
|
3287
3292
|
}
|
|
3288
3293
|
else {
|
|
3289
3294
|
const depthData = frame.getDepthInformation(view);
|
|
3290
3295
|
if (!depthData) {
|
|
3291
3296
|
return;
|
|
3292
3297
|
}
|
|
3293
|
-
this.updateCPUDepthData(depthData,
|
|
3298
|
+
this.updateCPUDepthData(depthData, viewId);
|
|
3294
3299
|
}
|
|
3295
3300
|
}
|
|
3296
3301
|
}
|
|
@@ -3348,10 +3353,10 @@ const aspectRatios = {
|
|
|
3348
3353
|
*
|
|
3349
3354
|
* @param rgbUv - The RGB UV coordinate, e.g., \{ u: 0.5, v: 0.5 \}.
|
|
3350
3355
|
* @param xrDeviceCamera - The device camera instance.
|
|
3351
|
-
* @returns The transformed UV coordinate in the
|
|
3356
|
+
* @returns The transformed UV coordinate in the render camera clip space, or null if
|
|
3352
3357
|
* inputs are invalid.
|
|
3353
3358
|
*/
|
|
3354
|
-
function
|
|
3359
|
+
function transformRgbToRenderCameraClip(rgbUv, xrDeviceCamera) {
|
|
3355
3360
|
if (xrDeviceCamera?.simulatorCamera) {
|
|
3356
3361
|
// The simulator camera crops the viewport image to match its aspect ratio,
|
|
3357
3362
|
// while the depth map covers the entire viewport, so we adjust for this.
|
|
@@ -3369,7 +3374,7 @@ function transformRgbToDepthUv(rgbUv, xrDeviceCamera) {
|
|
|
3369
3374
|
const relativeHeight = viewportAspect / cameraAspect;
|
|
3370
3375
|
v = v * relativeHeight + (1.0 - relativeHeight) / 2.0;
|
|
3371
3376
|
}
|
|
3372
|
-
return
|
|
3377
|
+
return new THREE.Vector2(2 * u - 1, 2 * v - 1);
|
|
3373
3378
|
}
|
|
3374
3379
|
if (!aspectRatios || !aspectRatios.depth || !aspectRatios.RGB) {
|
|
3375
3380
|
console.error('Invalid aspect ratios provided.');
|
|
@@ -3408,10 +3413,34 @@ function transformRgbToDepthUv(rgbUv, xrDeviceCamera) {
|
|
|
3408
3413
|
// Apply the final user-controlled scaling (zoom and stretch).
|
|
3409
3414
|
const finalNormX = u_fitted * params.scale * params.scaleX;
|
|
3410
3415
|
const finalNormY = v_fitted * params.scale * params.scaleY;
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3416
|
+
return new THREE.Vector2(2 * finalNormX, 2 * finalNormY);
|
|
3417
|
+
}
|
|
3418
|
+
/**
|
|
3419
|
+
* Maps a UV coordinate from a RGB space to a destination depth space,
|
|
3420
|
+
* applying Brown-Conrady distortion and affine transformations based on
|
|
3421
|
+
* aspect ratios. If the simulator camera is used, no transformation is applied.
|
|
3422
|
+
*
|
|
3423
|
+
* @param rgbUv - The RGB UV coordinate, e.g., \{ u: 0.5, v: 0.5 \}.
|
|
3424
|
+
* @param renderCameraWorldFromClip - Render camera world from clip, i.e. inverse of the View Projection matrix.
|
|
3425
|
+
* @param depthCameraClipFromWorld - Depth camera clip from world, i.e.
|
|
3426
|
+
* @param xrDeviceCamera - The device camera instance.
|
|
3427
|
+
* @returns The transformed UV coordinate in the depth image space, or null if
|
|
3428
|
+
* inputs are invalid.
|
|
3429
|
+
*/
|
|
3430
|
+
function transformRgbToDepthUv(rgbUv, renderCameraWorldFromClip, depthCameraClipFromWorld, xrDeviceCamera) {
|
|
3431
|
+
// Render camera clip space coordinates.
|
|
3432
|
+
const clipCoords = transformRgbToRenderCameraClip(rgbUv, xrDeviceCamera);
|
|
3433
|
+
if (!clipCoords) {
|
|
3434
|
+
return null;
|
|
3435
|
+
}
|
|
3436
|
+
// Backwards project from the render camera to depth camera.
|
|
3437
|
+
const depthClipCoord = new THREE.Vector4(clipCoords.x, clipCoords.y, 1, 1);
|
|
3438
|
+
depthClipCoord.applyMatrix4(renderCameraWorldFromClip);
|
|
3439
|
+
depthClipCoord.applyMatrix4(depthCameraClipFromWorld);
|
|
3440
|
+
depthClipCoord.multiplyScalar(1 / depthClipCoord.w);
|
|
3441
|
+
const finalU = 0.5 * depthClipCoord.x + 0.5;
|
|
3442
|
+
const finalV = 1.0 - (0.5 * depthClipCoord.y + 0.5);
|
|
3443
|
+
return { u: finalU, v: finalV };
|
|
3415
3444
|
}
|
|
3416
3445
|
/**
|
|
3417
3446
|
* Retrieves the world space position of a given RGB UV coordinate.
|
|
@@ -3421,19 +3450,30 @@ function transformRgbToDepthUv(rgbUv, xrDeviceCamera) {
|
|
|
3421
3450
|
*
|
|
3422
3451
|
* @param rgbUv - The RGB UV coordinate, e.g., \{ u: 0.5, v: 0.5 \}.
|
|
3423
3452
|
* @param depthArray - Array containing depth data.
|
|
3424
|
-
* @param
|
|
3453
|
+
* @param projectionMatrix - XRView object with corresponding
|
|
3425
3454
|
* projection matrix.
|
|
3426
|
-
* @param matrixWorld -
|
|
3455
|
+
* @param matrixWorld - Rendering camera's model matrix.
|
|
3427
3456
|
* @param xrDeviceCamera - The device camera instance.
|
|
3428
3457
|
* @param xrDepth - The SDK's Depth module.
|
|
3429
3458
|
* @returns Vertex at (u, v) in world space.
|
|
3430
3459
|
*/
|
|
3431
|
-
function transformRgbUvToWorld(rgbUv, depthArray,
|
|
3432
|
-
if (!depthArray || !
|
|
3433
|
-
|
|
3434
|
-
|
|
3460
|
+
function transformRgbUvToWorld(rgbUv, depthArray, projectionMatrix, matrixWorld, xrDeviceCamera, xrDepth = Depth.instance) {
|
|
3461
|
+
if (!depthArray || !projectionMatrix || !matrixWorld || !xrDepth) {
|
|
3462
|
+
throw new Error('Missing parameter in transformRgbUvToWorld');
|
|
3463
|
+
}
|
|
3464
|
+
const worldFromClip = matrixWorld
|
|
3465
|
+
.clone()
|
|
3466
|
+
.invert()
|
|
3467
|
+
.premultiply(projectionMatrix)
|
|
3468
|
+
.invert();
|
|
3469
|
+
const depthProjectionMatrixInverse = xrDepth.depthProjectionMatrices[0]
|
|
3470
|
+
.clone()
|
|
3471
|
+
.invert();
|
|
3472
|
+
const depthClipFromWorld = xrDepth.depthViewProjectionMatrices[0];
|
|
3473
|
+
const depthModelMatrix = xrDepth.depthViewMatrices[0].clone().invert();
|
|
3474
|
+
const depthUV = transformRgbToDepthUv(rgbUv, worldFromClip, depthClipFromWorld, xrDeviceCamera);
|
|
3435
3475
|
if (!depthUV) {
|
|
3436
|
-
|
|
3476
|
+
throw new Error('Failed to get depth UV');
|
|
3437
3477
|
}
|
|
3438
3478
|
const { u: depthU, v: depthV } = depthUV;
|
|
3439
3479
|
const depthX = Math.round(clamp(depthU * xrDepth.width, 0, xrDepth.width - 1));
|
|
@@ -3444,12 +3484,13 @@ function transformRgbUvToWorld(rgbUv, depthArray, viewProjectionMatrix, matrixWo
|
|
|
3444
3484
|
// Convert UV to normalized device coordinates and create a point on the near
|
|
3445
3485
|
// plane.
|
|
3446
3486
|
const viewSpacePosition = new THREE.Vector3(2.0 * (depthU - 0.5), 2.0 * (depthV - 0.5), -1);
|
|
3447
|
-
const viewProjectionMatrixInverse = viewProjectionMatrix.clone().invert();
|
|
3448
3487
|
// Unproject the point from clip space to view space and scale it along the
|
|
3449
3488
|
// ray from the camera to the correct depth. Camera looks down -Z axis.
|
|
3450
|
-
viewSpacePosition.applyMatrix4(
|
|
3489
|
+
viewSpacePosition.applyMatrix4(depthProjectionMatrixInverse);
|
|
3451
3490
|
viewSpacePosition.multiplyScalar(-depthInMeters / viewSpacePosition.z);
|
|
3452
|
-
const worldPosition = viewSpacePosition
|
|
3491
|
+
const worldPosition = viewSpacePosition
|
|
3492
|
+
.clone()
|
|
3493
|
+
.applyMatrix4(depthModelMatrix);
|
|
3453
3494
|
return worldPosition;
|
|
3454
3495
|
}
|
|
3455
3496
|
/**
|
|
@@ -4133,6 +4174,9 @@ class ScriptsManager {
|
|
|
4133
4174
|
this.callKeyUpBound = this.callKeyUp.bind(this);
|
|
4134
4175
|
/** The set of scripts currently being initialized. */
|
|
4135
4176
|
this.initializingScripts = new Set();
|
|
4177
|
+
this.seenScripts = new Set();
|
|
4178
|
+
this.syncPromises = [];
|
|
4179
|
+
this.checkScriptBound = this.checkScript.bind(this);
|
|
4136
4180
|
}
|
|
4137
4181
|
/**
|
|
4138
4182
|
* Initializes a script and adds it to the set of scripts which will receive
|
|
@@ -4163,29 +4207,33 @@ class ScriptsManager {
|
|
|
4163
4207
|
this.scripts.delete(script);
|
|
4164
4208
|
this.initializingScripts.delete(script);
|
|
4165
4209
|
}
|
|
4210
|
+
/**
|
|
4211
|
+
* Helper for scene traversal to avoid closure allocation.
|
|
4212
|
+
*/
|
|
4213
|
+
checkScript(obj) {
|
|
4214
|
+
if (obj.isXRScript) {
|
|
4215
|
+
const script = obj;
|
|
4216
|
+
this.syncPromises.push(this.initScript(script));
|
|
4217
|
+
this.seenScripts.add(script);
|
|
4218
|
+
}
|
|
4219
|
+
}
|
|
4166
4220
|
/**
|
|
4167
4221
|
* Finds all scripts in the scene and initializes them or uninitailizes them.
|
|
4168
4222
|
* Returns a promise which resolves when all new scripts are finished
|
|
4169
4223
|
* initalizing.
|
|
4170
4224
|
* @param scene - The main scene which is used to find scripts.
|
|
4171
4225
|
*/
|
|
4172
|
-
|
|
4173
|
-
|
|
4174
|
-
|
|
4175
|
-
scene.traverse(
|
|
4176
|
-
if (obj.isXRScript) {
|
|
4177
|
-
const script = obj;
|
|
4178
|
-
promises.push(this.initScript(script));
|
|
4179
|
-
seenScripts.add(script);
|
|
4180
|
-
}
|
|
4181
|
-
});
|
|
4182
|
-
await Promise.allSettled(promises);
|
|
4226
|
+
syncScriptsWithScene(scene) {
|
|
4227
|
+
this.seenScripts.clear();
|
|
4228
|
+
this.syncPromises.length = 0;
|
|
4229
|
+
scene.traverse(this.checkScriptBound);
|
|
4183
4230
|
// Delete missing scripts.
|
|
4184
4231
|
for (const script of this.scripts) {
|
|
4185
|
-
if (!seenScripts.has(script)) {
|
|
4232
|
+
if (!this.seenScripts.has(script)) {
|
|
4186
4233
|
this.uninitScript(script);
|
|
4187
4234
|
}
|
|
4188
4235
|
}
|
|
4236
|
+
return Promise.allSettled(this.syncPromises);
|
|
4189
4237
|
}
|
|
4190
4238
|
callSelectStart(event) {
|
|
4191
4239
|
for (const script of this.scripts) {
|
|
@@ -5778,6 +5826,7 @@ function traverseUtil(node, callback) {
|
|
|
5778
5826
|
return false;
|
|
5779
5827
|
}
|
|
5780
5828
|
|
|
5829
|
+
const tempBox = new THREE.Box3();
|
|
5781
5830
|
/**
|
|
5782
5831
|
* User is an embodied instance to manage hands, controllers, speech, and
|
|
5783
5832
|
* avatars. It extends Script to update human-world interaction.
|
|
@@ -6140,8 +6189,8 @@ class User extends Script {
|
|
|
6140
6189
|
const currentlyTouchedMeshes = [];
|
|
6141
6190
|
this.scene.traverse((object) => {
|
|
6142
6191
|
if (object.isMesh && object.visible) {
|
|
6143
|
-
|
|
6144
|
-
if (
|
|
6192
|
+
tempBox.setFromObject(object);
|
|
6193
|
+
if (tempBox.containsPoint(indexTipPosition)) {
|
|
6145
6194
|
currentlyTouchedMeshes.push(object);
|
|
6146
6195
|
}
|
|
6147
6196
|
}
|
|
@@ -6429,6 +6478,13 @@ function computePinch(context, config) {
|
|
|
6429
6478
|
const index = getJoint(context, 'index-finger-tip');
|
|
6430
6479
|
if (!thumb || !index)
|
|
6431
6480
|
return undefined;
|
|
6481
|
+
const supportMetrics = ['middle', 'ring', 'pinky']
|
|
6482
|
+
.map((finger) => computeFingerMetric(context, finger))
|
|
6483
|
+
.filter(Boolean);
|
|
6484
|
+
const supportCurl = supportMetrics.length > 0
|
|
6485
|
+
? average(supportMetrics.map((metrics) => metrics.curlRatio))
|
|
6486
|
+
: 1;
|
|
6487
|
+
const supportPenalty = clamp01((supportCurl - 1.05) / 0.35);
|
|
6432
6488
|
const handScale = estimateHandScale(context);
|
|
6433
6489
|
const threshold = config.threshold ?? Math.max(0.018, handScale * 0.35);
|
|
6434
6490
|
const distance = thumb.distanceTo(index);
|
|
@@ -6437,10 +6493,12 @@ function computePinch(context, config) {
|
|
|
6437
6493
|
}
|
|
6438
6494
|
const tightness = clamp01(1 - distance / (threshold * 0.85));
|
|
6439
6495
|
const loosePenalty = clamp01(1 - distance / (threshold * 1.4));
|
|
6440
|
-
|
|
6496
|
+
let confidence = clamp01(distance <= threshold ? tightness : loosePenalty * 0.4);
|
|
6497
|
+
confidence *= 1 - supportPenalty * 0.45;
|
|
6498
|
+
confidence = clamp01(confidence);
|
|
6441
6499
|
return {
|
|
6442
6500
|
confidence,
|
|
6443
|
-
data: { distance, threshold },
|
|
6501
|
+
data: { distance, threshold, supportPenalty },
|
|
6444
6502
|
};
|
|
6445
6503
|
}
|
|
6446
6504
|
function computeOpenPalm(context, config) {
|
|
@@ -6449,21 +6507,29 @@ function computeOpenPalm(context, config) {
|
|
|
6449
6507
|
return undefined;
|
|
6450
6508
|
const handScale = estimateHandScale(context);
|
|
6451
6509
|
const palmWidth = getPalmWidth(context) ?? handScale * 0.85;
|
|
6510
|
+
const palmUp = getPalmUp(context);
|
|
6452
6511
|
const extensionScores = fingerMetrics.map(({ tipDistance }) => clamp01((tipDistance - handScale * 0.5) / (handScale * 0.45)));
|
|
6453
6512
|
const straightnessScores = fingerMetrics.map(({ curlRatio }) => clamp01((curlRatio - 1.1) / 0.5));
|
|
6513
|
+
const orientationScore = palmUp && fingerMetrics.length
|
|
6514
|
+
? average(fingerMetrics.map((metrics) => fingerAlignmentScore(context, metrics, palmUp)))
|
|
6515
|
+
: 0.5;
|
|
6454
6516
|
const neighbors = getAdjacentFingerDistances(context);
|
|
6455
6517
|
const spreadScore = neighbors.average !== Infinity && palmWidth > EPSILON
|
|
6456
6518
|
? clamp01((neighbors.average - palmWidth * 0.55) / (palmWidth * 0.35))
|
|
6457
6519
|
: 0;
|
|
6458
6520
|
const extensionScore = average(extensionScores);
|
|
6459
6521
|
const straightScore = average(straightnessScores);
|
|
6460
|
-
const confidence = clamp01(extensionScore * 0.
|
|
6522
|
+
const confidence = clamp01(extensionScore * 0.4 +
|
|
6523
|
+
straightScore * 0.25 +
|
|
6524
|
+
spreadScore * 0.2 +
|
|
6525
|
+
orientationScore * 0.15);
|
|
6461
6526
|
return {
|
|
6462
6527
|
confidence,
|
|
6463
6528
|
data: {
|
|
6464
6529
|
extensionScore,
|
|
6465
6530
|
straightScore,
|
|
6466
6531
|
spreadScore,
|
|
6532
|
+
orientationScore,
|
|
6467
6533
|
threshold: config.threshold,
|
|
6468
6534
|
},
|
|
6469
6535
|
};
|
|
@@ -6480,15 +6546,26 @@ function computeFist(context, config) {
|
|
|
6480
6546
|
const clusterScore = neighbors.average !== Infinity && palmWidth > EPSILON
|
|
6481
6547
|
? clamp01((palmWidth * 0.5 - neighbors.average) / (palmWidth * 0.35))
|
|
6482
6548
|
: 0;
|
|
6549
|
+
const thumbTip = getJoint(context, 'thumb-tip');
|
|
6550
|
+
const indexBase = getFingerJoint(context, 'index', 'phalanx-proximal') ??
|
|
6551
|
+
getFingerJoint(context, 'index', 'metacarpal');
|
|
6552
|
+
const thumbWrapScore = thumbTip && indexBase && palmWidth > EPSILON
|
|
6553
|
+
? clamp01((palmWidth * 0.55 - thumbTip.distanceTo(indexBase)) /
|
|
6554
|
+
(palmWidth * 0.35))
|
|
6555
|
+
: 0;
|
|
6483
6556
|
const tipScore = clamp01((handScale * 0.55 - tipAverage) / (handScale * 0.25));
|
|
6484
6557
|
const curlScore = clamp01((1.08 - curlAverage) / 0.25);
|
|
6485
|
-
const confidence = clamp01(tipScore * 0.
|
|
6558
|
+
const confidence = clamp01(tipScore * 0.45 +
|
|
6559
|
+
curlScore * 0.3 +
|
|
6560
|
+
clusterScore * 0.1 +
|
|
6561
|
+
thumbWrapScore * 0.15);
|
|
6486
6562
|
return {
|
|
6487
6563
|
confidence,
|
|
6488
6564
|
data: {
|
|
6489
6565
|
tipAverage,
|
|
6490
6566
|
curlAverage,
|
|
6491
6567
|
clusterScore,
|
|
6568
|
+
thumbWrapScore,
|
|
6492
6569
|
threshold: config.threshold,
|
|
6493
6570
|
},
|
|
6494
6571
|
};
|
|
@@ -6525,8 +6602,8 @@ function computeThumbsUp(context, config) {
|
|
|
6525
6602
|
orientationScore = clamp01((alignment - 0.35) / 0.35);
|
|
6526
6603
|
}
|
|
6527
6604
|
}
|
|
6528
|
-
const confidence = clamp01(thumbExtendedScore * 0.
|
|
6529
|
-
curledScore * 0.
|
|
6605
|
+
const confidence = clamp01(thumbExtendedScore * 0.3 +
|
|
6606
|
+
curledScore * 0.35 +
|
|
6530
6607
|
orientationScore * 0.2 +
|
|
6531
6608
|
separationScore * 0.15);
|
|
6532
6609
|
return {
|
|
@@ -6550,17 +6627,33 @@ function computePoint(context, config) {
|
|
|
6550
6627
|
if (!otherMetrics.length)
|
|
6551
6628
|
return undefined;
|
|
6552
6629
|
const handScale = estimateHandScale(context);
|
|
6630
|
+
const palmWidth = getPalmWidth(context) ?? handScale * 0.85;
|
|
6631
|
+
const palmUp = getPalmUp(context);
|
|
6553
6632
|
const indexCurlScore = clamp01((indexMetrics.curlRatio - 1.2) / 0.35);
|
|
6554
6633
|
const indexReachScore = clamp01((indexMetrics.tipDistance - handScale * 0.6) / (handScale * 0.25));
|
|
6634
|
+
const indexDirectionScore = palmUp && indexMetrics
|
|
6635
|
+
? fingerAlignmentScore(context, indexMetrics, palmUp)
|
|
6636
|
+
: 0.4;
|
|
6555
6637
|
const othersCurl = average(otherMetrics.map((metrics) => metrics.curlRatio));
|
|
6556
6638
|
const othersCurledScore = clamp01((1.05 - othersCurl) / 0.25);
|
|
6557
|
-
const
|
|
6639
|
+
const thumbTip = getJoint(context, 'thumb-tip');
|
|
6640
|
+
const thumbTuckedScore = thumbTip && indexMetrics.metacarpal && palmWidth > EPSILON
|
|
6641
|
+
? clamp01((palmWidth * 0.75 - thumbTip.distanceTo(indexMetrics.metacarpal)) /
|
|
6642
|
+
(palmWidth * 0.4))
|
|
6643
|
+
: 0.5;
|
|
6644
|
+
const confidence = clamp01(indexCurlScore * 0.35 +
|
|
6645
|
+
indexReachScore * 0.25 +
|
|
6646
|
+
othersCurledScore * 0.2 +
|
|
6647
|
+
indexDirectionScore * 0.1 +
|
|
6648
|
+
thumbTuckedScore * 0.1);
|
|
6558
6649
|
return {
|
|
6559
6650
|
confidence,
|
|
6560
6651
|
data: {
|
|
6561
6652
|
indexCurlScore,
|
|
6562
6653
|
indexReachScore,
|
|
6563
6654
|
othersCurledScore,
|
|
6655
|
+
indexDirectionScore,
|
|
6656
|
+
thumbTuckedScore,
|
|
6564
6657
|
threshold: config.threshold,
|
|
6565
6658
|
},
|
|
6566
6659
|
};
|
|
@@ -6572,16 +6665,21 @@ function computeSpread(context, config) {
|
|
|
6572
6665
|
const handScale = estimateHandScale(context);
|
|
6573
6666
|
const palmWidth = getPalmWidth(context) ?? handScale * 0.85;
|
|
6574
6667
|
const neighbors = getAdjacentFingerDistances(context);
|
|
6668
|
+
const palmUp = getPalmUp(context);
|
|
6575
6669
|
const spreadScore = neighbors.average !== Infinity && palmWidth > EPSILON
|
|
6576
6670
|
? clamp01((neighbors.average - palmWidth * 0.6) / (palmWidth * 0.35))
|
|
6577
6671
|
: 0;
|
|
6578
6672
|
const extensionScore = clamp01((average(fingerMetrics.map((metrics) => metrics.curlRatio)) - 1.15) / 0.45);
|
|
6579
|
-
const
|
|
6673
|
+
const orientationScore = palmUp && fingerMetrics.length
|
|
6674
|
+
? average(fingerMetrics.map((metrics) => fingerAlignmentScore(context, metrics, palmUp)))
|
|
6675
|
+
: 0.5;
|
|
6676
|
+
const confidence = clamp01(spreadScore * 0.55 + extensionScore * 0.3 + orientationScore * 0.15);
|
|
6580
6677
|
return {
|
|
6581
6678
|
confidence,
|
|
6582
6679
|
data: {
|
|
6583
6680
|
spreadScore,
|
|
6584
6681
|
extensionScore,
|
|
6682
|
+
orientationScore,
|
|
6585
6683
|
threshold: config.threshold,
|
|
6586
6684
|
},
|
|
6587
6685
|
};
|
|
@@ -6709,6 +6807,16 @@ function getFingerJoint(context, finger, suffix) {
|
|
|
6709
6807
|
const prefix = FINGER_PREFIX[finger];
|
|
6710
6808
|
return getJoint(context, `${prefix}-${suffix}`);
|
|
6711
6809
|
}
|
|
6810
|
+
function fingerAlignmentScore(context, metrics, palmUp) {
|
|
6811
|
+
const base = metrics.metacarpal ?? getJoint(context, 'wrist');
|
|
6812
|
+
if (!base)
|
|
6813
|
+
return 0;
|
|
6814
|
+
const direction = new THREE.Vector3().subVectors(metrics.tip, base);
|
|
6815
|
+
if (direction.lengthSq() === 0)
|
|
6816
|
+
return 0;
|
|
6817
|
+
direction.normalize();
|
|
6818
|
+
return clamp01((direction.dot(palmUp) - 0.35) / 0.5);
|
|
6819
|
+
}
|
|
6712
6820
|
function clamp01(value) {
|
|
6713
6821
|
return THREE.MathUtils.clamp(value, 0, 1);
|
|
6714
6822
|
}
|
|
@@ -8137,6 +8245,15 @@ class SimulatorDepth {
|
|
|
8137
8245
|
this.depthWidth = 160;
|
|
8138
8246
|
this.depthHeight = 160;
|
|
8139
8247
|
this.depthBufferSlice = new Float32Array();
|
|
8248
|
+
/**
|
|
8249
|
+
* If true, copies the rendering camera's projection matrix each frame.
|
|
8250
|
+
*/
|
|
8251
|
+
this.autoUpdateDepthCameraProjection = true;
|
|
8252
|
+
/**
|
|
8253
|
+
* If true, copies the rendering camera's transform each frame.
|
|
8254
|
+
*/
|
|
8255
|
+
this.autoUpdateDepthCameraTransform = true;
|
|
8256
|
+
this.projectionMatrixArray = new Float32Array(16);
|
|
8140
8257
|
}
|
|
8141
8258
|
/**
|
|
8142
8259
|
* Initialize Simulator Depth.
|
|
@@ -8145,6 +8262,16 @@ class SimulatorDepth {
|
|
|
8145
8262
|
this.renderer = renderer;
|
|
8146
8263
|
this.camera = camera;
|
|
8147
8264
|
this.depth = depth;
|
|
8265
|
+
if (this.camera instanceof THREE.PerspectiveCamera) {
|
|
8266
|
+
this.depthCamera = new THREE.PerspectiveCamera();
|
|
8267
|
+
}
|
|
8268
|
+
else if (this.camera instanceof THREE.OrthographicCamera) {
|
|
8269
|
+
this.depthCamera = new THREE.OrthographicCamera();
|
|
8270
|
+
}
|
|
8271
|
+
else {
|
|
8272
|
+
throw new Error('Unknown camera type');
|
|
8273
|
+
}
|
|
8274
|
+
this.depthCamera.copy(this.camera, /*recursive=*/ false);
|
|
8148
8275
|
this.createRenderTarget();
|
|
8149
8276
|
this.depthMaterial = new SimulatorDepthMaterial();
|
|
8150
8277
|
}
|
|
@@ -8156,23 +8283,44 @@ class SimulatorDepth {
|
|
|
8156
8283
|
this.depthBuffer = new Float32Array(this.depthWidth * this.depthHeight);
|
|
8157
8284
|
}
|
|
8158
8285
|
update() {
|
|
8286
|
+
this.updateDepthCamera();
|
|
8159
8287
|
this.renderDepthScene();
|
|
8160
8288
|
this.updateDepth();
|
|
8161
8289
|
}
|
|
8290
|
+
updateDepthCamera() {
|
|
8291
|
+
const renderingCamera = this.camera;
|
|
8292
|
+
const depthCamera = this.depthCamera;
|
|
8293
|
+
if (this.autoUpdateDepthCameraProjection) {
|
|
8294
|
+
depthCamera.projectionMatrix.copy(renderingCamera.projectionMatrix);
|
|
8295
|
+
depthCamera.projectionMatrixInverse.copy(renderingCamera.projectionMatrixInverse);
|
|
8296
|
+
}
|
|
8297
|
+
if (this.autoUpdateDepthCameraTransform) {
|
|
8298
|
+
depthCamera.position.copy(renderingCamera.position);
|
|
8299
|
+
depthCamera.rotation.order = renderingCamera.rotation.order;
|
|
8300
|
+
depthCamera.quaternion.copy(renderingCamera.quaternion);
|
|
8301
|
+
depthCamera.scale.copy(renderingCamera.scale);
|
|
8302
|
+
depthCamera.matrix.copy(renderingCamera.matrix);
|
|
8303
|
+
depthCamera.matrixWorld.copy(renderingCamera.matrixWorld);
|
|
8304
|
+
depthCamera.matrixWorldInverse.copy(renderingCamera.matrixWorldInverse);
|
|
8305
|
+
}
|
|
8306
|
+
}
|
|
8162
8307
|
renderDepthScene() {
|
|
8163
8308
|
const originalRenderTarget = this.renderer.getRenderTarget();
|
|
8164
8309
|
this.renderer.setRenderTarget(this.depthRenderTarget);
|
|
8165
8310
|
this.simulatorScene.overrideMaterial = this.depthMaterial;
|
|
8166
|
-
this.renderer.render(this.simulatorScene, this.
|
|
8311
|
+
this.renderer.render(this.simulatorScene, this.depthCamera);
|
|
8167
8312
|
this.simulatorScene.overrideMaterial = null;
|
|
8168
8313
|
this.renderer.setRenderTarget(originalRenderTarget);
|
|
8169
8314
|
}
|
|
8170
|
-
updateDepth() {
|
|
8315
|
+
async updateDepth() {
|
|
8171
8316
|
// We preventively unbind the PIXEL_PACK_BUFFER before reading from the
|
|
8172
8317
|
// render target in case external libraries (Spark.js) left it bound.
|
|
8173
8318
|
const context = this.renderer.getContext();
|
|
8174
8319
|
context.bindBuffer(context.PIXEL_PACK_BUFFER, null);
|
|
8175
|
-
|
|
8320
|
+
// Cache the projection matrix and transform of the rendered depth.
|
|
8321
|
+
const projectionMatrix = this.depthCamera.projectionMatrix.clone();
|
|
8322
|
+
const transform = new XRRigidTransform(this.depthCamera.position, this.depthCamera.quaternion);
|
|
8323
|
+
await this.renderer.readRenderTargetPixelsAsync(this.depthRenderTarget, 0, 0, this.depthWidth, this.depthHeight, this.depthBuffer);
|
|
8176
8324
|
// Flip the depth buffer.
|
|
8177
8325
|
if (this.depthBufferSlice.length != this.depthWidth) {
|
|
8178
8326
|
this.depthBufferSlice = new Float32Array(this.depthWidth);
|
|
@@ -8188,11 +8336,14 @@ class SimulatorDepth {
|
|
|
8188
8336
|
// Copy the temp slice (original row i) to row j
|
|
8189
8337
|
this.depthBuffer.set(this.depthBufferSlice, j_offset);
|
|
8190
8338
|
}
|
|
8339
|
+
projectionMatrix.toArray(this.projectionMatrixArray);
|
|
8191
8340
|
const depthData = {
|
|
8192
8341
|
width: this.depthWidth,
|
|
8193
8342
|
height: this.depthHeight,
|
|
8194
8343
|
data: this.depthBuffer.buffer,
|
|
8195
8344
|
rawValueToMeters: 1.0,
|
|
8345
|
+
projectionMatrix: this.projectionMatrixArray,
|
|
8346
|
+
transform: transform,
|
|
8196
8347
|
};
|
|
8197
8348
|
this.depth.updateCPUDepthData(depthData, 0);
|
|
8198
8349
|
}
|
|
@@ -12308,6 +12459,15 @@ class VideoView extends View {
|
|
|
12308
12459
|
/** The cross-origin setting for the video element. Default is 'anonymous'. */
|
|
12309
12460
|
this.crossOrigin = 'anonymous';
|
|
12310
12461
|
this.videoAspectRatio = 0.0;
|
|
12462
|
+
// set video options if passed in
|
|
12463
|
+
this.autoplay = options.autoplay ?? this.autoplay;
|
|
12464
|
+
this.muted = options.muted ?? this.muted;
|
|
12465
|
+
this.loop = options.loop ?? this.loop;
|
|
12466
|
+
this.playsInline = options.playsInline ?? this.playsInline;
|
|
12467
|
+
if (options.crossOrigin)
|
|
12468
|
+
this.crossOrigin = options.crossOrigin;
|
|
12469
|
+
if (options.mode)
|
|
12470
|
+
this.mode = options.mode;
|
|
12311
12471
|
const videoGeometry = new THREE.PlaneGeometry(1, 1);
|
|
12312
12472
|
const videoMaterial = new THREE.MeshBasicMaterial({
|
|
12313
12473
|
transparent: true,
|
|
@@ -17159,5 +17319,5 @@ class VideoFileStream extends VideoStream {
|
|
|
17159
17319
|
}
|
|
17160
17320
|
}
|
|
17161
17321
|
|
|
17162
|
-
export { AI, AIOptions, AVERAGE_IPD_METERS, ActiveControllers, Agent, AnimatableNumber, AudioListener, AudioPlayer, BACK, BackgroundMusic, CategoryVolumes, Col, Core, CoreSound, DEFAULT_DEVICE_CAMERA_HEIGHT, DEFAULT_DEVICE_CAMERA_WIDTH, DEFAULT_RGB_TO_DEPTH_PARAMS, DOWN, Depth, DepthMesh, DepthMeshOptions, DepthOptions, DepthTextures, DetectedObject, DetectedPlane, DeviceCameraOptions, DragManager, DragMode, ExitButton, FORWARD, FreestandingSlider, GazeController, Gemini, GeminiOptions, GenerateSkyboxTool, GestureRecognition, GestureRecognitionOptions, GetWeatherTool, Grid, HAND_BONE_IDX_CONNECTION_MAP, HAND_JOINT_COUNT, HAND_JOINT_IDX_CONNECTION_MAP, HAND_JOINT_NAMES, Handedness, Hands, HandsOptions, HorizontalPager, IconButton, IconView, ImageView, Input, InputOptions, Keycodes, LEFT, LEFT_VIEW_ONLY_LAYER, LabelView, Lighting, LightingOptions, LoadingSpinnerManager, MaterialSymbolsView, MeshScript, ModelLoader, ModelViewer, MouseController, NEXT_SIMULATOR_MODE, NUM_HANDS, OCCLUDABLE_ITEMS_LAYER, ObjectDetector, ObjectsOptions, OcclusionPass, OcclusionUtils, OpenAI, OpenAIOptions, Options, PageIndicator, Pager, PagerState, Panel, PanelMesh, Physics, PhysicsOptions, PinchOnButtonAction, PlaneDetector, PlanesOptions, RIGHT, RIGHT_VIEW_ONLY_LAYER, Registry, Reticle, ReticleOptions, RotationRaycastMesh, Row, SIMULATOR_HAND_POSE_NAMES, SIMULATOR_HAND_POSE_TO_JOINTS_LEFT, SIMULATOR_HAND_POSE_TO_JOINTS_RIGHT, SOUND_PRESETS, ScreenshotSynthesizer, Script, ScriptMixin, ScriptsManager, ScrollingTroikaTextView, SetSimulatorModeEvent, ShowHandsAction, Simulator, SimulatorCamera, SimulatorControlMode, SimulatorControllerState, SimulatorControls, SimulatorDepth, SimulatorDepthMaterial, SimulatorHandPose, SimulatorHandPoseChangeRequestEvent, SimulatorHands, SimulatorInterface, SimulatorMediaDeviceInfo, SimulatorMode, SimulatorOptions, SimulatorRenderMode, SimulatorScene, SimulatorUser, SimulatorUserAction, SketchPanel, SkyboxAgent, SoundOptions, SoundSynthesizer, SpatialAudio, SpatialPanel, SpeechRecognizer, SpeechRecognizerOptions, SpeechSynthesizer, SpeechSynthesizerOptions, SplatAnchor, StreamState, TextButton, TextScrollerState, TextView, Tool, UI, UI_OVERLAY_LAYER, UP, UX, User, VIEW_DEPTH_GAP, VerticalPager, VideoFileStream, VideoStream, VideoView, View, VolumeCategory, WaitFrame, WalkTowardsPanelAction, World, WorldOptions, XRButton, XRDeviceCamera, XREffects, XRPass, XRTransitionOptions, XR_BLOCKS_ASSETS_PATH, ZERO_VECTOR3, add, ai, aspectRatios, callInitWithDependencyInjection, clamp, clampRotationToAngle, core, cropImage, extractYaw, getColorHex, getDeltaTime, getUrlParamBool, getUrlParamFloat, getUrlParamInt, getUrlParameter, getVec4ByColorString, getXrCameraLeft, getXrCameraRight, init, initScript, lerp, loadStereoImageAsTextures, loadingSpinnerManager, lookAtRotation, objectIsDescendantOf, parseBase64DataURL, placeObjectAtIntersectionFacingTarget, print, scene, showOnlyInLeftEye, showOnlyInRightEye, showReticleOnDepthMesh, transformRgbToDepthUv, transformRgbUvToWorld, traverseUtil, uninitScript, urlParams, user, world, xrDepthMeshOptions, xrDepthMeshPhysicsOptions, xrDepthMeshVisualizationOptions, xrDeviceCameraEnvironmentContinuousOptions, xrDeviceCameraEnvironmentOptions, xrDeviceCameraUserContinuousOptions, xrDeviceCameraUserOptions };
|
|
17322
|
+
export { AI, AIOptions, AVERAGE_IPD_METERS, ActiveControllers, Agent, AnimatableNumber, AudioListener, AudioPlayer, BACK, BackgroundMusic, CategoryVolumes, Col, Core, CoreSound, DEFAULT_DEVICE_CAMERA_HEIGHT, DEFAULT_DEVICE_CAMERA_WIDTH, DEFAULT_RGB_TO_DEPTH_PARAMS, DOWN, Depth, DepthMesh, DepthMeshOptions, DepthOptions, DepthTextures, DetectedObject, DetectedPlane, DeviceCameraOptions, DragManager, DragMode, ExitButton, FORWARD, FreestandingSlider, GazeController, Gemini, GeminiOptions, GenerateSkyboxTool, GestureRecognition, GestureRecognitionOptions, GetWeatherTool, Grid, HAND_BONE_IDX_CONNECTION_MAP, HAND_JOINT_COUNT, HAND_JOINT_IDX_CONNECTION_MAP, HAND_JOINT_NAMES, Handedness, Hands, HandsOptions, HorizontalPager, IconButton, IconView, ImageView, Input, InputOptions, Keycodes, LEFT, LEFT_VIEW_ONLY_LAYER, LabelView, Lighting, LightingOptions, LoadingSpinnerManager, MaterialSymbolsView, MeshScript, ModelLoader, ModelViewer, MouseController, NEXT_SIMULATOR_MODE, NUM_HANDS, OCCLUDABLE_ITEMS_LAYER, ObjectDetector, ObjectsOptions, OcclusionPass, OcclusionUtils, OpenAI, OpenAIOptions, Options, PageIndicator, Pager, PagerState, Panel, PanelMesh, Physics, PhysicsOptions, PinchOnButtonAction, PlaneDetector, PlanesOptions, RIGHT, RIGHT_VIEW_ONLY_LAYER, Registry, Reticle, ReticleOptions, RotationRaycastMesh, Row, SIMULATOR_HAND_POSE_NAMES, SIMULATOR_HAND_POSE_TO_JOINTS_LEFT, SIMULATOR_HAND_POSE_TO_JOINTS_RIGHT, SOUND_PRESETS, ScreenshotSynthesizer, Script, ScriptMixin, ScriptsManager, ScrollingTroikaTextView, SetSimulatorModeEvent, ShowHandsAction, Simulator, SimulatorCamera, SimulatorControlMode, SimulatorControllerState, SimulatorControls, SimulatorDepth, SimulatorDepthMaterial, SimulatorHandPose, SimulatorHandPoseChangeRequestEvent, SimulatorHands, SimulatorInterface, SimulatorMediaDeviceInfo, SimulatorMode, SimulatorOptions, SimulatorRenderMode, SimulatorScene, SimulatorUser, SimulatorUserAction, SketchPanel, SkyboxAgent, SoundOptions, SoundSynthesizer, SpatialAudio, SpatialPanel, SpeechRecognizer, SpeechRecognizerOptions, SpeechSynthesizer, SpeechSynthesizerOptions, SplatAnchor, StreamState, TextButton, TextScrollerState, TextView, Tool, UI, UI_OVERLAY_LAYER, UP, UX, User, VIEW_DEPTH_GAP, VerticalPager, VideoFileStream, VideoStream, VideoView, View, VolumeCategory, WaitFrame, WalkTowardsPanelAction, World, WorldOptions, XRButton, XRDeviceCamera, XREffects, XRPass, XRTransitionOptions, XR_BLOCKS_ASSETS_PATH, ZERO_VECTOR3, add, ai, aspectRatios, callInitWithDependencyInjection, clamp, clampRotationToAngle, core, cropImage, extractYaw, getColorHex, getDeltaTime, getUrlParamBool, getUrlParamFloat, getUrlParamInt, getUrlParameter, getVec4ByColorString, getXrCameraLeft, getXrCameraRight, init, initScript, lerp, loadStereoImageAsTextures, loadingSpinnerManager, lookAtRotation, objectIsDescendantOf, parseBase64DataURL, placeObjectAtIntersectionFacingTarget, print, scene, showOnlyInLeftEye, showOnlyInRightEye, showReticleOnDepthMesh, transformRgbToDepthUv, transformRgbToRenderCameraClip, transformRgbUvToWorld, traverseUtil, uninitScript, urlParams, user, world, xrDepthMeshOptions, xrDepthMeshPhysicsOptions, xrDepthMeshVisualizationOptions, xrDeviceCameraEnvironmentContinuousOptions, xrDeviceCameraEnvironmentOptions, xrDeviceCameraUserContinuousOptions, xrDeviceCameraUserOptions };
|
|
17163
17323
|
//# sourceMappingURL=xrblocks.js.map
|