From a9791bbe5e1a85e6073fdd2d59d078e2032b7bfc Mon Sep 17 00:00:00 2001 From: Pierre-Eric Pelloux-Prayer Date: Wed, 27 Jun 2018 10:44:47 +0200 Subject: [PATCH] option_2 --- src/Core/MainLoop.js | 36 ++++++--- src/Process/3dTilesProcessing.js | 2 +- src/Process/PointCloudProcessing.js | 7 +- src/Provider/3dTilesProvider.js | 12 ++- src/Provider/PointCloudProvider.js | 11 +-- utils/debug/3dTilesDebug.js | 112 +++++++++++++++------------- 6 files changed, 105 insertions(+), 75 deletions(-) diff --git a/src/Core/MainLoop.js b/src/Core/MainLoop.js index 2ca0ec8378..d2a36a9bd3 100644 --- a/src/Core/MainLoop.js +++ b/src/Core/MainLoop.js @@ -68,17 +68,33 @@ function updateElements(context, geometryLayer, elements) { const sub = geometryLayer.getObjectToUpdateForAttachedLayers(element); if (sub) { - if (__DEBUG__) { - if (!(sub.element.isObject3D)) { - throw new Error(` - Invalid object for attached layer to update. - Must be a THREE.Object and have a THREE.Material`); + if (sub.element) { + if (__DEBUG__) { + if (!(sub.element.isObject3D)) { + throw new Error(` + Invalid object for attached layer to update. + Must be a THREE.Object and have a THREE.Material`); + } } - } - // update attached layers - for (const attachedLayer of geometryLayer._attachedLayers) { - if (attachedLayer.ready) { - attachedLayer.update(context, attachedLayer, sub.element, sub.parent); + // update attached layers + for (const attachedLayer of geometryLayer._attachedLayers) { + if (attachedLayer.ready) { + attachedLayer.update(context, attachedLayer, sub.element, sub.parent); + } + } + } else if (sub.elements) { + for (let i = 0; i < sub.elements.length; i++) { + if (!(sub.elements[i].isObject3D)) { + throw new Error(` + Invalid object for attached layer to update. + Must be a THREE.Object and have a THREE.Material`); + } + // update attached layers + for (const attachedLayer of geometryLayer._attachedLayers) { + if (attachedLayer.ready) { + attachedLayer.update(context, attachedLayer, sub.elements[i], sub.parent); + } + } } } } diff --git a/src/Process/3dTilesProcessing.js b/src/Process/3dTilesProcessing.js index 01231ea5cb..771bc72c47 100644 --- a/src/Process/3dTilesProcessing.js +++ b/src/Process/3dTilesProcessing.js @@ -306,7 +306,7 @@ export function process3dTilesNode(cullingTest, subdivisionTest) { // toggle wireframe if (node.content && node.content.visible) { node.content.traverse((o) => { - if (o.material) { + if (o.userData.layer == layer && o.material) { o.material.wireframe = layer.wireframe; } }); diff --git a/src/Process/PointCloudProcessing.js b/src/Process/PointCloudProcessing.js index 92d7183873..53df6562d1 100644 --- a/src/Process/PointCloudProcessing.js +++ b/src/Process/PointCloudProcessing.js @@ -206,7 +206,6 @@ export default { layer.group.add(elt.obj); elt.obj.updateMatrixWorld(true); - elt.obj.owner = elt; elt.promise = null; }, (err) => { if (err instanceof CancelledCommandException) { @@ -265,7 +264,7 @@ export default { // This format doesn't require points to be evenly distributed, so // we're going to sort the nodes by "importance" (= on screen size) // and display only the first N nodes - layer.group.children.sort((p1, p2) => p2.owner.sse - p1.owner.sse); + layer.group.children.sort((p1, p2) => p2.userData.metadata.sse - p1.userData.metadata.sse); let limitHit = false; layer.displayedCount = 0; @@ -284,7 +283,7 @@ export default { const now = Date.now(); for (let i = layer.group.children.length - 1; i >= 0; i--) { const obj = layer.group.children[i]; - if (!obj.material.visible && (now - obj.owner.notVisibleSince) > 10000) { + if (!obj.material.visible && (now - obj.userData.metadata.notVisibleSince) > 10000) { // remove from group layer.group.children.splice(i, 1); @@ -292,7 +291,7 @@ export default { obj.geometry.dispose(); obj.material = null; obj.geometry = null; - obj.owner.obj = null; + obj.userData.metadata.obj = null; if (__DEBUG__) { if (obj.boxHelper) { diff --git a/src/Provider/3dTilesProvider.js b/src/Provider/3dTilesProvider.js index d4a82b6541..841d6346f3 100644 --- a/src/Provider/3dTilesProvider.js +++ b/src/Provider/3dTilesProvider.js @@ -65,15 +65,21 @@ function preprocessDataLayer(layer, view, scheduler) { // override the default method, since updated objects are metadata in this case layer.getObjectToUpdateForAttachedLayers = (meta) => { if (meta.content) { + const result = []; + meta.content.traverse((obj) => { + if (obj.isObject3D && obj.material && obj.userData.layer == layer) { + result.push(obj); + } + }); const p = meta.parent; if (p && p.content) { return { - element: meta.content, + elements: result, parent: p.content, }; } else { return { - element: meta.content, + elements: result, }; } } @@ -182,6 +188,8 @@ function executeCommand(command) { const setLayer = (obj) => { obj.layers.set(layer.threejsLayer); + obj.userData.metadata = metadata; + obj.userData.layer = layer; }; if (path) { // Check if we have relative or absolute url (with tileset's lopocs for example) diff --git a/src/Provider/PointCloudProvider.js b/src/Provider/PointCloudProvider.js index 6f72da61ac..0a3275bb3a 100644 --- a/src/Provider/PointCloudProvider.js +++ b/src/Provider/PointCloudProvider.js @@ -250,30 +250,31 @@ export default { executeCommand(command) { const layer = command.layer; - const node = command.requester; + const metadata = command.requester; // Query HRC if we don't have children metadata yet. - if (node.childrenBitField && node.children.length === 0) { - parseOctree(layer, layer.metadata.hierarchyStepSize, node).then(() => command.view.notifyChange(layer, false)); + if (metadata.childrenBitField && metadata.children.length === 0) { + parseOctree(layer, layer.metadata.hierarchyStepSize, metadata).then(() => command.view.notifyChange(layer, false)); } // `isLeaf` is for lopocs and allows the pointcloud server to consider that the current // node is the last one, even if we could subdivide even further. // It's necessary because lopocs doens't know about the hierarchy (it generates it on the fly // when we request .hrc files) - const url = `${node.baseurl}/r${node.name}.${layer.extension}?isleaf=${command.isLeaf ? 1 : 0}`; + const url = `${metadata.baseurl}/r${metadata.name}.${layer.extension}?isleaf=${command.isLeaf ? 1 : 0}`; return Fetcher.arrayBuffer(url, layer.fetchOptions).then(layer.parse).then((geometry) => { const points = new THREE.Points(geometry, layer.material.clone()); addPickingAttribute(points); points.frustumCulled = false; points.matrixAutoUpdate = false; - points.position.copy(node.bbox.min); + points.position.copy(metadata.bbox.min); points.scale.set(layer.metadata.scale, layer.metadata.scale, layer.metadata.scale); points.updateMatrix(); points.tightbbox = geometry.boundingBox.applyMatrix4(points.matrix); points.layers.set(layer.threejsLayer); points.layer = layer; + points.userData.metadata = metadata; return points; }); }, diff --git a/utils/debug/3dTilesDebug.js b/utils/debug/3dTilesDebug.js index 7b92572690..7f4eefe8ce 100644 --- a/utils/debug/3dTilesDebug.js +++ b/utils/debug/3dTilesDebug.js @@ -3,14 +3,20 @@ import OBBHelper from './OBBHelper'; import View from '../../src/Core/View'; import GeometryDebug from './GeometryDebug'; -export default function create3dTilesDebugUI(datDebugTool, view, layer) { - const gui = GeometryDebug.createGeometryDebugUI(datDebugTool, view, layer); +const invMatrixChangeUpVectorZtoY = new THREE.Matrix4().getInverse(new THREE.Matrix4().makeRotationX(Math.PI / 2)); +const invMatrixChangeUpVectorZtoX = new THREE.Matrix4().getInverse(new THREE.Matrix4().makeRotationZ(-Math.PI / 2)); + +export default function create3dTilesDebugUI(datDebugTool, view, _3dTileslayer) { + const gui = GeometryDebug.createGeometryDebugUI(datDebugTool, view, _3dTileslayer); + + const regionBoundingBoxParent = new THREE.Group(); + view.scene.add(regionBoundingBoxParent); // add wireframe - GeometryDebug.addWireFrameCheckbox(gui, view, layer); + GeometryDebug.addWireFrameCheckbox(gui, view, _3dTileslayer); // Bounding box control - const obb_layer_id = `${layer.id}_obb_debug`; + const obb_layer_id = `${_3dTileslayer.id}_obb_debug`; const debugIdUpdate = function debugIdUpdate(context, layer, node) { const enabled = context.camera.camera3D.layers.test({ mask: 1 << layer.threejsLayer }); @@ -18,74 +24,74 @@ export default function create3dTilesDebugUI(datDebugTool, view, layer) { if (!enabled) { return; } - var obbChildren = node.children.filter(n => n.layer == layer); + const metadata = node.userData.metadata; + + let helper = node.userData.obb; - if (node.visible && node.boundingVolume) { - // 3dTiles case - let helper; - if (obbChildren.length == 0) { + if (node.visible && metadata.boundingVolume) { + if (!helper) { // 3dtiles with region - if (node.boundingVolume.region) { - helper = new OBBHelper(node.boundingVolume.region, `id:${node.id}`); - helper.position.copy(node.boundingVolume.region.position); - helper.rotation.copy(node.boundingVolume.region.rotation); - node.add(helper); - helper.layer = layer; - // add the ability to hide all the debug obj for one layer at once - const l = context.view.getLayers(l => l.id === obb_layer_id)[0]; - const l3js = l.threejsLayer; - helper.layers.set(l3js); - helper.children[0].layers.set(l3js); - helper.updateMatrixWorld(); + if (metadata.boundingVolume.region) { + helper = new OBBHelper(metadata.boundingVolume.region, `id:${node.id}`); + helper.position.copy(metadata.boundingVolume.region.position); + helper.rotation.copy(metadata.boundingVolume.region.rotation); + regionBoundingBoxParent.add(helper); } // 3dtiles with box - if (node.boundingVolume.box) { - const size = node.boundingVolume.box.getSize(); + if (metadata.boundingVolume.box) { + const size = metadata.boundingVolume.box.getSize(); const g = new THREE.BoxGeometry(size.x, size.y, size.z); const material = new THREE.MeshBasicMaterial({ wireframe: true }); helper = new THREE.Mesh(g, material); - node.boundingVolume.box.getCenter(helper.position); - node.add(helper); - helper.layer = layer; - // add the ability to hide all the debug obj for one layer at once - const l = context.view.getLayers(l => l.id === obb_layer_id)[0]; - const l3js = l.threejsLayer; - helper.layers.set(l3js); - helper.updateMatrixWorld(); + metadata.boundingVolume.box.getCenter(helper.position); } // 3dtiles with Sphere - if (node.boundingVolume.sphere) { - const geometry = new THREE.SphereGeometry(node.boundingVolume.sphere.radius, 32, 32); + if (metadata.boundingVolume.sphere) { + const geometry = new THREE.SphereGeometry(metadata.boundingVolume.sphere.radius, 32, 32); const material = new THREE.MeshBasicMaterial({ wireframe: true }); helper = new THREE.Mesh(geometry, material); - helper.position.copy(node.boundingVolume.sphere.center); - node.add(helper); - helper.layer = layer; + helper.position.copy(metadata.boundingVolume.sphere.center); + } + + if (helper) { + helper.userData.layer = layer; // add the ability to hide all the debug obj for one layer at once - const l = context.view.getLayers(l => l.id === obb_layer_id)[0]; - const l3js = l.threejsLayer; + const l3js = layer.threejsLayer; helper.layers.set(l3js); + if (helper.children.length) { + helper.children[0].layers.set(l3js); + } + node.userData.obb = helper; + helper.updateMatrixWorld(); + } + + if (helper && !metadata.boundingVolume.region) { + // compensate B3dm orientation correction + const gltfUpAxis = _3dTileslayer.asset.gltfUpAxis; + helper.updateMatrix(); + if (gltfUpAxis === undefined || gltfUpAxis === 'Y') { + helper.matrix.premultiply(invMatrixChangeUpVectorZtoY); + } else if (gltfUpAxis === 'X') { + helper.matrix.premultiply(invMatrixChangeUpVectorZtoX); + } + helper.applyMatrix(new THREE.Matrix4()); + + node.add(helper); helper.updateMatrixWorld(); } } else { - helper = obbChildren[0]; + helper = node.userData.obb; } if (helper) { helper.visible = true; - for (const child of node.children.filter(n => n.layer == layer)) { - if (typeof child.setMaterialVisibility === 'function') { - child.setMaterialVisibility(true); - } - child.visible = true; + if (typeof helper.setMaterialVisibility === 'function') { + helper.setMaterialVisibility(true); } } - } else { - // hide obb children - for (const child of node.children.filter(n => n.layer == layer)) { - if (typeof child.setMaterialVisibility === 'function') { - child.setMaterialVisibility(false); - } - child.visible = false; + } else if (helper) { + helper.visible = false; + if (typeof helper.setMaterialVisibility === 'function') { + helper.setMaterialVisibility(false); } } }; @@ -96,14 +102,14 @@ export default function create3dTilesDebugUI(datDebugTool, view, layer) { type: 'debug', update: debugIdUpdate, visible: false, - }, layer).then((l) => { + }, _3dTileslayer).then((l) => { gui.add(l, 'visible').name('Bounding boxes').onChange(() => { view.notifyChange(); }); }); // The sse Threshold for each tile - gui.add(layer, 'sseThreshold', 0, 100).name('sseThreshold').onChange(() => { + gui.add(_3dTileslayer, 'sseThreshold', 0, 100).name('sseThreshold').onChange(() => { view.notifyChange(); }); }