Skip to content

Commit e16f043

Browse files
committed
fix: use world matrices in getSpaceFromAncestors for XRLayer positioning
XRLayers were incorrectly positioned when inside components that override updateWorldMatrix (e.g., UIKit's Content component which applies layout transforms like globalMatrix and childrenMatrix). The previous implementation accumulated local matrices via premultiply(), which missed any custom transforms applied during updateWorldMatrix(). This change switches to using matrixWorld directly, ensuring that any custom matrix computations are properly reflected in XRLayer positioning.
1 parent 7f9c77a commit e16f043

File tree

1 file changed

+20
-12
lines changed

1 file changed

+20
-12
lines changed

packages/xr/src/space.ts

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -48,19 +48,31 @@ export function getSpaceFromAncestors(
4848
originReferenceSpace?: XRReferenceSpace,
4949
targetOffsetMatrix?: Matrix4,
5050
) {
51-
targetOffsetMatrix?.copy(object.matrix)
52-
const result = getXRSpaceFromAncestorsRec(object.parent, targetOffsetMatrix)
53-
if (result != null) {
54-
return result
51+
// Update world matrices to ensure they're current.
52+
// This is critical for components that override updateWorldMatrix to apply
53+
// custom transforms (e.g., UIKit's Content component applies layout transforms).
54+
// The old approach of accumulating local matrices missed these overrides.
55+
object.updateWorldMatrix(true, false)
56+
57+
const xrSpaceAncestor = findXRSpaceAncestor(object.parent)
58+
59+
if (xrSpaceAncestor != null) {
60+
if (targetOffsetMatrix != null) {
61+
xrSpaceAncestor.updateWorldMatrix(true, false)
62+
// Compute offset: ancestor.matrixWorld^-1 * object.matrixWorld
63+
targetOffsetMatrix.copy(xrSpaceAncestor.matrixWorld).invert().multiply(object.matrixWorld)
64+
}
65+
return xrSpaceAncestor.xrSpace
5566
}
67+
5668
if (targetOffsetMatrix != null) {
5769
computeOriginReferenceSpaceOffset(object, origin, targetOffsetMatrix)
5870
}
5971
return originReferenceSpace
6072
}
6173

6274
function computeOriginReferenceSpaceOffset(object: Object3D, origin: Object3D | undefined, target: Matrix4): void {
63-
object.updateWorldMatrix(true, false)
75+
// object.updateWorldMatrix already called in getSpaceFromAncestors
6476
if (origin == null) {
6577
target.copy(object.matrixWorld)
6678
return
@@ -71,16 +83,12 @@ function computeOriginReferenceSpaceOffset(object: Object3D, origin: Object3D |
7183
target.copy(origin.matrixWorld).invert().multiply(object.matrixWorld)
7284
}
7385

74-
function getXRSpaceFromAncestorsRec(
75-
object: Object3D | null,
76-
targetOffsetMatrix: Matrix4 | undefined,
77-
): XRSpace | undefined {
86+
function findXRSpaceAncestor(object: Object3D | null): (Object3D & { xrSpace: XRSpace }) | undefined {
7887
if (object == null) {
7988
return undefined
8089
}
8190
if (object.xrSpace != null) {
82-
return object.xrSpace
91+
return object as Object3D & { xrSpace: XRSpace }
8392
}
84-
targetOffsetMatrix?.premultiply(object.matrix)
85-
return getXRSpaceFromAncestorsRec(object.parent, targetOffsetMatrix)
93+
return findXRSpaceAncestor(object.parent)
8694
}

0 commit comments

Comments
 (0)