Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 606dde5122 | |||
| 59e5a8c0c0 | |||
| a40ee3854b | |||
| 18246eab22 | |||
| a6a6cdd168 | |||
| d9869a469e | |||
| 0db7c08168 | |||
| 5e8ebf9491 | |||
| 4d28cf8bcb |
Binary file not shown.
Binary file not shown.
+20
-15
@@ -3,12 +3,14 @@
|
||||
import './page.css';
|
||||
|
||||
import { Environment, OrbitControls, useProgress } from "@react-three/drei";
|
||||
import { Canvas } from '@react-three/fiber';
|
||||
import { Bloom, BrightnessContrast, DepthOfField, EffectComposer, HueSaturation, Noise, SMAA, SSAO, Vignette } from '@react-three/postprocessing';
|
||||
import { Canvas, useLoader } from '@react-three/fiber';
|
||||
import { Bloom, BrightnessContrast, DepthOfField, EffectComposer, HueSaturation, LUT, Noise, SMAA, SSAO, Vignette } from '@react-three/postprocessing';
|
||||
import { useLayoutEffect, useState } from "react";
|
||||
import { folder, useControls, Leva } from 'leva';
|
||||
import SealCube from './scene-components/sealcube';
|
||||
import Terrain from './scene-components/terrain';
|
||||
import { LUTCubeLoader } from 'three/examples/jsm/Addons.js';
|
||||
import { AmbientSound } from './scene-components/ambient-sound';
|
||||
|
||||
function Loader() {
|
||||
const { progress, active } = useProgress();
|
||||
@@ -52,15 +54,15 @@ function Scene() {
|
||||
grassLODExponent
|
||||
} = useControls('Environment', {
|
||||
Terrain: folder({
|
||||
terrainDryColor: '#20270a',
|
||||
terrainLushColor: '#0f240f',
|
||||
terrainDryColor: '#232a0c',
|
||||
terrainLushColor: '#142a14',
|
||||
chunks: { value: 16, min: 4, max: 24, step: 2 },
|
||||
chunkSize: { value: 10.0, min: 5.0, max: 40.0, step: 1.0 },
|
||||
resolution: { value: 8.0, min: 4.0, max: 30.0, step: 1.0 },
|
||||
hillScale: { value: 0.1, min: 0.01, max: 0.5, step: 0.01 },
|
||||
hillHeight: { value: 6.0, min: 0.0, max: 20.0, step: 0.5 },
|
||||
hillScale: { value: 0.15, min: 0.01, max: 0.5, step: 0.01 },
|
||||
hillHeight: { value: 4.0, min: 0.0, max: 20.0, step: 0.5 },
|
||||
detailScale: { value: 1.0, min: 0.1, max: 5.0, step: 0.1 },
|
||||
detailHeight: { value: 0.2, min: 0.0, max: 2.0, step: 0.05 },
|
||||
detailHeight: { value: 0.3, min: 0.0, max: 2.0, step: 0.05 },
|
||||
}),
|
||||
Grass: folder({
|
||||
grassDryColor: '#495a17',
|
||||
@@ -110,6 +112,11 @@ function Scene() {
|
||||
</>)
|
||||
}
|
||||
|
||||
function LutEffect() {
|
||||
const lutTexture = useLoader(LUTCubeLoader, 'niko/lut/Landscape6.cube');
|
||||
return <LUT lut={lutTexture.texture3D} />;
|
||||
}
|
||||
|
||||
function PostProcessing() {
|
||||
return (<EffectComposer>
|
||||
<DepthOfField target={[0, 3, 0]} focalLength={10} bokehScale={5} />
|
||||
@@ -121,8 +128,9 @@ function PostProcessing() {
|
||||
luminanceSmoothing={0.1}
|
||||
/>
|
||||
<SMAA />
|
||||
<HueSaturation saturation={0.1} />
|
||||
<HueSaturation saturation={0.3} />
|
||||
<BrightnessContrast brightness={0.05} contrast={-0.1} />
|
||||
<LutEffect />
|
||||
</EffectComposer>)
|
||||
}
|
||||
|
||||
@@ -140,21 +148,18 @@ export default function Seal() {
|
||||
gl={{ antialias: true }}
|
||||
className='canvas'
|
||||
>
|
||||
<AmbientSound url="niko/snd/wind.mp3" volume={0.4}/>
|
||||
<AmbientSound url="niko/snd/birds.mp3" volume={0.1}/>
|
||||
|
||||
<Scene />
|
||||
<PostProcessing />
|
||||
|
||||
<Environment
|
||||
files={'niko/hdr/sky.hdr'}
|
||||
environmentIntensity={1}
|
||||
background
|
||||
/>
|
||||
|
||||
<OrbitControls
|
||||
target={[0, 3, 0]}
|
||||
enablePan={false}
|
||||
makeDefault
|
||||
minDistance={2}
|
||||
maxDistance={10}
|
||||
maxDistance={6}
|
||||
/>
|
||||
</Canvas>
|
||||
</>
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import { useEffect, useRef } from 'react'
|
||||
|
||||
interface AmbientSoundProps {
|
||||
url: string
|
||||
volume?: number
|
||||
}
|
||||
|
||||
export function AmbientSound({ url, volume = 0.5 }: AmbientSoundProps) {
|
||||
const audioRef = useRef<HTMLAudioElement | null>(null)
|
||||
|
||||
useEffect(() => {
|
||||
const audio = new Audio(url)
|
||||
audio.loop = true
|
||||
audio.volume = volume
|
||||
audioRef.current = audio
|
||||
|
||||
const startAudio = () => {
|
||||
audio.play().catch((err) => {
|
||||
console.warn('Autoplay blocked. Waiting for user interaction.', err)
|
||||
})
|
||||
}
|
||||
|
||||
startAudio()
|
||||
|
||||
window.addEventListener('click', startAudio, { once: true })
|
||||
window.addEventListener('keydown', startAudio, { once: true })
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('click', startAudio)
|
||||
window.removeEventListener('keydown', startAudio)
|
||||
audio.pause()
|
||||
audioRef.current = null
|
||||
}
|
||||
}, [url])
|
||||
|
||||
useEffect(() => {
|
||||
if (audioRef.current) {
|
||||
audioRef.current.volume = volume
|
||||
}
|
||||
}, [volume])
|
||||
|
||||
return null
|
||||
}
|
||||
@@ -27,7 +27,7 @@ interface GrassProps {
|
||||
grassLODExponent?: number;
|
||||
}
|
||||
|
||||
export default function({
|
||||
export default function Grass({
|
||||
x,
|
||||
y,
|
||||
size,
|
||||
|
||||
@@ -214,7 +214,7 @@ interface TerrainProps {
|
||||
grassLODStart?: number;
|
||||
grassLODExponent?: number;
|
||||
}
|
||||
export default function({
|
||||
export default function Terrain({
|
||||
chunks = 5,
|
||||
chunkSize = 10,
|
||||
resolution = 8,
|
||||
|
||||
Reference in New Issue
Block a user