76bad46d09
Loading screen, main menu, 3D flight sim with CRT post-processing, procedural terrain, airport with buildings, low-poly aircraft, flight physics, HUD instruments, and sound. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
109 lines
3.1 KiB
JavaScript
109 lines
3.1 KiB
JavaScript
import * as THREE from 'three';
|
|
|
|
export class RetroEffect {
|
|
constructor(renderer, width, height) {
|
|
this.renderer = renderer;
|
|
this.width = width;
|
|
this.height = height;
|
|
|
|
this.renderTarget = new THREE.WebGLRenderTarget(width, height, {
|
|
minFilter: THREE.NearestFilter,
|
|
magFilter: THREE.NearestFilter,
|
|
});
|
|
|
|
this.scene = new THREE.Scene();
|
|
this.camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1);
|
|
|
|
this.quad = new THREE.Mesh(
|
|
new THREE.PlaneGeometry(2, 2),
|
|
new THREE.ShaderMaterial({
|
|
uniforms: {
|
|
tDiffuse: { value: null },
|
|
resolution: { value: new THREE.Vector2(width, height) },
|
|
time: { value: 0 },
|
|
},
|
|
vertexShader: `
|
|
varying vec2 vUv;
|
|
void main() {
|
|
vUv = uv;
|
|
gl_Position = vec4(position, 0.0, 1.0);
|
|
}
|
|
`,
|
|
fragmentShader: `
|
|
uniform sampler2D tDiffuse;
|
|
uniform vec2 resolution;
|
|
uniform float time;
|
|
varying vec2 vUv;
|
|
|
|
vec2 barrelDistortion(vec2 uv, float amount) {
|
|
vec2 center = uv - 0.5;
|
|
float dist = dot(center, center);
|
|
return uv + center * dist * amount;
|
|
}
|
|
|
|
vec3 quantize(vec3 color, float levels) {
|
|
return floor(color * levels + 0.5) / levels;
|
|
}
|
|
|
|
void main() {
|
|
vec2 distortedUv = barrelDistortion(vUv, 0.25);
|
|
|
|
// Clamp distorted UV
|
|
distortedUv = clamp(distortedUv, 0.0, 1.0);
|
|
|
|
// Chromatic aberration
|
|
float aberration = 0.0015;
|
|
vec2 dir = distortedUv - 0.5;
|
|
float dist = length(dir);
|
|
|
|
float r = texture2D(tDiffuse, distortedUv + dir * aberration).r;
|
|
vec2 gbSample = distortedUv - dir * aberration * 0.5;
|
|
float g = texture2D(tDiffuse, gbSample).g;
|
|
float b = texture2D(tDiffuse, distortedUv - dir * aberration).b;
|
|
vec3 color = vec3(r, g, b);
|
|
|
|
// Scanline
|
|
float scanline = sin(vUv.y * resolution.y * 3.14159) * 0.08;
|
|
color -= scanline;
|
|
|
|
// Quantize to EGA-like palette
|
|
color = quantize(color, 16.0);
|
|
|
|
// Vignette
|
|
float vignette = 1.0 - dist * 0.6;
|
|
vignette = smoothstep(0.0, 1.0, vignette);
|
|
color *= vignette;
|
|
|
|
// Subtle phosphor warmth
|
|
color.r += 0.01;
|
|
color.g += 0.005;
|
|
|
|
// CRT curvature darkening at edges
|
|
float edgeDarken = smoothstep(0.3, 1.2, dist);
|
|
color *= 1.0 - edgeDarken * 0.3;
|
|
|
|
gl_FragColor = vec4(color, 1.0);
|
|
}
|
|
`,
|
|
})
|
|
);
|
|
|
|
this.scene.add(this.quad);
|
|
}
|
|
|
|
update(time) {
|
|
this.quad.material.uniforms.time.value = time;
|
|
}
|
|
|
|
render(scene, camera) {
|
|
// Render scene to offscreen target
|
|
this.renderer.setRenderTarget(this.renderTarget);
|
|
this.renderer.render(scene, camera);
|
|
|
|
// Render post-processed quad to screen
|
|
this.renderer.setRenderTarget(null);
|
|
this.quad.material.uniforms.tDiffuse.value = this.renderTarget.texture;
|
|
this.renderer.render(this.scene, this.camera);
|
|
}
|
|
}
|