diff --git a/packages/viewer/src/modules/InteractionHandler.js b/packages/viewer/src/modules/InteractionHandler.js index 7f3390f79..f378c5bf8 100644 --- a/packages/viewer/src/modules/InteractionHandler.js +++ b/packages/viewer/src/modules/InteractionHandler.js @@ -10,7 +10,10 @@ export default class InteractionHandler { this.selectionHelper = new SelectionHelper( this.viewer, { sectionBox: this.sectionBox, hover: false } ) this.selectionMeshMaterial = new THREE.MeshLambertMaterial( { color: 0x0B55D2, emissive: 0x0B55D2, side: THREE.DoubleSide } ) this.selectionMeshMaterial.clippingPlanes = this.viewer.sectionBox.planes - // console.log(this.viewer.sceneManager.allObjects) + // Fix overlapping faces flickering + this.selectionMeshMaterial.polygonOffset = true + this.selectionMeshMaterial.polygonOffsetFactor = -0.1 + this.selectionLineMaterial = new THREE.LineBasicMaterial( { color: 0x0B55D2 } ) this.selectionLineMaterial.clippingPlanes = this.viewer.sectionBox.planes diff --git a/packages/viewer/src/modules/SceneObjectManager.js b/packages/viewer/src/modules/SceneObjectManager.js index 8742e2b3d..5856d4894 100644 --- a/packages/viewer/src/modules/SceneObjectManager.js +++ b/packages/viewer/src/modules/SceneObjectManager.js @@ -224,8 +224,12 @@ export default class SceneObjectManager { let group = new THREE.Group() wrapper.bufferGeometry.forEach( g => { + if ( wrapper.meta.renderMaterial && !g.meta.renderMaterial ) { + g.meta.renderMaterial = wrapper.meta.renderMaterial + } let res = this.addObject( g, false ) - group.add( res ) + if ( res ) + group.add( res ) } ) group.applyMatrix4( wrapper.extras.transformMatrix ) diff --git a/packages/viewer/src/modules/SceneObjects.js b/packages/viewer/src/modules/SceneObjects.js index 0fae0ab13..81284755e 100644 --- a/packages/viewer/src/modules/SceneObjects.js +++ b/packages/viewer/src/modules/SceneObjects.js @@ -53,7 +53,6 @@ export default class SceneObjects { async asyncPause() { // Don't freeze the UI when doing all those traversals if ( Date.now() - this.lastAsyncPause >= 100 ) { - // if (Date.now() - this.lastAsyncPause > 200 ) console.log("FREEZED for ", Date.now() - this.lastAsyncPause) await new Promise( resolve => setTimeout( resolve, 0 ) ) this.lastAsyncPause = Date.now() } @@ -143,7 +142,6 @@ export default class SceneObjects { child.geometry.dispose() } threejsGroup.clear() - // console.log( 'Dispose in: ', Date.now() - t0 ) } async applyFilter( filter ) { @@ -153,6 +151,7 @@ export default class SceneObjects { if ( filter === null ) { // Remove filters, use allObjects let newGoupedSolidObjects = await this.groupSolidObjects( this.allSolidObjects ) + if ( this.groupedSolidObjects !== null ) { this.disposeAndClearGroup( this.groupedSolidObjects ) this.allObjects.remove( this.groupedSolidObjects ) @@ -231,18 +230,31 @@ export default class SceneObjects { let materialIdToMaterial = {} let materialIdToMeshes = {} + let groupedObjects = new THREE.Group() + groupedObjects.name = 'GroupedSolidObjects' + for ( let obj of threejsGroup.children ) { let meshes = [] if( obj instanceof THREE.Group ) { meshes = this.flattenGroup( obj ) - } else { meshes = [ obj ] } for( let mesh of meshes ) { let m = mesh.material - let materialId = `${m.type}/${m.vertexColors}/${m.color.toJSON()}/${m.side}/${m.transparent}/${m.opactiy}/${m.emissive}/${m.metalness}/${m.roughness}` + + // Pass-through non mesh materials (blocks can contain lines, that end up here) + if ( !( m instanceof THREE.MeshStandardMaterial || m instanceof THREE.MeshBasicMaterial ) ) { + // if ( mesh.type === 'Line' ) continue + // if ( groupedObjects.children.length >= 2 ) continue + groupedObjects.add( mesh.clone() ) + continue + } + + let materialId = `${m.type}/${m.vertexColors}/${m.color.toJSON()}/${m.side}/${m.transparent}/${m.opactiy}/${m.emissive}/${m.metalness}/${m.roughness}/${m.wireframe}` + + materialId += `--${Object.keys( mesh.geometry.attributes ).toString()}--${!!mesh.geometry.index}` if ( !( materialId in materialIdToBufferGeometry ) ) { materialIdToBufferGeometry[ materialId ] = [] @@ -265,18 +277,14 @@ export default class SceneObjects { } } } - - - let groupedObjects = new THREE.Group() - groupedObjects.name = 'GroupedSolidObjects' await this.asyncPause() for ( let materialId in materialIdToBufferGeometry ) { await this.asyncPause() - // TODO: does this handle transforms well ? let groupGeometry = BufferGeometryUtils.mergeBufferGeometries( materialIdToBufferGeometry[ materialId ] ) await this.asyncPause() + let groupMaterial = materialIdToMaterial[ materialId ] let groupMesh = new THREE.Mesh( groupGeometry, groupMaterial ) groupMesh.userData = null diff --git a/packages/viewer/src/modules/SectionBox.js b/packages/viewer/src/modules/SectionBox.js index 7740431c4..71ef6d930 100644 --- a/packages/viewer/src/modules/SectionBox.js +++ b/packages/viewer/src/modules/SectionBox.js @@ -97,6 +97,7 @@ export default class SectionBox { this.display.add( this.controls ) this.controls.addEventListener( 'change', this._draggingChangeHandler.bind( this ) ) this.controls.addEventListener( 'dragging-changed', ( event ) => { + if ( !this.display.visible ) return let val = !!event.value if( val ) { this.dragging = val @@ -114,6 +115,7 @@ export default class SectionBox { } _draggingChangeHandler( ) { + if ( !this.display.visible ) return this.boxHelper.update() this._generateOrUpdatePlanes() diff --git a/packages/viewer/src/modules/SelectionHelper.js b/packages/viewer/src/modules/SelectionHelper.js index 463724629..cfdcdddea 100644 --- a/packages/viewer/src/modules/SelectionHelper.js +++ b/packages/viewer/src/modules/SelectionHelper.js @@ -18,6 +18,7 @@ export default class SelectionHelper extends EventEmitter { super() this.viewer = parent this.raycaster = new THREE.Raycaster() + this.raycaster.params.Line.threshold = 0.1 // optional param allows for raycasting against a subset of objects // this.subset = typeof _options !== 'undefined' && typeof _options.subset !== 'undefined' ? _options.subset : null; diff --git a/packages/viewer/src/modules/context/CameraHanlder.js b/packages/viewer/src/modules/context/CameraHanlder.js index 8b5752dd4..1aa08a92c 100644 --- a/packages/viewer/src/modules/context/CameraHanlder.js +++ b/packages/viewer/src/modules/context/CameraHanlder.js @@ -39,7 +39,7 @@ export default class CameraHandler { ] this.orbiting = false - this.controls.addEventListener( 'wake', () => { this.orbiting = true } ) + this.controls.addEventListener( 'transitionstart', () => { this.orbiting = true } ) // note: moved to new controls event called "rest" this.controls.addEventListener( 'controlend', () => { } ) this.controls.addEventListener( 'rest', () => { setTimeout( () => { this.orbiting = false }, 400 ) } ) diff --git a/packages/viewer/src/modules/converter/Converter.js b/packages/viewer/src/modules/converter/Converter.js index 2b58524e3..cca6a4c85 100644 --- a/packages/viewer/src/modules/converter/Converter.js +++ b/packages/viewer/src/modules/converter/Converter.js @@ -30,7 +30,6 @@ export default class Coverter { if ( Date.now() - this.lastAsyncPause >= 100 ) { this.lastAsyncPause = Date.now() await new Promise( resolve => setTimeout( resolve, 0 ) ) - // if ( Date.now() - this.lastAsyncPause > 200 ) console.log( 'CONV Event loop lag: ', Date.now() - this.lastAsyncPause ) } } @@ -42,7 +41,6 @@ export default class Coverter { * @return {[type]} [description] */ async traverseAndConvert( obj, callback, scale = true ) { - //console.log("Active promises: ", this.activePromises) await this.asyncPause() // Exit on primitives (string, ints, bools, bigints, etc.) @@ -89,8 +87,8 @@ export default class Coverter { displayValue = await this.resolveReference( displayValue ) if ( !displayValue.units ) displayValue.units = obj.units try { - let { bufferGeometry } = await this.convert( displayValue, scale ) - await callback( new ObjectWrapper( bufferGeometry, obj ) ) // use the parent's metadata! + let convertedElement = await this.convert( displayValue, scale ) + await callback( new ObjectWrapper( convertedElement.bufferGeometry, obj, convertedElement.geometryType ) ) // use the parent's metadata! } catch ( e ) { console.warn( `(Traversing) Failed to convert obj with id: ${obj.id} — ${e.message}` ) } @@ -98,20 +96,20 @@ export default class Coverter { for ( let element of displayValue ) { let val = await this.resolveReference( element ) if ( !val.units ) val.units = obj.units - let { bufferGeometry } = await this.convert( val, scale ) - await callback( new ObjectWrapper( bufferGeometry, { renderMaterial: val.renderMaterial, ...obj } ) ) + let convertedElement = await this.convert( val, scale ) + await callback( new ObjectWrapper( convertedElement.bufferGeometry, { renderMaterial: val.renderMaterial, ...obj }, convertedElement.geometryType ) ) } } - } - // If this is a built element and has a display value, only iterate through the "elements" prop if it exists. - if ( displayValue && obj.speckle_type.toLowerCase().includes( 'builtelements' ) ) { - if ( obj['elements'] ) { + // If this is a built element and has a display value, only iterate through the "elements" prop if it exists. + if ( obj.speckle_type.toLowerCase().includes( 'builtelements' ) && obj['elements'] ) { childrenConversionPromisses.push( this.traverseAndConvert( obj['elements'], callback, scale ) ) this.activePromises += childrenConversionPromisses.length await Promise.all( childrenConversionPromisses ) this.activePromises -= childrenConversionPromisses.length } + + // If the object has a display value, don't iterate all properties return } @@ -244,7 +242,6 @@ export default class Coverter { 'position', new THREE.Float32BufferAttribute( !scale || conversionFactor === 1 ? vertices : vertices.map( v => v * conversionFactor ), 3 ) ) - // TODO: checkout colours let colorsRaw = await this.dechunk( obj.colors ) if ( colorsRaw && colorsRaw.length !== 0 ) { @@ -296,8 +293,6 @@ export default class Coverter { } async MeshToBufferGeometry( obj, scale = true ) { - // await this.asyncPause() - try { if ( !obj ) return @@ -313,8 +308,8 @@ export default class Coverter { let k = 0 while ( k < faces.length ) { - let n = faces[ k ] - if ( n <= 3 ) n += 3 // 0 -> 3, 1 -> 4 + let n = faces[ k ] + if ( n <= 3 ) n += 3 // 0 -> 3, 1 -> 4 if ( n === 4 ) { // QUAD FACE indices.push( faces[ k + 1 ], faces[ k + 2 ], faces[ k + 3 ] ) @@ -328,8 +323,8 @@ export default class Coverter { //throw new Error( `Mesh type not supported. Face topology indicator: ${faces[k]}` ) } - k += n + 1 - } + k += n + 1 + } buffer.setIndex( indices ) buffer.setAttribute(