Repository navigation
Expand file tree
/
Copy pathApp.tsx
More file actions
113 lines (108 loc) · 3.58 KB
/
Copy pathApp.tsx
File metadata and controls
113 lines (108 loc) · 3.58 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import { Suspense, useEffect } from "react";
import { Canvas, useThree } from "@react-three/fiber";
import { CameraControls, Environment, useTexture } from "@react-three/drei";
import {
ACESFilmicToneMapping,
AgXToneMapping,
CineonToneMapping,
EquirectangularReflectionMapping,
LinearToneMapping,
NeutralToneMapping,
NoToneMapping,
ReinhardToneMapping,
type Material,
type Mesh,
type ToneMapping,
} from "three";
import { createWebGPURenderer } from "./renderer/webgpu-renderer";
import { LIGHTING, TEXTURE_PATHS } from "./config/scene-config";
import type { ToneMappingMode } from "./types";
import { Scene } from "./scene/scene";
import { ControlsPanel } from "./ui/controls-panel";
import { GithubButton } from "./ui/github-button";
import { useSceneControls } from "./ui/use-scene-controls";
const TONE_MAPPING_VALUES: Record<ToneMappingMode, ToneMapping> = {
none: NoToneMapping,
linear: LinearToneMapping,
reinhard: ReinhardToneMapping,
cineon: CineonToneMapping,
aces: ACESFilmicToneMapping,
agx: AgXToneMapping,
neutral: NeutralToneMapping,
};
// Applies the selected tone mapping curve to the WebGPU renderer at runtime.
// In WebGPU the tone mapping function is compiled into each material's output,
// so switching it requires flagging existing materials for recompile.
function ToneMappingControl({ mode }: { mode: ToneMappingMode }) {
const gl = useThree((s) => s.gl);
const scene = useThree((s) => s.scene);
useEffect(() => {
gl.toneMapping = TONE_MAPPING_VALUES[mode];
scene.traverse((o) => {
const material = (o as Mesh).material;
if (!material) return;
const list = Array.isArray(material) ? material : [material];
list.forEach((m: Material) => (m.needsUpdate = true));
});
}, [gl, scene, mode]);
return null;
}
// drei's <Environment files> chooses a loader from the file extension and
// rejects plain .png equirectangulars. Load the texture ourselves and pass it
// via `map`, which bypasses that loader while still driving the visible
// background and the image-based lighting fill.
function SkyEnvironment() {
const skyTexture = useTexture(TEXTURE_PATHS.sky);
skyTexture.mapping = EquirectangularReflectionMapping;
return (
<Environment
map={skyTexture}
background
environmentIntensity={LIGHTING.environmentIntensity}
/>
);
}
export default function App() {
const { values, set } = useSceneControls();
return (
<>
<Canvas
flat
shadows
camera={{ position: [1.98, 4.46, 22.31] }}
gl={createWebGPURenderer}
>
<directionalLight
castShadow
color={LIGHTING.sunColor}
intensity={LIGHTING.sunIntensity}
position={LIGHTING.sunPosition}
shadow-mapSize-width={LIGHTING.shadowMapSize}
shadow-mapSize-height={LIGHTING.shadowMapSize}
shadow-bias={LIGHTING.shadowBias}
shadow-normalBias={LIGHTING.shadowNormalBias}
>
<orthographicCamera
attach="shadow-camera"
args={[
-LIGHTING.shadowFrustum,
LIGHTING.shadowFrustum,
LIGHTING.shadowFrustum,
-LIGHTING.shadowFrustum,
LIGHTING.shadowNear,
LIGHTING.shadowFar,
]}
/>
</directionalLight>
<ToneMappingControl mode={values.toneMapping} />
<Suspense fallback={null}>
<SkyEnvironment />
<Scene {...values} />
</Suspense>
<CameraControls />
</Canvas>
<ControlsPanel values={values} set={set} />
<GithubButton />
</>
);
}