Compare commits

..

9 Commits

Author SHA1 Message Date
neru 606dde5122 fix: remove duplicate env 2026-05-31 14:45:05 -03:00
neru 59e5a8c0c0 style: restrict max dist to 6 2026-05-31 14:41:55 -03:00
neru a40ee3854b feat: add ambient sound 2026-05-31 14:40:49 -03:00
neru 18246eab22 feat: add AmbientSound component 2026-05-31 14:40:36 -03:00
neru a6a6cdd168 give functions names 2026-05-31 14:36:34 -03:00
neru d9869a469e style: increase saturation 2026-05-31 14:29:36 -03:00
neru 0db7c08168 style: misc terrain generation params 2026-05-31 14:29:16 -03:00
neru 5e8ebf9491 style: change terrain colours again 2026-05-31 14:27:13 -03:00
neru 4d28cf8bcb feat: add LUT 2026-05-31 14:26:25 -03:00
6 changed files with 65 additions and 17 deletions
Binary file not shown.
Binary file not shown.
+20 -15
View File
@@ -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
}
+1 -1
View File
@@ -27,7 +27,7 @@ interface GrassProps {
grassLODExponent?: number;
}
export default function({
export default function Grass({
x,
y,
size,
+1 -1
View File
@@ -214,7 +214,7 @@ interface TerrainProps {
grassLODStart?: number;
grassLODExponent?: number;
}
export default function({
export default function Terrain({
chunks = 5,
chunkSize = 10,
resolution = 8,