Skip to content

Commit b80ee29

Browse files
zjm-metameta-codesync[bot]
authored andcommitted
feat(core): Add stereo support for cpu-optimized depth occlusion.
Summary: Added support of stereo depth occlusion for CPU optimized depth sensing mode using depth texture from different view ids. Also cleaned up unused code. Reviewed By: felixtrz Differential Revision: D93902470 fbshipit-source-id: f58550f34d54168a4e0ae8a1e3145708545322ba
1 parent 2cc3989 commit b80ee29

File tree

2 files changed

+113
-127
lines changed

2 files changed

+113
-127
lines changed

packages/core/src/depth/depth-sensing-system.ts

Lines changed: 45 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
*/
77

88
import { createSystem, Entity, Types } from '../ecs/index.js';
9-
import { ExternalTexture, Mesh, Texture, Vector2 } from '../runtime/three.js';
9+
import { Mesh, Vector2 } from '../runtime/three.js';
1010
import { DepthOccludable } from './depth-occludable.js';
1111
import { DepthTextures } from './depth-textures.js';
1212
import type { Shader, ShaderUniforms } from './types.js';
@@ -58,7 +58,6 @@ export class DepthSensingSystem extends createSystem(
5858
},
5959
) {
6060
private depthFeatureEnabled: boolean | undefined;
61-
private isGPUOptimized = false;
6261

6362
// Depth data storage
6463
cpuDepthData: XRCPUDepthInformation[] = [];
@@ -136,10 +135,7 @@ export class DepthSensingSystem extends createSystem(
136135
}
137136
// Only inject occlusion if not already present
138137
if (!shader.uniforms.occlusionEnabled) {
139-
DepthSensingSystem.addOcclusionToShader(
140-
shader,
141-
this.isGPUOptimized,
142-
);
138+
DepthSensingSystem.addOcclusionToShader(shader);
143139
}
144140
material.userData.shader = shader;
145141
entityUniforms.add(shader.uniforms);
@@ -163,19 +159,16 @@ export class DepthSensingSystem extends createSystem(
163159
/**
164160
* Modifies a material's shader in-place to incorporate inline depth-based
165161
* occlusion. Compares the virtual fragment's view-space depth against the
166-
* real-world depth from the XR depth texture.
162+
* real-world depth from the XR depth texture array.
163+
* Both GPU-optimized (ExternalTexture) and CPU-optimized (DataArrayTexture)
164+
* paths use sampler2DArray with VIEW_ID for correct stereo depth sampling.
167165
* @param shader - The shader object provided by onBeforeCompile.
168-
* @param isGPUOptimized - Whether the depth data uses GPU-optimized texture arrays.
169166
*/
170-
private static addOcclusionToShader(
171-
shader: Shader,
172-
isGPUOptimized: boolean,
173-
): void {
167+
private static addOcclusionToShader(shader: Shader): void {
174168
shader.uniforms.occlusionEnabled = { value: false };
175-
shader.uniforms.uXRDepthTexture = { value: null };
176169
shader.uniforms.uXRDepthTextureArray = { value: null };
177170
shader.uniforms.uRawValueToMeters = { value: 0.001 };
178-
shader.uniforms.uIsTextureArray = { value: false };
171+
shader.uniforms.uIsGPUDepth = { value: false };
179172
shader.uniforms.uDepthNear = { value: 0 };
180173
shader.uniforms.uViewportSize = { value: new Vector2() };
181174
shader.uniforms.uOcclusionBlurRadius = { value: 20.0 };
@@ -184,9 +177,6 @@ export class DepthSensingSystem extends createSystem(
184177
...(shader.defines ?? {}),
185178
USE_UV: true,
186179
};
187-
if (isGPUOptimized) {
188-
shader.defines.USE_DEPTH_TEXTURE_ARRAY = '';
189-
}
190180

191181
// Vertex shader: compute view-space depth for occlusion comparison
192182
shader.vertexShader = shader.vertexShader
@@ -203,34 +193,33 @@ export class DepthSensingSystem extends createSystem(
203193
].join('\n'),
204194
);
205195

206-
// Fragment shader: sample XR depth and compare against virtual depth
196+
// Fragment shader: sample XR depth array and compare against virtual depth
207197
shader.fragmentShader = shader.fragmentShader
208198
.replace(
209199
'uniform vec3 diffuse;',
210200
[
211201
'uniform vec3 diffuse;',
212202
'uniform bool occlusionEnabled;',
213-
'uniform sampler2D uXRDepthTexture;',
214203
'uniform float uRawValueToMeters;',
215-
'uniform bool uIsTextureArray;',
204+
'uniform bool uIsGPUDepth;',
216205
'uniform float uDepthNear;',
217206
'uniform vec2 uViewportSize;',
218207
'uniform float uOcclusionBlurRadius;',
219208
'varying float vOcclusionViewDepth;',
220209
'',
221-
'#ifdef USE_DEPTH_TEXTURE_ARRAY',
222210
'uniform sampler2DArray uXRDepthTextureArray;',
211+
'',
212+
'// Fallback for non-multiview sessions',
213+
'#ifndef VIEW_ID',
214+
'#define VIEW_ID 0',
223215
'#endif',
224216
'',
225217
'float OcclusionDepthGetMeters(in vec2 uv) {',
226-
' #ifdef USE_DEPTH_TEXTURE_ARRAY',
227-
' if (uIsTextureArray) {',
228-
' float textureValue = texture(uXRDepthTextureArray, vec3(uv.x, uv.y, float(VIEW_ID))).r;',
218+
' float textureValue = texture(uXRDepthTextureArray, vec3(uv.x, uv.y, float(VIEW_ID))).r;',
219+
' if (uIsGPUDepth) {',
229220
' return uRawValueToMeters * uDepthNear / (1.0 - textureValue);',
230221
' }',
231-
' #endif',
232-
' vec2 packedDepth = texture2D(uXRDepthTexture, uv).rg;',
233-
' return packedDepth.r * uRawValueToMeters;',
222+
' return textureValue * uRawValueToMeters;',
234223
'}',
235224
'',
236225
'float OcclusionGetSample(in vec2 depthUV, in vec2 offset) {',
@@ -245,7 +234,7 @@ export class DepthSensingSystem extends createSystem(
245234
'vec4 diffuseColor = vec4( diffuse, opacity );',
246235
'if (occlusionEnabled) {',
247236
' vec2 screenUV = gl_FragCoord.xy / uViewportSize;',
248-
' vec2 depthUV = uIsTextureArray ? screenUV : vec2(screenUV.x, 1.0 - screenUV.y);',
237+
' vec2 depthUV = uIsGPUDepth ? screenUV : vec2(screenUV.x, 1.0 - screenUV.y);',
249238
' vec2 texelSize = uOcclusionBlurRadius / uViewportSize;',
250239
' // 13-tap two-ring sampling pattern for smooth occlusion edges',
251240
' // Center sample',
@@ -273,7 +262,6 @@ export class DepthSensingSystem extends createSystem(
273262

274263
private cleanup(): void {
275264
this.depthFeatureEnabled = undefined;
276-
this.isGPUOptimized = false;
277265
this.cpuDepthData = [];
278266
this.gpuDepthData = [];
279267
}
@@ -285,7 +273,6 @@ export class DepthSensingSystem extends createSystem(
285273

286274
const enabledFeatures = xrSession.enabledFeatures;
287275
this.depthFeatureEnabled = enabledFeatures?.includes('depth-sensing');
288-
this.isGPUOptimized = xrSession.depthUsage === 'gpu-optimized';
289276

290277
if (!this.depthFeatureEnabled) {
291278
console.log(
@@ -320,16 +307,19 @@ export class DepthSensingSystem extends createSystem(
320307
if (xrRefSpace) {
321308
const pose = frame.getViewerPose(xrRefSpace);
322309
if (pose) {
323-
for (let viewId = 0; viewId < pose.views.length; ++viewId) {
324-
const view = pose.views[viewId];
325-
326-
if (session.depthUsage === 'gpu-optimized') {
327-
const depthData = binding.getDepthInformation(view);
328-
if (!depthData) {
329-
return;
330-
}
331-
this.updateGPUDepthData(depthData, viewId);
332-
} else {
310+
if (session.depthUsage === 'gpu-optimized') {
311+
// GPU path: the native texture is a texture array containing all
312+
// views. We only need to update the ExternalTexture once using the
313+
// first view's depth data.
314+
const view = pose.views[0];
315+
const depthData = binding.getDepthInformation(view);
316+
if (depthData) {
317+
this.updateGPUDepthData(depthData);
318+
}
319+
} else {
320+
// CPU path: each view has its own DataTexture.
321+
for (let viewId = 0; viewId < pose.views.length; ++viewId) {
322+
const view = pose.views[viewId];
333323
const depthData = frame.getDepthInformation(view);
334324
if (!depthData) {
335325
return;
@@ -358,55 +348,42 @@ export class DepthSensingSystem extends createSystem(
358348
/**
359349
* Update with GPU-optimized depth data.
360350
*/
361-
private updateGPUDepthData(
362-
depthData: XRWebGLDepthInformation,
363-
viewId = 0,
364-
): void {
365-
this.gpuDepthData[viewId] = depthData;
351+
private updateGPUDepthData(depthData: XRWebGLDepthInformation): void {
352+
this.gpuDepthData[0] = depthData;
366353

367354
if (this.config.enableDepthTexture.value && this.depthTextures) {
368-
this.depthTextures.updateNativeTexture(depthData, this.renderer, viewId);
355+
this.depthTextures.updateNativeTexture(depthData, this.renderer);
369356
}
370357
}
371358

372-
/**
373-
* Get the depth texture for a specific view.
374-
* @param viewId - The view index (0 for left eye, 1 for right eye).
375-
*/
376-
getTexture(viewId: number): Texture | undefined {
377-
if (!this.config.enableDepthTexture.value) return undefined;
378-
return this.depthTextures?.get(viewId);
379-
}
380-
381359
/**
382360
* Updates depth texture uniforms on all occludable materials each frame.
361+
* Both GPU and CPU paths set the texture array uniform; the shader uses
362+
* VIEW_ID to select the correct stereo layer.
383363
*/
384364
private updateOcclusionUniforms(): void {
385-
const leftDepth = this.getTexture(0);
386-
const rightDepth = this.getTexture(1);
387-
const isTextureArray =
388-
leftDepth instanceof ExternalTexture ||
389-
rightDepth instanceof ExternalTexture;
365+
const nativeTexture = this.depthTextures?.getNativeTexture();
366+
const dataArrayTexture = this.depthTextures?.getDataArrayTexture();
367+
const isGPUDepth = nativeTexture !== undefined;
390368
const depthNear =
391369
(this.gpuDepthData[0] as unknown as { depthNear: number } | undefined)
392370
?.depthNear ?? 0;
393371

372+
// Select the texture array: ExternalTexture for GPU, DataArrayTexture for CPU
373+
const depthTextureArray = isGPUDepth ? nativeTexture : dataArrayTexture;
374+
if (!depthTextureArray) return;
375+
394376
const viewportSize = new Vector2();
395377
this.renderer.getDrawingBufferSize(viewportSize);
396378

397379
for (const uniforms of this.occludableShaders) {
398-
if (leftDepth) {
399-
uniforms.uXRDepthTexture.value = leftDepth;
400-
}
401-
if (rightDepth) {
402-
uniforms.uXRDepthTextureArray.value = rightDepth;
403-
}
380+
uniforms.uXRDepthTextureArray.value = depthTextureArray;
404381
uniforms.uRawValueToMeters.value = this.rawValueToMeters;
405-
uniforms.uIsTextureArray.value = isTextureArray;
382+
uniforms.uIsGPUDepth.value = isGPUDepth;
406383
uniforms.uDepthNear.value = depthNear;
407384
(uniforms.uViewportSize.value as Vector2).copy(viewportSize);
408385
uniforms.uOcclusionBlurRadius.value = this.config.blurRadius.value;
409-
uniforms.occlusionEnabled.value = true;
386+
uniforms.occlusionEnabled.value = this.config.enableOcclusion.value;
410387
}
411388
}
412389
}

0 commit comments

Comments
 (0)