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();