From 1230240de1220dcd1c7543d0a124b731b19488a6 Mon Sep 17 00:00:00 2001 From: Untold Engine Date: Fri, 7 Aug 2026 05:40:56 -0700 Subject: [PATCH 1/2] [Patch] fixed gaussian not rendering --- Sources/UntoldEngineXR/UntoldEngineXR.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Sources/UntoldEngineXR/UntoldEngineXR.swift b/Sources/UntoldEngineXR/UntoldEngineXR.swift index 3bff6d6c8..6ba959158 100644 --- a/Sources/UntoldEngineXR/UntoldEngineXR.swift +++ b/Sources/UntoldEngineXR/UntoldEngineXR.swift @@ -796,6 +796,7 @@ snapshot.timing.cullingMs += cullingMs } #endif + executeGaussianFrustumCulling(commandBuffer) executeGaussianDepth(commandBuffer) executeRadixSort(commandBuffer) EngineProfiler.shared.endScope(.renderPrep) From 18f64be3f17769adc683fa333bdc50be02f7dbd4 Mon Sep 17 00:00:00 2001 From: Untold Engine Date: Fri, 7 Aug 2026 05:59:58 -0700 Subject: [PATCH 2/2] [Bugfix] Use the correct effective camera for gaussian --- .../UntoldEngine/Systems/GaussianSystem.swift | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/Sources/UntoldEngine/Systems/GaussianSystem.swift b/Sources/UntoldEngine/Systems/GaussianSystem.swift index 30c42b0c0..c52eb3f68 100644 --- a/Sources/UntoldEngine/Systems/GaussianSystem.swift +++ b/Sources/UntoldEngine/Systems/GaussianSystem.swift @@ -121,14 +121,22 @@ public func executeGaussianFrustumCulling(_ commandBuffer: MTLCommandBuffer) { profileTotals.dispatchCount += 1 let modelMatrix = simd_mul(worldTransformComponent.space, .identity) - let viewMatrix = cameraComponent.viewSpace + // Entity transforms are never modified when the scene root moves (SceneRootTransform + // applies its offset to the camera instead, as a "virtual camera" trick — see + // SceneRootTransform.swift). worldTransformComponent.space above is therefore in + // entity space, so the camera side of this product must go through + // effectiveViewMatrix, not the raw per-eye viewSpace — otherwise this cull silently + // drifts out of sync with where the draw pass (which already uses + // effectiveViewMatrix) actually renders the splats as soon as the scene root is + // translated/rotated (e.g. via SpatialManipulationSystem's pinch-drag). + let viewMatrix = SceneRootTransform.shared.effectiveViewMatrix(cameraComponent.viewSpace) let modelViewMatrix = simd_mul(viewMatrix, modelMatrix) var gaussianUniform = Uniforms() gaussianUniform.modelViewMatrix = modelViewMatrix gaussianUniform.viewMatrix = viewMatrix gaussianUniform.modelMatrix = modelMatrix - gaussianUniform.cameraPosition = cameraComponent.localPosition + gaussianUniform.cameraPosition = SceneRootTransform.shared.effectiveCameraPosition(cameraComponent.localPosition) gaussianUniform.projectionMatrix = renderInfo.perspectiveSpace var totalSplats = UInt32(gaussianComponent.splatCount) @@ -251,7 +259,10 @@ public func executeGaussianDepth(_ commandBuffer: MTLCommandBuffer) { let modelMatrix = simd_mul(worldTransformComponent.space, .identity) - let viewMatrix: simd_float4x4 = cameraComponent.viewSpace + // See the matching comment in executeGaussianFrustumCulling: worldTransformComponent + // is in entity space, so this must be the scene-root-corrected view, not the raw + // per-eye viewSpace. + let viewMatrix: simd_float4x4 = SceneRootTransform.shared.effectiveViewMatrix(cameraComponent.viewSpace) let modelViewMatrix = simd_mul(viewMatrix, modelMatrix) @@ -269,7 +280,7 @@ public func executeGaussianDepth(_ commandBuffer: MTLCommandBuffer) { gaussianUniform.modelMatrix = modelMatrix - gaussianUniform.cameraPosition = cameraComponent.localPosition + gaussianUniform.cameraPosition = SceneRootTransform.shared.effectiveCameraPosition(cameraComponent.localPosition) gaussianUniform.projectionMatrix = renderInfo.perspectiveSpace