Browse Source

3dtiles 改进 暂时都显示tiles

xzw 2 years ago
parent
commit
01c71c318a

+ 116 - 28
libs/three.js/3dtiles/three-loader-3dtiles.esm.js

@@ -30,7 +30,20 @@ const maxTexVisi = 500
 
 
 
-
+function getGpuMemoryUsage(win = window){//总的
+    let c = 0
+    viewer.objs.children.filter(e=>{
+        if(e.fileType == '3dTiles'){
+            let tileset3D = e.runtime.getTileset()
+            c += tileset3D.gpuMemoryUsageInBytes
+        }
+    })
+    
+    if(win.parent != win){//还有父级页面。 暂时只有子级需要考虑父级,假设父级在前台时子级已经销毁
+        c += getGpuMemoryUsage(win.parent)
+    } 
+    return  c
+}
 
 
 function __awaiter(thisArg, _arguments, P, generator) {
@@ -7511,11 +7524,18 @@ class TilesetCache {
     const sentinel = this._sentinel;
     let node = list.head;
 
-    while (node !== sentinel && (tileset.gpuMemoryUsageInBytes > maximumMemoryUsageInBytes || trimTiles)) {
+   /*  while (node !== sentinel && (tileset.gpuMemoryUsageInBytes > maximumMemoryUsageInBytes || trimTiles)) {
+      const tile = node.item;
+      node = node.next;
+      this.unloadTile(tileset, tile, unloadCallback);
+    } */
+    //改
+    while (node !== sentinel && ( getGpuMemoryUsage() > maximumMemoryUsageInBytes || trimTiles)) {
       const tile = node.item;
       node = node.next;
       this.unloadTile(tileset, tile, unloadCallback);
     }
+    
   }
 
   trim() {
@@ -7779,7 +7799,7 @@ class OrientedBoundingBox {
       return INTERSECTION.INSIDE;
     }
 
-    return INTERSECTION.INTERSECTING;
+    return INTERSECTION.INTERSECTING; //在相机frustum内
   }
 
   distanceTo(point) {
@@ -8277,11 +8297,15 @@ function update(frustum) {
 
   if (frustum.fov !== frustum._fov || frustum.aspectRatio !== frustum._aspectRatio || frustum.near !== frustum._near || frustum.far !== frustum._far || frustum.xOffset !== frustum._xOffset || frustum.yOffset !== frustum._yOffset) {
     assert$4(frustum.fov >= 0 && frustum.fov < Math.PI);
-    assert$4(frustum.aspectRatio > 0);
+    //assert$4(frustum.aspectRatio > 0);
+    if(frustum.aspectRatio == 0){
+        console.log(1)
+    }
+    
     assert$4(frustum.near >= 0 && frustum.near < frustum.far);
-    frustum._aspectRatio = frustum.aspectRatio;
+    frustum._aspectRatio = Math.max(0.001, frustum.aspectRatio);
     frustum._fov = frustum.fov;
-    frustum._fovy = frustum.aspectRatio <= 1 ? frustum.fov : Math.atan(Math.tan(frustum.fov * 0.5) / frustum.aspectRatio) * 2.0;
+    frustum._fovy = frustum._aspectRatio <= 1 ? frustum.fov : Math.atan(Math.tan(frustum.fov * 0.5) / frustum._aspectRatio) * 2.0;
     frustum._near = frustum.near;
     frustum._far = frustum.far;
     frustum._sseDenominator = 2.0 * Math.tan(0.5 * frustum._fovy);
@@ -8289,7 +8313,7 @@ function update(frustum) {
     frustum._yOffset = frustum.yOffset;
     f.top = frustum.near * Math.tan(0.5 * frustum._fovy);
     f.bottom = -f.top;
-    f.right = frustum.aspectRatio * f.top;
+    f.right = frustum._aspectRatio * f.top;
     f.left = -f.right;
     f.near = frustum.near;
     f.far = frustum.far;
@@ -9159,6 +9183,11 @@ class TileHeader {
 
     _defineProperty(this, "_initialTransform", void 0);
 
+    _defineProperty(this, "tilesetMatrix", void 0);//add
+
+
+
+
     this.header = header;
     this.tileset = tileset;
     this.id = extendedId || header.id;
@@ -9233,7 +9262,9 @@ class TileHeader {
   }
 
   get isVisibleAndInRequestVolume() {
-    return this._visible && this._inRequestVolume;
+    let v =  /* this._visible &&  */this.tileset.visible && this._inRequestVolume; //用_updateBoundingVolume这个算的在相机靠近时不准确,容易缺块
+    if(window.tileVisi2)v = this._visible && v
+    return v 
   }
 
   get hasRenderContent() {
@@ -9304,7 +9335,11 @@ class TileHeader {
     const useParentScreenSpaceError = parent && (!maySkipTile || this._screenSpaceError === 0.0 || parent.hasTilesetContent);
     const screenSpaceError = useParentScreenSpaceError ? parent._screenSpaceError : this._screenSpaceError;
     const rootScreenSpaceError = traverser.root ? traverser.root._screenSpaceError : 0.0;
-    return Math.max(rootScreenSpaceError - screenSpaceError, 0);
+    let v = Math.max(rootScreenSpaceError - screenSpaceError, 0);
+    if(!this._visible){
+        v = THREE.Math.clamp(v * 0.1,  -0.9, 100);//xzw add  因为this._visible我也令其显示所以这里降低这些的优先级
+    }
+    return v
   }
 
   async loadContent() {
@@ -9393,7 +9428,7 @@ class TileHeader {
     const parentVisibilityPlaneMask = parent ? parent._visibilityPlaneMask : CullingVolume.MASK_INDETERMINATE;
 
     if (this.tileset._traverser.options.updateTransforms) {
-      const parentTransform = parent ? parent.computedTransform : this.tileset.modelMatrix;
+      const parentTransform = parent ? parent.computedTransform : new Matrix4().elements    //this.tileset.modelMatrix;  改:去掉左乘modelMatrix
 
       this._updateTransform(parentTransform);
     }
@@ -9471,10 +9506,10 @@ class TileHeader {
   }
 
   _initializeTransforms(tileHeader) {
-    this.transform = tileHeader.transform ? new Matrix4(tileHeader.transform) : new Matrix4();
+    this.transform = tileHeader.transform ? new Matrix4(tileHeader.transform) : new Matrix4(); 
     const parent = this.parent;
     const tileset = this.tileset;
-    const parentTransform = parent && parent.computedTransform ? parent.computedTransform.clone() : tileset.modelMatrix.clone();
+    const parentTransform = parent && parent.computedTransform ? parent.computedTransform.clone() :  new Matrix4().elements // tileset.modelMatrix.clone();  改:去掉左乘modelMatrix
     this.computedTransform = new Matrix4(parentTransform).multiplyRight(this.transform);
     const parentInitialTransform = parent && parent._initialTransform ? parent._initialTransform.clone() : new Matrix4();
     this._initialTransform = new Matrix4(parentInitialTransform).multiplyRight(this.transform);
@@ -9543,32 +9578,38 @@ class TileHeader {
   }
 
   _updateBoundingVolume(header) {
-    this.boundingVolume = createBoundingVolume(header.boundingVolume, this.computedTransform, this.boundingVolume);
+      
+    let computedTransform = new Matrix4(this.tileset.modelMatrix).multiplyRight(this.computedTransform);  //add
+    //console.log('_updateBoundingVolume computedTransform', this.tileset.modelMatrix, computedTransform)  
+      
+    this.boundingVolume = createBoundingVolume(header.boundingVolume, computedTransform/* this.computedTransform */, this.boundingVolume);
     const content = header.content;
 
     if (!content) {
       return;
     }
-
+     
     if (content.boundingVolume) {
-      this._contentBoundingVolume = createBoundingVolume(content.boundingVolume, this.computedTransform, this._contentBoundingVolume);
+      this._contentBoundingVolume = createBoundingVolume(content.boundingVolume, computedTransform, this._contentBoundingVolume);
     }
 
     if (header.viewerRequestVolume) {
-      this._viewerRequestVolume = createBoundingVolume(header.viewerRequestVolume, this.computedTransform, this._viewerRequestVolume);
+      this._viewerRequestVolume = createBoundingVolume(header.viewerRequestVolume, computedTransform, this._viewerRequestVolume);
     }
   }
 
   _updateTransform(parentTransform = new Matrix4()) {
     const computedTransform = parentTransform.clone().multiplyRight(this.transform);
-    const didTransformChange = !computedTransform.equals(this.computedTransform);
+    const didTransformChange = !computedTransform.equals(this.computedTransform) || !this.tilesetMatrix || !this.tilesetMatrix.equals(this.tileset.modelMatrix) //改 后面加了两个判断,为了在模型移动后更新_updateBoundingVolume
 
     if (!didTransformChange) {
       return;
-    }
-
+    } 
+    this.tileset.modelMatrix
     this.computedTransform = computedTransform;
-
+    
+    this.tilesetMatrix = this.tileset.modelMatrix;  //add 标记
+    
     this._updateBoundingVolume(this.header);
   }
 
@@ -9887,6 +9928,10 @@ class Tileset3D extends EventDispatcher{//xzw add EventDispatcher
     _defineProperty(this, "frameStateData", void 0);
 
     _defineProperty(this, "maximumMemoryUsage", void 0);
+    
+    
+    _defineProperty(this, "visible", true);//add
+    
 
     assert$7(json);
     this.options = { ...DEFAULT_PROPS,
@@ -17499,6 +17544,7 @@ class Loader3DTiles {
                     threeMat.premultiply(lastRootTransform);
                     threeMat.copy(lastRootTransform).multiply(new Matrix4$1().copy(tileTrasnform).invert());
                     tileset.modelMatrix = new Matrix4(threeMat.toArray());
+                    //console.log('update tileset ModelMatrix', tileset.modelMatrix.elements)
                 }
             }
             // 更新瓦片显隐和瓦片迭代更新                                  
@@ -17516,6 +17562,7 @@ class Loader3DTiles {
                     });
                     sseDenominator = loadersFrustum.sseDenominator;
                     lastCameraAspect = camera.aspect;
+                    if(camera.aspect == 0)return//add
                     if (options.debug) {
                         console.log('Updated sse denonimator:', sseDenominator);
                     }
@@ -17557,7 +17604,7 @@ class Loader3DTiles {
                                     visiVertexCount += renderMap[tile.id].vertexCount  //xzw add
                                     options.debug && (boxMap[tile.id].material.opacity = 1)
                                 }else{
-                                    console.log('超出', visiVertexCount)
+                                    //console.log('超出', visiVertexCount)
                                 }
                             }   
                             /* if(!renderMap[tile.id].realVisible()){
@@ -17682,11 +17729,11 @@ class Loader3DTiles {
                             model.add(mesh);
                         return model;
                     },
-                    update: function (dt, renderer, camera) {
+                    update: function (dt, renderer, camera, ifForce) {
                         cameraReference = camera;
-                        rendererReference = renderer;
+                        rendererReference = renderer; 
                         timer += dt;
-                        if (tileset && timer >= UPDATE_INTERVAL) {
+                        if (tileset && (timer >= UPDATE_INTERVAL || ifForce)) {
                             if (!lastRootTransform.equals(root.matrixWorld)) {
                                 timer = 0;
                                 lastRootTransform.copy(root.matrixWorld);
@@ -17715,7 +17762,7 @@ class Loader3DTiles {
                             else {
                                 const cameraChanged = !camera.matrixWorld.equals(this.lastCameraTransform) ||
                                     !(camera.aspect == lastCameraAspect);
-                                if (cameraChanged) {
+                                if (cameraChanged || ifForce) {
                                     timer = 0;
                                     tileset._frameNumber++;
                                     camera.getWorldPosition(lastCameraPosition);
@@ -17762,9 +17809,13 @@ function createGLTFNodes(gltfLoader, tile, unlitMaterial, options, rootTransform
             const rotateX = new Matrix4$1().makeRotationAxis(new Vector3$1(1, 0, 0), Math.PI / 2);
             const shouldRotate = ((_a = tile.tileset.asset) === null || _a === void 0 ? void 0 : _a.gltfUpAxis) !== "Z";
             // The computed trasnform already contains the root's transform, so we have to invert it
-            const contentTransform = new Matrix4$1().fromArray(tile.computedTransform).premultiply(rootTransformInverse); //xzw 删。原先的会造成移动后tiles错乱
+            //const contentTransform = new Matrix4$1().fromArray(tile.computedTransform).premultiply(tileMatrix)//.premultiply(rootTransformInverse); //xzw 删。原先的会造成移动后tiles错乱
+            const contentTransform = new Matrix4$1().fromArray(tile.computedTransform).premultiply(tile.tileset.modelMatrix).premultiply(rootTransformInverse) 
+                // 这句同tile.computedTransform左乘tileTrasnform。  因为tileTrasnform拿不到所以使用modelMatrix。modelMatrix为tileTrasnform左乘rootTransform, 所以再左乘rootTransformInverse
             
-            //不知为何在刚开始加载时迅速移动模型,tiles位置会参差不齐。应该和contentTransform有关,也就是tile.computedTransform 和rootTransformInverse的问题。但即使每次_updateTransform后重新计算也不对
+            
+            //改动:contentTransform中的computedTransform 去掉左乘 root.modelMatrixWorld , 因为移动过后这个computedTransform没更新
+
             
             
             if (shouldRotate) {
@@ -17929,11 +17980,48 @@ export { GeoTransform, Loader3DTiles, PointCloudColoring, Shading };
 Loader3DTiles   :  const tileset = new Tileset3D
 tileset.dispatchEvent({type:'tileLoaded',tileContent})
  
-createGLTFNodes : gltfLoader.parse
+createGLTFNodes(gltfLoader  创建tile
+executeTraversal(root, frameState) 遍历root
+
+
+lastRootTransform  rootTransformInverse
+
+tileset._loadTiles 依次加载tiles
+_getPriority 加载优先级 加了一句
+
+
+笔记:
+
+
+主要类:
+class tileset3D 最外层整体。 获取方法: viewer.objs.children[index].runtime.getTileset()。   .tiles包含所有tiles
+class tileHeader 也就是tileset里面的一个个tile 。  其上有.tileset
 
 
 
 
 
 
+tileset里算的tileTrasnform之后是不会改变的, tile.transform也是,是json里的。
+
+tileset.modelMatrix  (通常这个值很大) 会随着位移改变
+tile.computedTransform   被我修改了,之前左乘了tileset.modelMatrix,现只包含了transform信息     _updateTransform(parentTransfor  其中有_updateBoundingVolume,这个影响可见性, 在computeVisibilityWithPlaneMask中计算
+
+ 
+tileset._cache.trim(), 然后再update //可以将所有不可见的tiles dispose
+
+
+
+相机靠近容易缺块的bug暂时修改如下:  _visible是由computeVisibilityWithPlaneMask计算得
+get isVisibleAndInRequestVolume() {
+    return  this._inRequestVolume; //去掉了_visible ||  
+}
+
+显示所有tile似乎也不会卡顿. 但好像影响了加载顺序从而变慢了。visiVertexCount过量。 怀疑应该还是文件的bound有问题。
+原本会消失的地方虽然不会消失了但一直是模糊的
  */
+
+
+
+
+

+ 35 - 21
src/custom/mergeStartTest.js

@@ -8,7 +8,7 @@ import './three.shim.js'
 import "./potree.shim.js"
 
  
-
+ 
 
 
 //多元融合模块
@@ -303,6 +303,25 @@ var start = function(dom, mapDom, number, fileServer, webSite){ //t-Zvd3w0m
          
     }
     viewer.setControls(viewer.orbitControls) 
+     
+     
+          
+      
+    let tilesetUrls = [ 
+        'https://4dkk.4dage.com/fusion/test/b3dm/tileset.json',  //高层小区
+        'https://testgis.4dage.com/LVBADUI_qp/tileset.json', //村庄
+        'https://4dkk.4dage.com/fusion/testb3dm/modelId_613/tileset.json',//"952.16MB"  港一
+        'https://4dkk.4dage.com/fusion/testb3dm/modelId_609/tileset.json',//618.37MB  田野 'https://4dkk.4dage.com/fusion/test/b3dmtest001/tileset.json',
+        'https://4dkk.4dage.com/fusion/test/model/modelId_614/tileset.json',//172.97MB 国家电网 //'https://4dkk.4dage.com/fusion/test/model/modelId_602/tileset.json',
+        'https://4dkk.4dage.com/fusion/test/model/modelId_602/Tile_016_011/tileset.json', //modelId_614的一部分
+        
+        //'https://4dkk.4dage.com/fusion/test/model/modelId_570/3dt/3dtiles.json', //only has boundingVolume.sphere  拉远了特别模糊,凑近了模型不太对
+        
+        
+    ], tileIndex = 0   
+          
+      
+    
     let modelType,  modelEditing, MergeEditor = viewer.modules.MergeEditor
     Potree.addModel = function(name, done){ 
         
@@ -314,16 +333,16 @@ var start = function(dom, mapDom, number, fileServer, webSite){ //t-Zvd3w0m
             if(isFirstLoad){
                 modelEditing = model; 
                 MergeEditor.setModelBtmHeight(model, 0) //默认离地高度为0                
-                if(name == '3dTiles'){
+                /* if(name == '3dTiles'){
                     setTimeout(()=>{
                         moveModel({pointer:{x:0,y:0}}) //3dTiles的移动会错乱,先默认放在当前视图中间吧 
                         confirmPos()
                     },1)
-                }else{
+                }else{ */
                     
                     viewer.addEventListener('global_mousemove', moveModel); 
                     viewer.addEventListener('global_click', confirmPos, 3);
-                } 
+                //} 
             }else{
                 modelEditing = null
             }
@@ -461,7 +480,7 @@ var start = function(dom, mapDom, number, fileServer, webSite){ //t-Zvd3w0m
                         position : [0,0,0]  
                     }  
                 },callback,onprogress)  */  
-                    
+                     
                 var path = `${Potree.resourcePath}/models/obj/28M/`
                 viewer.loadModel({
                     name, 
@@ -529,30 +548,25 @@ var start = function(dom, mapDom, number, fileServer, webSite){ //t-Zvd3w0m
                         position : [0,0,0]  
                     } 
                 },callback,onprogress)
-                  
+                        
                  
-            }else if(name == '3dTiles'){
+            }else if(name == '3dTiles'){ 
                  
                 viewer.loadModel({ 
                     fileType:'3dTiles',
-                    //url: 'https://4dkk.4dage.com/fusion/test/b3dm/tileset.json',
-                    //url: 'https://4dkk.4dage.com/fusion/test/b3dmtest001/tileset.json',
-                     //url: 'https://4dkk.4dage.com/fusion/test/model/modelId_570/3dt/3dtiles.json', //only has boundingVolume.sphere
-                    //url: 'https://4dkk.4dage.com/fusion/test/model/modelId_602/Tile_016_011/tileset.json',
-                    url: 'https://4dkk.4dage.com/fusion/test/model/modelId_602/tileset.json',
+                    url: tilesetUrls[tileIndex++],
+                     
                     transform : { 
                         rotation : [Math.PI/2,  0,   0],
                         position : [0,0,0]  
-                    }          
-       
-                    /* url: 'https://testgis.4dage.com/LVBADUI_qp/tileset.json',
-                    transform : { 
-                        rotation : [ 0,  0,   0],
-                        position : [0,0,0]   
-                    }  */  
-                    
-                    
+                    }  
                 },callback,onprogress)
+                
+                 
+                
+                 
+                
+                
             }
              
         }  

+ 1 - 1
src/custom/settings.js

@@ -285,7 +285,7 @@ const config = {//配置参数   不可修改
     panoFieldRadius : 10, //当前位置多远范围内可以切全景模式
     clickMaxDragDis:5,
     clickMaxPressTime:500, //ms
-    doubleClickTime:200,//双击间隔时间
+    doubleClickTime:300,//双击间隔时间
     testNodeCount1: browser.isMobile() ? 8 : 6,  //testMaxNode次数达到这个数字时,changePointSize才使用nodeMaxLevel。 (调试时比较卡,在线上实际只需要3)
      
     background: '#232323',

+ 3 - 3
src/custom/start.js

@@ -797,15 +797,15 @@ export function mergeEditStart(dom){
                 
                 if(prop.mode != 'single'){//如果不是模型展示页,模型会随着鼠标位置移动 
                     modelEditing = model;
-                    if(model.fileType == '3dTiles'){
+                    /* if(model.fileType == '3dTiles'){
                         setTimeout(()=>{
                             moveModel({pointer:{x:0,y:0}}) //3dTiles的移动会错乱,先默认放在当前视图中间吧 
                             confirmPos()
                         },1)
-                    }else{
+                    }else{ */
                         viewer.addEventListener('global_mousemove', moveModel); 
                         viewer.addEventListener('global_click', confirmPos, {importance:3});
-                    } 
+                    //} 
                 }
                 model.dispatchEvent("position_changed") 
             }else{

+ 7 - 1
src/custom/utils/Common.js

@@ -427,7 +427,13 @@ var Common = {
         
     }, 
         
-    
+    getRootWindow(){
+        let win = window
+        while(win.parent!=win){
+            win = win.parent
+        }
+        return win
+    },
     
     
 }  

+ 21 - 8
src/custom/utils/SplitScreen.js

@@ -75,11 +75,11 @@ class SplitScreen extends THREE.EventDispatcher{
         let info = {bound} 
         let {boundSize, boundCenter} = this.getViewBound(viewport)
         
-        
-        
+        this.setShiftTarget(viewport, boundCenter)
+        /* 
         viewport.targetPlane.setFromNormalAndCoplanarPoint( view.direction.clone(), boundCenter )  
         viewport.targetPlane.projectPoint(center, viewport.shiftTarget)  //target转换到过模型中心的平面,以保证镜头一定在模型外 this.shiftTarget是得到的
-        
+         */
         info.endPosition = this.getPosOutOfModel(viewport, boundSize) 
         
         //if(viewport.name == 'mapViewport')info.endPosition.z = Math.max(Potree.config.map.cameraHeight, info.endPosition.z) 
@@ -117,9 +117,10 @@ class SplitScreen extends THREE.EventDispatcher{
         viewer.viewports.forEach((viewport, i )=>{
             if(viewport != viewer.mainViewport){
                 let {boundSize, boundCenter} = this.getViewBound(viewport)
-                viewport.targetPlane.setFromNormalAndCoplanarPoint( viewport.view.direction.clone(), boundCenter) 
+                /* viewport.targetPlane.setFromNormalAndCoplanarPoint( viewport.view.direction.clone(), boundCenter) 
                 viewport.targetPlane.projectPoint(viewport.view.position, viewport.shiftTarget)  //target转换到过模型中心的平面,以保证镜头一定在模型外 this.shiftTarget是得到的
-         
+                */ 
+                this.setShiftTarget(viewport, boundCenter)
                  let endPosition = this.getPosOutOfModel(viewport, boundSize) 
                  //if(viewport.name == 'mapViewport')endPosition.z = Math.max(Potree.config.map.cameraHeight, endPosition.z) 
                  viewport.view.position.copy(endPosition)
@@ -127,15 +128,27 @@ class SplitScreen extends THREE.EventDispatcher{
         })  
     }  
      
+     
+     
+     
+    setShiftTarget(viewport, center){
+        if(!viewport.targetPlane ){
+            viewport.targetPlane = new THREE.Plane()
+            viewport.shiftTarget = new THREE.Vector3 //project在targetPlane上的位置
+        }
+         
+        viewport.targetPlane.setFromNormalAndCoplanarPoint(viewport.view.direction, center ) 
+        viewport.targetPlane.projectPoint(viewport.view.position,  viewport.shiftTarget )  //target转换到过模型中心的平面,以保证镜头一定在模型外
+        
+    }
+     
     rotateSideCamera(viewport, angle){//侧视图绕模型中心水平旋转
          
         //let {boundSize, center} = viewer.bound
         let {boundSize, boundCenter } = this.getViewBound(viewport)  
         let center = this.focusCenter || boundCenter //旋转中心,一般是所有模型的中心,除非想指定中心点
-        
+        this.setShiftTarget(viewport, center)
         //找到平移向量
-        viewport.targetPlane.setFromNormalAndCoplanarPoint(viewport.view.direction  , center ) 
-        viewport.targetPlane.projectPoint(viewport.view.position,  viewport.shiftTarget )  //target转换到过模型中心的平面,以保证镜头一定在模型外
         let vec = new THREE.Vector3().subVectors(center, viewport.shiftTarget)//相对于中心的偏移值,旋转后偏移值也旋转
         
         //旋转

+ 7 - 5
src/custom/utils/math.js

@@ -1,8 +1,8 @@
 
 import * as THREE from "../../../libs/three.js/build/three.module.js";
 import searchRings from "./searchRings.js";
-
-
+import {ExtendView} from '../../viewer/ExtendView.js'
+ 
 
 var math = {
     getBaseLog(x, y) {//返回以 x 为底 y 的对数(即 logx y) .  Math.log 返回一个数的自然对数
@@ -592,9 +592,11 @@ var math = {
     },
 
     getQuaFromPosAim( position, target ){ 
-        let matrix = (new THREE.Matrix4).lookAt(position, target, new THREE.Vector3(0,0,1))
-        return (new THREE.Quaternion).setFromRotationMatrix(matrix)
-        
+        /* let matrix = (new THREE.Matrix4).lookAt(position, target, new THREE.Vector3(0,0,1)) //这里垂直的话会默认给一个右向所以不这么写
+        return (new THREE.Quaternion).setFromRotationMatrix(matrix) */
+        let view = new ExtendView()
+        view.direction = new THREE.Vector3().subVectors(target,position) 
+        return view.quaternion
     },
     
     

+ 47 - 7
src/custom/viewer/ViewerNew.js

@@ -82,9 +82,20 @@ const manager = new THREE.LoadingManager();
 let loaders = {}
 
 let mapArea; 
-let shelterHistory = []
+let shelterHistory = [] 
 
 
+Potree.isIframeChild = window.parent!=window  //子页面
+if(Potree.isIframeChild){ 
+    let rootWin = Common.getRootWindow() 
+    rootWin.viewer.dispatchEvent({type:'createIframe', window}) //给祖先页面发送信息
+} 
+/* window.addEventListener('focus',()=>{
+    console.log('focus',window.winIndex)
+})
+window.addEventListener('blur',()=>{
+    console.log('blur',window.winIndex)
+}) */
 
 export class Viewer extends ViewerBase{
 	
@@ -762,6 +773,21 @@ export class Viewer extends ViewerBase{
             
         } 
         
+        
+        if(!Potree.isIframeChild){
+            window.winIndex = 0;
+            let index = 1;
+            this.addEventListener('createIframe',(e)=>{//创建了子页面
+                let child = e.window;
+                child.winIndex = index ++;
+                
+                
+            }) 
+            //不知道删除iframe时是否那些模型还在内存里,需要释放吗? 如果要需要加一个事件
+        }
+        
+        
+        
         /* {
             let setInteract = ()=>{
                 this.interacted = true //标记这一帧用户有操作屏幕
@@ -2974,7 +3000,7 @@ export class Viewer extends ViewerBase{
 
 	renderDefault(params_={}){
         
-        if(!this.visible || this.paused  )return
+        if(!this.visible  )return
         
          
 		let pRenderer = this.getPRenderer();
@@ -4212,7 +4238,7 @@ export class Viewer extends ViewerBase{
 	loop(timestamp){
         //let startTime = performance.now()
         //console.log('间隔:' ,parseInt((startTime - this.lastEndTime)*100 )/100)
-        
+        if(this.paused)return
         if(performance.getEntriesByName("loopWaitNext-start").length)viewer.addTimeMark('loopWaitNext','end') 
         
          
@@ -4794,16 +4820,15 @@ export class Viewer extends ViewerBase{
                     //basisTranscoderPath: '../utils/loaders/KTX2Loader/basis',
                     maximumScreenSpaceError: 30,  //如果本身tiles很密很小这个值就不能很大。
                     maxDepth: 100, 
-                    maximumMemoryUsage: 700, //缓存大小。 若太小,密集的tile反复加载很卡
+                    maximumMemoryUsage: 200, //缓存大小。单位M(但实际结果是 2.5*maximumMemoryUsage + 750  。超过2G会崩, 所以应该小于540) 若太小,密集的tile反复加载很卡. (任务管理器刷新网页后若内存不掉就要结束进程否则虚高)
                     //debug:true,
                     parent: this.scene.scene
                 },
             })
             console.log(result)
             result.model.runtime = result.runtime
-            loadDone(result.model/* , null, fileInfo.url */)  
-              
-
+            loadDone(result.model/* , null, fileInfo.url */) 
+ 
                
             let loaded = false
             let tileset = result.runtime.getTileset()
@@ -4817,6 +4842,21 @@ export class Viewer extends ViewerBase{
                 let opacity = result.model.opacity
                 MergeEditor.changeOpacity(e.tileContent,opacity) 
             })
+            
+            {
+                let vi = true
+                Object.defineProperty( result.model, "visible", {
+                    get: function() {
+                        return vi
+                    },
+                    set: function(v) {
+                        vi = v 
+                        tileset.visible = v;  //同步,使不加载
+                    }
+                })  
+            }
+            
+            
         }
         
          

+ 13 - 10
src/navigation/InputHandlerNew.js

@@ -62,6 +62,10 @@ export class InputHandler extends THREE.EventDispatcher {
 		this.domElement.addEventListener('click', this.onMouseClick.bind(this), false);
 		this.domElement.addEventListener('mousedown', this.onMouseDown.bind(this), false);
 		window.addEventListener('mouseup', this.onMouseUp.bind(this), false);
+        if(Potree.isIframeChild){//子页面的话在父页面也要加侦听(应该不会有多层吧?否则要一直加到最外层)
+            window.parent.addEventListener('mouseup', this.onMouseUp.bind(this), false);
+        }
+        
 		this.domElement.addEventListener('mousemove', this.onMouseMove.bind(this), false);
         //add
        /*  this.domElement.addEventListener("pointerout", this.onMouseUp.bind(this)),
@@ -76,17 +80,17 @@ export class InputHandler extends THREE.EventDispatcher {
 		
         this.domElement.addEventListener('keydown', this.onKeyDown.bind(this));
 		window.addEventListener('keyup', this.onKeyUp.bind(this));
+         
         
-        //window.addEventListener('focus',()=>{
         window.addEventListener('blur',this.onKeyUp.bind(this)); //add
             
-             
+              
          
 		this.domElement.addEventListener('touchstart', this.onTouchStart.bind(this));
 		this.domElement.addEventListener('touchend', this.onTouchEnd.bind(this));
 		this.domElement.addEventListener('touchmove', this.onTouchMove.bind(this));
           
-        
+          
         {
             this.addEventListener('isMeasuring',(e)=>{ 
                 //console.log('isMeasuring',e.v,e.cause)
@@ -98,9 +102,9 @@ export class InputHandler extends THREE.EventDispatcher {
             this.interactHistory = {}  //清空
         })
         
-        
-	}
-
+           
+	}  
+     
 	/* addInputListener (listener) {
 		this.inputListeners.push(listener);
 	}
@@ -690,9 +694,8 @@ export class InputHandler extends THREE.EventDispatcher {
                 
                 this.lastClickTime = now
             }
-
-            this.drag = null;
-             
+        
+            this.drag = null; 
 		}
 
         this.dragViewport = null
@@ -1189,7 +1192,7 @@ export class InputHandler extends THREE.EventDispatcher {
                 }
             )); 
         }
-		
+		 
 	}
 
 	/* getMousePointCloudIntersection (mouse) {

+ 35 - 23
src/navigation/OrbitControlsNew.js

@@ -22,7 +22,7 @@ let minRadius = 2
  
 export class OrbitControls extends THREE.EventDispatcher{
 	
-	constructor(viewer){
+	constructor(viewer, viewport){
 		super();
 		
 		this.viewer = viewer;
@@ -32,10 +32,13 @@ export class OrbitControls extends THREE.EventDispatcher{
 		this.sceneControls = new THREE.Scene();
 
 		this.rotationSpeed = 3;  //旋转速度
-        
          
+        viewport = viewport || viewer.viewports[0]
+        
+        this.setCurrentViewport({hoverViewport:viewport, force:true}) //this.currentViewport = viewport
+        
 
-		this.fadeFactor = 100;
+		this.fadeFactor = 20;
 		this.yawDelta = 0;
 		this.pitchDelta = 0;
 		this.panDelta = new THREE.Vector2(0, 0);
@@ -62,7 +65,7 @@ export class OrbitControls extends THREE.EventDispatcher{
             if(!this.enabled)return
  
             let viewport = e.dragViewport;
-            if(!viewport || viewport.camera.type == "OrthographicCamera" )return
+            if(!viewport /* || viewport.camera.type == "OrthographicCamera"  */)return
             //let camera = viewport.camera 
           
 
@@ -113,7 +116,7 @@ export class OrbitControls extends THREE.EventDispatcher{
                 var scale = this.dollyEnd.length() / this.dollyStart.length() 
                   
                 this.dollyStart.copy(this.dollyEnd); 
-                this.radiusDelta = (1-scale) * this.scene.view.radius 
+                this.radiusDelta = (1-scale) * this.currentViewport.view.radius 
 			  
                 //------------------------
                 //平移
@@ -148,7 +151,7 @@ export class OrbitControls extends THREE.EventDispatcher{
 
 		let scroll = (e) => {
             if(!this.enabled)return
-			let resolvedRadius = this.scene.view.radius + this.radiusDelta;
+			let resolvedRadius = this.currentViewport.view.radius + this.radiusDelta;
             if(resolvedRadius < 0.1 && e.delta>0)return; //防止缩放太小,导致很慢
 			this.radiusDelta += -e.delta * resolvedRadius * 0.1;
             
@@ -186,7 +189,7 @@ export class OrbitControls extends THREE.EventDispatcher{
 				let currDist = Math.sqrt(currDX * currDX + currDY * currDY);
 
 				let delta = currDist / prevDist;
-				let resolvedRadius = this.scene.view.radius + this.radiusDelta;
+				let resolvedRadius = this.currentViewport.view.radius + this.radiusDelta;
 				let newRadius = resolvedRadius / delta;
 				this.radiusDelta = newRadius - resolvedRadius;
 
@@ -261,6 +264,15 @@ export class OrbitControls extends THREE.EventDispatcher{
 	setScene (scene) {
 		this.scene = scene;
 	}
+    
+    setCurrentViewport(o={}){//add
+        if(!this.enabled && !o.force )return
+        if(o.hoverViewport && this.currentViewport != o.hoverViewport ){
+            this.currentViewport = o.hoverViewport  
+			 
+        } 
+    }
+    
     setEnable(enabled){
         this.enabled = enabled
     }
@@ -296,11 +308,11 @@ export class OrbitControls extends THREE.EventDispatcher{
 			let nodes = I.pointcloud.nodesOnRay(I.pointcloud.visibleNodes, ray);
 			let lastNode = nodes[nodes.length - 1];
 			let radius = lastNode.getBoundingSphere(new THREE.Sphere()).radius;
-			targetRadius = Math.min(this.scene.view.radius, radius);
+			targetRadius = Math.min(this.currentViewport.view.radius, radius);
 			targetRadius = Math.max(minimumJumpDistance, targetRadius);
 		}
 
-		let d = this.scene.view.direction.multiplyScalar(-1);
+		let d = this.currentViewport.view.direction.multiplyScalar(-1);
 		let cameraTargetPosition = new THREE.Vector3().addVectors(I.location, d.multiplyScalar(targetRadius));
 		// TODO Unused: let controlsTargetPosition = I.location;
 
@@ -313,19 +325,19 @@ export class OrbitControls extends THREE.EventDispatcher{
 			tween.easing(easing);
 			this.tweens.push(tween);
 
-			let startPos = this.scene.view.position.clone();
+			let startPos = this.currentViewport.view.position.clone();
 			let targetPos = cameraTargetPosition.clone();
-			let startRadius = this.scene.view.radius;
+			let startRadius = this.currentViewport.view.radius;
 			let targetRadius = cameraTargetPosition.distanceTo(I.location);
 
 			tween.onUpdate(() => {
 				let t = value.x;
-				this.scene.view.position.x = (1 - t) * startPos.x + t * targetPos.x;
-				this.scene.view.position.y = (1 - t) * startPos.y + t * targetPos.y;
-				this.scene.view.position.z = (1 - t) * startPos.z + t * targetPos.z;
+				this.currentViewport.view.position.x = (1 - t) * startPos.x + t * targetPos.x;
+				this.currentViewport.view.position.y = (1 - t) * startPos.y + t * targetPos.y;
+				this.currentViewport.view.position.z = (1 - t) * startPos.z + t * targetPos.z;
 
-				this.scene.view.radius = (1 - t) * startRadius + t * targetRadius;
-				this.viewer.setMoveSpeed(this.scene.view.radius);
+				this.currentViewport.view.radius = (1 - t) * startRadius + t * targetRadius;
+				this.viewer.setMoveSpeed(this.currentViewport.view.radius);
 			});
 
 			tween.onComplete(() => {
@@ -351,7 +363,7 @@ export class OrbitControls extends THREE.EventDispatcher{
         
         if(!I || !object)return;
         
-        let dis = this.scene.view.position.distanceTo(I); 
+        let dis = this.currentViewport.view.position.distanceTo(I); 
         
         
         let bound = object.boundingBox.clone().applyMatrix4(object.matrixWorld)
@@ -373,8 +385,8 @@ export class OrbitControls extends THREE.EventDispatcher{
 
 	update (delta) {
         if(!this.enabled)return
-		let view = this.scene.view;
-
+		let view = this.currentViewport.view//this.currentViewport.view;
+        let camera = this.currentViewport.camera
 
 
 
@@ -428,16 +440,16 @@ export class OrbitControls extends THREE.EventDispatcher{
 			view.yaw = yaw;
 			view.pitch = pitch;
 
-			let V = this.scene.view.direction.multiplyScalar(-view.radius);
+			let V = this.currentViewport.view.direction.multiplyScalar(-view.radius);
 			let position = new THREE.Vector3().addVectors(pivot, V);
 
 			view.position.copy(position);
 		}
 
-		{ // apply pan
+		if(camera.type != 'OrthographicCamera'){ // apply pan
 			/* let progression = Math.min(1, this.fadeFactor * delta);
 			let panDistance = progression * view.radius * 3; */
-            let camera = this.scene.getActiveCamera()
+            
             let panDistance = 2 * view.radius * Math.tan(THREE.Math.degToRad(camera.fov / 2));//参照4dkk。 平移target(也就是平移镜头位置),但还是难以保证跟手(navvis也不一定跟手,但是很奇怪在居中时中心点居然是跟手的,可能计算方式不同)
             //计算了下确实是这么算的。 平移pivot。 
             
@@ -469,7 +481,7 @@ export class OrbitControls extends THREE.EventDispatcher{
 
 		{
 			let speed = view.radius;
-			this.viewer.setMoveSpeed(speed);
+			this.viewer.setMoveSpeed && this.viewer.setMoveSpeed(speed);
 		}
 
 		{ // decelerate over time

+ 28 - 24
src/viewer/ExtendView.js

@@ -10,8 +10,8 @@ class ExtendView extends View {
         super()
         
 	 
-		this.yaw = 0//Math.PI / 4; // =  4dkk lon + 90  
-		this._pitch = 0//-Math.PI / 4; //上下旋转 = 4dkk lat 
+		this.yaw = 0   //Math.PI / 4; // =  4dkk lon + 90  
+		this._pitch = 0   //-Math.PI / 4; //上下旋转 = 4dkk lat 
 		 
         this.sid = sid++
         this.LookTransition = 'LookTransition'+this.sid
@@ -39,13 +39,19 @@ class ExtendView extends View {
         return rotation
     }
      
-    set rotation(rotation){
+    set rotation(rotation){//这个在数字很小(垂直向上看)的时候水平旋转精度可能损失,导致突变到另一个角度去了,用 set quaternion比较好
         //因为 rotation的y不一定是0 , 所以不能直接逆着写。
         this.direction = new THREE.Vector3(0,0,-1).applyEuler(rotation)
     }
     
    
+    get quaternion(){
+        return new THREE.Quaternion().setFromEuler(this.rotation)
+    }
     
+    set quaternion(q){
+        this.direction = new THREE.Vector3(0,0,-1).applyQuaternion(q)
+    }
     
     copy(a){
         Common.CopyClassObject(this, a, {ignoreList: ['_listeners']})
@@ -207,29 +213,27 @@ class ExtendView extends View {
         let endPosition = new THREE.Vector3().copy(info.position)
         let startPosition = this.position.clone();
 		let startQuaternion, endQuaternion, endTarget = null ;
-        
-        /* if(info.considerSceneTran){
-            endPosition.applyMatrix4(viewer.scene.scene.matrix)  
-        } 
-         */
-        
         this.restrictPos(endPosition)
-        
+         
 		if(info.target ){
 			endTarget = new THREE.Vector3().copy(info.target)  
-            endQuaternion = math.getQuaFromPosAim(endPosition,endTarget) 
+            endQuaternion = math.getQuaFromPosAim(endPosition,endTarget) //若为垂直,会自动偏向x负的方向
+            let dir = new THREE.Vector3().subVectors(endTarget, endPosition).normalize()
+           
+            let view = this.clone();
+            view.direction = dir;
+              
 		}else if(info.quaternion){
             endQuaternion = info.quaternion.clone()
         }
          
         if(endQuaternion){ 
             startQuaternion = new THREE.Quaternion().setFromEuler(this.rotation)
-            /*  const startTarget = this.getPivot();
-            let startQuaternion = math.getQuaFromPosAim(startPosition,startTarget) */
-            
+           
         }
         
         
+        
 		if(!info.duration){
 			this.position.copy(endPosition);
             this.restrictPos()
@@ -263,11 +267,13 @@ class ExtendView extends View {
             if(endQuaternion){
                 rotWaitDone = true 
                 transitions.start( (progress, delta )=>{
-                
+                   
                     let quaternion = (new THREE.Quaternion()).copy(startQuaternion) 
-                    lerp.quaternion(quaternion, endQuaternion)(progress),
-                    this.rotation = new THREE.Euler().setFromQuaternion(quaternion)
-                    
+                    lerp.quaternion(quaternion, endQuaternion)(progress)  //在垂直的视角下的角度突变的厉害,这时候可能渐变yaw比较好
+             
+                    //this.rotation = new THREE.Euler().setFromQuaternion(quaternion)
+                    this.quaternion = quaternion
+                     
                     posChange || info.onUpdate && info.onUpdate(progress, delta)  
                     
                 }, info.duration, rotDone , 0, info.Easing ? easing[info.Easing] : easing.easeInOutSine ,null, this.LookTransition, ()=>{
@@ -323,10 +329,8 @@ class ExtendView extends View {
             boundSize.set(1,1)  //避免infinity
         }
         
-        this.setView({ position:endPosition,  duration, 
-            callback:()=>{//done
-                 
-            },
+        this.setView( Object.assign(info,  { position:endPosition,  duration, 
+            
             onUpdate:(progress)=>{ 
                 if(boundSize || endZoom){ 
                     if(boundSize){
@@ -349,8 +353,8 @@ class ExtendView extends View {
             },
             
             Easing:easeName
-        
-        })
+         
+        }))
           
         
     }

+ 5 - 3
src/viewer/View.js

@@ -41,10 +41,12 @@ export class View{//base
 	}
 
 	set direction (dir) {
-
-		//if(dir.x === dir.y){
+        dir = dir.clone().normalize()//add
+        
 		if(dir.x === 0 && dir.y === 0){
-			this.pitch = Math.PI / 2 * Math.sign(dir.z);
+			this.pitch = Math.PI / 2 * Math.sign(dir.z); 
+            this.yaw = 0   //add:还是要指定一下, 否则不统一
+            
 		}else{
 			let yaw = Math.atan2(dir.y, dir.x) - Math.PI / 2;
 			let pitch = Math.atan2(dir.z, Math.sqrt(dir.x * dir.x + dir.y * dir.y));

+ 1 - 1
src/viewer/sidebarNew.js

@@ -159,7 +159,7 @@ export class Sidebar{
                 let startTime = Date.now()
                 Potree.addModel(name,()=>{
                     loading = false 
-                    $elem.text('删除')
+                    //$elem.text('删除')
                     let now = Date.now()
                     console.log('加载完毕', name, '用时', (now-startTime)/1000, 's')
                 })