diff --git a/src/fragments/FragmentIfcStreamer/index.html b/src/fragments/FragmentIfcStreamer/index.html index 8ec22f515..53c1600df 100644 --- a/src/fragments/FragmentIfcStreamer/index.html +++ b/src/fragments/FragmentIfcStreamer/index.html @@ -134,7 +134,6 @@ loader.url = "http://dev.api.thatopen.com/storage?fileId="; let fragments = new OBC.FragmentManager(components); - loader.culler.threshold = 20; async function loadModel(geometryURL, propertiesURL) { const rawGeometryData = await fetch(geometryURL); @@ -147,14 +146,25 @@ await loader.load(geometryData, true, propertiesData); } + loader.culler.useLowLod = true; + await loadModel( "../../../resources/small.ifc-processed.json", // "../../../resources/small.ifc-processed-properties.json" ); + + scene.add(loader.culler.lowLod.get(0).mesh); + + // const cam = components.camera.get(); + // cam.far = 20000; + // cam.updateProjectionMatrix(); + + + // loader.culler.threshold = 20; loader.culler.bboxThreshold = 500; - // loader.culler.maxHiddenTime = 1000; - // loader.culler.maxLostTime = 40000; + loader.culler.maxHiddenTime = 1000; + loader.culler.maxLostTime = 40000; components.camera.controls.addEventListener("controlend", () => { loader.culler.needsUpdate = true; @@ -450,12 +460,12 @@ // } // ); - // loader.culler.renderDebugFrame = true; - // const debugFrame = loader.culler.get().domElement; - // document.body.appendChild(debugFrame); - // debugFrame.style.position = 'fixed'; - // debugFrame.style.left = '0'; - // debugFrame.style.bottom = '0'; + loader.culler.renderDebugFrame = true; + const debugFrame = loader.culler.get().domElement; + document.body.appendChild(debugFrame); + debugFrame.style.position = 'fixed'; + debugFrame.style.left = '0'; + debugFrame.style.bottom = '0'; // Set up stats diff --git a/src/fragments/FragmentIfcStreamer/src/geometry-culler-renderer.ts b/src/fragments/FragmentIfcStreamer/src/geometry-culler-renderer.ts index c1a3e2eec..ee37871ba 100644 --- a/src/fragments/FragmentIfcStreamer/src/geometry-culler-renderer.ts +++ b/src/fragments/FragmentIfcStreamer/src/geometry-culler-renderer.ts @@ -32,6 +32,10 @@ export class GeometryCullerRenderer extends CullerRenderer { boxes = new Map(); + useLowLod = false; + + lowLod = new Map(); + private _geometry: THREE.BufferGeometry; private _material = new THREE.MeshBasicMaterial({ @@ -40,6 +44,8 @@ export class GeometryCullerRenderer extends CullerRenderer { opacity: 1, }); + private _lodMaterial = new THREE.MeshLambertMaterial(); + readonly onViewUpdated = new Event<{ toLoad: { [modelID: string]: Map> }; toRemove: { [modelID: string]: Set }; @@ -129,16 +135,27 @@ export class GeometryCullerRenderer extends CullerRenderer { this.boxes.set(modelIndex, bboxes); this.scene.add(bboxes.mesh); + if (this.useLowLod) { + const lowLod = new FRAGS.Fragment(this._geometry, this._lodMaterial, 10); + this.lowLod.set(modelIndex, lowLod); + } + const fragmentsGroup = new THREE.Group(); this.scene.add(fragmentsGroup); this._geometriesGroups.set(modelIndex, fragmentsGroup); - const items = new Map(); + const items = new Map< + number, + FRAGS.Item & { geometryColors: THREE.Color[] } + >(); for (const asset of assets) { // if (asset.id !== 664833) continue; for (const geometryData of asset.geometries) { - const { geometryID, transformation } = geometryData; + const { geometryID, transformation, color } = geometryData; + + const geometryColor = new THREE.Color(); + geometryColor.setRGB(color[0], color[1], color[2], "srgb"); const instanceID = this.getInstanceID(asset.id, geometryID); @@ -187,12 +204,14 @@ export class GeometryCullerRenderer extends CullerRenderer { throw new Error("Malformed item!"); } item.colors.push(threeColor); + item.geometryColors.push(geometryColor); item.transforms.push(instanceMatrix); } else { // This geometry exists only once in this asset (for now) items.set(instanceID, { id: instanceID, colors: [threeColor], + geometryColors: [geometryColor], transforms: [instanceMatrix], }); } @@ -217,6 +236,14 @@ export class GeometryCullerRenderer extends CullerRenderer { const itemsArray = Array.from(items.values()); bboxes.add(itemsArray); + if (this.useLowLod) { + for (const item of itemsArray) { + item.colors = item.geometryColors; + } + const lowLod = this.lowLod.get(modelIndex) as FRAGS.Fragment; + lowLod.add(itemsArray); + } + THREE.ColorManagement.enabled = colorEnabled; // const { geometry, material, count, instanceMatrix, instanceColor } = [ @@ -411,6 +438,9 @@ export class GeometryCullerRenderer extends CullerRenderer { const now = performance.now(); let viewWasUpdated = false; + const lodsToShow = new Set(); + const lodsToHide = new Set(); + let bboxAmount = 0; for (const [color, number] of colors) { if (number < this.threshold) { @@ -454,6 +484,9 @@ export class GeometryCullerRenderer extends CullerRenderer { toShow[modelID].add(geometry.geometryID); this._foundGeometries.add(color); viewWasUpdated = true; + if (this.useLowLod) { + lodsToHide.add(geometry); + } } else if (isFound && !exists) { // New geometry found if (!toLoad[modelID]) { @@ -469,12 +502,19 @@ export class GeometryCullerRenderer extends CullerRenderer { set.add(geometry.geometryID); this._foundGeometries.add(color); viewWasUpdated = true; + + if (this.useLowLod) { + lodsToHide.add(geometry); + } } else if (!isFound && exists) { // Geometry is hardly seen, so it can be considered lost if (bboxAmount < this.bboxThreshold) { // When too many bounding boxes on sight // don't hide / destroy geometry to prevent flickering this.handleLostGeometries(now, color, geometry, toRemove, toHide); + if (this.useLowLod) { + lodsToShow.add(geometry); + } viewWasUpdated = true; } } @@ -489,6 +529,9 @@ export class GeometryCullerRenderer extends CullerRenderer { throw new Error("Geometry not found!"); } this.handleLostGeometries(now, color, geometry, toRemove, toHide); + if (this.useLowLod) { + lodsToShow.add(geometry); + } viewWasUpdated = true; } } @@ -497,6 +540,15 @@ export class GeometryCullerRenderer extends CullerRenderer { await this.onViewUpdated.trigger({ toLoad, toRemove, toHide, toShow }); } + if (this.useLowLod) { + for (const geometry of lodsToShow) { + this.setLodVisibility(true, geometry); + } + for (const geometry of lodsToHide) { + this.setLodVisibility(false, geometry); + } + } + if (bboxAmount > this.bboxThreshold) { this.needsUpdate = true; } @@ -530,6 +582,14 @@ export class GeometryCullerRenderer extends CullerRenderer { } } + private setLodVisibility(visible: boolean, geometry: CullerBoundingBox) { + const lod = this.lowLod.get(geometry.modelIndex) as FRAGS.Fragment; + for (const assetID of geometry.assetIDs) { + const instanceID = this.getInstanceID(assetID, geometry.geometryID); + lod.setVisibility(visible, [instanceID]); + } + } + private createModelIndex(modelID: string) { if (this._modelIDIndex.has(modelID)) { throw new Error("Can't load the same model twice!"); diff --git a/src/navigation/EdgesClipper/index.html b/src/navigation/EdgesClipper/index.html index 164379eca..a3edfad44 100644 --- a/src/navigation/EdgesClipper/index.html +++ b/src/navigation/EdgesClipper/index.html @@ -120,6 +120,8 @@ scene.add(cube2); components.meshes.add(cube2); + + /*MD :::info Storing Components