Przeglądaj źródła

fix: panoEditor等改了很多 pick改进

xzw 2 lat temu
rodzic
commit
d73e418f0c
37 zmienionych plików z 1074 dodań i 682 usunięć
  1. 139 98
      src/ExtendPointCloudOctree.js
  2. 161 84
      src/PotreeRendererNew.js
  3. 1 1
      src/custom/modules/Particles/ParticleEditor.js
  4. 2 0
      src/custom/modules/datasetAlignment/Alignment.js
  5. 32 7
      src/custom/modules/mergeModel/MergeEditor.js
  6. 67 33
      src/custom/modules/panoEdit/panoEditor.js
  7. 9 2
      src/custom/modules/panos/DepthImageSampler.js
  8. 49 54
      src/custom/modules/panos/Images360.js
  9. 48 9
      src/custom/modules/panos/tile/PanoRenderer.js
  10. 35 23
      src/custom/modules/panos/tile/TileDownloader.js
  11. 3 2
      src/custom/modules/panos/tile/TilePrioritizer.js
  12. 8 6
      src/custom/modules/route/RouteGuider.js
  13. 1 1
      src/custom/objects/InfiniteGridHelper.js
  14. 1 1
      src/custom/objects/Magnifier.js
  15. 6 4
      src/custom/objects/Sprite.js
  16. 2 2
      src/custom/objects/tool/MeasuringTool.js
  17. 1 1
      src/custom/objects/tool/TagTool.js
  18. 2 2
      src/custom/objects/tool/TransformControls.js
  19. 57 41
      src/custom/potree.shim.js
  20. 8 4
      src/custom/settings.js
  21. 31 22
      src/custom/start.js
  22. 6 3
      src/custom/three.shim.js
  23. 82 0
      src/custom/utils/Common.js
  24. 215 167
      src/custom/viewer/ViewerNew.js
  25. 7 6
      src/custom/viewer/Viewport.js
  26. 1 1
      src/custom/viewer/map/Map.js
  27. 3 0
      src/custom/viewer/map/MapViewer.js
  28. 8 6
      src/materials/ExtendPointCloudMaterial.js
  29. 3 3
      src/materials/PointCloudMaterial.js
  30. 7 3
      src/materials/shaders/pointcloud_new.vs
  31. 3 2
      src/navigation/FirstPersonControlsNew.js
  32. 6 3
      src/navigation/InputHandlerNew.js
  33. 53 85
      src/viewer/EDLRendererNew.js
  34. 1 1
      src/viewer/NavigationCube.js
  35. 1 1
      src/viewer/potree.css
  36. 6 4
      src/viewer/sidebarNew.js
  37. 9 0
      改bug的历史.txt

+ 139 - 98
src/ExtendPointCloudOctree.js

