Feature: more colored windows

This commit is contained in:
Dejvino 2025-11-21 22:41:16 +01:00
parent 2811fdbbd8
commit ea813c88be

View File

@ -17,6 +17,7 @@ export class StainedGlass extends SceneFeature {
const aisleWidth = 6; const aisleWidth = 6;
const totalWidth = naveWidth + 2 * aisleWidth; const totalWidth = naveWidth + 2 * aisleWidth;
const aisleHeight = 8; const aisleHeight = 8;
const naveHeight = 15;
// --- Window Properties --- // --- Window Properties ---
const windowWidth = 3; const windowWidth = 3;
@ -35,30 +36,52 @@ export class StainedGlass extends SceneFeature {
emissive: 0x000000, // We will control emissiveness via update emissive: 0x000000, // We will control emissiveness via update
}); });
const colorPalette = [
new THREE.Color(0x6A0DAD), // Purple
new THREE.Color(0x00008B), // Dark Blue
new THREE.Color(0xB22222), // Firebrick Red
new THREE.Color(0xFFD700), // Gold
new THREE.Color(0x006400), // Dark Green
new THREE.Color(0x8B0000), // Dark Red
new THREE.Color(0x4B0082), // Indigo
];
// --- Procedural Geometry Generation --- // --- Procedural Geometry Generation ---
const createProceduralWindowGeometry = () => { const createProceduralWindowGeometry = (mainColor) => {
const secondColor = new THREE.Color((Math.random()), (Math.random()), (Math.random()));
const segmentsX = 8; const segmentsX = 8;
const segmentsY = 12; const segmentsY = 12;
const vertices = []; const vertices = [];
const colors = []; const colors = [];
const normals = []; const normals = [];
const colorPalette = [
new THREE.Color(0x6A0DAD), // Purple
new THREE.Color(0x00008B), // Dark Blue
new THREE.Color(0xB22222), // Firebrick Red
new THREE.Color(0xFFD700), // Gold
new THREE.Color(0x006400), // Dark Green
new THREE.Color(0x8B0000), // Dark Red
new THREE.Color(0x4B0082), // Indigo
];
const randomnessFactor = 0.4; // How much to vary the normals const randomnessFactor = 0.4; // How much to vary the normals
const addTriangle = (v1, v2, v3) => { const addTriangle = (v1, v2, v3, isBorder = false) => {
const color = colorPalette[Math.floor(Math.random() * colorPalette.length)]; let segmentColor;
const rand = Math.random();
if (rand < 0.05) { // 5% chance for a "lead line"
segmentColor = secondColor.clone();
} else if (isBorder && rand < 0.6) { // 60% chance for border segments to be the main color
segmentColor = mainColor.clone().offsetHSL(0, 0, -0.1); // Slightly darker border
} else if (isBorder) { // Remaining chance for border to be an accent
segmentColor = colorPalette[Math.floor(Math.random() * colorPalette.length)].clone().offsetHSL(0, 0, -0.1);
}
else { // Inner panels
if (rand < 0.65) { // 65% chance (after lead lines) to be a variation of the main color
segmentColor = mainColor.clone();
// Slightly shift hue, saturation, and lightness
segmentColor.offsetHSL((Math.random() - 0.5) * 0.2, (Math.random() - 0.5) * 0.2, (Math.random() - 0.5) * 0.4);
} else if (rand < 0.8) {
segmentColor = secondColor.clone().offsetHSL((Math.random() - 0.5) * 0.2, (Math.random() - 0.5) * 0.2, (Math.random() - 0.5) * 0.4);
} else { // Remaining chance for a random accent color
segmentColor = new THREE.Color((Math.random()), (Math.random()), (Math.random()));
}
}
vertices.push(v1.x, v1.y, v1.z, v2.x, v2.y, v2.z, v3.x, v3.y, v3.z); vertices.push(v1.x, v1.y, v1.z, v2.x, v2.y, v2.z, v3.x, v3.y, v3.z);
colors.push(color.r, color.g, color.b, color.r, color.g, color.b, color.r, color.g, color.b); colors.push(segmentColor.r, segmentColor.g, segmentColor.b, segmentColor.r, segmentColor.g, segmentColor.b, segmentColor.r, segmentColor.g, segmentColor.b);
// Calculate the base normal for the flat triangle face // Calculate the base normal for the flat triangle face
const edge1 = new THREE.Vector3().subVectors(v2, v1); const edge1 = new THREE.Vector3().subVectors(v2, v1);
@ -85,8 +108,9 @@ export class StainedGlass extends SceneFeature {
const v2 = new THREE.Vector3(x2, y, 0); const v2 = new THREE.Vector3(x2, y, 0);
const v3 = new THREE.Vector3(x, y2, 0); const v3 = new THREE.Vector3(x, y2, 0);
const v4 = new THREE.Vector3(x2, y2, 0); const v4 = new THREE.Vector3(x2, y2, 0);
addTriangle(v1, v2, v3); const isBorder = i === 0 || i === segmentsX - 1 || j === 0;
addTriangle(v2, v4, v3); addTriangle(v1, v2, v3, isBorder);
addTriangle(v2, v4, v3, isBorder);
} }
} }
@ -98,7 +122,7 @@ export class StainedGlass extends SceneFeature {
const v1 = archCenter; const v1 = archCenter;
const v2 = new THREE.Vector3(Math.cos(angle1) * -windowWidth / 2, Math.sin(angle1) * windowArchHeight + windowBaseHeight, 0); const v2 = new THREE.Vector3(Math.cos(angle1) * -windowWidth / 2, Math.sin(angle1) * windowArchHeight + windowBaseHeight, 0);
const v3 = new THREE.Vector3(Math.cos(angle2) * -windowWidth / 2, Math.sin(angle2) * windowArchHeight + windowBaseHeight, 0); const v3 = new THREE.Vector3(Math.cos(angle2) * -windowWidth / 2, Math.sin(angle2) * windowArchHeight + windowBaseHeight, 0);
addTriangle(v1, v2, v3); addTriangle(v1, v2, v3, true); // Treat all arch segments as part of the border
} }
const geometry = new THREE.BufferGeometry(); const geometry = new THREE.BufferGeometry();
@ -110,7 +134,9 @@ export class StainedGlass extends SceneFeature {
// --- Create and Place Windows --- // --- Create and Place Windows ---
const createAndPlaceWindow = (position, rotationY) => { const createAndPlaceWindow = (position, rotationY) => {
const geometry = createProceduralWindowGeometry(); // Generate unique geometry for each window // Pick a main color for this entire window
const mainColor = colorPalette[Math.floor(Math.random() * colorPalette.length)];
const geometry = createProceduralWindowGeometry(mainColor); // Generate unique geometry for each window
const windowMesh = new THREE.Mesh(geometry, material); const windowMesh = new THREE.Mesh(geometry, material);
windowMesh.position.copy(position); windowMesh.position.copy(position);
windowMesh.rotation.y = rotationY; windowMesh.rotation.y = rotationY;
@ -127,6 +153,17 @@ export class StainedGlass extends SceneFeature {
// Right side // Right side
createAndPlaceWindow(new THREE.Vector3(totalWidth / 2 - 0.01, y, z), -Math.PI / 2); createAndPlaceWindow(new THREE.Vector3(totalWidth / 2 - 0.01, y, z), -Math.PI / 2);
} }
// --- Add Windows to the Nave/Clerestory Walls ---
for (let i = 0; i < numWindowsPerSide * 2; i++) {
const z = -length / 2 + windowSpacing / 2 * (i + 0.5);
const y = aisleHeight + (naveHeight - aisleHeight - (windowBaseHeight + windowArchHeight)) / 2; // Center them vertically in the clerestory
// Left side of Nave
createAndPlaceWindow(new THREE.Vector3(-naveWidth / 2 + 0.01, y, z), Math.PI / 2);
// Right side of Nave
createAndPlaceWindow(new THREE.Vector3(naveWidth / 2 - 0.01, y, z), -Math.PI / 2);
}
} }
update(deltaTime) { update(deltaTime) {