From ef3c13d8c801d098858fb6af697e721f64f53c91 Mon Sep 17 00:00:00 2001 From: jessikitty Date: Mon, 24 Aug 2026 10:39:51 +1000 Subject: [PATCH] feat: cylinder occluders (shape/radiusCm/heightCm) for round props like the test rig post --- public/js/exhibit.js | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/public/js/exhibit.js b/public/js/exhibit.js index b8ab5a9..271f1c1 100644 --- a/public/js/exhibit.js +++ b/public/js/exhibit.js @@ -390,9 +390,21 @@ function buildOcclusion(scene) { occlusionGroup.clear(); const mat = new THREE.MeshBasicMaterial({ colorWrite: false }); // depth-only for (const b of scene.buildings || []) { - const geo = new THREE.BoxGeometry(b.size[0], b.size[1], b.size[2]); + /* Two occluder shapes. Boxes cover LEGO buildings; cylinders exist for round + * props (the test rig's 85mm post), where a box silhouette would wrongly + * hide ghosts at the corners. Positions are floor-level, so each mesh is + * lifted by half its height. */ + let geo, height; + if (b.shape === 'cylinder') { + const r = b.radiusCm ?? (b.size ? b.size[0] / 2 : 5); + height = b.heightCm ?? (b.size ? b.size[1] : 10); + geo = new THREE.CylinderGeometry(r, r, height, 24); + } else { + height = b.size[1]; + geo = new THREE.BoxGeometry(b.size[0], b.size[1], b.size[2]); + } const mesh = new THREE.Mesh(geo, mat); - mesh.position.set(b.position[0], b.position[1] + b.size[1] / 2, b.position[2]); + mesh.position.set(b.position[0], b.position[1] + height / 2, b.position[2]); mesh.rotation.y = THREE.MathUtils.degToRad(b.yawDeg || 0); mesh.renderOrder = -1; occlusionGroup.add(mesh);