@@ -104,6 +104,12 @@ export class ViewerEngine {
104104 /** Whether isolation mode is active. */
105105 private _isolated = false ;
106106
107+ /** Saved material state for isolation restore. */
108+ private savedMaterials = new Map <
109+ THREE . Material ,
110+ { opacity : number ; transparent : boolean ; depthWrite : boolean }
111+ > ( ) ;
112+
107113 /** Active section planes. */
108114 private sectionPlanes : THREE . Plane [ ] = [ ] ;
109115
@@ -484,49 +490,83 @@ export class ViewerEngine {
484490 }
485491
486492 /**
487- * Isolate an element: ghost everything at fragment level ,
488- * then restore the selected element to full opacity with accent color .
493+ * Isolate an element: ghost everything transparent ,
494+ * then highlight the selected element with an opaque overlay .
489495 *
490- * Uses FragmentsModel.setOpacity() for per-element control (works correctly
491- * even when elements share meshes in batched IFC geometry).
496+ * Material-level opacity + depthWrite:false ghosts all geometry.
497+ * Fragment-level highlight renders the selected element on top
498+ * (visible because ghosted materials no longer write to depth buffer).
492499 */
493500 async isolateElement ( globalId : string ) : Promise < void > {
494- if ( ! this . world || ! this . fragments ) return ;
501+ if ( ! this . world ) return ;
495502
496503 // Restore any previous isolation first
497- await this . clearIsolation ( ) ;
498-
499- // Get the selected element's model ID map
500- const selectedMap = await this . fragments . guidsToModelIdMap ( [ globalId ] ) ;
501-
502- // Ghost all elements, then restore + colorize the selected one
503- for ( const [ modelId , model ] of this . fragments . list ) {
504- // Ghost ALL items in this model at fragment level
505- await model . setOpacity ( undefined , GHOST_OPACITY ) ;
506-
507- // If this model contains the selected element, restore it
508- const selectedIds = selectedMap [ modelId ] ;
509- if ( selectedIds && selectedIds . size > 0 ) {
510- const ids = [ ...selectedIds ] ;
511- await model . resetOpacity ( ids ) ;
512- await model . setColor ( ids , new THREE . Color ( "#44B6A8" ) ) ; // Verdigris accent
504+ this . restoreMaterials ( ) ;
505+ await this . clearHighlights ( ) ;
506+
507+ // Ghost ALL meshes: transparent + no depth write so highlight shows through
508+ for ( const obj of this . modelObjects . values ( ) ) {
509+ obj . traverse ( ( child ) => {
510+ if ( ! ( child instanceof THREE . Mesh ) ) return ;
511+ const materials = Array . isArray ( child . material )
512+ ? child . material
513+ : [ child . material ] ;
514+ for ( const mat of materials ) {
515+ if ( ! mat || this . savedMaterials . has ( mat ) ) continue ;
516+ this . savedMaterials . set ( mat , {
517+ opacity : mat . opacity ,
518+ transparent : mat . transparent ,
519+ depthWrite : mat . depthWrite ,
520+ } ) ;
521+ mat . transparent = true ;
522+ mat . opacity = GHOST_OPACITY ;
523+ mat . depthWrite = false ;
524+ mat . needsUpdate = true ;
525+ }
526+ } ) ;
527+ }
528+
529+ // Highlight selected element with opaque overlay
530+ if ( this . fragments ) {
531+ try {
532+ const modelIdMap = await this . fragments . guidsToModelIdMap ( [ globalId ] ) ;
533+ if ( Object . keys ( modelIdMap ) . length > 0 ) {
534+ const style : FRAGS . MaterialDefinition = {
535+ color : new THREE . Color ( "#44B6A8" ) ,
536+ renderedFaces : FRAGS . RenderedFaces . TWO ,
537+ opacity : 1.0 ,
538+ transparent : false ,
539+ } ;
540+ await this . fragments . highlight ( style , modelIdMap ) ;
541+ }
542+ } catch {
543+ // Highlight failed — ghost-only mode still works
513544 }
514545 }
515546
516547 this . _isolated = true ;
517548 }
518549
519550 /**
520- * Clear isolation: reset all fragment opacities and colors .
551+ * Restore all materials to their original state .
521552 */
522- async clearIsolation ( ) : Promise < void > {
523- if ( ! this . _isolated || ! this . fragments ) return ;
524-
525- for ( const [ , model ] of this . fragments . list ) {
526- await model . resetOpacity ( undefined ) ;
527- await model . resetColor ( undefined ) ;
553+ private restoreMaterials ( ) : void {
554+ for ( const [ mat , saved ] of this . savedMaterials ) {
555+ mat . opacity = saved . opacity ;
556+ mat . transparent = saved . transparent ;
557+ mat . depthWrite = saved . depthWrite ;
558+ mat . needsUpdate = true ;
528559 }
560+ this . savedMaterials . clear ( ) ;
561+ }
529562
563+ /**
564+ * Clear isolation: restore all materials and remove highlight overlay.
565+ */
566+ async clearIsolation ( ) : Promise < void > {
567+ if ( ! this . _isolated ) return ;
568+ this . restoreMaterials ( ) ;
569+ await this . clearHighlights ( ) ;
530570 this . _isolated = false ;
531571 }
532572
0 commit comments