From 93cc86aa542b311e12f017a440de06fb6d5f5abd Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 29 Apr 2026 11:42:49 +0800 Subject: [PATCH] fix: streamline world 3d viewer overlay --- components/canvas/world3d/World3DViewer.tsx | 55 ++++++++++++++++----- 1 file changed, 42 insertions(+), 13 deletions(-) diff --git a/components/canvas/world3d/World3DViewer.tsx b/components/canvas/world3d/World3DViewer.tsx index 61d8032a5..9bb8819d8 100644 --- a/components/canvas/world3d/World3DViewer.tsx +++ b/components/canvas/world3d/World3DViewer.tsx @@ -730,6 +730,7 @@ function WorldSplatScene({ onLoadStateChange, onRevealComplete, resetViewToken, + showInfoOverlay = true, }: { splatUrl: string; revealPhase?: SplatLoadingPhase; @@ -742,6 +743,7 @@ function WorldSplatScene({ onLoadStateChange?: (state: "ready" | "error") => void; onRevealComplete?: () => void; resetViewToken?: number; + showInfoOverlay?: boolean; }) { const camera = useThree((state) => state.camera); const renderer = useThree((state) => state.gl); @@ -749,6 +751,7 @@ function WorldSplatScene({ const hasAppliedInitialViewRef = useRef(false); const lastCameraPoseRef = useRef(null); const lastResetViewTokenRef = useRef(resetViewToken); + const lastFirstPersonRef = useRef(firstPerson); const revealCompletedRef = useRef(false); const [controlsMountVersion, setControlsMountVersion] = useState(0); const [particleCloudData, setParticleCloudData] = useState(null); @@ -869,6 +872,24 @@ function WorldSplatScene({ }); }, [camera, groundPlaneOffset, resetViewToken, splatMesh]); + useEffect(() => { + if (!hasAppliedInitialViewRef.current) { + lastFirstPersonRef.current = firstPerson; + return; + } + + if (!lastFirstPersonRef.current && firstPerson) { + lastCameraPoseRef.current = positionCameraInsideWorld({ + camera, + controls: orbitControlsRef.current, + groundPlaneOffset, + splatMesh, + }); + } + + lastFirstPersonRef.current = firstPerson; + }, [camera, firstPerson, groundPlaneOffset, splatMesh]); + useEffect(() => { if (!orbitControlsRef.current || !lastCameraPoseRef.current) return; @@ -1006,20 +1027,24 @@ function WorldSplatScene({
-
- - SPZ - - {semanticFacts.map((fact) => ( - - {fact.label} {fact.value} + {showInfoOverlay ? ( +
+ + SPZ - ))} -
+ {semanticFacts.map((fact) => ( + + {fact.label} {fact.value} + + ))} +
+ ) : ( +
+ )} {interactionMode === "hotspot" ? (
点击场景放置热点 @@ -1099,6 +1124,7 @@ function WorldSplatViewer({ resetViewToken, minimalFrame = false, onCaptureReady, + showInfoOverlay = true, }: { splatUrl?: string | null; worldUrl?: string | null; @@ -1112,6 +1138,7 @@ function WorldSplatViewer({ semanticsMetadata?: Record | null; resetViewToken?: number; onCaptureReady?: (capture: (() => Promise) | null) => void; + showInfoOverlay?: boolean; }) { const [loadState, setLoadState] = useState<"loading" | "ready" | "error">("loading"); const [overlayPhase, setOverlayPhase] = useState("loading"); @@ -1187,6 +1214,7 @@ function WorldSplatViewer({ revealPhase={overlayPhase} resetViewToken={resetViewToken} semanticsMetadata={semanticsMetadata} + showInfoOverlay={showInfoOverlay} splatUrl={splatUrl} /> @@ -1316,6 +1344,7 @@ export function World3DViewer({ minimalFrame={minimalFrame} resetViewToken={resetViewToken} semanticsMetadata={semanticsMetadata} + showInfoOverlay={!minimalFrame} splatUrl={splatUrl} worldUrl={worldUrl} />