67 lines
2.4 KiB
TypeScript
67 lines
2.4 KiB
TypeScript
import * as THREE from 'three';
|
|
import type { SceneResourceBag } from '@/scene/resources';
|
|
import type { MutableChapterPalette } from './palette';
|
|
|
|
/** Thin, spatially separated air masses. No screen-sized render targets. */
|
|
export function createHorizonAir(resources: SceneResourceBag) {
|
|
const group = new THREE.Group();
|
|
group.name = 'horizon-air-masses';
|
|
const uniforms = {
|
|
uTime: { value: 0 },
|
|
uWarmth: { value: 0 },
|
|
uDawn: { value: 0 },
|
|
uColor: { value: new THREE.Color(0xc5646b) },
|
|
};
|
|
const material = resources.own(
|
|
'material',
|
|
new THREE.ShaderMaterial({
|
|
uniforms,
|
|
vertexShader: `
|
|
varying vec2 vUv;
|
|
void main(){vUv=uv;gl_Position=projectionMatrix*modelViewMatrix*vec4(position,1.0);}
|
|
`,
|
|
fragmentShader: `
|
|
uniform float uTime;
|
|
uniform float uWarmth;
|
|
uniform float uDawn;
|
|
uniform vec3 uColor;
|
|
varying vec2 vUv;
|
|
void main(){
|
|
float wave=sin(vUv.x*12.0+uTime*0.018)*0.055+sin(vUv.x*31.0-uTime*0.026)*0.018;
|
|
float ribbon=exp(-pow((vUv.y-0.45-wave)*5.6,2.0));
|
|
float thin=exp(-pow((vUv.y-0.51-wave)*37.0,2.0));
|
|
float horizontal=pow(max(0.0,sin(vUv.x*3.14159)),2.0);
|
|
float colorWave=0.5+0.5*sin(vUv.x*7.0+uTime*0.035);
|
|
vec3 color=mix(uColor,vec3(0.27,0.045,0.75),colorWave*0.55);
|
|
color=mix(color,vec3(0.05,0.52,0.75),smoothstep(0.54,0.82,vUv.y)*0.3);
|
|
gl_FragColor=vec4(color,(ribbon*0.16+thin*0.032)*horizontal*(0.7+uWarmth*0.3)*(1.0+uDawn));
|
|
#include <tonemapping_fragment>
|
|
#include <colorspace_fragment>
|
|
}
|
|
`,
|
|
transparent: true,
|
|
depthWrite: false,
|
|
depthTest: true,
|
|
blending: THREE.AdditiveBlending,
|
|
}),
|
|
);
|
|
const geometry = resources.own('geometry', new THREE.PlaneGeometry(1450, 95));
|
|
for (let i = 0; i < 3; i++) {
|
|
const mesh = new THREE.Mesh(geometry, material);
|
|
mesh.name = `stratified-air-${i + 1}`;
|
|
mesh.position.set((i - 1) * 85, 15 + i * 11, -500 - i * 70);
|
|
mesh.scale.set(1 - i * 0.12, 1 - i * 0.18, 1);
|
|
group.add(mesh);
|
|
}
|
|
return {
|
|
group,
|
|
/** dawn: END OF SHIFT, the air masses catch first light (gain up to 2x). */
|
|
update(palette: Readonly<MutableChapterPalette>, time: number, dawn = 0) {
|
|
uniforms.uTime.value = time;
|
|
uniforms.uDawn.value = Number.isFinite(dawn) ? Math.min(1, Math.max(0, dawn)) : 0;
|
|
uniforms.uWarmth.value = palette.warmth;
|
|
uniforms.uColor.value.copy(palette.sun);
|
|
},
|
|
};
|
|
}
|