fix: close final portfolio quality gaps

This commit is contained in:
2026-09-02 17:38:11 +03:00
parent 0899b6b00f
commit b4728ceef0
24 changed files with 1822 additions and 889 deletions

View File

@@ -1,16 +1,29 @@
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';
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 {
GpuRenderTargetAllocation,
GpuRenderTargetReporter,
SceneResourceBag,
} from "@/scene/resources";
export interface PostProcessor {
export interface PostProcessor extends GpuRenderTargetReporter {
resize(width: number, height: number, pixelRatio: number): void;
render(scene: unknown, camera: unknown): void;
dispose(): void;
}
interface RenderTargetLike {
width: number;
height: number;
samples?: number;
depthBuffer?: boolean;
}
interface ComposerLike {
renderTarget1?: RenderTargetLike;
renderTarget2?: RenderTargetLike;
addPass(pass: unknown): void;
setPixelRatio(pixelRatio: number): void;
setSize(width: number, height: number): void;
@@ -25,6 +38,9 @@ interface RenderPassLike {
}
interface BloomPassLike {
renderTargetBright?: RenderTargetLike;
renderTargetsHorizontal?: readonly RenderTargetLike[];
renderTargetsVertical?: readonly RenderTargetLike[];
dispose(): void;
}
@@ -37,12 +53,8 @@ export interface PostProcessingFactories {
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,
),
createBloomPass: () =>
new UnrealBloomPass(new THREE.Vector2(1, 1), 0.46, 0.32, 0.84),
};
export function createPostProcessor(
@@ -51,13 +63,19 @@ export function createPostProcessor(
factories: PostProcessingFactories = productionFactories,
): PostProcessor {
const composer = factories.createComposer(renderer);
const renderPass = factories.createRenderPass(new THREE.Scene(), new THREE.Camera());
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 = {
gpuRenderTargets() {
return collectRenderTargetAllocations(composer, bloomPass);
},
resize(width, height, pixelRatio) {
if (disposed) return;
composer.setPixelRatio(clamp(pixelRatio, 0.5, 2));
@@ -80,7 +98,41 @@ export function createPostProcessor(
composer.dispose();
},
};
return resources.own('pass', processor);
return resources.own("pass", processor);
}
function collectRenderTargetAllocations(
composer: ComposerLike,
bloomPass: BloomPassLike,
): readonly GpuRenderTargetAllocation[] {
const candidates: ReadonlyArray<
readonly [string, RenderTargetLike | undefined]
> = [
["composer-target-1", composer.renderTarget1],
["composer-target-2", composer.renderTarget2],
["bloom-bright", bloomPass.renderTargetBright],
...(bloomPass.renderTargetsHorizontal ?? []).map(
(target, index) => [`bloom-horizontal-${index}`, target] as const,
),
...(bloomPass.renderTargetsVertical ?? []).map(
(target, index) => [`bloom-vertical-${index}`, target] as const,
),
];
const seen = new Set<RenderTargetLike>();
return candidates.flatMap(([id, target]) => {
if (target === undefined || seen.has(target)) return [];
seen.add(target);
return [
{
id,
width: Math.max(1, Math.floor(finiteOr(target.width, 1))),
height: Math.max(1, Math.floor(finiteOr(target.height, 1))),
bytesPerPixel: 4,
attachments: target.depthBuffer === false ? 1 : 2,
samples: Math.max(1, Math.floor(finiteOr(target.samples ?? 1, 1))),
},
];
});
}
function finiteOr(value: number, fallback: number): number {