@@ -12,7 +12,13 @@ export class ExtendPointCloudOctree extends PointCloudOctree{
         material = material || new ExtendPointCloudMaterial();
         super(geometry, material)
         
-         
+        //xzw move from material  。 adaptive_point_size才使用
+        /* this.visibleNodesTexture = Utils.generateDataTexture(2048, 1, new THREE.Color(0xffffff));
+		this.visibleNodesTexture.minFilter = THREE.NearestFilter;
+		this.visibleNodesTexture.magFilter = THREE.NearestFilter; */
+        
+        
+        
         this.boundingBox = this.pcoGeometry.tightBoundingBox//this.pcoGeometry.boundingBox;  //boundingBox是正方体,所以换掉
 		this.boundingSphere = this.boundingBox.getBoundingSphere(new THREE.Sphere());
         this.nodeMaxLevel = 0;//add
@@ -116,7 +122,7 @@ export class ExtendPointCloudOctree extends PointCloudOctree{
         
         this.testMaxNodeCount ++
         viewer.testMaxNodeCount ++
-        if(this.testMaxNodeCount > 500){
+        if(this.testMaxNodeCount > 100){
             console.log('testMaxNodeLevel次数超出,强制结束:',this.dataset_id,  this.nodeMaxLevel,  this.nodeMaxLevelPredict.min) 
             this.testMaxNodeLevelDone = 'moreThanMaxCount'
             return; //在可以看见点云的情况下,超时,有可能是预测的max是错的    
@@ -138,9 +144,12 @@ export class ExtendPointCloudOctree extends PointCloudOctree{
         
     }       
       
+      
      
-     
-     
+    updateMatrixWorld(force){//add
+        super.updateMatrixWorld(force);
+        this.matrixWorldInverse = this.matrixWorld.clone().invert(); 
+    } 
      
     
     setPointLevel(){
@@ -200,15 +209,15 @@ export class ExtendPointCloudOctree extends PointCloudOctree{
 		let renderer = viewer.renderer;
 		let pRenderer = viewer.pRenderer;
 
-		performance.mark("pick-start");
+		viewer.addTimeMark('pick','start')
 
 		let getVal = (a, b) => a != void 0 ? a : b;
         
         
-        //let pickWindowSize_ = THREE.Math.clamp( Math.round((1.1-this.maxLevel/this.nodeMaxLevel)*80),  5, 100)
-        let pickWindowSize_ = THREE.Math.clamp( Math.round((1.1-this.maxLevel/this.nodeMaxLevel)*50),  3, 100)
-		let pickWindowSize = getVal(params.pickWindowSize, pickWindowSize_    ); /* 65 */ //拾取像素边长,越小越精准,但点云稀疏的话可能容易出现识别不到的情况。 另外左下侧会有缝隙无法识别到,缝隙大小和这个值有关
- 
+      
+        let pickWindowSize_ = THREE.Math.clamp( Math.round((1.1-this.maxLevel/this.nodeMaxLevel)*80),  5, 100)
+		let pickWindowSize = getVal(params.pickWindowSize, pickWindowSize_    ); /* 65 */ //拾取像素边长,越小越精准,但点云稀疏的话可能容易出现识别不到的情况。 另外左下侧会有缝隙无法识别到,缝隙大小和这个值有关//突然发现pickWindowSize在一百以内的变化对pick费时影响甚微,1和100差1毫秒不到,但400时会多4毫秒
+            
 		let pickOutsideClipRegion = getVal(params.pickOutsideClipRegion, false);
 
 		let size = viewport ? viewport.resolution : renderer.getSize(new THREE.Vector2());
@@ -229,9 +238,9 @@ export class ExtendPointCloudOctree extends PointCloudOctree{
 
 		let pointSizeType = getVal(params.pointSizeType, this.material.pointSizeType);
 		let pointSize = getVal(params.pointSize, this.material.size);
-
+ 
 		let nodes = this.nodesOnRay(this.visibleNodes, ray);
-
+ 
 		if (nodes.length === 0) { 
             
 			return null;
@@ -277,26 +286,11 @@ export class ExtendPointCloudOctree extends PointCloudOctree{
 			pickMaterial.uniforms.maxSize.value = this.material.uniforms.maxSize.value;
 			pickMaterial.classification = this.material.classification;
 			pickMaterial.recomputeClassification();
-
-			/* if(params.pickClipped){
-				pickMaterial.clipBoxes = this.material.clipBoxes;
-				pickMaterial.uniforms.clipBoxes = this.material.uniforms.clipBoxes;
-				if(this.material.clipTask === Potree.ClipTask.HIGHLIGHT){
-					pickMaterial.clipTask = Potree.ClipTask.NONE;
-				}else{
-					pickMaterial.clipTask = this.material.clipTask;
-				}
-				pickMaterial.clipMethod = this.material.clipMethod;
-			}else{
-				pickMaterial.clipBoxes = [];
-			} */ 
-            //pickClipped判断转移到上一层函数
-            pickMaterial.clipBoxes_in = this.material.clipBoxes_in; 
-            pickMaterial.clipBoxes_out = this.material.clipBoxes_out; 
-            pickMaterial.bigClipInBox = this.material.bigClipInBox; 
-            pickMaterial.uniforms.clipBoxes_in = this.material.uniforms.clipBoxes_in;
-            pickMaterial.uniforms.clipBoxes_out = this.material.uniforms.clipBoxes_out;
-            pickMaterial.uniforms.clipBoxBig_in = this.material.uniforms.clipBoxBig_in;
+ 
+            //pickClipped判断转移到上一层函数 
+            let {bigClipInBox,clipBoxes_in,clipBoxes_out} = this.material
+            pickMaterial.setClipBoxes(bigClipInBox, clipBoxes_in, clipBoxes_out, []) 
+             
 			this.updateMaterial(pickMaterial, nodes, camera, renderer, new THREE.Vector2(width, height));
 		}
 
@@ -315,6 +309,7 @@ export class ExtendPointCloudOctree extends PointCloudOctree{
 		renderer.state.buffers.depth.setTest(pickMaterial.depthTest);
 		renderer.state.buffers.depth.setMask(pickMaterial.depthWrite);
 		renderer.state.setBlending(THREE.NoBlending);
+		 
 
 		{ // RENDER
 			renderer.setRenderTarget(pickState.renderTarget);
@@ -341,9 +336,9 @@ export class ExtendPointCloudOctree extends PointCloudOctree{
 		let pixelCount = pickWindowSize * pickWindowSize//w * h;
 		let buffer = new Uint8Array(4 * pixelCount);
         //w<pickWindowSize会报错
-        
-		gl.readPixels(x, y, pickWindowSize, pickWindowSize, gl.RGBA, gl.UNSIGNED_BYTE, buffer);
-
+    
+		gl.readPixels(x, y, pickWindowSize, pickWindowSize, gl.RGBA, gl.UNSIGNED_BYTE, buffer); //这句花费最多时间 pc:2-4, 即使只有1*1像素
+ 
 		renderer.setRenderTarget(null);
 		renderer.state.reset();
 		renderer.setScissorTest(false);
@@ -354,7 +349,13 @@ export class ExtendPointCloudOctree extends PointCloudOctree{
 
 		// find closest hit inside pixelWindow boundaries
 		let min = Number.MAX_VALUE;
-		let hits = [];
+		let hits = [], hits2 = [], rSquare;
+        
+        if(!params.all){
+            let r = THREE.Math.clamp(Math.floor(pickWindowSize / 2),1, 40);
+            rSquare = r * r
+        }
+        
 		for (let u = 0; u < pickWindowSize; u++) {
 			for (let v = 0; v < pickWindowSize; v++) {
 				let offset = (u + v * pickWindowSize);
@@ -374,20 +375,26 @@ export class ExtendPointCloudOctree extends PointCloudOctree{
 					if(params.all){
 						hits.push(hit);
 					}else{
-						if(hits.length > 0){
+						if(hits.length > 0){//最后选取的是最靠近鼠标的那个pick
 							if(distance < hits[0].distanceToCenter){
 								hits[0] = hit;
-							}
+							} 
 						}else{
 							hits.push(hit);
 						}
-					}
-
-
+                        
+                        if(distance < rSquare) hits2.push(hit);  //add
+                         
+					} 
 				}
 			}
 		}
-
+        
+        if(!params.all){
+            if(hits2.length){//add 
+                hits = hits2
+            } 
+        }
 		
 		// { // DEBUG: show panel with pick image
 		// 	let img = Utils.pixelsArrayToImage(buffer, w, h);
@@ -436,6 +443,11 @@ export class ExtendPointCloudOctree extends PointCloudOctree{
 					position.applyMatrix4( pc.matrixWorld );
                     
 					point[attributeName] = position;
+                    
+                    //add
+                    if(!params.all){
+                        hit.disSquare = camera.position.distanceToSquared(position)
+                    }
 				} else if (attributeName === 'indices') {
 
 				} else {
@@ -460,25 +472,40 @@ export class ExtendPointCloudOctree extends PointCloudOctree{
 					//	point[attribute.name] = value;
 					//}
 				}
-
+                
 			}
 
 			hit.point = point;
 		}
-
-		performance.mark("pick-end");
-		performance.measure("pick", "pick-start", "pick-end");
-
+        
+        
+        viewer.addTimeMark('pick','end')
+        
 		if(params.all){
 			return hits.map(hit => hit.point);
 		}else{
 			if(hits.length === 0){
 				return null;
 			}else{
-				return hits[0].point;
-				//let sorted = hits.sort( (a, b) => a.distanceToCenter - b.distanceToCenter);
-
-				//return sorted[0].point;
+                //为了防止透过点云缝隙,选到后排的点云,将选取的位置离相机的距离考虑进去。倾向选择离相机近、且离鼠标位置近的点。(否则按照原方案只选离鼠标位置最近的,可能从高楼不小心走到下层,导航选点也是)
+                let sorted1 = hits.sort( (a, b) => a.disSquare - b.disSquare  );
+                
+                let nearest = sorted1[0]  //return nearest.point;  //直接用最近点 在点云稀疏时不太跟手,如地面上,最近点往往在鼠标下方
+                
+                
+                hits.forEach( hit=>{
+                    let disDiff = hit.disSquare - nearest.disSquare //和最近点的偏差 
+                    hit.disDiff = disDiff 
+                    let ratio = 0.1 //系数越大越不跟手,但更容易pick近处的。 (当pick的点较远时,获取框内的点距离可能差别很大,就要所以除以disSquare)
+                    hit.score = -hit.distanceToCenter - disDiff * rSquare/Math.max(nearest.disSquare,0.001) * ratio
+                })
+                
+                let sorted2 = hits.sort( (a, b) => b.score - a.score  );
+                   
+                //console.log(sorted2, 'nearest',nearest) 
+                return sorted2[0].point; 
+                  
+				//return hits[0].point;
 			}
 		}
 
@@ -487,48 +514,54 @@ export class ExtendPointCloudOctree extends PointCloudOctree{
 
     // 设置点大小
     changePointSize(num, sizeFitToLevel) {
- 
+        let size, nodeMaxLevel
         if(this.material.pointSizeType != PointSizeType.ATTENUATED){
-            return num && (this.material.size = num / Potree.config.material.realPointSize / 1.3)
-        }
-        if (num == void 0) {
-            num = this.temp.pointSize
-        } else {
-            this.temp.pointSize = num
+            num && (size = num / Potree.config.material.realPointSize / 1.3)
+        }else{
+            let num_ = num
+            if (num_ == void 0) {
+                num_ = this.temp.pointSize
+            } else {
+                this.temp.pointSize = num_ 
+            }
+            num_ = num_ / (Potree.config.material.realPointSize / Potree.config.material.pointSize) //兼容 
+               
+            num_ = Math.pow(num_, 1.05) * 6 
+             
             
-        }
-        num /= (Potree.config.material.realPointSize / Potree.config.material.pointSize) //兼容 
-           
-        num = Math.pow(num, 1.05) * 6 
-         
-        
-        let nodeMaxLevel = viewer.testMaxNodeCount > Potree.config.testNodeCount1 ? this.nodeMaxLevel : this.nodeMaxLevelPredict.max //防止刚开始因nodeMaxLevel没涨完,导致过大的点云突然出现
-         
-        if(sizeFitToLevel || Potree.settings.sizeFitToLevel){//按照点云质量来调整的版本:    近似将pointSizeType换成ADAPTIVE
-            let str = this.temp.pointSize+':'+this.maxLevel+':'+ nodeMaxLevel
-            let value = this.temp.sizeFitToLevel[str]  //储存。防止每次渲染(反复切换density)都要算。
-            if(value){
-                this.material.size = value
-            }else{
-                
-                let base = this.material.spacing / Math.pow(2, this.maxLevel) //点云大小在level为0时设置为spacing,每长一级,大小就除以2.  (不同场景还是会有偏差)
-                base *=  nodeMaxLevel > 0 ? Math.max(0.1, Math.pow(this.maxLevel /  nodeMaxLevel, 1.4)) : 0.1 //低质量的缩小点,因为视觉上看太大了。navvis是不铺满的,我们也留一点缝隙(但是ortho是不用缩小的,如果能分开判断就好了)
+            nodeMaxLevel = viewer.testMaxNodeCount > Potree.config.testNodeCount1 ? this.nodeMaxLevel : this.nodeMaxLevelPredict.max //防止刚开始因nodeMaxLevel没涨完,导致过大的点云突然出现
+            
+            if(sizeFitToLevel || Potree.settings.sizeFitToLevel){//按照点云质量来调整的版本:    近似将pointSizeType换成ADAPTIVE
+                let str = this.temp.pointSize+':'+this.maxLevel+':'+ nodeMaxLevel
+                let value = this.temp.sizeFitToLevel[str]  //储存。防止每次渲染(反复切换density)都要算。
+                if(value){
+                    size = value
+                }else{
+                    
+                    let base = this.material.spacing / Math.pow(2, this.maxLevel) //点云大小在level为0时设置为spacing,每长一级,大小就除以2.  (不同场景还是会有偏差)
+                    base *=  nodeMaxLevel > 0 ? Math.max(0.1, Math.pow(this.maxLevel /  nodeMaxLevel, 1.4)) : 0.1 //低质量的缩小点,因为视觉上看太大了。navvis是不铺满的,我们也留一点缝隙(但是ortho是不用缩小的,如果能分开判断就好了)
 
-                this.material.size = base * 5 * num/*  * window.devicePixelRatio */
-                //在t-8BCqxQAr93 会议室 和 t-e2Kb2iU 隧道 两个场景里调节,因为它们的spacing相差较大,观察会议室墙壁的龟裂程度
-                this.temp.sizeFitToLevel[str] = this.material.size
+                    size = base * 5 * num_/*  * window.devicePixelRatio */
+                    //在t-8BCqxQAr93 会议室 和 t-e2Kb2iU 隧道 两个场景里调节,因为它们的spacing相差较大,观察会议室墙壁的龟裂程度
+                    this.temp.sizeFitToLevel[str] = size
+                }
+            }else{ 
+            
+                /* let base = 0.007; */ let base = this.material.spacing / Math.pow(2,  nodeMaxLevel) //点云大小在level为0时设置为spacing,每长一级,大小就除以2
+                //base的数值理论上应该是右侧算出来的,但发现有的场景nodeMaxLevel和nodeMaxLevelPredict差别较大的点云显示也过大,而直接换成固定值反而可以适应所有场景。该固定值来源于 getHighestNodeSpacing 最小值,修改了下。(会不会是我们的相机其实该值是固定的,根据该值算出的spacing才是有误差的? 如果换了相机是否要改值?)
+                //2022-12-21又换回非固定值。因为有的场景如SS-t-t01myDqnfE的两个数据集密集程度差别很大,应该将稀疏点云的大小设置的大些。 但是这样的缺点是两个数据集因相接处有大有小无法融合。
+                size = base * 5 * num_ /* * window.devicePixelRatio  */
+            } 
+            
+        }  
+        //console.log('changePointSize:'  + this.dataset_id + ' , num: ' + (num && num.toPrecision(3)) + ' , size: ' + size.toPrecision(3),  'nodeMaxLevel', nodeMaxLevel.toPrecision(3), 'testMaxNodeCount',viewer.testMaxNodeCount     /* this.material.spacing */)
+        if(size){
+            if(Potree.settings.sortCloudMat){//被废弃,不给material分组了
+                this.size = size;this.material.size = size
+            }else{
+                this.material.size = size
             }
-        }else{ 
-        
-            /* let base = 0.007; */ let base = this.material.spacing / Math.pow(2,  nodeMaxLevel) //点云大小在level为0时设置为spacing,每长一级,大小就除以2
-            //base的数值理论上应该是右侧算出来的,但发现有的场景nodeMaxLevel和nodeMaxLevelPredict差别较大的点云显示也过大,而直接换成固定值反而可以适应所有场景。该固定值来源于 getHighestNodeSpacing 最小值,修改了下。(会不会是我们的相机其实该值是固定的,根据该值算出的spacing才是有误差的? 如果换了相机是否要改值?)
-            //2022-12-21又换回非固定值。因为有的场景如SS-t-t01myDqnfE的两个数据集密集程度差别很大,应该将稀疏点云的大小设置的大些。 但是这样的缺点是两个数据集因相接处有大有小无法融合。
-            this.material.size = base * 5 * num /* * window.devicePixelRatio  */
-        } 
-        
-        
-        //console.log('changePointSize  '  + this.dataset_id + '  , num : ' + num + ' , size : ' + this.material.size, this.material.spacing)
-    
+        }
         viewer.dispatchEvent('content_changed')     
          
     }  
@@ -544,44 +577,52 @@ export class ExtendPointCloudOctree extends PointCloudOctree{
             this.temp.pointOpacity = num
         }
         
-        if(Potree.settings.editType == 'merge'){ //not AdditiveBlending
+        if(Potree.settings.notAdditiveBlending){ 
             return this.material.opacity = num
         }
-      
+        let opacity
         if (num == 1) {
-            this.material.opacity = 1
+            opacity = 1
         } else { 
 
             let str = (Potree.settings.sizeFitToLevel?'sizeFit:':'')+ (canMoreThanOne ? 'canMoreThanOne:':'') +this.temp.pointOpacity+':'+this.maxLevel+':'+this.nodeMaxLevel
             let value = this.temp.opacity[str]  //储存。防止每次渲染(反复切换density)都要算。
             if(value){
-                this.material.opacity = value
+                opacity = value
             }else{
                 if(Potree.settings.sizeFitToLevel){//按照点云质量来调整的版本:
                     let base = this.material.spacing / Math.pow(1.5, this.maxLevel) //随着level提高,点云重叠几率增多
                     let minBase = this.material.spacing / Math.pow(1.5, this.nodeMaxLevel)
                     let ratio = Math.min(1 / base, 1 / minBase / 3) //ratio为一个能使opacity不大于1 的 乘量,minBase要除以一个数,该数调越大减弱效果越强。level越低opacity和面板越接,level越高效果越弱,以减免过度重叠后的亮度。
-                    this.material.opacity = base * ratio * num
+                    opacity = base * ratio * num
                     if(!canMoreThanOne){
-                        this.material.opacity = THREE.Math.clamp(this.material.opacity, 0, 0.999) //到1就不透明了(可能出现一段一样)
+                        opacity = THREE.Math.clamp(opacity, 0, 0.999) //到1就不透明了(可能出现一段一样)
                     }
                 }else{
                     let base = this.material.spacing / Math.pow(1.8, this.maxLevel) 
                     let minBase = this.material.spacing / Math.pow(1.8, this.nodeMaxLevel)
                     //console.log(1 / base, 1 / minBase / 6)
                     let ratio = Math.min(1 / base, 1 / minBase / 6) //ratio为一个能使opacity不大于1 的 乘量,minBase要除以一个数,该数调越大减弱效果越强。level越低opacity和面板越接,level越高效果越弱,以减免过度重叠后的亮度。
-                    this.material.opacity = base * ratio * num
+                    opacity = base * ratio * num
                     if(!canMoreThanOne){
-                        this.material.opacity = THREE.Math.clamp(this.material.opacity, 0, 0.999) //到1就不透明了(可能出现一段一样)
+                        opacity = THREE.Math.clamp(opacity, 0, 0.999) //到1就不透明了(可能出现一段一样)
                     }
                 }
-                this.temp.opacity[str] = this.material.opacity
+                this.temp.opacity[str] = opacity
             }
                 
             //缺点:防止颜色过亮主要是相机离远时,当在漫游点处由于离点云太近,可能会导致高质量点云看起来很暗。
         }
         //console.log('changePointOpacity ' + this.dataset_id + ', num : ' + num + ' , opacity : ' + this.material.opacity) //检查是否做到了低质量时num==opacity,中质量opacity稍小于num,高质量更小
-         
+        
+        
+        if(Potree.settings.sortCloudMat){
+            this.opacity = opacity; this.material.opacity = opacity
+        }else{
+            this.material.opacity = opacity
+        }
+        
+        
         viewer.dispatchEvent('content_changed') 
     } 
      

+ 161 - 84
src/PotreeRendererNew.js

@@ -712,11 +712,11 @@ export class Renderer {
 
 	renderNodes(octree, nodes, visibilityTextureData, camera, target, shader, params) {
 
-		if (exports.measureTimings) performance.mark("renderNodes-start");
+		viewer.addTimeMark('renderNodes','start')
 
 		let gl = this.gl;
 
-		let material = params.material ? params.material : octree.material;
+		let material = params.material ? params.material : octree.material; 
 		let shadowMaps = params.shadowMaps == null ? [] : params.shadowMaps;
 		let view = camera.matrixWorldInverse;
 
@@ -729,6 +729,88 @@ export class Renderer {
 		let mat4holder = new Float32Array(16);
 
 		let i = 0;
+        
+        
+        //---------从renderOctree搬到这----
+        shader.setUniform1f("size", material.usePanoMap ? Potree.config.material.absolutePanoramaSize * Math.min(window.devicePixelRatio,2) : material.size);//usePanoMap时控制在不大不小的范围内感觉较好,考虑到有的点云稀疏,用大一点的点
+        shader.setUniform1f("uOpacity", material.usePanoMap ? 1: material.opacity);
+        shader.setUniform3f("uColor", material.color.toArray());
+        
+       /*  let currentTextureBindingPoint = params.currentTextureBindingPoint
+        if (material.pointSizeType >= 0 && window.needvisibilityTexture) {
+            
+			if (material.pointSizeType === PointSizeType.ADAPTIVE ||
+				material.activeAttributeName === "level of detail") {
+
+				let vnNodes = (params.vnTextureNodes != null) ? params.vnTextureNodes : nodes;
+				visibilityTextureData = octree.computeVisibilityTextureData(vnNodes, camera);
+
+				const vnt = material.visibleNodesTexture;
+				const data = vnt.image.data;
+				data.set(visibilityTextureData.data);
+				vnt.needsUpdate = true;
+                 
+                
+                let vnWebGLTexture = this.textures.get(material.visibleNodesTexture);       //不知道为什么这段从renderOctree中移过来,会崩溃。暂时不移动了
+                if(vnWebGLTexture){
+                    shader.setUniform1i("visibleNodes", currentTextureBindingPoint);
+                    gl.activeTexture(gl.TEXTURE0 + currentTextureBindingPoint);
+                    gl.bindTexture(vnWebGLTexture.target, vnWebGLTexture.id);
+                    currentTextureBindingPoint++;
+                }   
+			}
+		} */  
+        let transparent = false;
+		if(params.transparent !== undefined){
+			transparent = params.transparent && material.opacity < 1;
+		}else{
+			transparent = material.usePanoMap ? false : (material.useFilterByNormal || material.opacity < 1); //add useFilterByNormal
+		}
+
+		if (transparent){
+			gl.enable(gl.BLEND);
+            
+            if(params.notAdditiveBlending){
+                gl.blendFuncSeparate( gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA ); //NormalBlending 
+                gl.enable(gl.DEPTH_TEST);
+                gl.depthMask(true); //如果不开启depthWrite,深度会错乱。 
+            }else{
+                gl.blendFunc(gl.SRC_ALPHA, gl.ONE); //AdditiveBlending   原本
+                gl.disable(gl.DEPTH_TEST);
+                gl.depthMask(false);
+            } 
+			
+			
+		} else {
+			gl.disable(gl.BLEND);
+			gl.depthMask(true);
+			gl.enable(gl.DEPTH_TEST);
+		}
+
+		if(params.blendFunc !== undefined){
+			gl.enable(gl.BLEND);
+			gl.blendFunc(...params.blendFunc);
+		}
+
+		if(params.depthTest !== undefined){
+			if(params.depthTest === true){
+				gl.enable(gl.DEPTH_TEST);
+			}else{
+				gl.disable(gl.DEPTH_TEST);
+			}
+		}
+
+		if(params.depthWrite !== undefined){
+			 if(params.depthWrite === true){
+				 gl.depthMask(true);
+			 }else{
+				 gl.depthMask(false);
+			 }
+			 
+		}
+        //---------------------------------
+        
+        
 		for (let node of nodes) {
 
 			if(exports.debug.allowedNodes !== undefined){
@@ -742,8 +824,9 @@ export class Renderer {
 
 			if (visibilityTextureData) {
 				let vnStart = visibilityTextureData.offsets.get(node);
+                console.log('vnStart',vnStart)
 				shader.setUniform1f("uVNStart", vnStart);
-			}
+			}  
 
 
 			let level = node.getLevel();
@@ -871,10 +954,7 @@ export class Renderer {
 			}
 
 			const geometry = node.geometryNode.geometry;
-/* if(!geometry){
-    console.error('no geometry', node)
-    continue
-} */
+ 
 			if(geometry.attributes["gps-time"]){
 				const bufferAttribute = geometry.attributes["gps-time"];
 				const attGPS = octree.getAttribute("gps-time");
@@ -1055,21 +1135,26 @@ export class Renderer {
 
 		gl.bindVertexArray(null);
 
-		if (exports.measureTimings) {
-			performance.mark("renderNodes-end");
-			performance.measure("render.renderNodes", "renderNodes-start", "renderNodes-end");
-		}
+		 
+        viewer.addTimeMark('renderNodes','end')
 	}
     
     
     
     
 
-	renderOctree(octree, nodes, camera, target, params = {}){
-
-		let gl = this.gl;
-
+	renderOctree(octrees, nodes, camera, target, params = {}){
+        viewer.addTimeMark('renderOctree','start') 
+       
+        let octree
+        if(octrees instanceof Array){
+            octree = octrees[0];
+        }else{
+            octree = octrees; octrees = [octree]
+        }
+        let gl = this.gl;
 		let material = params.material ? params.material : octree.material;
+        
 		let shadowMaps = params.shadowMaps == null ? [] : params.shadowMaps;
 		let view = camera.matrixWorldInverse;
 		let viewInv = camera.matrixWorld;
@@ -1087,21 +1172,23 @@ export class Renderer {
 		let visibilityTextureData = null;
 
 		let currentTextureBindingPoint = 0;
+        
+        
+        if (material.pointSizeType >= 0) {//最好搬到renderNodes
+            if (material.pointSizeType === PointSizeType.ADAPTIVE ||
+                material.activeAttributeName === "level of detail") {
 
-		if (material.pointSizeType >= 0) {
-			if (material.pointSizeType === PointSizeType.ADAPTIVE ||
-				material.activeAttributeName === "level of detail") {
-
-				let vnNodes = (params.vnTextureNodes != null) ? params.vnTextureNodes : nodes;
-				visibilityTextureData = octree.computeVisibilityTextureData(vnNodes, camera);
+                let vnNodes = (params.vnTextureNodes != null) ? params.vnTextureNodes : nodes;
+                visibilityTextureData = octree.computeVisibilityTextureData(vnNodes, camera);
 
-				const vnt = material.visibleNodesTexture;
-				const data = vnt.image.data;
-				data.set(visibilityTextureData.data);
-				vnt.needsUpdate = true;
+                const vnt = material.visibleNodesTexture;
+                const data = vnt.image.data;
+                data.set(visibilityTextureData.data);
+                vnt.needsUpdate = true;
 
-			}
-		}
+            }
+        } 
+		
 
 		{ // UPDATE SHADER AND TEXTURES
 			if (!this.shaders.has(material)) {
@@ -1113,7 +1200,7 @@ export class Renderer {
             
 			shader = this.shaders.get(material);
 
-			//if(material.needsUpdate){
+			if(material.shaderNeedsUpdate) 
 			{
 				let [vs, fs] = [material.vertexShader, material.fragmentShader];
 
@@ -1194,7 +1281,7 @@ export class Renderer {
 
 				shader.update(vs, fs);
 
-				material.needsUpdate = false;
+				material.shaderNeedsUpdate = false;
 			}
              
 			for (let uniformName of Object.keys(material.uniforms)) {
@@ -1228,7 +1315,7 @@ export class Renderer {
 
 		gl.useProgram(shader.program);
 
-		let transparent = false;
+		/* let transparent = false;
 		if(params.transparent !== undefined){
 			transparent = params.transparent && material.opacity < 1;
 		}else{
@@ -1275,7 +1362,7 @@ export class Renderer {
 				 gl.depthMask(false);
 			 }
 			 
-		}
+		} */
 
 
 		{ // UPDATE UNIFORMS
@@ -1360,7 +1447,6 @@ export class Renderer {
 			}
 
 
-			shader.setUniform1f("size", material.usePanoMap ? Potree.config.material.absolutePanoramaSize * Math.min(window.devicePixelRatio,2) : material.size);//usePanoMap时控制在不大不小的范围内感觉较好,考虑到有的点云稀疏,用大一点的点
 			shader.setUniform1f("maxSize", material.uniforms.maxSize.value);
 			shader.setUniform1f("minSize", material.uniforms.minSize.value);
 
@@ -1368,12 +1454,7 @@ export class Renderer {
 			// uniform float uPCIndex
 			shader.setUniform1f("uOctreeSpacing", material.spacing);
 			shader.setUniform("uOctreeSize", material.uniforms.octreeSize.value);
-
-
-			//uniform vec3 uColor;
-			shader.setUniform3f("uColor", material.color.toArray());
-			//uniform float opacity;
-			shader.setUniform1f("uOpacity", material.usePanoMap ? 1: material.opacity);
+ 
 
 			shader.setUniform2f("elevationRange", material.elevationRange);
 			shader.setUniform2f("intensityRange", material.intensityRange);
@@ -1409,19 +1490,21 @@ export class Renderer {
             //gl.TEXTURE_CUBE_MAP: 34067
             //gl.TEXTURE0=33984 , vnWebGLTexture.target=gl.TEXTURE_2D = 3353
             
-			let vnWebGLTexture = this.textures.get(material.visibleNodesTexture);
-			if(vnWebGLTexture){
-				shader.setUniform1i("visibleNodesTexture", currentTextureBindingPoint);
-				gl.activeTexture(gl.TEXTURE0 + currentTextureBindingPoint);
-				gl.bindTexture(vnWebGLTexture.target, vnWebGLTexture.id);
-				currentTextureBindingPoint++;
-			}
+            let vnWebGLTexture = this.textures.get(material.visibleNodesTexture);//最好搬到renderNodes
+            if(vnWebGLTexture){
+                shader.setUniform1i("visibleNodes", currentTextureBindingPoint); //为何之前写的是"visibleNodesTexture",但和"visibleNodes"效果相同?可shader里只有"visibleNodes"
+                gl.activeTexture(gl.TEXTURE0 + currentTextureBindingPoint);
+                gl.bindTexture(vnWebGLTexture.target, vnWebGLTexture.id);
+                currentTextureBindingPoint++;
+            }  
 
 			let gradientTexture = this.textures.get(material.gradientTexture);
 			shader.setUniform1i("gradient", currentTextureBindingPoint);
 			gl.activeTexture(gl.TEXTURE0 + currentTextureBindingPoint);
 			gl.bindTexture(gradientTexture.target, gradientTexture.id);
-
+            currentTextureBindingPoint++;
+            
+            
 			const repeat = material.elevationGradientRepeat;
 			if(repeat === ElevationGradientRepeat.REPEAT){
 				gl.texParameteri(gradientTexture.target, gl.TEXTURE_WRAP_S, gl.REPEAT);
@@ -1447,7 +1530,10 @@ export class Renderer {
 			gl.bindTexture(matcapTexture.target, matcapTexture.id);
 			currentTextureBindingPoint++;
 
-
+            
+            
+            
+            
 			if (material.snapEnabled === true) {
 
 				{
@@ -1512,8 +1598,6 @@ export class Renderer {
             
             
 
-
-
             //=============add===========
             
             
@@ -1542,34 +1626,29 @@ export class Renderer {
                 //注: three.js我添加了个 _textures,   safeSetTextureCube里主要就是activeTexture和bindTexture
              
             }   
+		}
 
 
-            
-            
-            
-            
-            
-		}
+        viewer.addTimeMark('renderOctree','end') 
 
-		this.renderNodes(octree, nodes, visibilityTextureData, camera, target, shader, params);
+         
+
+        params.currentTextureBindingPoint = currentTextureBindingPoint
+        octrees.forEach(octree=>{  
+            this.renderNodes(octree, nodes || octree.visibleNodes, visibilityTextureData, camera, target, shader, params);
+        })
 
 		gl.activeTexture(gl.TEXTURE2);
 		gl.bindTexture(gl.TEXTURE_2D, null);
-		gl.activeTexture(gl.TEXTURE0);
-        
-        
-        
+		gl.activeTexture(gl.TEXTURE0); 
         //gl.bindTexture(gl.TEXTURE_2D, null); //add
-        
-        
-        
-        
+          
         //add  恢复为不透明(否则renderToCubeMap时的贴图会被渲染成高亮的颜色)
         gl.disable(gl.BLEND);
         gl.depthMask(true);
         gl.enable(gl.DEPTH_TEST);
             //DEPTH_TEST等需要恢复吗
-         
+
         
 	}
     
@@ -1586,7 +1665,7 @@ export class Renderer {
 
 
 	render(scene, camera, target = null, params = {}) {
- 
+
 		const gl = this.gl;
 
 		// PREPARE 
@@ -1596,7 +1675,7 @@ export class Renderer {
 
 		//camera.updateProjectionMatrix();
 		// camera.matrixWorldInverse.invert(camera.matrixWorld);
-
+ 
 		const traversalResult = this.traverse(scene);
         
         //排序
@@ -1617,26 +1696,23 @@ export class Renderer {
             })
         }
         
+         
+		// RENDER
         
+        let mat = traversalResult.octrees[0].material
+         
+        if(Potree.settings.cloudSameMat && viewer.scene.volumes.length == 0 && mat.pointSizeType != PointSizeType.ADAPTIVE && mat.activeAttributeName != "level of detail"){
+            this.renderOctree(traversalResult.octrees, null, camera, target, params);  //所有点云除了个别属性需要在shader中更新,其他都使用第一个点云的材质
+        }else for (const octree of traversalResult.octrees) {  
+            for (const octree of traversalResult.octrees) { 
+                this.renderOctree(octree, octree.visibleNodes, camera, target, params);
+            }  
+		} 
         
+        //if (octree  material.pointSizeType === PointSizeType.ADAPTIVE || material.activeAttributeName === "level of detail") {
+        
+         
         
-		// RENDER
-		for (const octree of traversalResult.octrees) {
-			let nodes = octree.visibleNodes;
-            
-            
-            
-            /* nodes.sort((node1,node2)=>{//姑且
-                
-                let center = node.getBoundingSphere().center.clone().applyMatrix4(octree.matrixWorld)
-                return  
-                
-                
-            }) */
-            
-			this.renderOctree(octree, nodes, camera, target, params);
-		}
-
 
 		// CLEANUP
 		gl.activeTexture(gl.TEXTURE1);
@@ -1645,6 +1721,7 @@ export class Renderer {
 		gl.bindVertexArray(null);
 
 		this.threeRenderer.resetState();
+         
 	}
 
 

+ 1 - 1
src/custom/modules/Particles/ParticleEditor.js

@@ -169,7 +169,7 @@ let ParticleEditor = {
         }
      
         
-        viewer.addEventListener('global_click', click, 10)//add importance:10
+        viewer.addEventListener('global_click', click, {importance:10})//add  importance
         viewer.dispatchEvent({
             type : "CursorChange", action : "add",  name:"addSth"
         });

+ 2 - 0
src/custom/modules/datasetAlignment/Alignment.js

@@ -246,6 +246,8 @@ var Alignment = {
         //pointcloud.matrixWorldNeedsUpdate = true //更新matrixWorld (非计算,直接赋值)
         pointcloud.updateMatrixWorld(true)
         
+        
+        
         if(this.editing){
             Alignment.changeCallBack && Alignment.changeCallBack();
         } 

+ 32 - 7
src/custom/modules/mergeModel/MergeEditor.js

@@ -55,13 +55,13 @@ let MergeEditor = {
     
     init(){  
         { 
-            let ground = this.ground = new InfiniteGridHelper(1, 10000, new THREE.Color('#fff'), 10000, 0.2, 0.3)
+            let ground = this.ground = new InfiniteGridHelper(1, 10000, new THREE.Color('#eee'), 10000, 0.2, 0.3)
             viewer.scene.scene.add(ground) 
             //再加两条线否则在正侧边看不到
-            let line1 = LineDraw.createLine([new THREE.Vector3(-10000, 0, 0),new THREE.Vector3(10000, 0, 0) ], {color:'#666', })
+            let line1 = LineDraw.createLine([new THREE.Vector3(-10000, 0, 0),new THREE.Vector3(10000, 0, 0) ], {color:'#aaa', })
             let line2 = LineDraw.createLine([new THREE.Vector3(0, -10000, 0),new THREE.Vector3(0, 10000, 0) ], {mat:line1.material})
             ground.renderOrder = Potree.config.renderOrders.model + 1//line1.renderOrder + 1  //要比模型低,否则模型透明时效果不对
-            ground.add(line1)
+            ground.add(line1) 
             ground.add(line2)
              
             ground.material.polygonOffset = true //多边形偏移(视觉上没有移动模型位置),防止闪烁
@@ -229,7 +229,7 @@ let MergeEditor = {
             }
             
             viewer.addEventListener('global_mousedown',  drag) 
-            viewer.addEventListener('global_drag', drag, 10)
+            viewer.addEventListener('global_drag', drag, {importance:10})
             viewer.addEventListener('global_mousemove', (e)=>{
                 if(this.split && this.transformState && !e.drag && (e.hoverViewport.name == 'top' ||  this.transformState == 'translate')){
                     
@@ -408,6 +408,7 @@ let MergeEditor = {
                 dispose(e) 
             })
             viewer.objs.remove(model)
+            this.updatePointQuality()
         }   
         
         
@@ -649,11 +650,35 @@ let MergeEditor = {
         isRoot && (model.opacity = opacity)//记录在最外层
 
         
-    }
-    
-    
+    },
     
     
+    updatePointQuality(){
+        
+        let posCount=0, gltfCount=0     //gltf的怎么获取模型复杂度?暂时只根据个数吧
+        viewer.objs.children.forEach(e=>{
+            if(e.name == 'glb' || e.name == 'obj'){
+                e.traverse((mesh)=>{
+                    if(mesh.geometry){
+                        posCount += mesh.geometry.attributes.position.count
+                    }
+                })
+            }else if(e.name == 'gltf'){
+                gltfCount ++
+            }
+        })
+        let score = posCount + gltfCount * 5000
+        let min = 3, max = 5, minP = 20000, maxP = 1000000;
+        let ratio = max - ( max - min) * THREE.Math.clamp((score - minP)  / (maxP - minP),0,1)  
+                
+        
+        
+        Potree.pointBudget = ratio*1000*1000
+        
+        
+        
+        
+    },
 }   
     
     

+ 67 - 33
src/custom/modules/panoEdit/panoEditor.js

@@ -11,7 +11,7 @@ import {transitions, easing, lerp} from '../../utils/transitions.js'
 import {TransformControls} from "../../objects/tool/TransformControls.js";
 import SplitScreen from "../../utils/SplitScreen.js"
 import DepthBasicMaterial from "../../materials/DepthBasicMaterial.js";
-
+import {BoxVolume} from '../../../utils/VolumeNew.js'
 
 
 let clickPanoToDisLink = false;//是否在编辑漫游点连接时,通过点击漫游点能断开连接
@@ -114,6 +114,17 @@ class PanoEditor extends THREE.EventDispatcher{
         this.initViews()
         
         
+        
+        /* {
+            this.box = new BoxVolume({
+                clip:true 
+            }) 
+            this.box.clipTask = ClipTask['SHOW_INSIDE_Big'  ]
+             
+            this.box.name = "panoEditClipBox"; 
+             
+        } */
+        
         viewer.addEventListener('allLoaded',()=>{
             images360 = viewer.images360 
             Alignment = viewer.modules.Alignment 
@@ -183,11 +194,7 @@ class PanoEditor extends THREE.EventDispatcher{
                 })
             }
             
-            
-            
-            
-            
-            
+             
             
             this.initPanoLink() 
             
@@ -195,24 +202,44 @@ class PanoEditor extends THREE.EventDispatcher{
             
             
             viewer.scene.pointclouds.forEach(e=>{
-                e.material.color = pointColor.default 
-                 
-            })
-            
+                e.material.color = pointColor.default  
+            }) 
+            viewer.setEDLEnabled(true) //为了降一倍的绘制. 同时用描边增强立体感,弥补点云稀疏
+            viewer.setEDLRadius(3)
+            viewer.setEDLStrength(0.02)
             
             
             
             this.switchView('top')
             
-            SiteModel.bus.addEventListener('initDataDone',()=>{ 
-                let floor = SiteModel.entities.find(e=>e.buildType == 'floor' && e.panos.length) //选择有漫游点的一层
-                if(!floor){
-                    floor = 'all'  //SiteModel.entities.find(e=>e.buildType == 'floor')
-                    console.log('没有一层有漫游点?!')
+            {//默认选择一个楼层
+                let panoVisiReady, siteModelReady;
+                let floorInit = ()=>{
+                    if(!panoVisiReady || !siteModelReady)return
+                    setTimeout(()=>{
+                        if(this.currentFloor == 'all'){//还未选择楼层的话
+                            let floor = SiteModel.entities.find(e=>e.buildType == 'floor' && e.panos.length) //选择有漫游点的一层
+                            if(!floor){
+                                floor = 'all'  //SiteModel.entities.find(e=>e.buildType == 'floor')
+                                console.log('没有一层有漫游点?!')
+                            }
+                            console.log('initDataDone') 
+                        
+                            console.log('gotoFloor 1') 
+                            this.gotoFloor(floor)
+                        }
+                    },1) //2d那边用了nextTick ,so setTimeout here
                 }
-                this.gotoFloor(floor)  
-            })
-             
+                
+                SiteModel.bus.addEventListener('initDataDone',()=>{ 
+                    siteModelReady = true;
+                    floorInit() 
+                },{once:true})
+                this.addEventListener('panoVisiReady',()=>{//2d初始化完成,才可以由3d修改pano显示 (因为在之前2d会给每个pano传来显示的消息,在这之前的修改都会别覆盖)
+                    panoVisiReady = true 
+                    floorInit()
+                },{once:true})   
+            }
             
             Alignment.bus.addEventListener('switchHandle', this.updateCursor.bind(this))
             
@@ -324,6 +351,7 @@ class PanoEditor extends THREE.EventDispatcher{
     
     
     setTranMode(mode){//rotate or translate 
+        console.log('setTranMode',mode)
         this.tranMode = mode
         if(this.activeViewName == 'mainView'){
             mode && this.transformControls.setMode(mode)
@@ -393,13 +421,14 @@ class PanoEditor extends THREE.EventDispatcher{
         view.position.copy(this.splitScreenTool.getPosOutOfModel(viewer.mainViewport))
         if(view.zoom)camera.zoom = view.zoom//恢复上次的zoom
          
+       
         
         viewer.updateScreenSize({forceUpdateSize:true})//更新camera aspect  left等
         this.updateCursor()
          
         if(name == 'mainView'){ 
             viewer.mainViewport.alignment =  null
-             
+            
             let changeMat = ()=>{
                 viewer.scene.pointclouds.forEach(e=>{
                     e.material.activeAttributeName = 'rgba' 
@@ -407,15 +436,15 @@ class PanoEditor extends THREE.EventDispatcher{
                     e.changePointOpacity(1 )  
                 })
             }
-            if(prop.openCount == 0){ //点数较多时,首次转到3D视角会卡顿,因为要切换材质。
+            /* if(prop.openCount == 0){ //点数较多时,首次转到3D视角会卡顿,因为要切换材质。
                 let delay1 = THREE.Math.clamp(viewer.scene.pointclouds.length*0.5, 1, 200) 
                 setTimeout(()=>{
                     this.activeViewName == 'mainView' && changeMat() 
                 },delay1)  
                 //console.log('switchview',delay1 )
-            }else{
+            }else{ */
                 changeMat() 
-            }
+            //}
             
              
             
@@ -521,13 +550,15 @@ class PanoEditor extends THREE.EventDispatcher{
             
             viewer.scene.pointclouds.forEach(e=>{
                 e.material.activeAttributeName = 'color' 
-                e.material.useFilterByNormal = true  //defines :  use_filter_by_normal  attenuated_opacity
+                e.material.useFilterByNormal = true   
                       
                 let opaProp = name == 'top' ? opacitys.topView : opacitys.sideView 
-                if(this.selectedPano && this.selectedClouds.includes(e) /* this.selectedPano.pointcloud == e */){
+                if(this.selectedPano && this.selectedClouds.includes(e) ){
                     e.changePointOpacity(opaProp.selected,true)
+                    e.material.color = pointColor.selected;  
                 }else{
                     e.changePointOpacity(opaProp.default,true)
+                    e.material.color = pointColor.default; 
                 }
                 
             })
@@ -612,7 +643,7 @@ class PanoEditor extends THREE.EventDispatcher{
     }
      
      
-    gotoFloor(floor, force, duration = 600, informBy2d, fitBound){// 选择不同楼层, 切换点位显示。   'all'为全部显示
+    gotoFloor(floor, force, duration = 600, informBy2d, fitBound=true){// 选择不同楼层, 切换点位显示。   'all'为全部显示
         
         floor = floor || 'all' 
    
@@ -663,9 +694,9 @@ class PanoEditor extends THREE.EventDispatcher{
         
         this.currentFloor = floor
         
-        if(!informBy2d){
+        //if(!informBy2d){ //注释原因:2d居然不会自己变
             this.dispatchEvent({type:'changeFloor', floor})
-        }
+        //}
     }
      
     getPanosBound(floor){
@@ -685,6 +716,7 @@ class PanoEditor extends THREE.EventDispatcher{
     
     
     switchPanoVisible(pano, v, informBy2d){ 
+        //console.log(pano.id,v)
         pano.circle.visible = v   
         Potree.Utils.updateVisible(pano, 'panoEditor', v)
         Potree.Utils.updateVisible(pano.pointcloud, 'panoEditor', v)
@@ -695,7 +727,8 @@ class PanoEditor extends THREE.EventDispatcher{
             index>-1 && this.visiblePanos.splice(index,1)
         }
         
-        if(informBy2d){
+        if(informBy2d){ 
+            this.dispatchEvent('panoVisiReady')
             this.updateLinesVisible()
         }
          
@@ -1232,7 +1265,7 @@ class PanoEditor extends THREE.EventDispatcher{
         let percent2 = maxPer - ( maxPer - minPer) * THREE.Math.clamp((visiCount2 - minCount)  / (maxCount - minCount),0,1)   
         let percent = percent1*percent2
         
-        if(this.activeViewName == 'mainView'){
+        if(this.activeViewName == 'mainView' ){  
             //假设每个pointcloud所带的点个数大致相同,那么当可见点云个数越多,所能展示的level越低,否则因总个数超过budget的话密度会参差不齐。
             
             //pointcloud.changePointSize()
@@ -1243,10 +1276,11 @@ class PanoEditor extends THREE.EventDispatcher{
             Potree.settings.UserDensityPercent = 1 
             viewer.setPointBudget(maxBudget * percent) 
         }
-         
-        viewer.setPointLevels() 
+        viewer.setPointBudget(maxBudget * percent)  
         
-        console.warn('setPointBudget', Potree.pointBudget, visiCount1,visiCount2,  Potree.settings.UserDensityPercent)
+        viewer.setPointLevels() 
+        //侧面容易卡顿,但和显示的点数无关,似乎是因加载点云多而卡?为何正面不会
+        //console.warn('setPointBudget', Potree.pointBudget, visiCount1,visiCount2,  Potree.settings.UserDensityPercent)
     }
     
     getPanoRtkState(pano){
@@ -1297,7 +1331,7 @@ class PanoEditor extends THREE.EventDispatcher{
             group = this.panoGroup.find(panos=>panos[0].pointcloud.dataset_id == datasetId )
             if(!group)return //要找的数据集的pano全部都孤立了
         }
-        if(!datasetId)return
+        if(datasetId == void 0)return
         let panos = Potree.settings.datasetsPanos[datasetId].panos
         return panos.length == group.length
     }

+ 9 - 2
src/custom/modules/panos/DepthImageSampler.js

@@ -32,8 +32,15 @@ class DepthImageSampler {
     getDepth(UVx, UVy) {//根据图片像素获取深度值 
         var x = Math.round(UVx * (this.canvas.width - 1))
           , y = Math.round(UVy * (this.canvas.height - 1));
-        if (!(x < 0 || y < 0 || x >= this.canvas.width || y >= this.canvas.height)) {
-            var r = this.context.getImageData(x, y, 1, 1).data;
+        if (!(x < 0 || y < 0 || x >= this.canvas.width || y >= this.canvas.height)) { 
+         
+            viewer.addTimeMark('depthSampler','start')
+            
+            var r = this.context.getImageData(x, y, 1, 1).data;     //pc chrome 耗时0.01毫秒左右(排除第一次的50) , 但firefox: 4。  
+            
+            viewer.addTimeMark('depthSampler','end')
+            
+             
             //console.log('color', r, x,y)
             return r[1] + r[0] / 256
         }

+ 49 - 54
src/custom/modules/panos/Images360.js

@@ -243,13 +243,13 @@ export class Images360 extends THREE.EventDispatcher{
         
         {//切换模式
             let displayMode = '';  
-            let latestRequestMode = '';//因为可能延迟,所以记录下每次的请求模式,延迟后判断这个
+            this.latestRequestMode = '';//因为可能延迟,所以记录下每次的请求模式,延迟后判断这个
             Object.defineProperty(Potree.settings , "displayMode",{  
                 get: function() {
                     return displayMode
                 },
                 set:  (mode)=> {
-                    latestRequestMode = mode
+                    this.latestRequestMode = mode
                     console.warn('Request setMode: ' + mode)  
                                    
                     if(mode != displayMode){ 
@@ -258,7 +258,7 @@ export class Images360 extends THREE.EventDispatcher{
                         let camera = viewer.scene.getActiveCamera()
                         if(mode == 'showPanos' && viewer.mainViewport.view.isFlying()){//飞完才能切换全景 
                             let f = ()=>{
-                                if(latestRequestMode == mode){//如果ui还是停在这个模式的话
+                                if(this.latestRequestMode == mode){//如果ui还是停在这个模式的话
                                     Potree.settings.displayMode = mode 
                                 }
                                 viewer.mainViewport.view.removeEventListener('flyingDone', f)
@@ -279,7 +279,7 @@ export class Images360 extends THREE.EventDispatcher{
                                 let wait = (e)=>{
                                     this.removeEventListener('flyToPanoDone',wait) 
                                     setTimeout(()=>{
-                                        if(latestRequestMode == mode ){
+                                        if(this.latestRequestMode == mode ){
                                             Potree.settings.displayMode = mode 
                                         } 
                                     },e.makeIt ? 1 : 50) 
@@ -290,7 +290,7 @@ export class Images360 extends THREE.EventDispatcher{
                                     //dealDoneWhenCancel:true,
                                     /* callback: ()=>{ 
                                         setTimeout(()=>{ //防止循环,所以延迟
-                                           if(latestRequestMode == mode ){
+                                           if(this.latestRequestMode == mode ){
                                                 Potree.settings.displayMode = mode 
                                             } 
                                         },1)  
@@ -316,7 +316,7 @@ export class Images360 extends THREE.EventDispatcher{
                             let wait = (e)=> {
                                 if(e.pano && e.pano != this.currentPano)return//loadedDepthImg
                                 setTimeout( ()=>{
-                                    if(latestRequestMode == mode ){
+                                    if(this.latestRequestMode == mode ){
                                         Potree.settings.displayMode = mode 
                                     }
                                 },1)
@@ -860,6 +860,8 @@ export class Images360 extends THREE.EventDispatcher{
         
         this.cubePanos = [pano0, pano1]
         
+        viewer.addTimeMark('updateCube','start')
+         
         //console.log('updateCube',pano0.id, pano1&&pano1.id)
         
         let useBound = (bound, size)=>{ 
@@ -895,20 +897,26 @@ export class Images360 extends THREE.EventDispatcher{
             let score = (1+sin*3) * dis //score越大创建的mesh越不适合
             //console.log('dis',dis, this.isNeighbour(pano0, pano1), score) 
             //如果存在不含深度图的就直接useBound 
+            
+            let depthTiming = Potree.timeCollect.depthSampler.median    //pc firefox达到4.  chrome为0.01
+            
             if(!pano0.pointcloud.hasDepthTex || !pano1.pointcloud.hasDepthTex || (this.isNeighbour(pano0, pano1) ? score > 1000 : score > 100) ){  
                 let bound = getPanoBound(pano0).union(getPanoBound(pano1))
                 let size = bound.getSize(new THREE.Vector3) 
                 let max = Math.max(size.x, size.y, size.z) 
                 size.set(max,max,max)        //距离太远的数据集,过渡会畸变。所以扩大skybox,且为立方体
                 return useBound(bound, size)
-            }else if(this.isNeighbour(pano0, pano1) ? score > 200 : score > 15 ){
+            }else if(depthTiming > 1 || (this.isNeighbour(pano0, pano1) ? score > 200 : score > 15)){
                 dontAddSides = true //pano间有阻挡时得到的side点可能使通道变窄,所以去掉。
             }
             //俯仰角增大时可能不在同一楼层,算出来的mesh不太好,所以更倾向直接使用cube,或去除side。
              
-            
-             
-            const half = pano0.pointcloud.hasDepthTex && pano0.pointcloud.hasDepthTex ?  6  : (browser.isMobile() ? 2 : 3)  //自行输入  (点云计算的慢,还不准) 
+            let half            //6  : (browser.isMobile() ? 2 : 3)  //自行输入  (点云计算的慢,还不准) 
+            {
+                let min = 3,max = 6, minTime = 0, maxTime = 3
+                half = max - ( max - min) * THREE.Math.clamp((depthTiming - minTime)  / (maxTime - minTime),0,1)  
+                half = Math.round(half)
+            } 
             let count1 = 2*half//偶数个 每个pano向 外dir 个数 
             //奇数个的好处:在窄空间内能探测到最远距离,坏处是前方有尖角。偶数个的坏处就是可能检测距离太近。
             
@@ -941,15 +949,12 @@ export class Images360 extends THREE.EventDispatcher{
                     deg = THREE.Math.clamp(deg, 1,  80);
                     return Math.tan(THREE.Math.degToRad(deg))
                 }
-                let dirs_ = [
-                    //注意:角度太大会碰到天花板或地板,越远越容易碰到, 在地下停车场就会伸展不开。 户外时需要更多向上的方向,所以上方向多一个
-                    dir.clone().setZ(getZ(35)).normalize(), 
-                    dir.clone().setZ(getZ(20)).normalize(), 
-                    dir.clone().setZ(getZ(7)).normalize(), 
-                    dir.clone(),            // 水平方向
-                    dir.clone().setZ(-getZ(5)).normalize(), 
-                    //dir.clone().setZ(-Math.tan(THREE.Math.degToRad(30))).normalize(), 
-                ]; 
+                let dirs_  //注意:角度太大会碰到天花板或地板,越远越容易碰到, 在地下停车场就会伸展不开。 户外时需要更多向上的方向,所以上方向多一个
+                if(depthTiming > 2) dirs_ = [35,0,-5]
+                else if(depthTiming > 0.5) dirs_ = [35,10,0,-5]
+                else dirs_ = [35,20,7, 0,-5] 
+                dirs_ = dirs_.map(deg=> dir.clone().setZ(getZ(deg)).normalize() )
+              
                 
                 let max = 50
                 let count2 = dirs_.length
@@ -977,14 +982,20 @@ export class Images360 extends THREE.EventDispatcher{
                 }else{//天花板高度值
                     //用三个间隔120度散开,和中心垂直线成一定夹角的三个向量去求 最高高度 (不求平均的原因:万一是0不好算)
                     let rotMat = new THREE.Matrix4().makeRotationX(THREE.Math.degToRad(40))// 角度不能小于天花板中空的半径,大概就是0.2*Math.PI=36度
-                    let dir1 = new THREE.Vector3(0,0,1).applyMatrix4(rotMat)
-                    let rotMat1 = new THREE.Matrix4().makeRotationZ(Math.PI*2 / 3);
-                    let rotMat2 = new THREE.Matrix4().makeRotationZ(-Math.PI*2 / 3);
+                     
+                    let dirs = [new THREE.Vector3(0,0,1).applyMatrix4(rotMat)];
+                    if(depthTiming < 1){
+                        let rotMat1 = new THREE.Matrix4().makeRotationZ(Math.PI*2 / 3);
+                        dirs.push(dirs[0].clone().applyMatrix4(rotMat1))
+                    }
+                    if(depthTiming < 0.3){
+                        let rotMat2 = new THREE.Matrix4().makeRotationZ(-Math.PI*2 / 3);
+                        dirs.push(dirs[0].clone().applyMatrix4(rotMat2)); 
+                    }
+                    
                     
-                    let dir2 = dir1.clone().applyMatrix4(rotMat1)
-                    let dir3 = dir1.clone().applyMatrix4(rotMat2)
                     let skyHeight = 50
-                    let zs = [dir1,dir2,dir3].map(dir_=>{ 
+                    let zs = dirs.map(dir_=>{ 
                         let intersect = getIntersect(pano, dir_) 
                         let z = intersect ? intersect.location.z : pano.position.z+skyHeight //没有intersect代表可能是天空
                         return z 
@@ -1089,13 +1100,8 @@ export class Images360 extends THREE.EventDispatcher{
                     let dir = e.dir.clone().multiplyScalar(e.disB || e.dis);
                     [maxZ,minZ].forEach(z=>{  
                         posArr.push(pano.position.clone().setZ(z).add(dir))  //获取到外墙点
-                    })   
-                        
-                     
-                }); 
-                
-                              
-                                 
+                    })  
+                });                 
             }
             
             
@@ -1105,22 +1111,7 @@ export class Images360 extends THREE.EventDispatcher{
                 let midMaxZ = (pano0.ceilZ + pano1.ceilZ)/2
                 let midMinZ = (pano0.floorPosition.z+pano1.floorPosition.z)/2;
                 let mid = new THREE.Vector3().addVectors(pano0.position, pano1.position).multiplyScalar(0.5)
-                
-                /* let sideDis_ = [(sideDis0[0] + sideDis1[1])/2,  (sideDis0[1] + sideDis1[0])/2];
-                let sideDis = [Math.min(sideDis0[0] , sideDis1[1]),  Math.min(sideDis0[1] , sideDis1[0])]//
-                 */
-                /* let maxH = 40, minH = 2, height = pano.ceilZ - pano.floorPosition.z, minR = 0.5, maxR = 2  
-                 
-                let r = minR + ( maxR - minR) * THREE.Math.clamp((height - minH)  / (maxH - minH),0,1)   //THREE.Math.smoothstep(currentDis,  op.nearBound,  op.farBound);
                  
-                let getZ = (deg)=>{
-                    deg *= r 
-                    deg = THREE.Math.clamp(deg, 1,  80);
-                    return Math.tan(THREE.Math.degToRad(deg))
-                }
-                 */
-             
-                
                 if(!dontAddSides){ 
                     if( pano0.pointcloud.hasDepthTex && pano0.pointcloud.hasDepthTex){
                         let panos = [pano0,pano1]
@@ -1136,8 +1127,7 @@ export class Images360 extends THREE.EventDispatcher{
                             //console.log('angle',angle)  
                             return THREE.Math.degToRad(angle)
                         })     
-                      
-                        //let angles = [THREE.Math.degToRad(40), THREE.Math.degToRad(70)] 
+                       
                         axis.forEach((axis_, index0)=>{
                             let disToSides = []
                             let accordingPano = index0 == 0 ? pano0 : pano1; //根据离该点在vec方向上的距离顺序来存顶点
@@ -1305,16 +1295,22 @@ export class Images360 extends THREE.EventDispatcher{
             useBound(getPanoBound(pano0)) 
             
         }
+        
+        viewer.addTimeMark('updateCube','end')
     } 
 
     /* 
         关于卡顿:
         即使使用cube,若scale设置为只容纳两个pano,也会卡顿。但也是有的卡有的不卡。
         若按照原先的复杂geo,一般在平直的街道上行走流畅,经过拐弯或者复杂区域较卡。减小geo复杂度没有什么作用。
-
-    */
-    /* 
+        
+     
         注: 修改skybox,若不准的话,会遮住其他mesh,比如marker。尤其在没有深度贴图时。 
+        
+        
+        耗时: chrome: 20+ ,但是firefox:500+  咋回事 ?    iphonex safari: 40+
+        
+        
      */
 
 
@@ -1845,8 +1841,7 @@ export class Images360 extends THREE.EventDispatcher{
     
     
     
-	update(){
- 
+	update(){ 
         if(this.tileDownloader.started){
             
             var vectorForwards = this.getTileDirection()

+ 48 - 9
src/custom/modules/panos/tile/PanoRenderer.js

@@ -7,9 +7,8 @@ import {settings,config} from '../../../settings.js'
 /* import config from '../../config' */
 import * as THREE from "../../../../../libs/three.js/build/three.module.js"; 
 import math from '../../../utils/math.js' 
-import browser from '../../../utils/browser.js'
- 
- 
+import browser from '../../../utils/browser.js' 
+import Common from '../../../utils/Common.js'
 let {PanoSizeClass, PanoRendererEvents , Vectors,SceneRendererEvents,TileDownloaderEvents, GLCubeFaces} = Potree.defines
  
 
@@ -26,7 +25,7 @@ function createDescriptor() {
 
       
 
-function upload() { 
+/* function upload() { 
     if (!this.uploadIntervalCancelled) {
         if (this.overlayTilesLoaded || !this.usingTileOverlay) {
             b = !0   
@@ -38,7 +37,7 @@ function upload() {
             this.refreshUploadInterval(this.uploadIntervalDelay)
         }
     }
-}
+} */
 
 var b = !1,
     w = config.tiling.uploadIntervalDelay,
@@ -63,7 +62,7 @@ class PanoRenderer extends THREE.EventDispatcher{
         this.forceQueue = [];
         this.uploadQueues = {};
         this.uploadInterval = null;
-        this.uploadIntervalCancelled = !1;
+        this.uploadIntervalCancelled = true//!1;
         this.usingTileOverlay = !1;
         this.overlayTilesLoaded = !1;
         this.overlayTileBase = null;
@@ -831,7 +830,9 @@ PanoRenderer.prototype.getNextFromUploadQueue = function () {
         return t && t.length > 0 ? e(t) : null
     }
 }()
-PanoRenderer.prototype.refreshUploadInterval = function () {
+
+
+/* PanoRenderer.prototype.refreshUploadInterval = function () {
     var e = null;
     return function (t) {
         this.uploadIntervalCancelled || (e || (e = upload.bind(this)),
@@ -840,7 +841,7 @@ PanoRenderer.prototype.refreshUploadInterval = function () {
             this.uploadInterval = window.setTimeout(e, t),
             this.uploadIntervalDelay = t)
     }
-}()
+}()  
 
 PanoRenderer.prototype.update = function () {
     var e = performance.now(),
@@ -858,7 +859,45 @@ PanoRenderer.prototype.update = function () {
         }
         t++;
     }
-}()
+}() */
+
+
+
+
+
+
+PanoRenderer.prototype.update = function () {
+    //this.uploadIntervalCancelled = true ; //不使用setTimeout,而是在sceneRenderer每帧都update
+    
+    if(viewer.images360.latestRequestMode == 'showPanos'){  
+        let maxNonBaseUploadsPerFrame = viewer.lastFrameChanged ? Common.getBestCount('maxStandard', 1,  2, undefined, undefined /* ,true  */) : 2  //this.maxNonBaseUploadsPerFrame //原先2。这是每帧uploadTile非512的瓦片tex的数量。之前的2太卡了,降为1。(检测卡顿方法:在一个pano点旋转至所有2048的tile都加载完,然后之后到这个点看看卡不卡。因为该点tiles都下载完了所以会在飞过来时陆续都加载,所以容易卡)
+        let maxBaseUploadsPerFrame = viewer.lastFrameChanged ? Common.getBestCount('maxBase',1,6,     2, 20  /* ,true */ ) : 6 //this.maxBaseUploadsPerFrame //原先6. 但持续前进过程中会请求加载下一个漫游图,一次加6张会卡的。
+         
+        this.updateUploadQueue(maxNonBaseUploadsPerFrame, maxBaseUploadsPerFrame) 
+        
+        //注:静止时看不出卡顿所以全速加载
+    }
+} 
+
+
+
+/* function upload() { 
+    if (!this.uploadIntervalCancelled) {
+        if (this.overlayTilesLoaded || !this.usingTileOverlay) {
+            b = !0   
+            let maxNonBaseUploadsPerFrame = viewer.mainViewport.view.isFlying() ? 1 : this.maxNonBaseUploadsPerFrame //原先2。这是每帧uploadTile非512的瓦片tex的数量。之前的2太卡了,降为1。(检测卡顿方法:在一个pano点旋转至所有2048的tile都加载完,然后之后到这个点看看卡不卡。因为该点tiles都下载完了所以会在飞过来时陆续都加载,所以容易卡)
+            this.updateUploadQueue(maxNonBaseUploadsPerFrame, this.maxBaseUploadsPerFrame) 
+            let time = viewer.mainViewport.view.isFlying() ? 60 : w  //add 飞行有时候会卡,增长间隔 
+            this.peekNextFromUploadQueue() ? this.refreshUploadInterval(time) : this.uploadInterval = null  //定时下一次更新
+        } else {
+            this.refreshUploadInterval(this.uploadIntervalDelay)
+        }
+    }
+} */
+
+
+
+
 PanoRenderer.prototype.uploadTile = function () {//重写
     var collection = {},
         overlayStyle = config.tiling.overlayStyle;

+ 35 - 23
src/custom/modules/panos/tile/TileDownloader.js

@@ -69,7 +69,7 @@ class TileDownloader extends THREE.EventDispatcher{
             Potree.Utils.updateVisible(this,'showPanos', true )
             this.judgeStart()            
         }else{
-            this.refreshInterval || this.judgeStart()
+            //this.refreshInterval || this.judgeStart()
         }
     }
 
@@ -85,30 +85,38 @@ class TileDownloader extends THREE.EventDispatcher{
         if(this.visible){
             //console.log('judgeStart true')
             this.started = true 
-            this.refreshUpdateInterval(0)
+            //this.refreshUpdateInterval(0)
         }else{
             //console.log('judgeStart false')
             this.started = false
-            window.clearTimeout(this.refreshInterval)
+            //window.clearTimeout(this.refreshInterval)
         }
         
     }
 
-    refreshUpdateInterval(e) {
+    /* refreshUpdateInterval(e) {
         e || (e = 0),
             this.refreshInterval = window.setTimeout(function() {
                     var e = this.update();
                     e ? this.refreshUpdateInterval(TileDownloader.ACTIVE_REFRESH_DELAY) : this.refreshUpdateInterval(TileDownloader.IDLE_REFRESH_DELAY)
                 }
                 .bind(this), e)
-    }
+    } */
 
     update() { 
         if(this.downloadCubeTex){ //可以下载贴图
             var e = this.forceQueue.length > 0;
             this.processQueueForDownloading(this.forceQueue);
-            if (this.processPriorityQueue) {
-                this.queuePrioritizedTilesForPanos(this.panos);
+            if (this.processPriorityQueue) { 
+                this.needPrioritize = true
+                Potree.Common.intervalTool.isWaiting('processPriorityQueue', ()=>{ //延时update,防止崩溃 , 未到时间就拦截(第一次直接执行)
+                    if(this.needPrioritize && this.downloadCubeTex){
+                        this.needPrioritize = false
+                        this.queuePrioritizedTilesForPanos(this.panos)   //这句比较耗时 降四倍时大概1-2毫秒
+                        return true  
+                    }
+                }, 66)
+                
                 this.priorityQueue.length > 0 && (e = !0);
                 this.processQueueForDownloading(this.priorityQueue);
             }
@@ -176,25 +184,29 @@ class TileDownloader extends THREE.EventDispatcher{
 
     processQueueForDownloading(e, t) {//执行下载任务
         this.cleanupActiveDownloads();
-        if (this.activeDownloads.length < this.concurrentDownloads || t) {
-            var i = t ? e.length : this.concurrentDownloads - this.activeDownloads.length;
+        if(e.length){
+            let concurrentDownloads = Potree.Common.getBestCount('concurrentDownloads',1,6,    1.8, 14/* ,true */) //flying ? (isMobile ? 2 : 3) : 6 
+            
+            if (this.activeDownloads.length < concurrentDownloads || t) {
+                var i = t ? e.length : concurrentDownloads - this.activeDownloads.length;
 
-            for (var n = 0, r = 0; n < i && e.length > 0; r++) {
-                var o = e.shift();
-                
-                
-                if(o){
-                    //add 为了防止1024的在512前下载完,这里强行等待512下载完毕再开始下载
-                    if(o.panoSize > 512 && !this.isPanoDownloaded(o.pano, 512) ){
-                        //console.log('512的还没下载好呢!')
-                        e.push(o)
-                        break;//一般512的都是连续下载的,所以后面就都不是512了直接中断 
-                    } 
+                for (var n = 0, r = 0; n < i && e.length > 0; r++) {
+                    var o = e.shift();
+                    
+                    
+                    if(o){
+                        //add 为了防止1024的在512前下载完,这里强行等待512下载完毕再开始下载
+                        if(o.panoSize > 512 && !this.isPanoDownloaded(o.pano, 512) ){
+                            //console.log('512的还没下载好呢!')
+                            e.push(o)
+                            break;//一般512的都是连续下载的,所以后面就都不是512了直接中断 
+                        } 
+                        
+                        this.startDownload(o)
+                        n++
+                    }
                     
-                    this.startDownload(o)
-                    n++
                 }
-                
             }
         }
     } 

+ 3 - 2
src/custom/modules/panos/tile/TilePrioritizer.js

@@ -210,8 +210,8 @@ TilePrioritizer.prototype.filterDepthTex = function (panos ) {//仅下载depthTe
     let t = [] 
     //获得视野范围内的邻近点位序列t
     this.populateScoredPanos(this.priorityCriteria.pano, panos, t, cameraDirLocals , TilePrioritizer.MAX_SCORED_PANOS_TOCONSIDER);
+    t.filter(p=>!p.depthTex).slice(0, Potree.config.depTexDlCount).forEach(p=>p.loadDepthImg()) //add
     
-    t.forEach(p=>p.loadDepthImg()) 
 }
 
 
@@ -239,7 +239,8 @@ TilePrioritizer.prototype.filterAndPrioritize = function () {//挑选出优先
         //获得视野范围内的邻近点位序列t
         this.populateScoredPanos(this.priorityCriteria.pano, panos, t, cameraDirLocals , TilePrioritizer.MAX_SCORED_PANOS_TOCONSIDER);
         
-        t.forEach(p=>p.loadDepthImg()) //add
+        
+        t.filter(p=>!p.depthTex).slice(0, Potree.config.depTexDlCount).forEach(p=>p.loadDepthImg()) //add
         
         var s = this.baseSize //512
             ,

+ 8 - 6
src/custom/modules/route/RouteGuider.js

@@ -11,7 +11,7 @@ const arrowSize = arrowSpacing * 0.5
 const planeGeo = new THREE.PlaneBufferGeometry(1,1);
 
 const sphereSizeInfo = {
-      nearBound : 2, scale:arrowSize, restricMeshScale : true,
+      nearBound : 0.1,   farBound:25, minSize : 50,  maxSize : 200 //scale:arrowSize, restricMeshScale : true,
 }
 //const arrowsShowingCount = 25; //场景里最多展示多少个箭头
 const arrowShowMinDis = 10
@@ -191,24 +191,24 @@ export class RouteGuider extends THREE.EventDispatcher{
     
     
     createPole(polesMats, name){
-        const height = 1.5, sphereCount = 6, shadowSize = sphereSizeInfo.scale,  sphereSize = 0.04
+        const height = 1.5, sphereCount = 6, shadowSize = 0.5 /* sphereSizeInfo.scale */,  sphereSize = 0.05
         
         var group = new THREE.Object3D;
             group.name = 'pole_'+name
-        var shadow = new THREE.Mesh(planeGeo,polesMats.shadowMat)
+        var shadow = new THREE.Mesh(planeGeo, polesMats.shadowMat)
         shadow.scale.set(shadowSize,shadowSize,shadowSize)
         var sliceDis = height / (sphereCount+1);
         group.add(shadow) 
          
         for(let i=0;i<sphereCount;i++){
-            var sphere = new Sprite({mat: polesMats.sphereMat}) 
+            var sphere = new Sprite({mat: polesMats.sphereMat, renderOrder:3}) 
             sphere.position.set(0,0,sliceDis*(i+1))
             sphere.scale.set(sphereSize,sphereSize,sphereSize);
             sphere.visible = false
             group.add(sphere)
         }
         
-        var hatSphere = new Sprite({mat: polesMats.hatMats[name], sizeInfo:sphereSizeInfo}) 
+        var hatSphere = new Sprite({mat: polesMats.hatMats[name], sizeInfo:sphereSizeInfo, renderOrder:4}) 
         sphere.visible = false
         hatSphere.position.set(0,0,height)
         hatSphere.scale.copy(shadow.scale)
@@ -644,5 +644,7 @@ export class RouteGuider extends THREE.EventDispatcher{
     存在的问题:
     路径不准确。起始点和终点偏移。
 
-
+    https://uat-laser.4dkankan.com/routeDebug/   可查整个map的通路点位图
+    
+    
  */

+ 1 - 1
src/custom/objects/InfiniteGridHelper.js

@@ -27,7 +27,7 @@ class InfiniteGridHelper extends THREE.Mesh{
                     value: size2
                 },
                 
-                opacity1:{//线条1的
+                opacity1:{//线条1的 小格子
                     value: opacity1
                 },
                 opacity2:{//线条2的

+ 1 - 1
src/custom/objects/Magnifier.js

@@ -208,7 +208,7 @@ export default class Magnifier extends THREE.Object3D {//放大镜or望远镜
         }else{
             Potree.Utils.updateVisible(this, "measure", false) 
             viewer.addEventListener("measureMovePoint",()=>{//测量开始
-                Potree.Utils.updateVisible(this, "measure", true) 
+                //Potree.Utils.updateVisible(this, "measure", true) 
             })
             viewer.addEventListener("endMeasureMove",()=>{
                 Potree.Utils.updateVisible(this, "measure", false) 

+ 6 - 4
src/custom/objects/Sprite.js

@@ -117,10 +117,13 @@ export default class Sprite extends THREE.Mesh{
             
             
             var scale
-            if(info.restricMeshScale){//仅限制最大或最小的话,不判断像素大小,直接限制mesh的scale
+            if(info.nearBound == void 0 && info.farBound != void 0 || info.nearBound != void 0 && info.farBound == void 0){//仅限制最大或最小的话,不判断像素大小,直接限制mesh的scale
+                //这个判断也可以写到getScaleForConstantSize里,可以更严谨控制像素宽度,这里只简单计算大小
                 var dis = camera.position.distanceTo(this.root.getWorldPosition(new THREE.Vector3()))
-                if(dis < info.nearBound){
+                if(info.farBound == void 0 && dis < info.nearBound){
                     scale = info.scale * dis / info.nearBound
+                }else if(info.nearBound == void 0  && dis > info.farBound){
+                    scale = info.scale * dis / info.farBound
                 }else{
                     scale = info.scale
                 }
@@ -128,8 +131,7 @@ export default class Sprite extends THREE.Mesh{
                 scale = math.getScaleForConstantSize($.extend(info,{//规定下最小最大像素 
                     camera , position:this.root.getWorldPosition(new THREE.Vector3()) ,
                     resolution: e.viewport.resolution//2
-                }))
-                
+                })) 
             } 
             
             if(!isNaN(scale)){

+ 2 - 2
src/custom/objects/tool/MeasuringTool.js

@@ -398,7 +398,7 @@ export class MeasuringTool extends THREE.EventDispatcher{
                     if(measure.markers.length>0){
                         measure.markers[0].removeEventListener('mousedown',end)
                         measure.reDraw() 
-                        this.viewer.addEventListener('global_click', click, 10) 
+                        this.viewer.addEventListener('global_click', click, {importance:10})
                         measure.editStateChange(true)
                     }
                     return
@@ -570,7 +570,7 @@ export class MeasuringTool extends THREE.EventDispatcher{
         
         viewer.inputHandler.dispatchEvent({type: 'isMeasuring', v: true, cause:'startInsertion'})
         
-        this.viewer.addEventListener('global_click', click, 10)//add importance:10
+        this.viewer.addEventListener('global_click', click, {importance:10})//add  importance
             
         let ifAtWrongPlace = (e)=>{
             if(measure.unableDragAtMap && e.hoverViewport.name == 'mapViewport' ){ 

+ 1 - 1
src/custom/objects/tool/TagTool.js

@@ -83,7 +83,7 @@ export class TagTool extends THREE.EventDispatcher{
             return {stopContinue:true}
             
         }
-        this.viewer.addEventListener('global_click', click, 10)
+        this.viewer.addEventListener('global_click', click,  {importance:10})
         return deferred.promise()
     }  
     

+ 2 - 2
src/custom/objects/tool/TransformControls.js

@@ -135,8 +135,8 @@ var TransformControls = function ( camera, domElement, options ) {
                 return {stopContinue:true}
             }
         }
-        this.addEventListener('dragging',drag,10)
-        viewer.addEventListener('global_drag',drag,10)
+        this.addEventListener('dragging',drag,{importance:10})
+        viewer.addEventListener('global_drag',drag,{importance:10})
         
 
 	}

+ 57 - 41
src/custom/potree.shim.js

@@ -1,11 +1,10 @@
-// Potree.prototype.addEventListener = function(type, listener, importance=0){ 
-
-// }
+ 
 import * as THREE from "../../libs/three.js/build/three.module.js";
 import math from "./utils/math.js";
 import browser from "./utils/browser.js"; 
 import cameraLight from "./utils/cameraLight.js";
 import {Utils} from "../utils.js";
+import Common from "./utils/Common.js";
 import {BinaryLoader} from "../loader/BinaryLoader.js";
 import {Features} from "../Features.js";
 
@@ -208,7 +207,8 @@ Utils.loadSkybox = function(path, oldSky ) {
         texture.flipY = false 
         texture.magFilter = THREE.LinearFilter
         texture.minFilter = THREE.LinearFilter
-        scene.children[0].material.uniforms.tDiffuse.value = texture        
+        scene.children[0].material.uniforms.tDiffuse.value = texture  
+        viewer.dispatchEvent('content_changed')
     },null,(e)=>{//error
         console.error('loadSkybox失败',path) 
     });
@@ -278,7 +278,7 @@ Utils.getMousePointCloudIntersection = function(viewport, mouse, pointer, camera
     let visiMap = new Map()
     let needsUpdate = false;
     
-    if(pickParams.isMeasuring || Potree.settings.displayMode == 'showPanos'){ //测量或全景模式提高精准度
+    if(pickParams.isMeasuring || Potree.settings.displayMode == 'showPanos') { //(无深度图) 测量或全景模式提高精准度,因为漫游的
         density = Potree.settings.pointDensity 
         Potree.settings.pointDensity = 'magnifier' 
         
@@ -293,8 +293,8 @@ Utils.getMousePointCloudIntersection = function(viewport, mouse, pointer, camera
             e.changePointSize(Potree.config.material.realPointSize*2, true)//更改点云大小到能铺满为止,否则容易识别不到
         }) 
         needsUpdate = true
-    }else{
-        if(viewer.viewports.filter(e=>!e.noPointcloud && e.active).length>1 || pickParams.cameraChanged){
+    }else{ 
+        if(viewer.viewports.filter(e=>!e.noPointcloud && e.active).length>1 || pickParams.cameraChanged){//在pick时相机和渲染时不一样的话 
             viewport.beforeRender && viewport.beforeRender()
             needsUpdate = true //不updatePointClouds的话hover久了会不准 因node是错的
             //但依旧需要camera真的移动到那个位置才能加载出点云
@@ -313,7 +313,7 @@ Utils.getMousePointCloudIntersection = function(viewport, mouse, pointer, camera
     }
     
     if(needsUpdate){
-        Potree.updatePointClouds(pointclouds,  camera, viewport.resolution );
+        Potree.updatePointClouds(pointclouds,  camera, viewport.resolution );  //最好只更新pick的范围的resolution
     }
     //------------------------------------------------
     
@@ -352,7 +352,7 @@ Utils.getMousePointCloudIntersection = function(viewport, mouse, pointer, camera
             }
             e.visible = visiMap.get(e)  
         })
-    }else{
+    }else{ 
         /* if(viewer.viewports.filter(e=>!e.noPointcloud).length>1){
             viewport.afterRender && viewport.afterRender() 
         } */
@@ -955,7 +955,9 @@ ProfileWindow.prototype.initTHREE = function(){
 
 //Potree_update_visibility
 Potree.updatePointClouds =  function(pointclouds,camera, areaSize  ){
- 
+    viewer.addTimeMark('updateClouds','start')
+    
+   
 	for (let pointcloud of pointclouds) {
 		let start = performance.now();
 
@@ -980,6 +982,8 @@ Potree.updatePointClouds =  function(pointclouds,camera, areaSize  ){
 	}
 
 	Potree.lru.freeMemory();//即Potree.lru 能看到所有在加载的node
+    
+    viewer.addTimeMark('updateClouds','end')
 
 	return result;
 };
@@ -990,12 +994,31 @@ Potree.updateVisibilityStructures = function(pointclouds, camera, areaSize) {
 	let camObjPositions = {}
 	let priorityQueue = new BinaryHeap(function (x) { return 1 / x.weight; });//二叉堆。
 
+                
+  
+
+    //camera.updateMatrixWorld();
+    let viewI = camera.matrixWorldInverse;
+    let proj = camera.projectionMatrix; 
+    let view = camera.matrixWorld;
+    let projViewI = new THREE.Matrix4().multiply(proj).multiply(viewI)
+    
+    /* let list = pointclouds  // stopWhenAllUsed = !viewer.lastFrameChanged
+    let min = 5, max = Math.max(20 , Math.round(list.length / 10 )) 
+    let result = Common.batchHandling.getSlice('pcGetFrustum', list, {  min,max, durBound1: 3, durBound2: 10} ) //iphonex稳定后大概在7-10。  
+     */
+    
+    
+    
 	for (let i = 0; i < pointclouds.length; i++) {
 		let pointcloud = pointclouds[i];
 
 		if (!pointcloud.initialized()) {
 			continue;
 		}
+         
+      /*   let info = history.get(pointcloud)
+        if() */
         
         
 		pointcloud.numVisibleNodes = 0;
@@ -1008,41 +1031,39 @@ Potree.updateVisibilityStructures = function(pointclouds, camera, areaSize) {
         // 因漫游模式而隐藏的话 依旧需要加入visibleNodes,因为pick需要
         /* if (pointcloud.visible && pointcloud.root !== null) {
 			priorityQueue.push({pointcloud: i, node: pointcloud.root, weight: Number.MAX_VALUE});
-		}  */                                   
+		}  */    
+       
 		if (pointcloud.visible || !pointcloud.hasDepthTex && pointcloud.unvisibleReasons && pointcloud.unvisibleReasons.length == 1 && pointcloud.unvisibleReasons[0].reason == 'displayMode'   &&  pointcloud.root !== null) {//改 visible -> 
             priorityQueue.push({pointcloud: i, node: pointcloud.root, weight: Number.MAX_VALUE});
-		}else{
+        }else{
             continue
         }            
-        
-        
-        
-        
-		// frustum in object space
-		camera.updateMatrixWorld();
+       
+      
+        // frustum in object space
+		
 		let frustum = new THREE.Frustum();
-		let viewI = camera.matrixWorldInverse;
+		
 		let world = pointcloud.matrixWorld;
 		
 		// use close near plane for frustum intersection
-		let frustumCam = camera.clone();
+		/* let frustumCam = camera.clone();
         frustumCam.zoom = camera.zoom //add
 		frustumCam.near = Math.min(camera.near, 0.1);
-		frustumCam.updateProjectionMatrix();
-		let proj = camera.projectionMatrix;
+		frustumCam.updateProjectionMatrix(); */ //----没用到frustumCam,删了
+        
 
-		let fm = new THREE.Matrix4().multiply(proj).multiply(viewI).multiply(world);
+		let fm = new THREE.Matrix4().multiply(projViewI).multiply(world);
 		frustum.setFromProjectionMatrix(fm);
-		frustums[i] = frustum  //frustums.push(frustum);
+		frustums[i] =  frustum  //frustums.push(frustum);
 
 		// camera position in object space
-		let view = camera.matrixWorld;
-		let worldI = world.clone().invert();
+		
+		let worldI = pointcloud.matrixWorldInverse
 		let camMatrixObject = new THREE.Matrix4().multiply(worldI).multiply(view);
 		let camObjPos = new THREE.Vector3().setFromMatrixPosition(camMatrixObject);
 		camObjPositions[i] = camObjPos//camObjPositions.push(camObjPos);
-        
-        
+  
 
 		// hide all previously visible nodes
 		// if(pointcloud.root instanceof PointCloudOctreeNode){
@@ -1057,6 +1078,8 @@ Potree.updateVisibilityStructures = function(pointclouds, camera, areaSize) {
 		}
 	}
 
+ 
+      
 	return {
 		'frustums': frustums,
 		'camObjPositions': camObjPositions,
@@ -1125,7 +1148,8 @@ Potree.updateVisibility = function(pointclouds, camera, areaSize){
 			}
 		}
 	}
-
+    
+    
 	while (priorityQueue.size() > 0) {
 		let element = priorityQueue.pop(); //取出权重最大的一个
          
@@ -1402,16 +1426,9 @@ Potree.updateVisibility = function(pointclouds, camera, areaSize){
         /* for (let i = 0; i < Math.min(Potree.maxNodesLoading, unloadedGeometry.length); i++) {
             unloadedGeometry[i].node.load(unloadedGeometry[i].pointcloud.pcoGeometry); 
         }  */ 
-     
-        let timeStamp = performance.getEntriesByName("loop-start");
-        let maxNodesLoading
-        if(timeStamp.length){
-            let dur = performance.now() - timeStamp[timeStamp.length-1].startTime;
-            maxNodesLoading = THREE.Math.clamp(Math.round(9 - dur), 1, 6 )   //dur在iphoneX中静止有7,pc是2
-            //console.log('maxNodesLoading',maxNodesLoading, dur)
-        }else{
-            maxNodesLoading = 6
-        } 
+        
+        let maxNodesLoading = Common.getBestCount('unloadedGeometry', viewer.lastFrameChanged?1:3, 6,  4, 15 /*  , true  */ )//dur在iphoneX中静止有7,pc是2  //!lastFrameChanged静止时加速下载
+        //THREE.Math.clamp(Math.round(9 - dur), 1, 6 ) 
         
         //主要在手机端有效果。不改之前在展示的点云较多时前进会卡。
         for (let i = 0; i < Math.min(maxNodesLoading, unloadedGeometry.length); i++) {
@@ -1424,8 +1441,7 @@ Potree.updateVisibility = function(pointclouds, camera, areaSize){
     
     //add:
     Potree.numVisiblePoints = numVisiblePoints
-    
-    
+   
 	return {
 		visibleNodes: visibleNodes,
 		numVisiblePoints: numVisiblePoints,

+ 8 - 4
src/custom/settings.js

@@ -124,8 +124,7 @@ const config = {//配置参数   不可修改
             pointBudget :6*1000*1000, //比最高的低一点,避免卡顿
             percentByUser:true,
             minNodeSize : 50,
-        },
-        
+        }, 
         low:{//highPerformance
             maxLevelPercent: 0.4, //最小为0
             percentByUser:true, //如果用户定义了percent,使用用户的
@@ -287,7 +286,7 @@ const config = {//配置参数   不可修改
     clickMaxDragDis:5,
     clickMaxPressTime:500, //ms
     doubleClickTime:200,//双击间隔时间
-    testNodeCount1: browser.isMobile() ? 6 : 3,  //testMaxNode次数达到这个数字时,changePointSize才使用nodeMaxLevel
+    testNodeCount1: browser.isMobile() ? 8 : 6,  //testMaxNode次数达到这个数字时,changePointSize才使用nodeMaxLevel。 (调试时比较卡,在线上实际只需要3)
      
     background: '#232323',
     mapBG:/* '#232323',   */  '#F5F5F5',   //地图的clearColor
@@ -310,6 +309,7 @@ const config = {//配置参数   不可修改
         "deep orange": [ 255,61,0],
          
     },
+    depTexDlCount : browser.isMobile() ? 1 : 3
 }
 
  
@@ -327,6 +327,8 @@ config.OrthoCameraLimit = {
 }
 
 
+
+
 /* 显示模式:
 
 1只显示点云: 滚轮为前进后退,方向键可以行走。进入漫游点时自动变为混合(这样全景可以弥补缝隙),过渡时只显示点云。
@@ -425,10 +427,12 @@ let settings = {//设置   可修改
     precision:2,  // 两位小数 
     useV4url:true, //v4的全景图等路径不一样 scene_view_data
     
-    //testRT:true,  //似乎感觉不出差别
+    useRTskybox:true,  //直接使用rtEDL绘制到屏幕,当是全景模式时. 在降4倍时能给render节省1毫秒
     showCompass : isTest,
     showAxis : isTest,
     //testCube : true,
+    
+    cloudSameMat:true,  //因为点云个数较多,就使用相同的材质,可见降低绘制速度(要保证所有点云的maxNodelevel一样,且要算出 material.spacing的平均值)
 }
   
  

+ 31 - 22
src/custom/start.js

@@ -20,24 +20,23 @@ export function start(dom, mapDom, number ){ //t-Zvd3w0m
     }
      */ 
     Potree.settings.number = number || 't-o5YMR13'// 't-iksBApb'// 写在viewer前
-    //Potree.measureTimings = true //test
-    Potree.settings.mapCompany = browser.urlHasValue('google')? 'google' :  'default' /////////test
-
-     
+ 
+    
+    if(browser.urlHasValue('google'))Potree.settings.mapCompany = 'google' 
+    if(browser.urlHasValue('timing'))Potree.measureTimings = 1
     
     let viewer = new Potree.Viewer(dom , mapDom);
     
     let Alignment = viewer.modules.Alignment
     
     
-    //let pointDensity = config.pointDensity.middle
+  
 	viewer.setEDLEnabled(false);
-    viewer.setFOV(Potree.config.view.fov);
-    //viewer.setPointBudget(pointDensity.pointBudget);
+    viewer.setFOV(Potree.config.view.fov); 
     //viewer.loadSettingsFromURL(); 
     
     
-    if(!Potree.settings.isOfficial){ 
+     if(!Potree.settings.isOfficial){ 
         viewer.loadGUI(() => {
             viewer.setLanguage('en');
             //$("#menu_appearance").next().show();
@@ -49,7 +48,7 @@ export function start(dom, mapDom, number ){ //t-Zvd3w0m
         }); 
         Potree.settings.sizeFitToLevel = true//当type为衰减模式时自动根据level调节大小。每长一级,大小就除以2
         Potree.settings.rotAroundPoint = false
-    }
+    }  
 
     Potree.loadDatasetsCallback = function(data, ifReload){
         if(!data || data.length == 0)return console.error('getDataSet加载的数据为空')
@@ -148,7 +147,7 @@ export function start(dom, mapDom, number ){ //t-Zvd3w0m
             pointcloud.updateMatrixWorld()
             
             
-            Potree.Log(`点云${pointcloud.dataset_id}旋转值:${pointcloud.orientationUser}, 位置${math.toPrecision(pointcloud.translateUser.toArray(),3)}, 经纬度 ${locationLonLat}, spacing ${pointcloud.material.spacing}`, null, 13 )
+            Potree.Log(`点云${pointcloud.dataset_id}(${pointcloud.name})旋转值:${pointcloud.orientationUser}, 位置${math.toPrecision(pointcloud.translateUser.toArray(),3)}, 经纬度 ${locationLonLat}, spacing ${pointcloud.material.spacing}`, null, 13 )
             
             
             //-------------------
@@ -173,16 +172,21 @@ export function start(dom, mapDom, number ){ //t-Zvd3w0m
                 lonlatTo4550 : transform2       // 转大地坐标EPSG:4550  
             } 
             
-            if(window.AMapWith84 && Potree.settings.mapCompany != 'google'){//需要转换, 因本地高德用的lonlat和数据里的不一样,数据是84的
+            if(window.AMapWith84 && Potree.settings.mapCompany != 'google'){//需要转换, 因本地高德用的lonlat和数据里的84不一样. (google地图在国内也用的高德,国外84)
                 let change = (transform)=>{
                     let forward = transform.forward
                     let inverse = transform.inverse;
                     
                     transform.forward = function(e){
-                         let needTran = e.x == void 0
-                         if(needTran)e = {x:e[0],y:e[1]}
-                         var a = AMapWith84.wgs84ToAMap(e)
-                         needTran &&  (a = [a.x, a.y] )                        
+                         let needTran = e.x == void 0 
+                         if(needTran)var a1 = {x:e[0],y:e[1]}
+                         else var a1 = e
+                         var a = AMapWith84.wgs84ToAMap(a1)
+                         if(needTran){
+                             a = [a.x, a.y];  e[2] != void 0 && (a[2] = e[2])
+                         }else{
+                             e.z != void 0 && (a.z = e.z)
+                         }       
                          return  forward(a)
                     }
                     
@@ -191,7 +195,12 @@ export function start(dom, mapDom, number ){ //t-Zvd3w0m
                         var a = inverse(e)
                         needTran && (a = {x:a[0],y:a[1]})
                         a = AMapWith84.aMapToWgs84(a)  
-                        needTran && (a = [a.x,a.y])
+                        
+                        if(needTran){
+                            a = [a.x,a.y];  e[2] != void 0 && (a[2] = e[2])
+                        }else{
+                            e.z != void 0 && (a.z = e.z)
+                        } 
                         return a
                         
                     } 
@@ -227,15 +236,15 @@ export function start(dom, mapDom, number ){ //t-Zvd3w0m
                     
                     
                     pointcloud.datasetData = dataset
+                    pointcloud.dataset_id = dataset.id;//供漫游点找到属于的dataset点云
                     pointcloud.hasDepthTex = Potree.settings.useDepthTex && (!!dataset.has_depth  ||  Potree.settings.isLocalhost && Potree.settings.number == 'SS-t-7DUfWAUZ3V') //test   
                     material.minSize =  config.minSize
                     material.maxSize =  config.maxSize   
-                    material.pointSizeType = /* Potree.settings.isOfficial ? */ config.pointSizeType/*  : 'ADAPTIVE' */  //Potree.PointSizeType[config.pointSizeType]//Potree.PointSizeType.ADAPTIVE;//FIXED
+                    material.pointSizeType =/*   Potree.settings.isOfficial ?   */ config.pointSizeType    /* : 'ADAPTIVE'    */   //Potree.PointSizeType[config.pointSizeType]//Potree.PointSizeType.ADAPTIVE;//FIXED
                     pointcloud.changePointSize(config.realPointSize)  //material.size =  config.pointSize;
                     pointcloud.changePointOpacity(1)
                     material.shape = Potree.PointShape.SQUARE; 
                     pointcloud.color = pointcloud.material.color = dataset.color  
-                    pointcloud.dataset_id = dataset.id;//供漫游点找到属于的dataset点云
                     pointcloud.timeStamp = timeStamp 
                     transformPointcloud(pointcloud,dataset)
                     scene.addPointCloud(pointcloud);
@@ -367,7 +376,7 @@ export function panoEditStart(dom, number, fileServer){
     
     Potree.settings.unableNavigate = true
     Potree.settings.sizeFitToLevel = true//当type为衰减模式时自动根据level调节大小。每长一级,大小就除以2
-    
+     
     
     let viewer = new Potree.Viewer(dom); 
     let Alignment = viewer.modules.Alignment
@@ -743,7 +752,7 @@ export function mergeEditStart(dom){
                 
                 if(prop.mode != 'single'){//如果不是模型展示页,模型会随着鼠标位置移动
                     viewer.addEventListener('global_mousemove', moveModel); 
-                    viewer.addEventListener('global_click', confirmPos, 3);
+                    viewer.addEventListener('global_click', confirmPos, {importance:3});
                     modelEditing = model;
                 }
                 model.dispatchEvent("position_changed") 
@@ -753,7 +762,7 @@ export function mergeEditStart(dom){
             }
             
             
-            
+            model.isPointcloud || MergeEditor.updatePointQuality()
             
         }
         
@@ -855,7 +864,7 @@ export function mergeEditStart(dom){
                     
                     viewer.outlinePass.selectedObjects = [pointcloud]
                     return {stopContinue:true}
-                },1)
+                },{importance:1})
                 pointcloud.addEventListener('deselect',(e)=>{
                     console.log('deselect',e) 
                     //viewer.setControls(viewer.fpControls)  

+ 6 - 3
src/custom/three.shim.js

@@ -119,7 +119,7 @@ THREE.WebGLRenderer.prototype.paramThreeToGL = function(e) {
 }
 
 
-THREE.EventDispatcher.prototype.addEventListener = function(type, listener, importance=0){    //add importance
+THREE.EventDispatcher.prototype.addEventListener = function(type, listener, {importance=0, once}={}){    //add importance
 	if ( this._listeners === undefined ) this._listeners = {};
 
 		const listeners = this._listeners;
@@ -132,7 +132,7 @@ THREE.EventDispatcher.prototype.addEventListener = function(type, listener, impo
 
 		if ( !listeners[ type ].some(e=>e.listener == listener )  ) { 
 			//listeners[ type ].push( listener );
-            listeners[type].push({ listener,  importance});
+            listeners[type].push({ listener, importance, once});
             listeners[type] = listeners[type].sort((e,a)=> a.importance - e.importance)//add
 		}
 }
@@ -192,8 +192,11 @@ THREE.EventDispatcher.prototype.dispatchEvent = function(event){
 
         // Make a copy, in case listeners are removed while iterating.
          
-        for(let {listener} of listenerArray.slice(0)){
+        for(let {listener, once} of listenerArray.slice(0)){
             let result = listener.call(this, event);   //add stopContinue
+            if(once){
+                this.removeEventListener(event.type,listener)
+            }
             if(result && result.stopContinue){
                 break
             }

+ 82 - 0
src/custom/utils/Common.js

@@ -297,6 +297,88 @@ var Common = {
         }
     },
      
+
+
+    getBestCount : function(name, minCount=1,maxCount=6, durBound1 = 1.2, durBound2 = 8, ifLog){
+       
+       
+        let timeStamp = performance.getEntriesByName("loop-start");
+        let count
+        if(timeStamp.length){
+            let dur = performance.now() - timeStamp[timeStamp.length-1].startTime; 
+            let k = -(maxCount-minCount)/(durBound2 - durBound1)
+            let m = maxCount - durBound1 * k
+            count = THREE.MathUtils.clamp(Math.round(k * dur + m), minCount, maxCount )   //dur在iphoneX中静止有7,pc是2
+             
+            if(ifLog){//注意,console.log本身用时挺高, 降4倍时可能占用0.5毫秒
+               name && console.log(name,   count , ' ,dur:', dur)
+            }
+            
+        }else{
+            count = maxCount  //  ? 
+        } 
+        
+        //主要在手机端有效果。 
+        return count 
+    },
+    
+    
+        
+    batchHandling : {//分批处理
+        
+        lists:[],
+         
+        getSlice : function(name, items , {stopWhenAllUsed,  min=5,max=100, durBound1 , durBound2 }){
+            if(!this.lists[name]) this.lists[name] = {list:[] }
+            //更新列表项目,但不变原来的顺序
+            let list = this.lists[name].list.filter(a=>items.some(item=>a.item == item))//去掉已经不在items里的项目
+            this.lists[name].list = list
+              
+            items.forEach(item=>{//增加新的项目。
+                if(!list.some(a=>a.item == item)){
+                    list.push({item, count:0})
+                }
+            })
+            //至此,在后排的都是未使用的
+            
+            
+            
+            const maxUseCount = Common.getBestCount(name, min,max , durBound1, durBound2 /*  , true  */  )  ; //本次最多可以使用的个数
+             
+            let unUsed = list.filter(e=>e.count == 0)//未使用的项目(count为0)优先
+            let result = []
+            unUsed.slice(0,maxUseCount).forEach(e=>{
+                result.push(e.item);
+                e.count ++;
+            })
+            if(unUsed.length > maxUseCount){
+                //还是剩有未使用的项目,等待下一次
+                 
+            }else{
+                //所有项目都能使用一次
+                if(!stopWhenAllUsed){   //若不是全部使用就停止
+                    let wholeCount = Math.min(items.length, maxUseCount);
+                    let restCount = wholeCount - result.length; //补齐
+                    list.slice(0,restCount).forEach(e=>{
+                        result.push(e.item);
+                        e.count ++;
+                    })
+                     
+                }
+                list.forEach(e=>e.count--) //复原,等待新的循环
+            }
+            
+             
+            
+            
+            return {list:result  }
+            
+            
+        }
+        
+    }, 
+        
+    
     
     
 }  

+ 215 - 167
src/custom/viewer/ViewerNew.js

@@ -122,10 +122,17 @@ export class Viewer extends ViewerBase{
                 CamAniEditor, 
             }
         }
-       
-        
+        {
+            Potree.timeCollect = {
+                depthSampler : {minCount:20, median:0.5}, //median预置一个中等值,以防止cpu过低的设备首次卡顿  
+            }
+            for(let i in Potree.timeCollect){
+                Potree.timeCollect[i].measures = [];
+                Potree.timeCollect[i].sum = 0;
+            }
+        }
          
-        //console.log('create viewer')
+  
         
         this.navigateMode = 'free' // 'panorama'; 'free'自由模式是只显示点云或者未进入到漫游点, 
         this.isEdit = true
@@ -716,7 +723,7 @@ export class Viewer extends ViewerBase{
         }
         
         
-        if(Potree.settings.editType != 'merge'){  
+        {  
             let updated, zoomLevel
             this.addEventListener('camera_changed', e => {
                 
@@ -725,7 +732,7 @@ export class Viewer extends ViewerBase{
                     blockedByIntersectHistory.clear() //清空
                     this.updateDatasetAt()  //更新所在数据集  
                     
-                    if(Potree.settings.ifShowMarker){
+                    if(Potree.settings.ifShowMarker && Potree.settings.editType != 'merge'){
                         updated = true
                         
                         Common.intervalTool.isWaiting('updateMarkerVisibles', ()=>{
@@ -2239,8 +2246,8 @@ export class Viewer extends ViewerBase{
 	}
 
 	update(delta, timestamp){
-
-		if(Potree.measureTimings) performance.mark("update-start");
+        
+		viewer.addTimeMark('update','start')
 
 		this.dispatchEvent({
 			type: 'update_start',
@@ -2257,9 +2264,9 @@ export class Viewer extends ViewerBase{
 		
 		Potree.pointLoadLimit = Potree.pointBudget * 2;
 
-		const lTarget = camera.position.clone().add(camera.getWorldDirection(new THREE.Vector3()).multiplyScalar(1000));
+		/* const lTarget = camera.position.clone().add(camera.getWorldDirection(new THREE.Vector3()).multiplyScalar(1000));
 		this.scene.directionalLight.position.copy(camera.position);
-		this.scene.directionalLight.lookAt(lTarget);
+		this.scene.directionalLight.lookAt(lTarget); */
         
         
 		for (let pointcloud of visiblePointClouds) {
@@ -2280,6 +2287,8 @@ export class Viewer extends ViewerBase{
 
 			this.updateMaterialDefaults(pointcloud);
 		}
+ 
+
 
 		{
 			if(this.showBoundingBox){
@@ -2305,8 +2314,9 @@ export class Viewer extends ViewerBase{
         
         
         if(this.boundNeedUpdate)this.updateModelBound()  //add
- 
-		
+
+
+	
 		this.scene.cameraP.fov = this.fov;
 		
 		let controls = this.getControls();
@@ -2328,9 +2338,8 @@ export class Viewer extends ViewerBase{
             }) 
 		}
 		 
-         
         
-        this.cameraChanged()//判断camera画面是否改变
+        this.lastFrameChanged = this.cameraChanged()//判断camera画面是否改变
        
 
 		{ // update clip boxes 
@@ -2383,7 +2392,8 @@ export class Viewer extends ViewerBase{
 		}
 
 		this.updateAnnotations();
-		
+
+        
 		if(this.mapView){
 			this.mapView.update(delta);
 			if(this.mapView.sceneProjection){
@@ -2396,25 +2406,19 @@ export class Viewer extends ViewerBase{
         transitions.update(delta);
         this.transformationTool.update();
         
+ 	
         if(Potree.settings.editType != 'pano' && Potree.settings.editType != 'merge'){
             this.modules.ParticleEditor.update(delta) 
-            this.mapViewer.update(delta)            
+            this.mapViewer.update(delta)     //地图更新       
         }
-
-		this.dispatchEvent({
-			type: 'update',
-			delta: delta,
-			timestamp: timestamp});
-			
-		if(Potree.measureTimings) {
-			performance.mark("update-end");
-			performance.measure("update", "update-start", "update-end");
-		}
-        
-        
+    
+		this.dispatchEvent({ type: 'update', delta: delta, timestamp: timestamp});  //在有sidebar时耗高cpu,占本update函数80%
+         
+		 
+        viewer.addTimeMark('update','end')
         //add ------
         this.reticule.updateVisible() 
-        
+    
 
 	}
 
@@ -2728,6 +2732,8 @@ export class Viewer extends ViewerBase{
         }
         viewports = viewports.filter(v=>v.active) 
         if(viewports.length == 0)return   
+		 
+        viewer.addTimeMark('renderDefault','start')
         
         //console.log('render', viewports.map(e=>e.name).join(','))
         
@@ -2847,7 +2853,8 @@ export class Viewer extends ViewerBase{
         
         this.renderer.setRenderTarget(null)
         this.needRender = false
-        
+		 
+        viewer.addTimeMark('renderDefault','end')
 	}
     
     renderBG(view){ 
@@ -2931,9 +2938,12 @@ export class Viewer extends ViewerBase{
    
     */
 
-    renderOverlay(params){  
+    renderOverlay(params){   
+        viewer.addTimeMark('renderOverlay','start')
         this.renderOverlay1(params)
         this.renderOverlay2(params) 
+        viewer.addTimeMark('renderOverlay','end')
+        
     }
      
     renderOverlay1(params){ 
@@ -3039,9 +3049,8 @@ export class Viewer extends ViewerBase{
     /* 大规模WebGL应用引发浏览器崩溃的几种情况及解决办法
     https://blog.csdn.net/weixin_30378311/article/details/94846947 */
      
-	render(params={}){//add params
-		if(Potree.measureTimings) performance.mark("render-start");
-        
+	render(params={}){//add params 
+        viewer.addTimeMark('render','start')
         const vrActive = this.renderer.xr.isPresenting;
 
         if(vrActive){
@@ -3054,30 +3063,30 @@ export class Viewer extends ViewerBase{
                 this.renderDefault(params);
             }  
         }
-		if(Potree.measureTimings){
-			performance.mark("render-end");
-			performance.measure("render", "render-start", "render-end");
-		}
+		viewer.addTimeMark('render','end')
 	} 
 
 
 
     
 
-    startScreenshot(info={},  width=800, height=400, compressRatio){//add
-        let deferred = info.deferred || $.Deferred();
+    startScreenshot(info={},  width=800, height=400, compressRatio ){//add
+        //let deferred = info.deferred || $.Deferred();
+        let getImageDeferred = info.getImageDeferred || $.Deferred();
+        let finishDeferred = info.finishDeferred || $.Deferred();
+ 
         let viewerMaster = info.map ? this.mapViewer : this; //截图主体
         let useMap = info.type == 'measure' || info.map
         
         
         if(this.images360.flying){//如果在飞,飞完再截图
-            info.deferred = deferred 
+            info.getImageDeferred = getImageDeferred , info.finishDeferred = finishDeferred
             let f = ()=>{
                 this.startScreenshot(info,  width, height, compressRatio)
                 this.images360.removeEventListener('cameraMoveDone', f)
             } 
             this.images360.addEventListener('cameraMoveDone', f) //once 
-            return deferred.promise()
+            return {getImagePromise:getImageDeferred.promise(), finishPromise:finishDeferred.promise()}
         }
         
         var sid = Date.now()
@@ -3099,14 +3108,15 @@ export class Viewer extends ViewerBase{
         }
         
         let screenshot = ()=>{ 
+            let pose
             
             useMap && (viewer.mapViewer.needRender = true)
             
             this.needRender = true
             
             let { dataUrl  } = viewerMaster.makeScreenshot( new THREE.Vector2(width,height), null, compressRatio    );
-        
-             
+           
+            
             
             if(!Potree.settings.isOfficial){
                 Common.downloadFile(dataUrl, 'screenshot.jpg') 
@@ -3136,11 +3146,9 @@ export class Viewer extends ViewerBase{
                     }) 
                 })  */
                 updateCamera()       
-                
-                
-                
-                
-                deferred.resolve(dataUrl)
+                 
+                finishDeferred.resolve({dataUrl, pose})
+               
                 console.log('screenshot done: '+sid)
             }
             
@@ -3172,13 +3180,27 @@ export class Viewer extends ViewerBase{
                     mapViewport.camera.updateProjectionMatrix()  
                 } 
                       
+                  
                 
-                if(Potree.settings.displayMode == 'showPanos') {
-                    viewer.images360.flyToPano({pano:oldStates.pano, duration:0, callback:()=>{
+                
+                let recover = ()=>{ 
+                    if(Potree.settings.displayMode == 'showPanos') {
+                        viewer.images360.flyToPano({pano:oldStates.pano, duration:0, callback:()=>{
+                            finish()
+                        }}) 
+                    }else{
                         finish()
-                    }}) 
+                    } 
+                }
+                
+                if(info.ifGetPose){
+                    Potree.sdk.scene.getPose().done(pose_ =>{
+                        pose = pose_
+                        getImageDeferred.resolve({dataUrl, pose})  
+                        recover() 
+                    }) 
                 }else{
-                    finish()
+                    recover()
                 }
                 
             }  
@@ -3280,8 +3302,8 @@ export class Viewer extends ViewerBase{
             测量线的截图因为要调用分屏的,会改变画面
             但是普通截图的话,不会改变画面
          */
-        
-        return deferred.promise()
+ 
+        return {getImagePromise:getImageDeferred.promise(), finishPromise:finishDeferred.promise()}
         
         
     }
@@ -3704,108 +3726,135 @@ export class Viewer extends ViewerBase{
         
     }
 
+ 
+    addTimeMark(name, type){
+        let record = Potree.timeCollect[name] 
+        let needRecord = record && record.measures.length < record.minCount
+             
+        if(needRecord || Potree.measureTimings){
+            performance.mark(name+"-"+type)
+            if(type == 'end'){
+                let measure = performance.measure(name,name+"-start",name+"-end");
+                
+                if(needRecord){ 
+                    record.measures.push( measure.duration ) 
+                    record.sum += measure.duration;
+                    record.mean = record.sum / record.measures.length;  
+                    record.measures.sort( (a, b) => a - b   ); 
+                    record.median = record.measures[parseInt(record.measures.length / 2)] 
+                   
+                }
+            }
+        } 
+    }    
 
 
+	resolveTimings(timestamp,log){//打印用时。   注:performance手机的精度只到整数位 。 sidebar中监听update时有高cpu的函数所以不要用demo测
+		 
+        if(!this.toggle){
+            this.toggle = timestamp;
+        }
+        let duration = timestamp - this.toggle;
+        if(duration > 1000.0){
+            if(log){
+                let measures = performance.getEntriesByType("measure");
+                
+                let names = new Set();
+                for(let measure of measures){
+                    names.add(measure.name);
+                }
+                
+                let groups = new Map();
+                for(let name of names){
+                    groups.set(name, {
+                        measures: [],
+                        sum: 0,
+                        n: 0,
+                        min: Infinity,
+                        max: -Infinity
+                    });
+                }
+                
+                for(let measure of measures){
+                    let group = groups.get(measure.name);
+                    group.measures.push(measure);
+                    group.sum += measure.duration;
+                    group.n++;
+                    group.min = Math.min(group.min, measure.duration);
+                    group.max = Math.max(group.max, measure.duration);
+                }
 
+                /* let glQueries = Potree.resolveQueries(this.renderer.getContext());  // resolveQueries 无
+                for(let [key, value] of glQueries){
 
-	resolveTimings(timestamp){//打印用时。   注:performance手机的精度只到整数位
-		if(Potree.measureTimings){
-			if(!this.toggle){
-				this.toggle = timestamp;
-			}
-			let duration = timestamp - this.toggle;
-			if(duration > 1000.0){
-			
-				let measures = performance.getEntriesByType("measure");
-				
-				let names = new Set();
-				for(let measure of measures){
-					names.add(measure.name);
-				}
-				
-				let groups = new Map();
-				for(let name of names){
-					groups.set(name, {
-						measures: [],
-						sum: 0,
-						n: 0,
-						min: Infinity,
-						max: -Infinity
-					});
-				}
-				
-				for(let measure of measures){
-					let group = groups.get(measure.name);
-					group.measures.push(measure);
-					group.sum += measure.duration;
-					group.n++;
-					group.min = Math.min(group.min, measure.duration);
-					group.max = Math.max(group.max, measure.duration);
-				}
+                    let group = {
+                        measures: value.map(v => {return {duration: v}}),
+                        sum: value.reduce( (a, i) => a + i, 0),
+                        n: value.length,
+                        min: Math.min(...value),
+                        max: Math.max(...value)
+                    };
 
-				/* let glQueries = Potree.resolveQueries(this.renderer.getContext());  // resolveQueries 无
-				for(let [key, value] of glQueries){
-
-					let group = {
-						measures: value.map(v => {return {duration: v}}),
-						sum: value.reduce( (a, i) => a + i, 0),
-						n: value.length,
-						min: Math.min(...value),
-						max: Math.max(...value)
-					};
-
-					let groupname = `[tq] ${key}`;
-					groups.set(groupname, group);
-					names.add(groupname);
-				} */
-				
-				for(let [name, group] of groups){
-					group.mean = group.sum / group.n;
-					group.measures.sort( (a, b) => a.duration - b.duration );
-					
-					if(group.n === 1){
-						group.median = group.measures[0].duration;
-					}else if(group.n > 1){
-						group.median = group.measures[parseInt(group.n / 2)].duration;
-					}
-					
-				}
-				
-				let cn = Array.from(names).reduce( (a, i) => Math.max(a, i.length), 0) + 5;
-				let cmin = 10;
-				let cmed = 10;
-				let cmax = 10;
-				let csam = 6;
-				
-				let message = ` ${"NAME".padEnd(cn)} |` 
-					+ ` ${"MIN".padStart(cmin)} |`
-					+ ` ${"MEDIAN".padStart(cmed)} |`
-					+ ` ${"MAX".padStart(cmax)} |`
-					+ ` ${"SAMPLES".padStart(csam)} \n`;
-				message += ` ${"-".repeat(message.length) }\n`;
-				
-				names = Array.from(names).sort();
-				for(let name of names){
-					let group = groups.get(name);
-					let min = group.min.toFixed(3);
-					let median = group.median.toFixed(3);
-					let max = group.max.toFixed(3);
-					let n = group.n;
-					
-					message += ` ${name.padEnd(cn)} |`
-						+ ` ${min.padStart(cmin)} |`
-						+ ` ${median.padStart(cmed)} |`
-						+ ` ${max.padStart(cmax)} |`
-						+ ` ${n.toString().padStart(csam)}\n`;
-				}
-				message += `\n`;
-				console.log(message);
-				
-				performance.clearMarks();
-				performance.clearMeasures();
-				this.toggle = timestamp;
-			}
-		}
+                    let groupname = `[tq] ${key}`;
+                    groups.set(groupname, group);
+                    names.add(groupname);
+                } */
+                
+                for(let [name, group] of groups){
+                    group.mean = group.sum / group.n;
+                    group.measures.sort( (a, b) => a.duration - b.duration );
+                    
+                    if(group.n === 1){
+                        group.median = group.measures[0].duration;
+                    }else if(group.n > 1){
+                        group.median = group.measures[parseInt(group.n / 2)].duration;
+                    }
+                    
+                }
+                
+                let cn = Array.from(names).reduce( (a, i) => Math.max(a, i.length), 0) + 5;
+                let cmin = 6;
+                let cmed = 6;
+                let cmax = 6;
+                let csam = 4;
+                
+                let message = ` ${"NAME".padEnd(cn)} |` 
+                    + ` ${"MIN".padStart(cmin)} |`
+                    + ` ${"MEDIAN".padStart(cmed)} |`
+                    + ` ${"MAX".padStart(cmax)} |`
+                    + ` ${"AVE".padStart(cmax)} |`
+                    + ` ${"SAMPLES".padStart(csam)} \n`;
+                message += ` ${"-".repeat(message.length) }\n`;
+                
+                names = Array.from(names).sort();
+                for(let name of names){
+                    let group = groups.get(name);
+                    let min = group.min.toFixed(3);
+                    let median = group.median.toFixed(3);
+                    let max = group.max.toFixed(3);
+                    let ave = group.mean.toFixed(3); //add
+                    let n = group.n;
+                    
+                    message += ` ${name.padEnd(cn)} |`
+                        + ` ${min.padStart(cmin)} |`
+                        + ` ${median.padStart(cmed)} |`
+                        + ` ${max.padStart(cmax)} |`
+                        + ` ${ave.padStart(cmax)} |`
+                        + ` ${n.toString().padStart(csam)}\n`;
+                }
+                message += `\n`;
+                console.log(message);
+            }
+            
+            
+            
+            
+            performance.clearMarks();
+            performance.clearMeasures();
+            this.toggle = timestamp;
+        }
+		 
+        //注意,console.log本身用时挺高,降4倍时可能占用0.5毫秒,所以不能每帧都打印 
 	}
 
 	loop(timestamp){
@@ -3817,10 +3866,8 @@ export class Viewer extends ViewerBase{
 		if(this.stats){
 			this.stats.begin();
 		}
-
-		//if(Potree.measureTimings){
-			performance.mark("loop-start");
-		//}
+        viewer.addTimeMark('loop','start')
+		 
 
 		this.update(this.clock.getDelta(), timestamp);
         this.magnifier.render();
@@ -3845,24 +3892,25 @@ export class Viewer extends ViewerBase{
 		// }
 
         
-		if(Potree.measureTimings){ 
-            performance.mark("loop-end");
-			performance.measure("loop", "loop-start", "loop-end");
-		}
 		
-		this.resolveTimings(timestamp);
-
 		Potree.framenumber++;
-
+        
+        
+        //-------------
+        this.images360.tileDownloader.update() 
+        this.images360.panoRenderer.update()
+       
+        
+        
+        //-------------
 		if(this.stats){
 			this.stats.end();
 		}
         
-        
-        //let endTime = performance.now()
-        //console.log('费时:' ,parseInt((endTime-startTime)*100 )/100)
-        
-        //this.lastEndTime = endTime
+       
+        viewer.addTimeMark('loop','end')
+		this.resolveTimings(timestamp, Potree.measureTimings);
+
 	}
 
 	postError(content, params = {}){

+ 7 - 6
src/custom/viewer/Viewport.js

@@ -59,22 +59,23 @@ export default class Viewport extends THREE.EventDispatcher{
                 projectionMatrix: this.camera.projectionMatrix.clone(),//worldMatrix在this.control时归零了所以不用了吧,用position和qua也一样
                 position: this.camera.position.clone(),
                 quaternion: this.camera.quaternion.clone(),
-                 
+                active:this.active,
+                resolution:this.resolution.clone(),
             }; 
         }
-        let projectionChanged = true
-        let positionChanged = true
-        let quaternionChanged = true
+        let projectionChanged = true, positionChanged = true, quaternionChanged = true, activeChanged = true, resolutionChanged = true
         let getChanged = ()=>{
             return {
-                projectionChanged,positionChanged,quaternionChanged, 
-                changed:projectionChanged || positionChanged || quaternionChanged
+                projectionChanged,positionChanged,quaternionChanged, activeChanged, resolutionChanged,
+                changed:projectionChanged || positionChanged || quaternionChanged || activeChanged || resolutionChanged
             }
         }
         if (this.previousState){ 
             projectionChanged = !this.camera.projectionMatrix.equals(this.previousState.projectionMatrix) 
             positionChanged = !this.camera.position.equals(this.previousState.position)  
             quaternionChanged = !this.camera.quaternion.equals(this.previousState.quaternion) 
+            activeChanged = this.active != this.previousState.active
+            resolutionChanged = !this.resolution.equals(this.previousState.resolution)
         }   
         copy() 
         

+ 1 - 1
src/custom/viewer/map/Map.js

@@ -843,7 +843,7 @@ export class TiledMapFromEntity extends TiledMapBase{
  
  
  
- https://lbs.amap.com/tools/picker  高德坐标拾取器,但和这里展示的不一样, 要转成84。
+ https://lbs.amap.com/tools/picker  高德坐标拾取器,但和这里展示的不一样, 要用AMapWith84.aMapToWgs84({x: ,y: })转成84。  (qq or 手机登录)
  https://www.google.com/maps/@77.7730021,-34.4952712,4z     google取点
  
  

+ 3 - 0
src/custom/viewer/map/MapViewer.js

@@ -705,6 +705,7 @@ export class MapViewer extends ViewerBase{
         if(!this.visible && !this.attachedToViewer || !this.needRender && !params.force){  //注意:mapViewer.needRender的权重高于它的viewport的needRender,也就是说,当attachedToViewer时,viewer即使needRender, mapViewer也不一定会渲染。
             return 
         } 
+        viewer.addTimeMark('mapRender','start') 
         let renderer = params.renderer || this.renderer
          
         if(this.mapChanged){  //渲染地图背景
@@ -741,6 +742,8 @@ export class MapViewer extends ViewerBase{
     
         this.needRender = false
         
+		viewer.addTimeMark('mapRender','end')
+        
         return true      
     }
 

+ 8 - 6
src/materials/ExtendPointCloudMaterial.js

@@ -90,7 +90,7 @@ export class ExtendPointCloudMaterial extends PointCloudMaterial {
         
         this.clipBoxes_in = [];
         this.clipBoxes_out = [];
-
+        this.highlightBoxes = [];
 		 
 		this.updateShaderSource();
 	}
@@ -143,7 +143,7 @@ export class ExtendPointCloudMaterial extends PointCloudMaterial {
 			this.depthWrite = false;
 		}
 
-		this.needsUpdate = true;
+		this.shaderNeedsUpdate = true;
 	}
 
 	getDefines () {
@@ -301,12 +301,14 @@ export class ExtendPointCloudMaterial extends PointCloudMaterial {
 			return;
 		}
 
-		/* let doUpdate = (this.clipBoxes_in.length !== clipBoxes_in.length) && (clipBoxes_out.length === 0 || this.clipBoxes_out.length === 0);
+        let doUpdate = (this.clipBoxes_in.length !== clipBoxes_in.length) || (this.clipBoxes_out.length != clipBoxes_out.length)
+                    || this.highlightBoxes.length !== highlightBoxes.length || this.bigClipInBox != bigClipInBox; 
 		//this.clipBoxes = clipBoxes; 
 		if (doUpdate) {
-			this.updateShaderSource();
-		}  //好像是实时更新的
-         */
+			this.shaderNeedsUpdate = true//this.updateShaderSource();
+            viewer.dispatchEvent('content_changed')
+		}  
+         
         
         this.bigClipInBox = bigClipInBox
         this.clipBoxes_in = clipBoxes_in

+ 3 - 3
src/materials/PointCloudMaterial.js

@@ -17,9 +17,9 @@ export class PointCloudMaterial extends THREE.RawShaderMaterial {//base
 	constructor (parameters = {}) {
 		super();
 
-		this.visibleNodesTexture = Utils.generateDataTexture(2048, 1, new THREE.Color(0xffffff));
+        this.visibleNodesTexture = Utils.generateDataTexture(2048, 1, new THREE.Color(0xffffff));
 		this.visibleNodesTexture.minFilter = THREE.NearestFilter;
-		this.visibleNodesTexture.magFilter = THREE.NearestFilter;
+		this.visibleNodesTexture.magFilter = THREE.NearestFilter; 
 
 		let getValid = (a, b) => {
 			if(a !== undefined){
@@ -108,7 +108,7 @@ export class PointCloudMaterial extends THREE.RawShaderMaterial {//base
 			clipPolygonVCount:	{ type: "iv", value: [] },
 			clipPolygonVP:		{ type: "Matrix4fv", value: [] },
 
-			visibleNodes:		{ type: "t", value: this.visibleNodesTexture },
+			visibleNodes:		{ type: "t", value:  this.visibleNodesTexture   },
 			pcIndex:			{ type: "f", value: 0 },
 			gradient:			{ type: "t", value: this.gradientTexture },
 			classificationLUT:	{ type: "t", value: this.classificationTexture },

+ 7 - 3
src/materials/shaders/pointcloud_new.vs

@@ -721,7 +721,7 @@ vec3 getColor(){
 
 float getPointSize(){
 	float pointSize = 1.0;
-	
+	float maxSize_ = maxSize;
 	float slope = tan(fov / 2.0);
 	float projFactor = -0.5 * resolution.y / (slope * vViewPosition.z);
     
@@ -748,25 +748,29 @@ float getPointSize(){
 			//pointSize = size * 100.0;  //加个乘数
             
             pointSize = size / uOrthoWidth  * resolution.x; //改成近似adaptive_point_size根据窗口缩放
-            
+            maxSize_ = 3.0;  //for panoEditor, when zoom in, need more details, rather than always same size
+
 		}else{  //近大远小,模拟真实mesh,边缘放大
 			//pointSize = size * spacing * projFactor;  //spacing是attribute  为空  如果有这个值就能更自适应填补
             //pointSize = size * uOctreeSpacing * projFactor / 18.0; //直接用cloud的spacing里,不过因为都一样所以可能没有什么意义
 			//pointSize = pointSize * projFactor;
             pointSize = size * projFactor  ;
 		}
+         
 	#elif defined adaptive_point_size
 		if(uUseOrthographicCamera) {
 			float worldSpaceSize = 1.0 * size * r / getPointSizeAttenuation();
 			pointSize = (worldSpaceSize / uOrthoWidth) * resolution.x;    //uScreenWidth;
+            maxSize_ = 3.0;
 		} else {
 			float worldSpaceSize = 1.0 * size * r / getPointSizeAttenuation();
 			pointSize = worldSpaceSize * projFactor;
 		}
+        
 	#endif
 
 	pointSize = max(minSize, pointSize);
-	pointSize = min(maxSize, pointSize);
+	pointSize = min(maxSize_, pointSize);
 	
 	vRadius = pointSize / projFactor;
 

+ 3 - 2
src/navigation/FirstPersonControlsNew.js

@@ -214,8 +214,9 @@ export class FirstPersonControls extends THREE.EventDispatcher {
                             } 
                         }
                         
-                        if(!pointclouds && e.buttons === Buttons.LEFT && viewport.rotateSide){//侧视图
-                            return PanoEditor.rotateSideCamera(-e.drag.pointerDelta.x)
+                        if(!pointclouds && e.buttons === Buttons.LEFT && viewport.rotateSide){//侧视图  (有时候会卡顿,是mousemove执行延迟了,一般发生在突然加载很多点云时)
+                            //console.log('rotateSide') 
+                            return PanoEditor.rotateSideCamera(-e.drag.pointerDelta.x) 
                         }
                     }else if(Potree.settings.editType == 'merge'){ 
                         if(e.buttons === Buttons.LEFT && viewport.rotateSide){ 

+ 6 - 3
src/navigation/InputHandlerNew.js

@@ -832,14 +832,17 @@ export class InputHandler extends THREE.EventDispatcher {
         
         let canUseDepthTex = Potree.settings.displayMode == 'showPanos' && viewer.images360.currentPano.pointcloud.hasDepthTex  && viewport == viewer.mainViewport && !usePointcloud 
         
-        if(canUseDepthTex && !this.isMeasuring){
+        
+        if(canUseDepthTex)getByDepthTex()
+        else getByCloud() 
+        /* if(canUseDepthTex && !this.isMeasuring){
             getByDepthTex()
         }else{
             getByCloud() 
-            if(!intersectPoint && canUseDepthTex  ){  //若在测量,先尝试点云,再用全景
+            if(!intersectPoint && canUseDepthTex  ){  //若在测量,先尝试点云,再用全景 //后来发现有深度图的点云全景visibleNode为空,pick不到的
                 getByDepthTex()
             }
-        }  
+        }  */ 
         
         
                    

+ 53 - 85
src/viewer/EDLRendererNew.js

@@ -61,7 +61,7 @@ export class EDLRenderer{//Eye-Dome Lighting 眼罩照明
                 depthTest: false,
                 depthWrite: false
             }); */
-        if(Potree.settings.testRT){
+        if(Potree.settings.useRTskybox){
             viewer.images360.addEventListener('endChangeMode',()=>{
                 this.resize({viewport:viewer.mainViewport})
             }) 
@@ -72,7 +72,7 @@ export class EDLRenderer{//Eye-Dome Lighting 眼罩照明
 	resize(e){
         if(Features.EXT_DEPTH.isSupported()){  
             let viewport = e.viewport
-            let size = Potree.settings.testRT && Potree.settings.displayMode == 'showPanos' ? viewport.resolution2 : viewport.resolution; //若要渲染skybox,需要和设备一样精度的rt
+            let size = Potree.settings.useRTskybox && Potree.settings.displayMode == 'showPanos' ? viewport.resolution2 : viewport.resolution; //若要渲染skybox,需要和设备一样精度的rt
             this.getRtEDL(viewport).setSize( size.x, size.y  );   //理论上可以是任意尺寸,但会影响精度,且aspect最好和渲染的一致
         }
 	}
@@ -176,22 +176,24 @@ export class EDLRenderer{//Eye-Dome Lighting 眼罩照明
 
 	}
 
-	render(params={}){
- 
+
+
+
+
+
+
+
+
+
+
+
+	render(params={}){ 
          
-        /* 
-            渲染顺序:
-                底层:背景 -> skybox(也可中间)
-                中间层(含有深度信息):1 点云、marker等mesh,
-                                        2 测量线(现在被做成借用depthTex
-                顶层:maginifier 
-            magnifier的贴图渲染不需要顶层、中间层只需要点云。
-         */
-        
         const viewer = this.viewer; 
 		let camera = params.camera ? params.camera : viewer.scene.getActiveCamera();
 		const resolution = params.viewport ? params.viewport.resolution : this.viewer.renderer.getSize(new THREE.Vector2());//突然发现mobile用resolution2点云会放大
-        let rtEDL = params.rtEDL || this.getRtEDL(params.viewport)
+        let rtEDL = Features.EXT_DEPTH.isSupported() && camera.type != "OrthographicCamera" && !params.dontRenderRtEDL && (params.rtEDL || this.getRtEDL(params.viewport))  // 平面相机不用depthTex直接打开depthTest?且不使用edl
+        let useEDL = viewer.useEDL && rtEDL && Potree.settings.displayMode != 'showPanos'
         let target = params.target || null
         viewer.renderer.setRenderTarget(target);
         
@@ -203,20 +205,19 @@ export class EDLRenderer{//Eye-Dome Lighting 眼罩照明
 				lights.push(node);
 			}
 		}); */
-        
-        
+    
         //skybox  全景图
         if(!params.magnifier){
             Potree.Utils.setCameraLayers(camera, ['skybox'])
             let useDepthTex
-            if(Potree.settings.displayMode == 'showPanos' && viewer.images360.currentPano.pointcloud.hasDepthTex && Features.EXT_DEPTH.isSupported()){//渲染深度图
+            if(Potree.settings.displayMode == 'showPanos' && viewer.images360.currentPano.pointcloud.hasDepthTex && rtEDL){//渲染深度图
                 useDepthTex = true
              
                 viewer.renderer.setRenderTarget(rtEDL) //将带有深度图的skybox画在rtEDL一下,这样就不需要绘制后边的点云了
                 viewer.renderer.render(viewer.scene.scene, camera);
                 viewer.renderer.setRenderTarget(target);
                 
-                if(Potree.settings.testRT){//直接使用rtEDL,但是会失去抗锯齿,不知在skybox上需要抗锯齿吗
+                if(Potree.settings.useRTskybox){//直接使用rtEDL,但是会失去抗锯齿,不知在skybox上需要抗锯齿吗
                     this.recoverToScreenMat.uniforms.depthTex.value = rtEDL.depthTexture
                     this.recoverToScreenMat.uniforms.tDiffuse.value = rtEDL.texture  
                     Utils.screenPass.render(viewer.renderer, this.recoverToScreenMat, target);  
@@ -238,50 +239,39 @@ export class EDLRenderer{//Eye-Dome Lighting 眼罩照明
             e.oldVisi = e.visible
             e.visible = true; 
         })
-
-        
-         
+ 
         Potree.Utils.setCameraLayers(camera, ['pointcloud'])
         camera.layers.set(Potree.config.renderLayers.pointcloud);
 		
         //TODO adapt to multiple lights
 		//this.renderShadowMap(visiblePointClouds2, camera, lights);  //???????
 
-		{ 
+		{  
 			for (let pointcloud of visiblePointClouds2) {
                 
                 let material = pointcloud.material; 
                 let octreeSize = pointcloud.pcoGeometry.boundingBox.getSize(new THREE.Vector3()).x;
                 material.fov = THREE.Math.degToRad(camera.fov)  
-                material.resolution = resolution 
-               
-                
-                
+                material.resolution = resolution  
                 material.spacing = pointcloud.pcoGeometry.spacing; // * Math.max(this.scale.x, this.scale.y, this.scale.z);
                 material.near = camera.near;
                 material.far = camera.far;
                 material.uniforms.octreeSize.value = octreeSize
 	
-                if(viewer.useEDL && Potree.settings.displayMode != 'showPanos'){ 
-                    /* material.weighted = false;
-                    material.useLogarithmicDepthBuffer = false;  */ 
+                if(useEDL ){  
                     material.useEDL = true;
                     //material.fakeEDL = false; //add
                 }else{
                     material.useEDL = false;
                     //material.fakeEDL = true; //add 使也输出深度
-                }   
-                
+                }  
 			}
-            
+
              
-            if(Features.EXT_DEPTH.isSupported() && !params.dontRenderRtEDL){  
-                //借用rtEDL存储深度信息  
+            if(rtEDL/* Features.EXT_DEPTH.isSupported() && !params.dontRenderRtEDL */){ //借用rtEDL存储深度信息  
                 viewer.renderer.setRenderTarget( rtEDL );
-               
-               
-                if(visiblePointClouds2.length>0){ 
-                    //渲染scenePointCloud到rtEDL
+                
+                if(visiblePointClouds2.length>0){  //渲染scenePointCloud到rtEDL
                     viewer.pRenderer.render(viewer.scene.scenePointCloud, camera,  rtEDL, {
                         shadowMaps:  lights.length > 0 ? [this.shadowMap] : null,
                         clipSpheres: viewer.scene.volumes.filter(v => (v instanceof SphereVolume)),
@@ -294,27 +284,10 @@ export class EDLRenderer{//Eye-Dome Lighting 眼罩照明
                     viewer.renderer.render(viewer.scene.scene, camera);
                     viewer.objs.traverse(e=>{if(e.material)e.material.depthWrite = e._OlddepthWrite})
                     //缺点:半透明的model 就算完全透明, 也会遮住测量线
-                }
-                //test
-                /* {
-                    viewer.objs.traverse((obj)=>{
-                        if(obj.material){
-                            obj.material = obj.depthMat
-                        }
-                    })
-                    Potree.Utils.setCameraLayers(camera, ['sceneObjects'])
-                    viewer.renderer.render(viewer.scene.scene, camera)
-                    viewer.objs.traverse((obj)=>{
-                        if(obj.material){
-                            obj.material = obj.standardMat
-                        }
-                    })
-                } */ 
+                }  
             } 
 		}
-        
-        
-        
+           
          
         //渲染到rtEDL完毕
 		viewer.dispatchEvent({type: "render.pass.scene", viewer: viewer });
@@ -323,37 +296,24 @@ export class EDLRenderer{//Eye-Dome Lighting 眼罩照明
         if(!params.magnifier)visiblePointClouds2.forEach(e=>{//放大镜显示点云
             e.visible = e.oldVisi
         })
-        
-         
          
+        
         if(showPointClouds){ //绘制点云到画布
-            if(viewer.useEDL) {  //设置edlMaterial
-                //Features.EXT_DEPTH不支持的话不会到这一块
+            if(useEDL) {  //设置edlMaterial  //Features.EXT_DEPTH不支持的话不会到这一块
+                 
+                const uniforms = this.edlMaterial.uniforms; 
+                uniforms.resolution.value.copy(resolution) 
+                uniforms.edlStrength.value = viewer.edlStrength;
+                uniforms.radius.value = viewer.edlRadius;
+                uniforms.useEDL.value = 1;//add
                  
-                const uniforms = this.edlMaterial.uniforms;
-                //if(viewer.useEDL){
-                    /* uniforms.screenWidth.value = width;
-                    uniforms.screenHeight.value = height; */
-                    uniforms.resolution.value.copy(resolution)
-                    
-                    uniforms.edlStrength.value = viewer.edlStrength;
-                    uniforms.radius.value = viewer.edlRadius;
-                    uniforms.useEDL.value = 1;//add
-                /* }else{
-                    uniforms.useEDL.value = 0;//add
-                } */
-                
                 let proj = camera.projectionMatrix;
                 let projArray = new Float32Array(16);
                 projArray.set(proj.elements);
                 uniforms.uProj.value = projArray;
              
-                uniforms.uEDLColor.value = rtEDL.texture;
-                //uniforms.uEDLDepth.value = rtEDL.depthTexture; //其实没用到
-                 
-                uniforms.opacity.value = viewer.edlOpacity; // HACK
-                 
-                
+                uniforms.uEDLColor.value = rtEDL.texture; 
+                uniforms.opacity.value = viewer.edlOpacity; // HACK 
                 Utils.screenPass.render(viewer.renderer, this.edlMaterial, target);  //相当于一个描边后期特效。 缺点: 因为target上的没有抗锯齿,所以点云在晃动镜头时会不稳定地闪烁1px位置。优点:比不打开edl少绘制一次点云,更流畅了?!
             }else{ 
                 //渲染点云 (直接用rtEDL上的会失去抗锯齿, 导致频闪、密集时出现条纹,  自己写抗锯齿也要渲染好几次。另外透明度也要处理下) 
@@ -365,16 +325,24 @@ export class EDLRenderer{//Eye-Dome Lighting 眼罩照明
                 }
                  
                 viewer.pRenderer.render(viewer.scene.scenePointCloud, camera, null , prop);  
-                    
                 
             }
         }        
-          
-		//viewer.dispatchEvent({type: "render.pass.end",viewer: viewer});
+           
         visiblePointClouds2.forEach(e=>{
             e.visible = e.oldVisi
-        })
-        
+        }) 
+        //viewer.dispatchEvent({type: "render.pass.end",viewer: viewer});
 	}
+    
+    /* 
+        渲染顺序:
+            底层:背景 -> skybox(也可中间)
+            中间层(含有深度信息):1 点云、marker等mesh,
+                                    2 测量线(现在被做成借用depthTex
+            顶层:maginifier 
+        magnifier的贴图渲染不需要顶层、中间层只需要点云。
+     */
+        
 }
 

+ 1 - 1
src/viewer/NavigationCube.js

@@ -113,7 +113,7 @@ export class NavigationCube extends THREE.Object3D {
 
 	update(rotation) {
 		this.camera.rotation.copy(rotation);
-		this.camera.updateMatrixWorld();
+		this.visible && this.camera.updateMatrixWorld();
 	}
 
 }

+ 1 - 1
src/viewer/potree.css

@@ -134,7 +134,7 @@
 #potree_quick_buttons{
 	position: absolute;
 	left: 4px;
-	top: 4px; 
+	top: 50px; 
 	width: 10px; 
 	height: 10px; 
 	z-index: 10000;

+ 6 - 4
src/viewer/sidebarNew.js

@@ -1491,14 +1491,15 @@ export class Sidebar{
 			};
 
 			this.viewer.addEventListener("update", (e) => {
+  
 				let extent = this.viewer.getGpsTimeExtent();
 				let gpsTimeAvailable = extent[0] !== Infinity;
 
 				if(!initialized && gpsTimeAvailable){
 					initialize();
 				}
-
-				slider.setRange(extent);
+  
+				slider.setRange(extent); //高耗cpu
 			});
 		}
 
@@ -1558,7 +1559,8 @@ export class Sidebar{
 				initialized = true;
 			};
 
-			this.viewer.addEventListener("update", (e) => {
+			this.viewer.addEventListener("update", (e) => { 
+                
 				let extent = this.viewer.filterPointSourceIDRange;
 
 				if(!initialized){
@@ -1566,7 +1568,7 @@ export class Sidebar{
 
 					slider.setValues(extent);
 				}
-				
+  		
 			});
 		}
 

+ 9 - 0
改bug的历史.txt

@@ -1,3 +1,12 @@
+
+
+2023.2.7
+
+发现viewer.update函数cpu高(降4倍),因为sidebar中某个函数所致。在正式laser工程中不会用到。
+
+改写renderOctree, 所有pointcloud只执行一次可以节省很多时间,但 adaptive型的点云遇到问题,无法支持。   所以点云编辑不能使用adaptive
+
+
 2023.1.4 
 
 cpu过高:(静止时)