init
This commit is contained in:
128
src/AtmosphereScene.jsx
Normal file
128
src/AtmosphereScene.jsx
Normal file
@@ -0,0 +1,128 @@
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { useFrame, useThree } from '@react-three/fiber';
|
||||
import { PerspectiveCamera } from '@react-three/drei';
|
||||
import { EffectComposer, ToneMapping } from '@react-three/postprocessing';
|
||||
import { ToneMappingMode } from 'postprocessing';
|
||||
import * as THREE from 'three';
|
||||
|
||||
import { AerialPerspective, Atmosphere } from '@takram/three-atmosphere/r3f';
|
||||
import { Clouds, CloudLayer } from '@takram/three-clouds/r3f';
|
||||
|
||||
import { TilesPlugin, TilesRenderer } from '3d-tiles-renderer/r3f';
|
||||
import {
|
||||
GLTFExtensionsPlugin,
|
||||
GoogleCloudAuthPlugin,
|
||||
TileCompressionPlugin,
|
||||
TilesFadePlugin,
|
||||
UpdateOnChangePlugin,
|
||||
} from '3d-tiles-renderer/plugins';
|
||||
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
|
||||
|
||||
import { FollowCamera } from './controls/CameraRig';
|
||||
|
||||
const TIME_SCALE = 100;
|
||||
const INITIAL_DATE = new Date('2024-06-21T12:00:00');
|
||||
const WEATHER_INTERVAL = 5 * 60 * 1000;
|
||||
|
||||
const WEATHER_PRESETS = [
|
||||
{
|
||||
name: 'Clear',
|
||||
coverage: 0.05,
|
||||
layers: [
|
||||
{ channel: 'r', altitude: 2000, height: 500, densityScale: 0.05 },
|
||||
{ channel: 'b', altitude: 7500, height: 500, densityScale: 0.05 },
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'Sunny',
|
||||
coverage: 0.2,
|
||||
layers: [
|
||||
{ channel: 'r', altitude: 1500, height: 500, densityScale: 0.3 },
|
||||
{ channel: 'b', altitude: 7500, height: 500, densityScale: 0.15 },
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'Cloudy',
|
||||
coverage: 0.4,
|
||||
layers: [
|
||||
{ channel: 'r', altitude: 1500, height: 500, densityScale: 0.4 },
|
||||
{ channel: 'g', altitude: 2000, height: 800, densityScale: 0.3 },
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
const dracoLoader = new DRACOLoader();
|
||||
dracoLoader.setDecoderPath('https://www.gstatic.com/draco/v1/decoders/');
|
||||
|
||||
function GoogleMaps3DTiles() {
|
||||
const apiKey = import.meta.env.VITE_GOOGLE_MAP_API_KEY;
|
||||
if (!apiKey) return null;
|
||||
|
||||
return (
|
||||
<TilesRenderer url={`https://tile.googleapis.com/v1/3dtiles/root.json?key=${apiKey}`}>
|
||||
<TilesPlugin plugin={GoogleCloudAuthPlugin} args={{ apiToken: apiKey }} />
|
||||
<TilesPlugin plugin={GLTFExtensionsPlugin} dracoLoader={dracoLoader} />
|
||||
<TilesPlugin plugin={TileCompressionPlugin} />
|
||||
<TilesPlugin plugin={UpdateOnChangePlugin} />
|
||||
<TilesPlugin plugin={TilesFadePlugin} />
|
||||
</TilesRenderer>
|
||||
);
|
||||
}
|
||||
|
||||
export default function AtmosphereScene() {
|
||||
const { gl } = useThree();
|
||||
const sunRef = useRef();
|
||||
const atmosphereRef = useRef();
|
||||
const dateRef = useRef(new Date(INITIAL_DATE));
|
||||
const [weather, setWeather] = useState(WEATHER_PRESETS[1]);
|
||||
|
||||
useEffect(() => {
|
||||
gl.toneMapping = THREE.NoToneMapping;
|
||||
gl.toneMappingExposure = 10.0;
|
||||
}, [gl]);
|
||||
|
||||
useEffect(() => {
|
||||
const interval = setInterval(() => {
|
||||
setWeather(prev => {
|
||||
const others = WEATHER_PRESETS.filter(w => w.name !== prev.name);
|
||||
return others[Math.floor(Math.random() * others.length)];
|
||||
});
|
||||
}, WEATHER_INTERVAL);
|
||||
return () => clearInterval(interval);
|
||||
}, []);
|
||||
|
||||
useFrame((_, delta) => {
|
||||
const currentDate = dateRef.current;
|
||||
currentDate.setTime(currentDate.getTime() + delta * TIME_SCALE * 1000);
|
||||
|
||||
if (atmosphereRef.current) {
|
||||
atmosphereRef.current.updateByDate(currentDate);
|
||||
const sunDirection = atmosphereRef.current.sunDirection;
|
||||
if (sunRef.current && sunDirection) {
|
||||
sunRef.current.position.copy(sunDirection);
|
||||
sunRef.current.intensity = sunDirection.y < -0.1 ? 0.1 : 3.0;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<PerspectiveCamera makeDefault near={10} far={10000000} fov={45} />
|
||||
<FollowCamera />
|
||||
<directionalLight ref={sunRef} position={[0, 1, 0]} intensity={3.0} castShadow />
|
||||
<Atmosphere ref={atmosphereRef}>
|
||||
<GoogleMaps3DTiles />
|
||||
<EffectComposer multisampling={0} disableNormalPass={false}>
|
||||
<Clouds disableDefaultLayers coverage={weather.coverage}>
|
||||
{weather.layers.map((layer, i) => (
|
||||
<CloudLayer key={i} channel={layer.channel} altitude={layer.altitude}
|
||||
height={layer.height} densityScale={layer.densityScale} shapeAmount={0.5} />
|
||||
))}
|
||||
</Clouds>
|
||||
<AerialPerspective sky />
|
||||
<ToneMapping mode={ToneMappingMode.AGX} />
|
||||
</EffectComposer>
|
||||
</Atmosphere>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user