feat: layer the nightdrive sky and atmosphere
This commit is contained in:
92
src/scene/post-processing.ts
Normal file
92
src/scene/post-processing.ts
Normal file
@@ -0,0 +1,92 @@
|
||||
import * as THREE from 'three';
|
||||
import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer.js';
|
||||
import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass.js';
|
||||
import { UnrealBloomPass } from 'three/examples/jsm/postprocessing/UnrealBloomPass.js';
|
||||
import type { SceneResourceBag } from '@/scene/resources';
|
||||
|
||||
export interface PostProcessor {
|
||||
resize(width: number, height: number, pixelRatio: number): void;
|
||||
render(scene: unknown, camera: unknown): void;
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
interface ComposerLike {
|
||||
addPass(pass: unknown): void;
|
||||
setPixelRatio(pixelRatio: number): void;
|
||||
setSize(width: number, height: number): void;
|
||||
render(): void;
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
interface RenderPassLike {
|
||||
scene: unknown;
|
||||
camera: unknown;
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
interface BloomPassLike {
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
export interface PostProcessingFactories {
|
||||
createComposer(renderer: unknown): ComposerLike;
|
||||
createRenderPass(scene: unknown, camera: unknown): RenderPassLike;
|
||||
createBloomPass(): BloomPassLike;
|
||||
}
|
||||
|
||||
const productionFactories: PostProcessingFactories = {
|
||||
createComposer: (renderer) => new EffectComposer(renderer),
|
||||
createRenderPass: (scene, camera) => new RenderPass(scene, camera),
|
||||
createBloomPass: () => new UnrealBloomPass(
|
||||
new THREE.Vector2(1, 1),
|
||||
0.46,
|
||||
0.32,
|
||||
0.84,
|
||||
),
|
||||
};
|
||||
|
||||
export function createPostProcessor(
|
||||
resources: SceneResourceBag,
|
||||
renderer: unknown,
|
||||
factories: PostProcessingFactories = productionFactories,
|
||||
): PostProcessor {
|
||||
const composer = factories.createComposer(renderer);
|
||||
const renderPass = factories.createRenderPass(new THREE.Scene(), new THREE.Camera());
|
||||
const bloomPass = factories.createBloomPass();
|
||||
composer.addPass(renderPass);
|
||||
composer.addPass(bloomPass);
|
||||
let disposed = false;
|
||||
|
||||
const processor: PostProcessor = {
|
||||
resize(width, height, pixelRatio) {
|
||||
if (disposed) return;
|
||||
composer.setPixelRatio(clamp(pixelRatio, 0.5, 2));
|
||||
composer.setSize(
|
||||
Math.max(1, Math.floor(finiteOr(width, 1))),
|
||||
Math.max(1, Math.floor(finiteOr(height, 1))),
|
||||
);
|
||||
},
|
||||
render(scene, camera) {
|
||||
if (disposed) return;
|
||||
renderPass.scene = scene;
|
||||
renderPass.camera = camera;
|
||||
composer.render();
|
||||
},
|
||||
dispose() {
|
||||
if (disposed) return;
|
||||
disposed = true;
|
||||
renderPass.dispose();
|
||||
bloomPass.dispose();
|
||||
composer.dispose();
|
||||
},
|
||||
};
|
||||
return resources.own('pass', processor);
|
||||
}
|
||||
|
||||
function finiteOr(value: number, fallback: number): number {
|
||||
return Number.isFinite(value) ? value : fallback;
|
||||
}
|
||||
|
||||
function clamp(value: number, minimum: number, maximum: number): number {
|
||||
return THREE.MathUtils.clamp(finiteOr(value, minimum), minimum, maximum);
|
||||
}
|
||||
Reference in New Issue
Block a user