music-video-gen/party-cathedral/src/scene/room-walls.js

157 lines
7.0 KiB
JavaScript

import * as THREE from 'three';
import { state } from '../state.js';
import wallTextureUrl from '/textures/stone_wall.png';
import sceneFeatureManager from './SceneFeatureManager.js';
import { SceneFeature } from './SceneFeature.js';
const length = 40;
export class RoomWalls extends SceneFeature {
constructor() {
super();
sceneFeatureManager.register(this);
}
init() {
const naveWidth = 12;
const aisleWidth = 6;
const totalWidth = naveWidth + 2 * aisleWidth;
const aisleHeight = 8;
const naveHeight = 15;
const roofPeakHeight = 6; // Additional height for the nave's vaulted roof peak
// --- Pillar and Arch Dimensions ---
const pillarSize = 1.0;
const pillarHeight = aisleHeight;
const numPillars = 5; // Number of pillars along each side
const pillarSpacing = length / (numPillars + 1);
// --- Materials and Textures ---
const wallTexture = state.loader.load(wallTextureUrl);
wallTexture.wrapS = THREE.RepeatWrapping;
wallTexture.wrapT = THREE.RepeatWrapping;
const wallMaterial = new THREE.MeshStandardMaterial({
map: wallTexture,
side: THREE.DoubleSide,
shininess: 5,
roughness: 0.2,
metalness: 0.1,
specular: 0x111111
});
// --- Geometry Definitions ---
const pillarGeo = new THREE.CylinderGeometry(pillarSize / 2, pillarSize / 2, pillarHeight, 24);
// --- Object Creation Functions ---
const createMesh = (geometry, material, position, rotation = new THREE.Euler()) => {
const mesh = new THREE.Mesh(geometry, material);
mesh.position.copy(position);
mesh.rotation.copy(rotation);
mesh.castShadow = true;
mesh.receiveShadow = true;
state.scene.add(mesh);
return mesh;
};
// --- Build the Cathedral ---
// 1. Back Wall
const backWallGeo = new THREE.PlaneGeometry(totalWidth, aisleHeight);
const backWallMat = wallMaterial.clone();
backWallMat.map = wallTexture.clone();
backWallMat.map.repeat.set(totalWidth / 4, aisleHeight / 4);
createMesh(backWallGeo, backWallMat, new THREE.Vector3(0, aisleHeight / 2, -length / 2));
// 2. Outer Aisle Walls
const outerWallGeo = new THREE.PlaneGeometry(length, aisleHeight);
const outerWallMat = wallMaterial.clone();
outerWallMat.map = wallTexture.clone();
outerWallMat.map.repeat.set(length / 4, aisleHeight / 4);
createMesh(outerWallGeo, outerWallMat, new THREE.Vector3(-totalWidth / 2, aisleHeight / 2, 0), new THREE.Euler(0, Math.PI / 2, 0));
createMesh(outerWallGeo, outerWallMat, new THREE.Vector3(totalWidth / 2, aisleHeight / 2, 0), new THREE.Euler(0, -Math.PI / 2, 0));
// 3. Aisle Roofs (Flat)
const aisleRoofGeo = new THREE.PlaneGeometry(aisleWidth, length);
const aisleRoofMat = wallMaterial.clone();
aisleRoofMat.map = wallTexture.clone();
aisleRoofMat.map.repeat.set(aisleWidth / 4, length / 4);
createMesh(aisleRoofGeo, aisleRoofMat, new THREE.Vector3(-naveWidth / 2 - aisleWidth / 2, aisleHeight, 0), new THREE.Euler(-Math.PI / 2, 0, 0));
createMesh(aisleRoofGeo, aisleRoofMat, new THREE.Vector3(naveWidth / 2 + aisleWidth / 2, aisleHeight, 0), new THREE.Euler(-Math.PI / 2, 0, 0));
// 4. Pillars and Arcades
const arcadeWallHeight = aisleHeight - pillarHeight;
const arcadeWallGeo = new THREE.PlaneGeometry(pillarSpacing - pillarSize, arcadeWallHeight);
const arcadeWallMat = wallMaterial.clone();
arcadeWallMat.map = wallTexture.clone();
arcadeWallMat.map.repeat.set((pillarSpacing - pillarSize) / 4, arcadeWallHeight / 4);
for (let i = 0; i <= numPillars; i++) {
const z = -length / 2 + pillarSpacing * (i + 0.5);
// Add wall sections between pillars
if (i <= numPillars) {
createMesh(arcadeWallGeo, arcadeWallMat, new THREE.Vector3(-naveWidth / 2 , pillarHeight + arcadeWallHeight / 2, z));
createMesh(arcadeWallGeo, arcadeWallMat, new THREE.Vector3(naveWidth / 2, pillarHeight + arcadeWallHeight / 2, z));
}
const pillarZ = -length / 2 + pillarSpacing * (i + 1) - pillarSize / 2;
// Left side pillars
createMesh(pillarGeo, wallMaterial, new THREE.Vector3(-naveWidth / 2 - pillarSize, pillarHeight / 2, pillarZ));
// Right side pillars
createMesh(pillarGeo, wallMaterial, new THREE.Vector3(naveWidth / 2 + pillarSize, pillarHeight / 2, pillarZ));
}
// 5. Clerestory (Upper Nave Walls)
const clerestoryHeight = naveHeight - aisleHeight;
const clerestoryGeo = new THREE.PlaneGeometry(length, clerestoryHeight);
const clerestoryMat = wallMaterial.clone();
clerestoryMat.map = wallTexture.clone();
clerestoryMat.map.repeat.set(length / 4, clerestoryHeight / 4);
// Left and Right Clerestory walls
createMesh(clerestoryGeo, clerestoryMat, new THREE.Vector3(-naveWidth / 2, aisleHeight + clerestoryHeight / 2, 0), new THREE.Euler(0, - Math.PI / 2, 0));
createMesh(clerestoryGeo, clerestoryMat, new THREE.Vector3(naveWidth / 2, aisleHeight + clerestoryHeight / 2, 0), new THREE.Euler(0, Math.PI/2, 0));
// Upper part of the back wall (for the nave)
const backClerestoryGeo = new THREE.PlaneGeometry(naveWidth, clerestoryHeight);
const backClerestoryMat = wallMaterial.clone();
backClerestoryMat.map = wallTexture.clone();
backClerestoryMat.map.repeat.set(naveWidth / 4, clerestoryHeight / 4);
createMesh(backClerestoryGeo, backClerestoryMat, new THREE.Vector3(0, aisleHeight + clerestoryHeight / 2, -length / 2));
// 6. Nave's Vaulted Roof
const roofPanelWidth = Math.sqrt(Math.pow(naveWidth / 2, 2) + Math.pow(roofPeakHeight, 2));
const roofAngle = Math.atan2(roofPeakHeight, naveWidth / 2);
const roofGeo = new THREE.PlaneGeometry(roofPanelWidth, length); // Swapped width and length
const roofMat = wallMaterial.clone();
roofMat.map = wallTexture.clone();
roofMat.map.repeat.set(roofPanelWidth / 4, length / 4);
// Left and Right roof panels
createMesh(roofGeo, roofMat,
new THREE.Vector3(-naveWidth / 4, naveHeight + roofPeakHeight / 2, 0),
new THREE.Euler(Math.PI / 2, roofAngle, 0) // Flipped the roof right side up
);
createMesh(roofGeo, roofMat,
new THREE.Vector3(naveWidth / 4, naveHeight + roofPeakHeight / 2, 0),
new THREE.Euler(Math.PI / 2, -roofAngle, 0) // Flipped the roof right side up
);
// 7. Back gable wall (triangle part)
const gableShape = new THREE.Shape();
gableShape.moveTo(-naveWidth / 2, naveHeight);
gableShape.lineTo(naveWidth / 2, naveHeight);
gableShape.lineTo(0, naveHeight + roofPeakHeight);
const gableGeo = new THREE.ShapeGeometry(gableShape);
const gableMat = wallMaterial.clone();
gableMat.map = wallTexture.clone();
gableMat.map.repeat.set(naveWidth / 8, roofPeakHeight / 8);
createMesh(gableGeo, gableMat, new THREE.Vector3(0, 0, -length / 2));
// Note: crawlSurfaces and landingSurfaces might need to be updated if spiders/rats are used.
}
update(deltaTime) {
// Add any per-frame update logic here, if needed
}
}
new RoomWalls();