From 90cd4d40cc63d44c2cf702c49b429fbba93f1197 Mon Sep 17 00:00:00 2001 From: Tom Boullay Date: Wed, 13 May 2026 11:03:16 +0200 Subject: [PATCH] fix: update sky model loading --- src/components/three/world/SkyModel.tsx | 106 ++++++++++++++++++++++-- src/data/world/environmentConfig.ts | 5 +- src/world/Environment.tsx | 12 ++- 3 files changed, 114 insertions(+), 9 deletions(-) diff --git a/src/components/three/world/SkyModel.tsx b/src/components/three/world/SkyModel.tsx index 56fd5eb..a3e89cd 100644 --- a/src/components/three/world/SkyModel.tsx +++ b/src/components/three/world/SkyModel.tsx @@ -1,34 +1,126 @@ import { useFrame, useThree } from "@react-three/fiber"; import { useGLTF } from "@react-three/drei"; -import { useRef } from "react"; +import { Component, useMemo, useRef, type ReactNode } from "react"; import * as THREE from "three"; -import { useClonedObject } from "@/hooks/three/useClonedObject"; import { useLoggedGLTF } from "@/hooks/three/useLoggedGLTF"; interface SkyModelProps { modelPath: string; + fallbackModelPath?: string | undefined; + fallbackScale?: number | undefined; + scale?: number | undefined; +} + +interface SkyModelContentProps { + modelPath: string; + scale: number; +} + +interface SkyModelErrorBoundaryProps { + children: ReactNode; + fallback: ReactNode; +} + +interface SkyModelErrorBoundaryState { + hasError: boolean; } const SKY_MODEL_SCALE = 1; +const SKY_MODEL_RENDER_ORDER = -1000; +const LEGACY_SKY_MODEL_PATH = "/models/sky/model.glb"; -export function SkyModel({ modelPath }: SkyModelProps): React.JSX.Element { +class SkyModelErrorBoundary extends Component< + SkyModelErrorBoundaryProps, + SkyModelErrorBoundaryState +> { + constructor(props: SkyModelErrorBoundaryProps) { + super(props); + this.state = { hasError: false }; + } + + static getDerivedStateFromError(): SkyModelErrorBoundaryState { + return { hasError: true }; + } + + render(): ReactNode { + if (this.state.hasError) { + return this.props.fallback; + } + + return this.props.children; + } +} + +export function SkyModel({ + fallbackModelPath, + fallbackScale = SKY_MODEL_SCALE, + modelPath, + scale = SKY_MODEL_SCALE, +}: SkyModelProps): React.JSX.Element { + const fallback = fallbackModelPath ? ( + + ) : null; + + return ( + + + + ); +} + +function SkyModelContent({ + modelPath, + scale, +}: SkyModelContentProps): React.JSX.Element { const camera = useThree((state) => state.camera); const groupRef = useRef(null); const { scene } = useLoggedGLTF(modelPath, { scope: "SkyModel", - scale: SKY_MODEL_SCALE, + scale, }); - const model = useClonedObject(scene); + const model = useMemo(() => createSkyModel(scene), [scene]); useFrame(() => { groupRef.current?.position.copy(camera.position); }); return ( - + ); } -useGLTF.preload("/models/sky/model.glb"); +function createSkyModel(scene: THREE.Object3D): THREE.Object3D { + const model = scene.clone(true); + + model.traverse((object) => { + object.frustumCulled = false; + object.renderOrder = SKY_MODEL_RENDER_ORDER; + + if (!(object instanceof THREE.Mesh)) return; + + object.material = Array.isArray(object.material) + ? object.material.map(createSkyMaterial) + : createSkyMaterial(object.material); + }); + + return model; +} + +function createSkyMaterial(material: T): T { + const skyMaterial = material.clone(); + skyMaterial.side = THREE.BackSide; + skyMaterial.depthTest = false; + skyMaterial.depthWrite = false; + + return skyMaterial as T; +} + +useGLTF.preload("/models/skybox/skybox.gltf"); +useGLTF.preload(LEGACY_SKY_MODEL_PATH); diff --git a/src/data/world/environmentConfig.ts b/src/data/world/environmentConfig.ts index f5f1222..bf287f7 100644 --- a/src/data/world/environmentConfig.ts +++ b/src/data/world/environmentConfig.ts @@ -1,2 +1,5 @@ -export const GAME_SCENE_SKY_MODEL_PATH = "/models/sky/model.glb"; +export const GAME_SCENE_SKY_MODEL_PATH = "/models/skybox/skybox.gltf"; +export const GAME_SCENE_FALLBACK_SKY_MODEL_PATH = "/models/sky/model.glb"; +export const GAME_SCENE_SKY_MODEL_SCALE = 300; +export const GAME_SCENE_FALLBACK_SKY_MODEL_SCALE = 1; export const PHYSICS_SCENE_BACKGROUND_COLOR = "#0b1018"; diff --git a/src/world/Environment.tsx b/src/world/Environment.tsx index 152234f..a9a7627 100644 --- a/src/world/Environment.tsx +++ b/src/world/Environment.tsx @@ -1,5 +1,8 @@ import { + GAME_SCENE_FALLBACK_SKY_MODEL_PATH, + GAME_SCENE_FALLBACK_SKY_MODEL_SCALE, GAME_SCENE_SKY_MODEL_PATH, + GAME_SCENE_SKY_MODEL_SCALE, PHYSICS_SCENE_BACKGROUND_COLOR, } from "@/data/world/environmentConfig"; import { useSceneMode } from "@/hooks/debug/useSceneMode"; @@ -14,5 +17,12 @@ export function Environment(): React.JSX.Element { ); } - return ; + return ( + + ); }