fix(viewer): keep ceiling-hosted items visible in dollhouse
Items mounted on a ceiling (lamps, fans, recessed lights) are child nodes of the ceiling, so hiding the whole occluder node hid them too. Hide only the ceiling/roof's own meshes (stop descending at nested identity nodes) so hosted items stay visible when a floor is opened up. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
5aedc366a6
commit
0e55d86416
@@ -387,6 +387,26 @@ export function GlbScene({
|
|||||||
}, [gltf.scene])
|
}, [gltf.scene])
|
||||||
const zoneById = useMemo(() => new Map(zoneEntries.map((zone) => [zone.id, zone])), [zoneEntries])
|
const zoneById = useMemo(() => new Map(zoneEntries.map((zone) => [zone.id, zone])), [zoneEntries])
|
||||||
|
|
||||||
|
// The dollhouse hides ceilings/roof — but only their OWN geometry. Items hosted
|
||||||
|
// on a ceiling (lamps, fans, recessed lights) are child identity nodes; hiding
|
||||||
|
// the whole occluder node would hide them too, so collect just the occluder's
|
||||||
|
// own meshes (stop descending at any nested identity node) and toggle those.
|
||||||
|
const occluderOwnMeshes = useMemo(() => {
|
||||||
|
const meshes: THREE.Mesh[] = []
|
||||||
|
const walk = (node: THREE.Object3D) => {
|
||||||
|
for (const child of node.children) {
|
||||||
|
if ((child.userData as PascalExtras).pascalId) continue // hosted item — keep visible
|
||||||
|
if ((child as THREE.Mesh).isMesh) meshes.push(child as THREE.Mesh)
|
||||||
|
walk(child)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const occluder of occluders) {
|
||||||
|
if ((occluder as THREE.Mesh).isMesh) meshes.push(occluder as THREE.Mesh)
|
||||||
|
walk(occluder)
|
||||||
|
}
|
||||||
|
return meshes
|
||||||
|
}, [occluders])
|
||||||
|
|
||||||
// Move the camera to match the drill depth: a saved bookmark (extras.camera)
|
// Move the camera to match the drill depth: a saved bookmark (extras.camera)
|
||||||
// wins; otherwise fit to the target's bounds (the object, the room's polygon
|
// wins; otherwise fit to the target's bounds (the object, the room's polygon
|
||||||
// footprint for empty zone nodes, the level, or the whole building). Mirrors
|
// footprint for empty zone nodes, the level, or the whole building). Mirrors
|
||||||
@@ -726,7 +746,7 @@ export function GlbScene({
|
|||||||
// focused level actually has rooms. Focusing a zone-less floor keeps the
|
// focused level actually has rooms. Focusing a zone-less floor keeps the
|
||||||
// building intact (otherwise its roof would just vanish with nothing to show).
|
// building intact (otherwise its roof would just vanish with nothing to show).
|
||||||
const revealing = !walk && selection.levelId != null && levelsWithZones.has(selection.levelId)
|
const revealing = !walk && selection.levelId != null && levelsWithZones.has(selection.levelId)
|
||||||
for (const occluder of occluders) occluder.visible = !revealing
|
for (const mesh of occluderOwnMeshes) mesh.visible = !revealing
|
||||||
|
|
||||||
for (const { id, levelId, meshes, uniforms } of zoneFills.current) {
|
for (const { id, levelId, meshes, uniforms } of zoneFills.current) {
|
||||||
const show =
|
const show =
|
||||||
@@ -938,9 +958,9 @@ export function GlbScene({
|
|||||||
outliner.hoveredObjects.length = 0
|
outliner.hoveredObjects.length = 0
|
||||||
document.body.style.cursor = 'auto'
|
document.body.style.cursor = 'auto'
|
||||||
// Restore ceilings/roof — the GLB scene is cached by drei and may be reused.
|
// Restore ceilings/roof — the GLB scene is cached by drei and may be reused.
|
||||||
for (const occluder of occluders) occluder.visible = true
|
for (const mesh of occluderOwnMeshes) mesh.visible = true
|
||||||
},
|
},
|
||||||
[occluders],
|
[occluderOwnMeshes],
|
||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
Reference in New Issue
Block a user