Skip to content

Commit 6fc639d

Browse files
committed
XRLayer: depth sorting prototype
- XRLayerEntry now requires an Object3D prop - depth sorting is calculated in onBeforeRender
1 parent bcef5d5 commit 6fc639d

File tree

3 files changed

+33
-5
lines changed

3 files changed

+33
-5
lines changed

packages/react/xr/src/layer.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,11 @@ export const XRLayerImplementation = forwardRef<
239239
if (layer == null) {
240240
return
241241
}
242-
const layerEntry = (layerEntryRef.current = { layer, renderOrder: renderOrderRef.current })
242+
const layerEntry = (layerEntryRef.current = {
243+
layer,
244+
renderOrder: renderOrderRef.current,
245+
object3D: internalRef.current!,
246+
})
243247
store.addLayerEntry(layerEntry)
244248
if (resolvedSrc instanceof HTMLVideoElement || resolvedSrc instanceof WebGLRenderTarget) {
245249
return () => {

packages/xr/src/layer.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,11 @@ import { getSpaceFromAncestors } from './space.js'
2020
import { XRState, XRStore } from './store.js'
2121
import { toDOMPointInit } from './utils.js'
2222

23-
export type XRLayerEntry = { renderOrder: number; readonly layer: XRCylinderLayer | XRQuadLayer | XREquirectLayer }
23+
export type XRLayerEntry = {
24+
renderOrder: number
25+
readonly layer: XRCylinderLayer | XRQuadLayer | XREquirectLayer
26+
readonly object3D: Object3D
27+
}
2428

2529
export type XRLayerOptions = Pick<
2630
Partial<XRCylinderLayerInit & XRQuadLayerInit & XREquirectLayerInit>,

packages/xr/src/store.ts

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { XRDevice } from 'iwer'
2-
import { Camera, Object3D, WebXRManager } from 'three'
2+
import { Camera, Object3D, WebXRManager, Vector3 } from 'three'
33
import { StoreApi, createStore } from 'zustand/vanilla'
44
import { XRControllerLayoutLoaderOptions, updateXRControllerState } from './controller/index.js'
55
import { XRHandLoaderOptions } from './hand/index.js'
@@ -427,6 +427,10 @@ declare global {
427427
}
428428
}
429429

430+
//helpers for layer sorting
431+
const cameraWorldPosition = new Vector3()
432+
const tempLayerWorldPosition = new Vector3()
433+
430434
export function createXRStore<T extends XRElementImplementations>(options?: XRStoreOptions<T>): XRStore<T> {
431435
//dom overlay root element creation
432436
const domOverlayRoot =
@@ -678,8 +682,24 @@ export function createXRStore<T extends XRElementImplementations>(options?: XRSt
678682
if (currentLayers == null) {
679683
return
680684
}
681-
//TODO: sort by distance to camera
682-
;(layerEntries as Array<(typeof layerEntries)[number]>).sort((l1, l2) => l1.renderOrder - l2.renderOrder)
685+
//sort by distance to camera
686+
const xrCamera = xrManager.getCamera()
687+
xrCamera.getWorldPosition(cameraWorldPosition)
688+
;(layerEntries as Array<XRLayerEntry>).sort((entryA, entryB) => {
689+
entryA.object3D.getWorldPosition(tempLayerWorldPosition)
690+
const distA_sq = tempLayerWorldPosition.distanceToSquared(cameraWorldPosition)
691+
692+
entryB.object3D.getWorldPosition(tempLayerWorldPosition)
693+
const distB_sq = tempLayerWorldPosition.distanceToSquared(cameraWorldPosition)
694+
695+
const depthDifference = distB_sq - distA_sq
696+
697+
//if the distance is the same, fall back to renderOrder
698+
if (Math.abs(depthDifference) < 0.00001) {
699+
return entryA.renderOrder - entryB.renderOrder
700+
}
701+
return depthDifference
702+
})
683703
let changed = false
684704
const layers = layerEntries.map<XRLayer>(({ layer }, i) => {
685705
if (layer != currentLayers[i]) {

0 commit comments

Comments
 (0)