Feature: medieval musicians
This commit is contained in:
parent
a5548d8044
commit
47e11a497c
@ -13,12 +13,12 @@ function updateCamera() {
|
|||||||
// Base Camera Position in front of the TV
|
// Base Camera Position in front of the TV
|
||||||
const baseX = 0;
|
const baseX = 0;
|
||||||
const baseY = 1.6;
|
const baseY = 1.6;
|
||||||
const baseZ = 10.0;
|
const baseZ = -10.0;
|
||||||
|
|
||||||
// Base LookAt target (Center of the screen)
|
// Base LookAt target (Center of the screen)
|
||||||
const baseTargetX = 0;
|
const baseTargetX = 0;
|
||||||
const baseTargetY = 1.6;
|
const baseTargetY = 1.6;
|
||||||
const baseTargetZ = -10.0;
|
const baseTargetZ = -30.0;
|
||||||
|
|
||||||
// Camera Position Offsets (Drift)
|
// Camera Position Offsets (Drift)
|
||||||
const camOffsetX = Math.sin(globalTime * 3.1) * camAmplitude;
|
const camOffsetX = Math.sin(globalTime * 3.1) * camAmplitude;
|
||||||
|
|||||||
@ -1 +1,101 @@
|
|||||||
// This file will contain the Three.js code for creating and animating the medieval musicians on the stage.
|
import * as THREE from 'three';
|
||||||
|
import { state } from '../state.js';
|
||||||
|
import { SceneFeature } from './SceneFeature.js';
|
||||||
|
import sceneFeatureManager from './SceneFeatureManager.js';
|
||||||
|
import musiciansTextureUrl from '/textures/musician1.png';
|
||||||
|
|
||||||
|
export class MedievalMusicians extends SceneFeature {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.musicians = [];
|
||||||
|
sceneFeatureManager.register(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
init() {
|
||||||
|
// --- Stage dimensions for positioning ---
|
||||||
|
const stageHeight = 1.5;
|
||||||
|
const stageDepth = 5;
|
||||||
|
const length = 40;
|
||||||
|
|
||||||
|
// --- Billboard Properties ---
|
||||||
|
const musicianHeight = 2.5;
|
||||||
|
const musicianWidth = 2.5;
|
||||||
|
|
||||||
|
// Load the texture and create the material inside the callback
|
||||||
|
state.loader.load(musiciansTextureUrl, (texture) => {
|
||||||
|
// 1. Draw texture to canvas to process it
|
||||||
|
const image = texture.image;
|
||||||
|
const canvas = document.createElement('canvas');
|
||||||
|
canvas.width = image.width;
|
||||||
|
canvas.height = image.height;
|
||||||
|
const context = canvas.getContext('2d');
|
||||||
|
context.drawImage(image, 0, 0);
|
||||||
|
|
||||||
|
// 2. Get the key color from the top-left pixel
|
||||||
|
const keyPixelData = context.getImageData(0, 0, 1, 1).data;
|
||||||
|
const keyColor = { r: keyPixelData[0], g: keyPixelData[1], b: keyPixelData[2] };
|
||||||
|
|
||||||
|
// 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
|
||||||
|
|
||||||
|
for (let i = 0; i < data.length; i += 4) {
|
||||||
|
const r = data[i];
|
||||||
|
const g = data[i + 1];
|
||||||
|
const b = data[i + 2];
|
||||||
|
|
||||||
|
const distance = Math.sqrt(Math.pow(r - keyColor.r, 2) + Math.pow(g - keyColor.g, 2) + Math.pow(b - keyColor.b, 2));
|
||||||
|
|
||||||
|
if (distance < threshold) {
|
||||||
|
data[i + 3] = 0; // Set alpha to 0 (transparent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
context.putImageData(imageData, 0, 0);
|
||||||
|
|
||||||
|
// 4. Create a new texture from the modified canvas
|
||||||
|
const processedTexture = new THREE.CanvasTexture(canvas);
|
||||||
|
|
||||||
|
// 5. Create a standard material with the new texture
|
||||||
|
const material = new THREE.MeshStandardMaterial({
|
||||||
|
map: processedTexture,
|
||||||
|
side: THREE.DoubleSide,
|
||||||
|
transparent: true,
|
||||||
|
roughness: 0.7,
|
||||||
|
metalness: 0.1,
|
||||||
|
});
|
||||||
|
|
||||||
|
// 6. Create and position the musicians
|
||||||
|
const geometry = new THREE.PlaneGeometry(musicianWidth, musicianHeight);
|
||||||
|
|
||||||
|
const musicianPositions = [
|
||||||
|
new THREE.Vector3(-2, stageHeight + musicianHeight / 2, -length / 2 + stageDepth / 2 - 1),
|
||||||
|
new THREE.Vector3(0, stageHeight + musicianHeight / 2, -length / 2 + stageDepth / 2 - 1.5),
|
||||||
|
new THREE.Vector3(2.5, stageHeight + musicianHeight / 2, -length / 2 + stageDepth / 2 - 1.2),
|
||||||
|
];
|
||||||
|
|
||||||
|
musicianPositions.forEach(pos => {
|
||||||
|
const musician = new THREE.Mesh(geometry, material);
|
||||||
|
musician.position.copy(pos);
|
||||||
|
|
||||||
|
state.scene.add(musician);
|
||||||
|
this.musicians.push(musician);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
update(deltaTime) {
|
||||||
|
// Billboard effect: make each musician face the camera
|
||||||
|
if (this.musicians.length > 0) {
|
||||||
|
const cameraPosition = new THREE.Vector3();
|
||||||
|
state.camera.getWorldPosition(cameraPosition);
|
||||||
|
|
||||||
|
this.musicians.forEach(musician => {
|
||||||
|
// We only want to rotate on the Y axis to keep them upright
|
||||||
|
musician.lookAt(cameraPosition.x, musician.position.y, cameraPosition.z);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
new MedievalMusicians();
|
||||||
@ -6,6 +6,8 @@ import sceneFeatureManager from './SceneFeatureManager.js';
|
|||||||
import { RoomWalls } from './room-walls.js';
|
import { RoomWalls } from './room-walls.js';
|
||||||
import { LightBall } from './light-ball.js';
|
import { LightBall } from './light-ball.js';
|
||||||
import { Pews } from './pews.js';
|
import { Pews } from './pews.js';
|
||||||
|
import { Stage } from './stage.js';
|
||||||
|
import { MedievalMusicians } from './medieval-musicians.js';
|
||||||
// Scene Features ^^^
|
// Scene Features ^^^
|
||||||
|
|
||||||
// --- Scene Modeling Function ---
|
// --- Scene Modeling Function ---
|
||||||
|
|||||||
@ -1 +1,44 @@
|
|||||||
// This file will contain the Three.js code for creating the stage at the front of the cathedral.
|
import * as THREE from 'three';
|
||||||
|
import { state } from '../state.js';
|
||||||
|
import { SceneFeature } from './SceneFeature.js';
|
||||||
|
import sceneFeatureManager from './SceneFeatureManager.js';
|
||||||
|
import woodTextureUrl from '/textures/wood.png';
|
||||||
|
|
||||||
|
export class Stage extends SceneFeature {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
sceneFeatureManager.register(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
init() {
|
||||||
|
// --- Dimensions from room-walls.js for positioning ---
|
||||||
|
const length = 40;
|
||||||
|
const naveWidth = 12;
|
||||||
|
|
||||||
|
// --- Stage Properties ---
|
||||||
|
const stageWidth = naveWidth - 1; // Slightly narrower than the nave
|
||||||
|
const stageHeight = 1.5;
|
||||||
|
const stageDepth = 5;
|
||||||
|
|
||||||
|
// --- Material ---
|
||||||
|
const woodTexture = state.loader.load(woodTextureUrl);
|
||||||
|
woodTexture.wrapS = THREE.RepeatWrapping;
|
||||||
|
woodTexture.wrapT = THREE.RepeatWrapping;
|
||||||
|
woodTexture.repeat.set(stageWidth / 2, stageDepth / 2);
|
||||||
|
const woodMaterial = new THREE.MeshStandardMaterial({
|
||||||
|
map: woodTexture,
|
||||||
|
roughness: 0.8,
|
||||||
|
metalness: 0.1,
|
||||||
|
});
|
||||||
|
|
||||||
|
// --- Create Stage Mesh ---
|
||||||
|
const stageGeo = new THREE.BoxGeometry(stageWidth, stageHeight, stageDepth);
|
||||||
|
const stageMesh = new THREE.Mesh(stageGeo, woodMaterial);
|
||||||
|
stageMesh.castShadow = true;
|
||||||
|
stageMesh.receiveShadow = true;
|
||||||
|
stageMesh.position.set(0, stageHeight / 2, -length / 2 + stageDepth / 2);
|
||||||
|
state.scene.add(stageMesh);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
new Stage();
|
||||||
BIN
party-cathedral/textures/musician1.png
Normal file
BIN
party-cathedral/textures/musician1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 866 KiB |
Loading…
Reference in New Issue
Block a user