[claude] Dynamic shadow system from energy sources (#252) #342
35
app.js
35
app.js
@@ -53,13 +53,26 @@ const forwardVector = new THREE.Vector3();
|
||||
const ambientLight = new THREE.AmbientLight(0x0a1428, 1.4);
|
||||
scene.add(ambientLight);
|
||||
|
||||
const overheadLight = new THREE.PointLight(0x8899bb, 0.6, 60);
|
||||
// SpotLight replaces PointLight so shadows can be cast with a single depth map
|
||||
// (PointLights require 6 cube-face renders; SpotLights need only 1)
|
||||
const overheadLight = new THREE.SpotLight(0x8899bb, 0.6, 80, Math.PI / 3.5, 0.5, 1.0);
|
||||
overheadLight.position.set(0, 25, 0);
|
||||
overheadLight.target.position.set(0, 0, 0);
|
||||
overheadLight.castShadow = true;
|
||||
overheadLight.shadow.mapSize.set(2048, 2048);
|
||||
overheadLight.shadow.camera.near = 5;
|
||||
overheadLight.shadow.camera.far = 60;
|
||||
overheadLight.shadow.bias = -0.001;
|
||||
scene.add(overheadLight);
|
||||
scene.add(overheadLight.target);
|
||||
|
||||
const renderer = new THREE.WebGLRenderer({ antialias: true });
|
||||
renderer.setPixelRatio(window.devicePixelRatio);
|
||||
renderer.setSize(window.innerWidth, window.innerHeight);
|
||||
// === SHADOW SYSTEM ===
|
||||
// PCFSoftShadowMap provides smooth penumbra edges matching the holographic aesthetic.
|
||||
renderer.shadowMap.enabled = true;
|
||||
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
|
||||
document.body.appendChild(renderer.domElement);
|
||||
|
||||
// === STAR FIELD ===
|
||||
@@ -167,12 +180,16 @@ const platformFrameMat = new THREE.MeshStandardMaterial({
|
||||
const platformRimGeo = new THREE.RingGeometry(4.7, 5.3, 64);
|
||||
const platformRim = new THREE.Mesh(platformRimGeo, platformFrameMat);
|
||||
platformRim.rotation.x = -Math.PI / 2;
|
||||
platformRim.castShadow = true;
|
||||
platformRim.receiveShadow = true;
|
||||
glassPlatformGroup.add(platformRim);
|
||||
|
||||
// Raised border torus for visible 3-D thickness
|
||||
const borderTorusGeo = new THREE.TorusGeometry(5.0, 0.1, 6, 64);
|
||||
const borderTorus = new THREE.Mesh(borderTorusGeo, platformFrameMat);
|
||||
borderTorus.rotation.x = Math.PI / 2;
|
||||
borderTorus.castShadow = true;
|
||||
borderTorus.receiveShadow = true;
|
||||
glassPlatformGroup.add(borderTorus);
|
||||
|
||||
// Glass tile material — highly transmissive to reveal the void below
|
||||
@@ -339,12 +356,15 @@ const perlin = createPerlinNoise();
|
||||
metalness: 0.04,
|
||||
});
|
||||
const topMesh = new THREE.Mesh(geo, topMat);
|
||||
topMesh.castShadow = true;
|
||||
topMesh.receiveShadow = true;
|
||||
|
||||
// Underside — tapered cylinder giving the island its rocky underbelly
|
||||
const bottomGeo = new THREE.CylinderGeometry(ISLAND_RADIUS * 0.82, ISLAND_RADIUS * 0.35, 2.0, 64, 1);
|
||||
const bottomMat = new THREE.MeshStandardMaterial({ color: 0x0c0a08, roughness: 0.92, metalness: 0.03 });
|
||||
const bottomMesh = new THREE.Mesh(bottomGeo, bottomMat);
|
||||
bottomMesh.position.y = -1.0;
|
||||
bottomMesh.castShadow = true;
|
||||
|
||||
const islandGroup = new THREE.Group();
|
||||
islandGroup.add(topMesh);
|
||||
@@ -1998,7 +2018,13 @@ const tomeSpine = new THREE.Mesh(new THREE.BoxGeometry(0.06, 0.12, 1.4), tomeSpi
|
||||
tomeSpine.position.set(-0.52, 0, 0);
|
||||
tomeGroup.add(tomeSpine);
|
||||
|
||||
tomeGroup.traverse(o => { if (o.isMesh) o.userData.zoomLabel = 'The Oath'; });
|
||||
tomeGroup.traverse(o => {
|
||||
if (o.isMesh) {
|
||||
o.userData.zoomLabel = 'The Oath';
|
||||
o.castShadow = true;
|
||||
o.receiveShadow = true;
|
||||
}
|
||||
});
|
||||
scene.add(tomeGroup);
|
||||
|
||||
// Gentle glow beneath the tome
|
||||
@@ -2010,6 +2036,11 @@ scene.add(tomeGlow);
|
||||
const oathSpot = new THREE.SpotLight(0xffd700, 0, 40, Math.PI / 7, 0.4, 1.2);
|
||||
oathSpot.position.set(0, 22, 0);
|
||||
oathSpot.target.position.set(0, 0, 0);
|
||||
oathSpot.castShadow = true;
|
||||
oathSpot.shadow.mapSize.set(1024, 1024);
|
||||
oathSpot.shadow.camera.near = 1;
|
||||
oathSpot.shadow.camera.far = 50;
|
||||
oathSpot.shadow.bias = -0.002;
|
||||
scene.add(oathSpot);
|
||||
scene.add(oathSpot.target);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user