Feature: add postprocessing and tune it

This commit is contained in:
Dejvino 2025-11-22 14:41:09 +01:00
parent ed47fb9fdc
commit 87a524b013
8 changed files with 55 additions and 11 deletions

View File

@ -1,5 +1,6 @@
import * as THREE from 'three';
import { state } from '../state.js';
import { onResizePostprocessing } from './postprocessing.js';
import { updateScreenEffect } from '../scene/magic-mirror.js'
import sceneFeatureManager from '../scene/SceneFeatureManager.js';
@ -53,7 +54,11 @@ export function animate() {
updateScreenEffect();
// RENDER!
state.renderer.render(state.scene, state.camera);
if (state.composer) {
state.composer.render();
} else {
state.renderer.render(state.scene, state.camera);
}
}
// --- Window Resize Handler ---
@ -61,4 +66,5 @@ export function onWindowResize() {
state.camera.aspect = window.innerWidth / window.innerHeight;
state.camera.updateProjectionMatrix();
state.renderer.setSize(window.innerWidth, window.innerHeight);
onResizePostprocessing();
}

View File

@ -3,7 +3,7 @@ import { state, initState } from '../state.js';
import { EffectsManager } from '../effects/EffectsManager.js';
import { createSceneObjects } from '../scene/root.js';
import { animate, onWindowResize } from './animate.js';
import { loadVideoFile, playNextVideo } from './video-player.js';
import { initPostprocessing } from './postprocessing.js';
// --- Initialization ---
export function init() {
@ -36,7 +36,9 @@ export function init() {
// 9. Event Listeners
window.addEventListener('resize', onWindowResize, false);
initPostprocessing();
// Start the animation loop
animate();
}

View File

@ -0,0 +1,34 @@
import * as THREE from 'three';
import { state } from '../state.js';
import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer.js';
import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass.js';
import { OutputPass } from 'three/examples/jsm/postprocessing/OutputPass.js';
import { UnrealBloomPass } from 'three/addons/postprocessing/UnrealBloomPass.js';
export function initPostprocessing() {
const composer = new EffectComposer(state.renderer);
// 1. The first pass is always to render the scene itself.
const renderPass = new RenderPass(state.scene, state.camera);
composer.addPass(renderPass);
const resolution = new THREE.Vector2( window.innerWidth, window.innerHeight );
const bloomPass = new UnrealBloomPass( resolution, 0.9, 0.1, 0.6 );
composer.addPass( bloomPass );
// 3. Add an output pass to render the final result to the screen.
const outputPass = new OutputPass();
composer.addPass(outputPass);
// Store the composer and passes in the global state
state.composer = composer;
}
export function onResizePostprocessing() {
if (state.composer) {
state.composer.setSize(window.innerWidth, window.innerHeight);
}
if (state.ssaoPass) {
state.ssaoPass.setSize(window.innerWidth, window.innerHeight);
}
}

View File

@ -1,6 +1,5 @@
import * as THREE from 'three';
import { init } from './core/init.js';
import { StainedGlass } from './scene/stained-glass-window.js';
// Start everything
init();

View File

@ -17,14 +17,14 @@ export class LightBall extends SceneFeature {
init() {
// --- Ball Properties ---
const ballRadius = 0.4;
const ballRadius = 0.2;
const lightIntensity = 5.0;
const lightColors = [0xff0000, 0x00ff00, 0x0000ff, 0xffff00, 0x00ffff, 0xff00ff]; // Red, Green, Blue, Yellow
const lightColors = [0xff2222, 0x11ff11, 0x2222ff, 0xffff11, 0x00ffff, 0xff00ff]; // Red, Green, Blue, Yellow
lightColors.forEach(color => {
// --- Create the Ball ---
const ballGeometry = new THREE.SphereGeometry(ballRadius, 32, 32);
const ballMaterial = new THREE.MeshBasicMaterial({ color: color, emissive: color, emissiveIntensity: 1.0 });
const ballMaterial = new THREE.MeshBasicMaterial({ color: color, emissive: color, emissiveIntensity: 1.2 });
const ball = new THREE.Mesh(ballGeometry, ballMaterial);
ball.castShadow = false;
ball.receiveShadow = false;
@ -40,7 +40,7 @@ export class LightBall extends SceneFeature {
);
light.position.copy(ball.position);
state.scene.add(ball);
//state.scene.add(ball);
state.scene.add(light);
this.lightBalls.push({

View File

@ -42,7 +42,7 @@ export class MedievalMusicians extends SceneFeature {
// 3. Process the entire canvas to make background transparent
const imageData = context.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
const threshold = 20; // Adjust this for more/less color tolerance
const threshold = 25; // Adjust this for more/less color tolerance
for (let i = 0; i < data.length; i += 4) {
const r = data[i];
@ -85,8 +85,8 @@ export class MedievalMusicians extends SceneFeature {
// Get the pure texture color
vec4 texColor = texture2D(vibrancyMap, vMapUv);
// Mix the final lit color with the pure texture color to keep it vibrant
float vibrancy = 0.6; // 0.0 = full lighting, 1.0 = full texture color
gl_FragColor.rgb = mix(gl_FragColor.rgb, texColor.rgb, vibrancy);
float vibrancy = 0.3; // 0.0 = full lighting, 1.0 = full texture color
gl_FragColor.rgb = mix(gl_FragColor.rgb, texColor.rgb, vibrancy) + texColor.rgb * 0.2;
`
);
};

View File

@ -15,6 +15,7 @@ import { Dancers } from './dancers.js';
import { MusicVisualizer } from './music-visualizer.js';
import { RoseWindowLight } from './rose-window-light.js';
import { RoseWindowLightshafts } from './rose-window-lightshafts.js';
import { StainedGlass } from './stained-glass-window.js';
// Scene Features ^^^
// --- Scene Modeling Function ---

View File

@ -9,6 +9,8 @@ export function initState() {
camera: null,
renderer: null,
clock: new THREE.Clock(),
composer: null,
ssaoPass: null,
tvScreen: null,
tvScreenPowered: false,
videoTexture: null,