feat: sculpt portfolio into an immersive midnight expressway
Author physical road furniture, layered terrain and atmosphere, projected illuminated route signs, and detailed Blender coachwork. Refine camera mass, wheel contact, chapter composition, and compact reading space while preserving approved content and audio contracts. Include isolated Blender source, before/after and hardware Chrome motion evidence, preservation hashes, validated preview checks, and documented inherited unit failures.
This commit is contained in:
60
src/scene/world/horizon-air.ts
Normal file
60
src/scene/world/horizon-air.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
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 },
|
||||
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 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);
|
||||
vec3 color=mix(uColor,vec3(0.21,0.49,0.59),vUv.y*0.25);
|
||||
gl_FragColor=vec4(color,(ribbon*0.12+thin*0.026)*horizontal*(0.6+uWarmth*0.4));
|
||||
#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,
|
||||
update(palette: Readonly<MutableChapterPalette>, time: number) {
|
||||
uniforms.uTime.value = time;
|
||||
uniforms.uWarmth.value = palette.warmth;
|
||||
uniforms.uColor.value.copy(palette.sun);
|
||||
},
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user