Files
neru.rip/src/app/niko/page.tsx
T
2026-06-01 17:31:13 -03:00

173 lines
4.8 KiB
TypeScript

'use client';
import './page.css';
import { Environment, OrbitControls, useProgress } from "@react-three/drei";
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();
const [visible, setVisible] = useState(true);
useLayoutEffect(() => {
if (!active && progress === 100) {
const timeout = setTimeout(() => setVisible(false), 500);
return () => clearTimeout(timeout);
}
}, [progress, active]);
return (
<div className={`loader ${!visible ? 'loader hidden' : ''}`}>
<picture>
<img src='niko/img/niko.jpg' className='niko-spin' />
</picture>
</div>
);
}
function Scene() {
const {
terrainDryColor,
terrainLushColor,
chunks,
chunkSize,
resolution,
hillScale,
hillHeight,
detailScale,
detailHeight,
grassDryColor,
grassLushColor,
grassCount,
grassSize,
grassLOD,
grassBlades,
grassSegments,
grassLODStart,
grassLODExponent
} = useControls('Environment', {
Terrain: folder({
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.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.3, min: 0.0, max: 2.0, step: 0.05 },
}),
Grass: folder({
grassDryColor: '#495a17',
grassLushColor: '#255825',
grassCount: { value: 8000, min: 1000, max: 30000, step: 500 },
grassSize: { value: 0.85, min: 0.1, max: 2.0, step: 0.05 },
grassLOD: { value: 60, min: 10, max: 200, step: 5 },
grassBlades: { value: 3, min: 1, max: 5, step: 1 },
grassSegments: { value: 4, min: 1, max: 5, step: 1 },
grassLODStart: { value: 0.15, min: 0.0, max: 0.9, step: 0.05 },
grassLODExponent: { value: 1.8, min: 0.5, max: 3.0, step: 0.1 },
})
});
return (<>
<Environment
files={'niko/hdr/sky.hdr'}
environmentIntensity={0.85}
background
/>
<fogExp2 attach='fog' args={[0xa3a5ba, 0.0125]} />
<ambientLight intensity={0.5} />
<directionalLight
position={[15, 25, 15]}
intensity={1}
/>
<Terrain
chunks={chunks}
chunkSize={chunkSize}
resolution={resolution}
scale={1}
hillScale={hillScale}
hillHeight={hillHeight}
detailScale={detailScale}
detailHeight={detailHeight}
grassCount={grassCount}
grassSize={grassSize}
grassLOD={grassLOD}
terrainDryColor={terrainDryColor}
terrainLushColor={terrainLushColor}
grassDryColor={grassDryColor}
grassLushColor={grassLushColor}
grassBlades={grassBlades}
grassSegments={grassSegments}
grassLODStart={grassLODStart}
grassLODExponent={grassLODExponent}
/>
<SealCube />
</>)
}
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} />
<Vignette />
<Noise opacity={0.05} />
<Bloom
intensity={0.8}
luminanceThreshold={0.4}
luminanceSmoothing={0.5}
/>
<SMAA />
<HueSaturation saturation={0.3} />
<BrightnessContrast brightness={0.05} contrast={-0.1} />
<LutEffect />
</EffectComposer>)
}
export default function Seal() {
const isProduction = process.env.NODE_ENV === 'production';
return (
<>
<Leva hidden={isProduction} />
<Loader />
<Canvas
shadows
camera={{ position: [0, 5, 15], fov: 50, far: 100 }}
gl={{ antialias: false, powerPreference: "high-performance" }}
className='canvas'
>
<AmbientSound url="niko/snd/wind.mp3" volume={0.4} />
<AmbientSound url="niko/snd/birds.mp3" volume={0.1} />
<Scene />
<PostProcessing />
<OrbitControls
target={[0, 3, 0]}
enablePan={false}
makeDefault
minDistance={2}
maxDistance={6}
/>
</Canvas>
</>
);
}