fix: update sky model loading
This commit is contained in:
@@ -1,34 +1,126 @@
|
|||||||
import { useFrame, useThree } from "@react-three/fiber";
|
import { useFrame, useThree } from "@react-three/fiber";
|
||||||
import { useGLTF } from "@react-three/drei";
|
import { useGLTF } from "@react-three/drei";
|
||||||
import { useRef } from "react";
|
import { Component, useMemo, useRef, type ReactNode } from "react";
|
||||||
import * as THREE from "three";
|
import * as THREE from "three";
|
||||||
import { useClonedObject } from "@/hooks/three/useClonedObject";
|
|
||||||
import { useLoggedGLTF } from "@/hooks/three/useLoggedGLTF";
|
import { useLoggedGLTF } from "@/hooks/three/useLoggedGLTF";
|
||||||
|
|
||||||
interface SkyModelProps {
|
interface SkyModelProps {
|
||||||
modelPath: string;
|
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_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 ? (
|
||||||
|
<SkyModelContent modelPath={fallbackModelPath} scale={fallbackScale} />
|
||||||
|
) : null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SkyModelErrorBoundary key={modelPath} fallback={fallback}>
|
||||||
|
<SkyModelContent modelPath={modelPath} scale={scale} />
|
||||||
|
</SkyModelErrorBoundary>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function SkyModelContent({
|
||||||
|
modelPath,
|
||||||
|
scale,
|
||||||
|
}: SkyModelContentProps): React.JSX.Element {
|
||||||
const camera = useThree((state) => state.camera);
|
const camera = useThree((state) => state.camera);
|
||||||
const groupRef = useRef<THREE.Group>(null);
|
const groupRef = useRef<THREE.Group>(null);
|
||||||
const { scene } = useLoggedGLTF(modelPath, {
|
const { scene } = useLoggedGLTF(modelPath, {
|
||||||
scope: "SkyModel",
|
scope: "SkyModel",
|
||||||
scale: SKY_MODEL_SCALE,
|
scale,
|
||||||
});
|
});
|
||||||
const model = useClonedObject(scene);
|
const model = useMemo(() => createSkyModel(scene), [scene]);
|
||||||
|
|
||||||
useFrame(() => {
|
useFrame(() => {
|
||||||
groupRef.current?.position.copy(camera.position);
|
groupRef.current?.position.copy(camera.position);
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<group ref={groupRef} scale={SKY_MODEL_SCALE} frustumCulled={false}>
|
<group
|
||||||
|
ref={groupRef}
|
||||||
|
renderOrder={SKY_MODEL_RENDER_ORDER}
|
||||||
|
scale={scale}
|
||||||
|
frustumCulled={false}
|
||||||
|
>
|
||||||
<primitive object={model} />
|
<primitive object={model} />
|
||||||
</group>
|
</group>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
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<T extends THREE.Material>(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);
|
||||||
|
|||||||
@@ -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";
|
export const PHYSICS_SCENE_BACKGROUND_COLOR = "#0b1018";
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
import {
|
import {
|
||||||
|
GAME_SCENE_FALLBACK_SKY_MODEL_PATH,
|
||||||
|
GAME_SCENE_FALLBACK_SKY_MODEL_SCALE,
|
||||||
GAME_SCENE_SKY_MODEL_PATH,
|
GAME_SCENE_SKY_MODEL_PATH,
|
||||||
|
GAME_SCENE_SKY_MODEL_SCALE,
|
||||||
PHYSICS_SCENE_BACKGROUND_COLOR,
|
PHYSICS_SCENE_BACKGROUND_COLOR,
|
||||||
} from "@/data/world/environmentConfig";
|
} from "@/data/world/environmentConfig";
|
||||||
import { useSceneMode } from "@/hooks/debug/useSceneMode";
|
import { useSceneMode } from "@/hooks/debug/useSceneMode";
|
||||||
@@ -14,5 +17,12 @@ export function Environment(): React.JSX.Element {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return <SkyModel modelPath={GAME_SCENE_SKY_MODEL_PATH} />;
|
return (
|
||||||
|
<SkyModel
|
||||||
|
fallbackModelPath={GAME_SCENE_FALLBACK_SKY_MODEL_PATH}
|
||||||
|
fallbackScale={GAME_SCENE_FALLBACK_SKY_MODEL_SCALE}
|
||||||
|
modelPath={GAME_SCENE_SKY_MODEL_PATH}
|
||||||
|
scale={GAME_SCENE_SKY_MODEL_SCALE}
|
||||||
|
/>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user