music-video-gen/party-cathedral/src/scene/pews.js
2025-11-22 14:11:00 +01:00

103 lines
3.9 KiB
JavaScript

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 Pews extends SceneFeature {
constructor() {
super();
sceneFeatureManager.register(this);
}
init() {
// --- Dimensions from room-walls.js for positioning ---
const length = 40;
const naveWidth = 12;
const aisleWidth = 6;
// --- Pew Properties ---
const pewLength = aisleWidth - 2.5; // A bit shorter than the aisle is wide
const seatDepth = 0.5;
const seatHeight = 0.5;
const backHeight = 1.0;
const numPewsPerSide = 15;
const pewSpacing = (length - 10) / numPewsPerSide; // Leave space at the front and back
// --- Material ---
const woodTexture = state.loader.load(woodTextureUrl);
const woodMaterial = new THREE.MeshStandardMaterial({
map: woodTexture,
roughness: 0.8,
metalness: 0.1,
});
// --- Reusable Pew Model ---
const createPew = () => {
const pewGroup = new THREE.Group();
// Seat
const seatGeo = new THREE.BoxGeometry(pewLength, seatDepth, 0.1);
const seat = new THREE.Mesh(seatGeo, woodMaterial);
seat.rotation.x = Math.PI / 2;
seat.position.set(0, seatHeight, 0);
pewGroup.add(seat);
// Backrest
const backGeo = new THREE.BoxGeometry(pewLength, backHeight, 0.1);
const backrest = new THREE.Mesh(backGeo, woodMaterial);
backrest.position.set(0, seatHeight + backHeight / 2, -seatDepth / 2);
pewGroup.add(backrest);
// Side Supports
const supportHeight = seatHeight + backHeight;
const supportDepth = seatDepth + 0.1;
const supportGeo = new THREE.BoxGeometry(0.1, supportHeight, supportDepth);
const leftSupport = new THREE.Mesh(supportGeo, woodMaterial);
leftSupport.position.set(-pewLength / 2, supportHeight / 2, -supportDepth / 2 + 0.1);
const rightSupport = new THREE.Mesh(supportGeo, woodMaterial);
rightSupport.position.set(pewLength / 2, supportHeight / 2, -supportDepth / 2 + 0.1);
pewGroup.add(leftSupport, rightSupport);
// Add a simple "baked" shadow plane underneath
const shadowGeo = new THREE.PlaneGeometry(pewLength, supportDepth);
const shadowMaterial = new THREE.MeshBasicMaterial({
color: 0x000000,
transparent: true,
opacity: 0.3
});
const shadowMesh = new THREE.Mesh(shadowGeo, shadowMaterial);
shadowMesh.rotation.x = -Math.PI / 2;
shadowMesh.position.y = 0.01; // Place it just above the floor to prevent z-fighting
pewGroup.add(shadowMesh);
pewGroup.traverse(child => {
if (child.isMesh) {
child.castShadow = true;
child.receiveShadow = true;
}
});
return pewGroup;
};
// --- Place Pews in Aisles ---
for (let i = 0; i < numPewsPerSide; i++) {
const z = -length / 2 + 8 + (i * pewSpacing);
// Left Aisle
const pewLeft = createPew();
pewLeft.position.set(-naveWidth / 2 - aisleWidth / 2, 0, z);
pewLeft.rotation.y = Math.PI; // Turn around 180 degrees
state.scene.add(pewLeft);
// Right Aisle
const pewRight = createPew();
pewRight.position.set(naveWidth / 2 + aisleWidth / 2, 0, z);
pewRight.rotation.y = Math.PI; // Turn around 180 degrees
state.scene.add(pewRight);
}
}
}
new Pews();