← back to Dw War Room
src/showroom/ShowroomEnvironment.ts
94 lines
// ShowroomEnvironment.ts — HDR environment map for photorealistic IBL
import * as THREE from 'three';
/**
* Generate a high-quality procedural environment map for gallery/showroom IBL.
* Creates a warm gallery interior environment rather than the cold command-center gradient.
*
* This procedural approach avoids needing an external HDRI file download.
* It simulates a well-lit interior with warm ceiling lights and neutral walls.
*/
export function createShowroomEnvMap(renderer: THREE.WebGLRenderer): THREE.Texture {
const pmrem = new THREE.PMREMGenerator(renderer);
pmrem.compileEquirectangularShader();
const envScene = new THREE.Scene();
// Sky dome — warm dark interior
const skyGeo = new THREE.SphereGeometry(50, 32, 16);
const skyMat = new THREE.MeshBasicMaterial({
color: 0x1a1815,
side: THREE.BackSide,
});
envScene.add(new THREE.Mesh(skyGeo, skyMat));
// Ceiling highlight — warm white overhead panels (gallery lighting ~3200K)
const ceilGeo = new THREE.SphereGeometry(40, 16, 8, 0, Math.PI * 2, 0, Math.PI * 0.2);
const ceilMat = new THREE.MeshBasicMaterial({
color: 0xf5e6d0,
side: THREE.BackSide,
});
const ceil = new THREE.Mesh(ceilGeo, ceilMat);
ceil.rotation.x = Math.PI;
envScene.add(ceil);
// Floor reflection — dark polished concrete
const floorGeo = new THREE.SphereGeometry(40, 16, 8, 0, Math.PI * 2, Math.PI * 0.75, Math.PI * 0.25);
const floorMat = new THREE.MeshBasicMaterial({
color: 0x0d0c0a,
side: THREE.BackSide,
});
envScene.add(new THREE.Mesh(floorGeo, floorMat));
// Wall bands — warm brick tones from 4 sides
const wallMaterials: THREE.MeshBasicMaterial[] = [];
for (let i = 0; i < 4; i++) {
const wallGeo = new THREE.PlaneGeometry(30, 15);
const wallMat = new THREE.MeshBasicMaterial({
color: 0x3a2820,
side: THREE.DoubleSide,
});
wallMaterials.push(wallMat);
const wall = new THREE.Mesh(wallGeo, wallMat);
const angle = (i / 4) * Math.PI * 2;
wall.position.set(Math.cos(angle) * 35, 5, Math.sin(angle) * 35);
wall.lookAt(0, 5, 0);
envScene.add(wall);
}
// Track light spots — bright warm points at ceiling level
const spotMaterials: THREE.MeshBasicMaterial[] = [];
for (let i = 0; i < 6; i++) {
const spotGeo = new THREE.SphereGeometry(2, 8, 8);
const spotMat = new THREE.MeshBasicMaterial({ color: 0xffe8c0 });
spotMaterials.push(spotMat);
const spot = new THREE.Mesh(spotGeo, spotMat);
const angle = (i / 6) * Math.PI * 2;
spot.position.set(Math.cos(angle) * 15, 18, Math.sin(angle) * 15);
envScene.add(spot);
}
const envRenderTarget = pmrem.fromScene(envScene as any, 0.02);
const texture = envRenderTarget.texture;
// Cleanup — dispose PMREM render target, generator, and all env scene materials/geometries
pmrem.dispose();
envRenderTarget.dispose();
skyGeo.dispose();
skyMat.dispose();
ceilGeo.dispose();
ceilMat.dispose();
floorGeo.dispose();
floorMat.dispose();
wallMaterials.forEach(m => m.dispose());
spotMaterials.forEach(m => m.dispose());
// Dispose wall and spot geometries via traversal
envScene.traverse(child => {
if (child instanceof THREE.Mesh && child.geometry) {
child.geometry.dispose();
}
});
return texture;
}