Browse Source

fix: 触屏双指缩放 改为缩放且平移
改善全景模式下点击热点和测量线后跳转的位置。

xzw 2 years ago
parent
commit
d2169a7fe0

+ 24 - 4
src/Potree.js

@@ -332,10 +332,30 @@ export async function loadPanosInfo(callback){
 
 
 
-export function Log(value, color, fontSize){ 
-    color = color || '#13f'
-    fontSize = fontSize || 14
-    console.warn(`%c${value}`, `color:${color};font-size:${fontSize}px`) 
+export function Log(){ 
+    
+    let args = Array.from(arguments)
+    let params = args[args.length-1] 
+    if(params && params.font) {params = params.font, args.pop()}
+    else params = {} 
+    
+    let str = '', color = params.color || '#13f', fontSize = params.fontSize || 12
+     
+    
+    args.forEach((e,i)=>{ 
+        i > 0 && (str += ' , ' ) 
+        /* if(params.toFixed && typeof e == 'number'){
+            e = e.toFixed(params.toFixed)
+        }  */
+        if(params.toFixed ){
+            e = Potree.math.toPrecision(e, params.toFixed) 
+        }  
+        str += e    //object可以JSON.stringify,但不是所有都行 
+    })              
+    
+
+     
+    console.warn(`%c${str}`, `color:${color};font-size:${fontSize}px`) 
 }
 
  

+ 7 - 3
src/custom/materials/postprocessing/EffectComposer.js

@@ -51,6 +51,10 @@ var EffectComposer = function ( renderer, renderTarget ) {
 
 	this.copyPass = new ShaderPass( CopyShader );
     
+    viewer.addEventListener('resize',(e)=>{
+        this.setSize(e.viewport.resolution.x,e.viewport.resolution.y) //暂时假设composer渲染的viewer的viewports.length == 1
+    })
+    
 };
 
 Object.assign(  EffectComposer.prototype, {
@@ -90,7 +94,7 @@ Object.assign(  EffectComposer.prototype, {
 		var pass, i, il = passes.length;
 
         if(this.readTarget){ //add 使用当前renderTarget中的像素 
-            this.copyPass.render(scene, this.renderer, this.readBuffer, this.renderer.getRenderTarget()  );
+            this.copyPass.render( scene, camera,viewports, this.renderer, this.readBuffer, this.renderer.getRenderTarget()  );
         }  
         
 		for ( i = 0; i < il; i ++ ) {
@@ -110,7 +114,7 @@ Object.assign(  EffectComposer.prototype, {
 
 					context.stencilFunc( context.NOTEQUAL, 1, 0xffffffff );
                     
-					this.copyPass.render( this.renderer, this.writeBuffer, this.readBuffer   );// delta 
+					this.copyPass.render(null,null, viewports, this.renderer, this.writeBuffer, this.readBuffer   );// delta 
 
 					context.stencilFunc( context.EQUAL, 1, 0xffffffff );
 
@@ -141,7 +145,7 @@ Object.assign(  EffectComposer.prototype, {
          if(!pass.renderToScreen){ //最后一个如果没有绘制到屏幕or target上
             this.copyPass.renderToScreen = true
             
-            this.copyPass.render(null,null, this.renderer, this.writeBuffer, this.readBuffer)
+            this.copyPass.render(null,null, viewports,this.renderer, this.writeBuffer, this.readBuffer)
             
         } 
           

+ 4 - 3
src/custom/materials/postprocessing/FXAAShader.js

@@ -86,8 +86,9 @@ const FXAAShader = {
 	#endif
 
 	/*--------------------------------------------------------------------------*/
-	#define FxaaTexTop(t, p) texture2D(t, p, -100.0)
-	#define FxaaTexOff(t, p, o, r) texture2D(t, p + (o * r), -100.0)
+    //第三个参数加入后只能在片元着色器中调用,且只对采样器为mipmap类型纹理时有效。不明白作用??? 但警告说范围在16之内
+	#define FxaaTexTop(t, p) texture2D(t, p, -15.0);    //-100.0);   
+	#define FxaaTexOff(t, p, o, r) texture2D(t, p + (o * r), -15.0); //-100.0)
 	/*--------------------------------------------------------------------------*/
 
 	#define NUM_SAMPLES 5
@@ -265,7 +266,7 @@ const FXAAShader = {
 	}
 
 	void main() {
-			const float edgeDetectionQuality = .05 ;  //越高,越保留细节;越低,越平滑 但模糊
+			const float edgeDetectionQuality = 0.2;//.05 ;  //越高,越保留细节;越低,越平滑 但模糊
 			const float invEdgeDetectionQuality = 1. / edgeDetectionQuality;
 
 			gl_FragColor = FxaaPixelShader(

+ 1 - 1
src/custom/materials/postprocessing/RenderPass.js

@@ -25,7 +25,7 @@ class RenderPass extends Pass {
 
 	}
 
-	render(scene, camera, renderer, writeBuffer, readBuffer /*, deltaTime, maskActive */ ) {
+	render(scene, camera, viewports,renderer, writeBuffer, readBuffer /*, deltaTime, maskActive */ ) {
 
 		const oldAutoClear = renderer.autoClear;
 		renderer.autoClear = false;

+ 1 - 1
src/custom/materials/postprocessing/SSAARenderPass.js

@@ -205,7 +205,7 @@ SSAARenderPass.prototype = Object.assign( Object.create( Pass.prototype ), {
             renderer.setRenderTarget(this.sampleRenderTarget)  
             renderer.clear()
             if(this.useCopy){
-                this.copyPass.render(scene,camera, renderer, writeBuffer, readBuffer )
+                this.copyPass.render(scene,camera, null,renderer, writeBuffer, readBuffer )
             }else{
                 if(renderFun){
                     renderFun({target : this.sampleRenderTarget})

+ 1 - 1
src/custom/materials/postprocessing/ShaderPass.js

@@ -74,7 +74,7 @@ ShaderPass.prototype = Object.assign( Object.create(  Pass.prototype ), {
 
 	constructor: ShaderPass,
 
-	render: function(scene,camera, renderer, writeBuffer, readBuffer, delta, maskActive ) {
+	render: function(scene,camera, viewports, renderer, writeBuffer, readBuffer, delta, maskActive ) {
         let oldTarget = renderer.getRenderTarget();
         /* if(this.readTarget){ //add
             readBuffer = oldTarget

+ 1 - 1
src/custom/modules/mergeModel/MergeEditor.js

@@ -146,7 +146,7 @@ let MergeEditor = {
             if(e.intersect){
                 let object = e.intersect.object || e.intersect.pointcloud
                 let objects = this.getAllObjects()
-                if(objects.includes(object)){ 
+                if(objects.includes(object) && this.selected != object){ 
                     this.selectModel(object) 
                 }else{
                     //if(!viewer.inputHandler.selection[0]){//正在平移和旋转,不允许取消

+ 50 - 22
src/custom/modules/panos/Images360.js

@@ -914,8 +914,10 @@ export class Images360 extends THREE.EventDispatcher{
             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)
+                //half = max - ( max - min) * THREE.Math.clamp((depthTiming - minTime)  / (maxTime - minTime),0,1)  
+                half = math.linearClamp(depthTiming, minTime,maxTime, max,min)
+                half = Math.round(half) 
+                
             } 
             let count1 = 2*half//偶数个 每个pano向 外dir 个数 
             //奇数个的好处:在窄空间内能探测到最远距离,坏处是前方有尖角。偶数个的坏处就是可能检测距离太近。
@@ -942,8 +944,10 @@ export class Images360 extends THREE.EventDispatcher{
                 let maxH = 40, minH = 2, minR = 0.5, maxR = 2  
                 height = height == void 0 ? (pano.ceilZ - pano.floorPosition.z) : height
                 //let r = height (maxH - minH)* 0.14  // 高度越小,角度越小 
-                let r = minR + ( maxR - minR) * THREE.Math.clamp((height - minH)  / (maxH - minH),0,1)   //THREE.Math.smoothstep(currentDis,  op.nearBound,  op.farBound);
-                 
+                //let r = minR + ( maxR - minR) * THREE.Math.clamp((height - minH)  / (maxH - minH),0,1)   //THREE.Math.smoothstep(currentDis,  op.nearBound,  op.farBound);
+                let r = math.linearClamp(height, minH,maxH,   minR,  maxR) 
+                
+                
                 let getZ = (deg)=>{
                     deg *= r 
                     deg = THREE.Math.clamp(deg, 1,  80);
@@ -1120,8 +1124,11 @@ export class Images360 extends THREE.EventDispatcher{
                         let dis2d = new THREE.Vector2().subVectors(pano0.position, pano1.position).length()//水平上的距离
                          
                         let maxDis = 50, minDis = 0.5,  minR = 0.2, maxR = 1.2 
-                        let r = maxR - ( maxR - minR) * THREE.Math.clamp((dis2d - minDis)  / (maxDis - minDis),0,1) //dis2d越大,角度要越小  //THREE.Math.smoothstep(currentDis,  op.nearBound,  op.farBound);
+                        //let r = maxR - ( maxR - minR) * THREE.Math.clamp((dis2d - minDis)  / (maxDis - minDis),0,1) //dis2d越大,角度要越小  //THREE.Math.smoothstep(currentDis,  op.nearBound,  op.farBound);
+                        let r = math.linearClamp(dis2d, minDis,maxDis,   maxR,  minR) 
                         //console.log('dis2d',dis2d,'r',r) 
+                         
+                        
                         let angles = (browser.isMobile ? [50] : [35,65]).map(deg=>{ //正的在左边  尽量能够平分中间这段墙体。 (角度为从中心向外)
                             let angle = THREE.Math.clamp(deg * r, 5, 80);
                             //console.log('angle',angle)  
@@ -1936,7 +1943,7 @@ export class Images360 extends THREE.EventDispatcher{
 
     fitPanoTowardPoint(o){  //寻找最适合的点位
 		var point = o.point,     //相机最佳位置
-            target = o.target,   //实际要看的位置 
+            target = o.target || o.point,   //实际要看的位置 
 			require = o.require || [],
 			rank = o.rank || [],
 			force = o.force,
@@ -1951,7 +1958,11 @@ export class Images360 extends THREE.EventDispatcher{
          
         
         //if(o.floor)require.push(Panorama.filters.atFloor(o.floor))
-            
+        let depthTiming = Potree.timeCollect.depthSampler.median        
+        let checkIntersect = o.checkIntersect && depthTiming < 0.3
+        
+        
+        
         
         if(o.boundSphere){//只接受boundSphere
             let aspect = 1//size.x / size.y
@@ -1966,36 +1977,53 @@ export class Images360 extends THREE.EventDispatcher{
             bestDistance = dis//*0.8 
             
         } 
-        
+        let disSquareMap = new Map()
         
         let bestDisSquared = bestDistance * bestDistance
         rank.push((pano)=>{
             let dis1 = Math.abs(pano.position.distanceToSquared(point) - bestDisSquared); //距离最佳位置
+            disSquareMap.set(pano, dis1)
             if(!target){
                 return -dis1 
             }else{
                 let dis2 = pano.position.distanceToSquared(target);  //距离目标点
                 let vec2 = new THREE.Vector3().subVectors(target,pano.position).normalize()
                 let cos = dir.dot(vec2)  
-                let result = (- dis1  - Math.pow(dis2 , 1.5)) / (cos + 2)  // cos+2是为了调整到1-3, 尽量贴近最佳位置的角度;
-                //console.log(pano.id, dis1,dis2,  cos,  result)
+                //let result = (- dis1  - Math.pow(dis2 , 1.5)) / (cos + 2)  // cos+2是为了调整到1-3, 
+                
+                let result =  (dis1 + dis2*0.3) * ( -1 + cos*0.9 ) //尽量贴近最佳位置的角度, 或贴近相机原来的角度 。尽量靠近最佳观测点,并且优先选择靠近目标点的位置.(注意cos的乘数不能太接近1,否则容易只考虑角度)
+                Potree.Log(pano.id, dis1, dis2,  cos,  result,{font:{toFixed:2,fontSize:10}}) 
                 return result
             } 
-        },(pano)=>{ 
-            if(pano.depthTex && o.checkIntersect && this.panos.length<20){      //没加载好的话,不管了
-                let intersect = viewer.inputHandler.ifBlockedByIntersect(target, 0.1 , null, null, null, pano)
-                if(intersect){
-                    //console.log('intersected', pano.id )
-                    return -10000
-                }else return 0
-            }else return 0 
-        }) 
+            //注:热点最好加上法线信息,这样可以多加一个限制,尽量顺着热点像展示的方向。 
+        },) 
      
-		/* var temp = {position:point}
- 		rank.push(Panorama.scoreFunctions.distanceSquared(temp, -2)); */
 		 
 		var g = Common.sortByScore(this.panos,  require, rank);
-		
+		let result1 = g && g.slice(0, 10)
+        if(result1){ 
+            g = Common.sortByScore(result1,  [], [(e)=>{//避免遮挡
+                let pano = e.item;
+                let disSquare = disSquareMap.get(pano), score = 0
+                if(pano.depthTex && checkIntersect){    
+                    let intersect = viewer.inputHandler.ifBlockedByIntersect(target, 0.1 , null, null, null, pano)
+                    if(intersect){ 
+                        score = 0
+                    }else { 
+                        score = 1000  
+                    }
+                    console.log('intersect score ', pano.id, score) 
+                }else{
+                    score = 900  //没加载好的话,不管了 , 几乎当做无遮挡,否则容易到不了最近点
+                } 
+                return score + e.score 
+            }]);
+            if(g){
+                g.forEach(e=>{e.item = e.item.item})
+            }                
+        }
+        
+        
 		if(getAll)return g;
 		return g && g.length > 0 && g[0].item
 		

+ 15 - 3
src/custom/modules/siteModel/SiteModel.js

@@ -405,7 +405,9 @@ var SiteModel = {
                 } 
                 entity.isNew = false 
                 entity.addMidMarkers() 
-                
+                let boundingBox = entity.getBound()
+                let center = boundingBox.getCenter(new THREE.Vector3())   
+                viewer.controls.setTarget(center,2)
             }else{
                 this.removeEntity(entity) //直接删除没画好的,比较简单。这样就不用担心旧的continueDrag仍旧触发了
         
@@ -743,7 +745,7 @@ var SiteModel = {
         if(state === false){
             entity.unselect()
             if(this.selected == entity)this.selected = null
-            
+            viewer.controls.setTarget(null,2)
             return 
         }
         
@@ -756,6 +758,13 @@ var SiteModel = {
         if(entity){
             entity.select()
             
+            if(!entity.isNew){
+                let boundingBox = entity.getBound()
+                let center = boundingBox.getCenter(new THREE.Vector3())   //中心点不一定在entity中,比如半环形建筑(所以要不要改成到漫游点呢)
+                viewer.controls.setTarget(center,2)
+            }
+        }else{
+            viewer.controls.setTarget(null,2)
         }
            
         
@@ -771,7 +780,10 @@ var SiteModel = {
             this.startInsertion('resume',entity)   //继续画     
         }
         
-         
+        
+        
+        
+        
     },
     
     

+ 9 - 1
src/custom/objects/tool/ctrlPolygon.js

@@ -409,6 +409,14 @@ export class ctrlPolygon extends THREE.Object3D {
         if (this.isNew && e.pressDistance>Potree.config.clickMaxDragDis){//拖拽的话返回
             return this.continueDrag(null,e)   
         } 
+         
+        if(e.hoverViewport != e.drag.dragViewport){//copy from dragMarker, for sitemodel, only mapViewport can be dropped
+            return this.continueDrag(null,e)    
+        }
+        
+        
+        
+        
         
         if(e.isTouch){ 
             if(e.hoverViewport != viewer.mainViewport && this.unableDragAtMap){
@@ -422,7 +430,7 @@ export class ctrlPolygon extends THREE.Object3D {
             this.dragMarker(e) //触屏时必须先更新下点 
             
         }
-        
+         
         
         if (e.button != THREE.MOUSE.RIGHT && (//右键click的话继续执行,因为会停止
                 this.isIntersectSelf && this.isNew //有线相交了

+ 39 - 14
src/custom/potree.shim.js

@@ -473,16 +473,16 @@ Utils.screenPass = new function () {
 	this.screenScene.add(this.screenQuad);
 	this.camera = new THREE.Camera();
 
-	this.render = function (renderer, material, target) {
+	this.render = function (renderer, material, target, composer) {
 		this.screenQuad.material = material;
-
+          
 		if (typeof target === 'undefined') {
-			renderer.render(this.screenScene, this.camera);
+			(composer || renderer).render(this.screenScene, this.camera);
 		} else {
             let oldTarget = renderer.getRenderTarget()
             renderer.setRenderTarget(target)
-            renderer.clear()
-			renderer.render(this.screenScene, this.camera);
+            renderer.clear(); 
+			(composer || renderer).render(this.screenScene, this.camera);
             renderer.setRenderTarget(oldTarget)  
 		}
 	};
@@ -992,6 +992,7 @@ Potree.updatePointClouds =  function(pointclouds,camera, areaSize  ){
 Potree.updateVisibilityStructures = function(pointclouds, camera, areaSize) {
 	let frustums = {};
 	let camObjPositions = {}
+    let camObjDirs = {} //add
 	let priorityQueue = new BinaryHeap(function (x) { return 1 / x.weight; });//二叉堆。
 
                 
@@ -1060,11 +1061,14 @@ Potree.updateVisibilityStructures = function(pointclouds, camera, areaSize) {
 		// camera position in object space
 		
 		let worldI = pointcloud.matrixWorldInverse
-		let camMatrixObject = new THREE.Matrix4().multiply(worldI).multiply(view);
+		let camMatrixObject = new THREE.Matrix4().multiply(worldI).multiply(view);//假设点云无变换的话,相机相对于点云的变换矩阵
 		let camObjPos = new THREE.Vector3().setFromMatrixPosition(camMatrixObject);
 		camObjPositions[i] = camObjPos//camObjPositions.push(camObjPos);
   
-
+        let quaternion = new THREE.Quaternion().setFromRotationMatrix(camMatrixObject)
+        let camDir = (new THREE.Vector3(0,0,-1)).applyQuaternion(quaternion)
+        camObjDirs[i] = camDir
+        
 		// hide all previously visible nodes
 		// if(pointcloud.root instanceof PointCloudOctreeNode){
 		//	pointcloud.hideDescendants(pointcloud.root.sceneNode);
@@ -1083,7 +1087,8 @@ Potree.updateVisibilityStructures = function(pointclouds, camera, areaSize) {
 	return {
 		'frustums': frustums,
 		'camObjPositions': camObjPositions,
-		'priorityQueue': priorityQueue
+		'priorityQueue': priorityQueue,
+        camObjDirs
 	};
 }; 
 
@@ -1106,7 +1111,10 @@ Potree.updateVisibility = function(pointclouds, camera, areaSize){
 	let frustums = s.frustums;
 	let camObjPositions = s.camObjPositions;
 	let priorityQueue = s.priorityQueue;
-
+    let camObjDirs = s.camObjDirs
+    
+    
+    
 	let loadedToGPUThisFrame = 0;
 	
 	let domWidth = areaSize.x; //renderer.domElement.clientWidth;
@@ -1168,6 +1176,10 @@ Potree.updateVisibility = function(pointclouds, camera, areaSize){
 		let frustum = frustums[element.pointcloud];
 		let camObjPos = camObjPositions[element.pointcloud];
         if(!frustum) continue //add
+        
+        let camObjDir = camObjDirs[element.pointcloud];
+        
+        
 		let insideFrustum = frustum.intersectsBox(box);
 		let maxLevel = pointcloud.maxLevel == void 0 ? Infinity : pointcloud.maxLevel;
 		let level = node.getLevel();
@@ -1334,8 +1346,12 @@ Potree.updateVisibility = function(pointclouds, camera, areaSize){
                                
 			}
  
-			if (pointcloud.showBoundingBox && !node.boundingBoxNode && node.getBoundingBox) {
-				let boxHelper = new Box3Helper(node.getBoundingBox());
+			if (pointcloud.showBoundingBox && !node.boundingBoxNode && node.getBoundingBox) { 
+                let colorHue = level / (maxLevel+1)
+                let s = 0.1 + level / (maxLevel+1)
+                let color = (new THREE.Color()).setHSL(colorHue, s, s) 
+                 
+				let boxHelper = new Box3Helper(node.getBoundingBox(),color);
 				boxHelper.matrixAutoUpdate = false;
 				pointcloud.boundingBoxNodes.push(boxHelper);
 				node.boundingBoxNode = boxHelper;
@@ -1365,7 +1381,9 @@ Potree.updateVisibility = function(pointclouds, camera, areaSize){
 				let center = sphere.center;
 				let dd = sphere.center.distanceToSquared(camObjPos);
 				  
-                const addPow = 0.25   //0-0.5,正常原本是0. 数字越大近处加载越快。但会造成远处加载慢甚至因pointBudge限制不加载 
+                
+                let addPow = viewer.mainViewport.view.isFlying() ? 0 : 0.5  //0-0.5,正常原本是0. 数字越大近处加载越快。但会造成远处加载慢甚至因pointBudge限制不加载。  isFlying:漫游时需要尽量加载一下远处的点云
+                addPow *= window.devicePixelRatio    //devicePixelRatio高的手机需要优先加载最近的高级点云,减少远处的中高级点云。
 				let distance = Math.pow(dd,0.5+addPow)//Math.sqrt(dd); //提高距离权重,为了提高近处加载速度。   某些场景近处加载慢优化明显,如SS-t-cqCAL6rJ5i 
 				
 				//let attenuateDis = 10;//add
@@ -1383,12 +1401,19 @@ Potree.updateVisibility = function(pointclouds, camera, areaSize){
                 if(screenPixelRadius < pointcloud.minimumNodePixelSize / Math.pow(dd,addPow)){  //理论上因手机像素小,更不容易堆叠铺满,minimumNodePixelSize应该除以window.deviceRatio 但会造成加载过多,而内存小
 					continue;
 				}
-                //如果能得到该方向上的密度,也就是node数量,密度大的远处少加载,因为被遮挡了显示也没有意义,就好了。
 				weight = screenPixelRadius;
-
+                
+                if(!sphere.containsPoint(camObjPos) ){ //add 优先加载屏幕中央的点云(手机端缩小离远效果明显,不会那么稀疏)
+                    let dir = new THREE.Vector3().subVectors(center, camObjPos).normalize() 
+                    let cos = dir.dot(camObjDir) 
+                    weight *= cos*cos 
+                } 
+                
 				if(distance - radius < 0){
 					weight = Number.MAX_VALUE;
 				}
+                
+                //如果能得到每个方向上的密度,也就是node数量,密度大的远处少加载,因为被遮挡了显示也没有意义,就好了。
 			} else {
 				// TODO ortho visibility
 				//let bb = child.getBoundingBox();

+ 6 - 6
src/custom/settings.js

@@ -123,28 +123,28 @@ const config = {//配置参数   不可修改
             maxLevelPercent: 1,  //在远处时由于pointBudget限制而展示稀疏,凑近时就变为最高质量了
             pointBudget :6*1000*1000, //比最高的低一点,避免卡顿
             percentByUser:true,
-            minNodeSize : 50,
+            minNodeSize : 50 ,
         }, 
         low:{//highPerformance
             maxLevelPercent: 0.4, //最小为0
             percentByUser:true, //如果用户定义了percent,使用用户的
             pointBudget : browser.isMobile() ? 1*1000*1000 : 2*1000*1000, 
-            minNodeSize :  40  ,
+            minNodeSize :  40 / window.devicePixelRatio ,
         }, 
         middle:{//balanced  //不同场景相同级别所产生的numVisibleNodes和numVisiblePoints不同,如果分层比较细,可能要到level8才能看清,那么level5看到的点就很大且很少,如隧道t-e2Kb2iU
             maxLevelPercent: 0.7,
             percentByUser:true,
             pointBudget: browser.isMobile() ? 2.0*1000*1000 : 3.5*1000*1000, 
-            minNodeSize :  30  ,
+            minNodeSize :  30 / window.devicePixelRatio ,
         },
         high:{//highQuality
             maxLevelPercent: 1, 
             percentByUser:true,
             pointBudget:browser.isMobile() ? 3*1000*1000 : 6*1000*1000,  //原本最高是8,但是大部分电脑都太卡了,降
-            minNodeSize :  30   ,
+            minNodeSize :   20 / window.devicePixelRatio  , //手机上因为像素点小,远一点的时候更需要加载密集的点云。(没事,有pointBudget限制着,会先从近处加载高级node,再远就不加载了)
         }
-        //browser.isMobile() 时要不要限制下pointBudget,还是让用户自己调低质量?
-        //minNodeSize?
+       
+ 
         //数值由testLevelSteps得来,其中nodeMaxLevel为2时,low和middle的都是1,如果真有这么低的点云就单独处理下。
         //多个viewport尽量保证pointBudget一样,或者pointBudget不能太低于所需,否则会反复加载了又清除
     },  

+ 7 - 8
src/custom/start.js

@@ -72,8 +72,7 @@ export function start(dom, mapDom, number ){ //t-Zvd3w0m
           
             let {boundSize, center} = viewer.bound
            
-            //Potree.Log(`中心点: ${math.toPrecision(center.toArray(),2)}, boundSize: ${math.toPrecision(boundSize.toArray(),2)} ` , null, 12)
-            
+             
             if(!Potree.settings.isOfficial){
                 Potree.loadMapEntity('all') //加载floorplan 
             }
@@ -86,7 +85,7 @@ export function start(dom, mapDom, number ){ //t-Zvd3w0m
                     Potree.settings.UserPointDensity = 'high'//'middle' 
                 }                                            
                  
-                Potree.Log('loadPointCloudDone  点云加载完毕', null, 10)  
+                Potree.Log('loadPointCloudDone  点云加载完毕', {font:[null, 10]})  
             }      
              
             
@@ -147,7 +146,7 @@ export function start(dom, mapDom, number ){ //t-Zvd3w0m
             pointcloud.updateMatrixWorld()
             
             
-            Potree.Log(`点云${pointcloud.dataset_id}(${pointcloud.name})旋转值:${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}`,  {font:[null, 13]} )
             
             
             //-------------------
@@ -272,7 +271,7 @@ export function start(dom, mapDom, number ){ //t-Zvd3w0m
             }else{
                 let pointcloud = viewer.scene.pointclouds.find(p => p.dataset_id == dataset.id)
                 if(!pointcloud){
-                    Potree.Log('数据集id变了,自动使用第一个','#500')
+                    Potree.Log('数据集id变了,自动使用第一个',   {font:['#500'  ]} )
                     pointcloud = viewer.scene.pointclouds[0]
                 }
                 //先归零 
@@ -409,7 +408,7 @@ export function panoEditStart(dom, number, fileServer){
         viewer.updateModelBound()
         let {boundSize, center} = viewer.bound
        
-        Potree.Log(`中心点: ${math.toPrecision(center.toArray(),2)}, boundSize: ${math.toPrecision(boundSize.toArray(),2)} ` , null, 12)
+        Potree.Log(`中心点: ${math.toPrecision(center.toArray(),2)}, boundSize: ${math.toPrecision(boundSize.toArray(),2)} ` , {font:[null, 12]} )
           
         viewer.scene.view.setView({ 
             position: center.clone().add(new THREE.Vector3(10,5,10)), 
@@ -422,7 +421,7 @@ export function panoEditStart(dom, number, fileServer){
             Potree.settings.UserPointDensity = 'panoEdit'//'middle' 
         }
          
-        Potree.Log('loadPointCloudDone  点云加载完毕', null, 10)  
+        Potree.Log('loadPointCloudDone  点云加载完毕',{font:[null, 10]})  
         
         viewer.dispatchEvent('allLoaded');
     }
@@ -572,7 +571,7 @@ export function mergeEditStart(dom){
                         Potree.settings.UserPointDensity = 'high'//'middle' 
                     }
                      
-                    Potree.Log('loadPointCloudDone  点云加载完毕', null, 10)    
+                    Potree.Log('loadPointCloudDone  点云加载完毕',  {font:[null,10] })    
                 } 
                     
                 /* Potree.loadPanos(dataset.id, (data) => { //暂时不加载panos了,因为没有id 

+ 6 - 4
src/custom/utils/Common.js

@@ -1,7 +1,7 @@
 
 
 import * as THREE from "../../../libs/three.js/build/three.module.js";
-
+import math from './math.js'
 
 var Common = {
     /* sortByScore: function(list, request, rank){
@@ -305,10 +305,12 @@ var Common = {
         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 dur = performance.now() - timeStamp[timeStamp.length-1].startTime;  //dur在iphoneX中静止有7,pc是2
+            /* 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
+            count = THREE.MathUtils.clamp(Math.round(k * dur + m), minCount, maxCount )    
+             */
+            count = Math.round(math.linearClamp(dur, durBound1,durBound2,   maxCount,  minCount))
              
             if(ifLog){//注意,console.log本身用时挺高, 降4倍时可能占用0.5毫秒
                name && console.log(name,   count , ' ,dur:', dur)

+ 12 - 3
src/custom/utils/math.js

@@ -100,7 +100,13 @@ var math = {
 				e[s] = f(e[s], t);
 			}
 			return e;
-		} else return f(e, t)
+		} else if(typeof e == 'number'){
+            return f(e, t)
+        }else{
+            return e
+        }
+            
+        
 	},
     isEmptyQuaternion: function(e) {
         return 0 === Math.abs(e.x) && 0 === Math.abs(e.y) && 0 === Math.abs(e.z) && 0 === Math.abs(e.w)
@@ -609,8 +615,11 @@ var math = {
         }
     },
 
-
-
+        
+    linearClamp(value,  x1,x2, y1, y2){//x为bound.min, bound.max
+        value = THREE.Math.clamp(value, x1,x2)
+        return y1 + ( y2 - y1) * (value - x1)  / (x2 - x1)  
+    }
 };
 
  

+ 29 - 42
src/custom/viewer/ViewerNew.js

@@ -371,59 +371,44 @@ export class Viewer extends ViewerBase{
                 this.composer = new EffectComposer( this.renderer );
                 this.ssaaRenderPass = new SSAARenderPass(0x000000, 0);
                 this.composer.addPass( this.ssaaRenderPass ); 
-                
+                 
                 //this.ssaaRenderPass.useCopy = true
                 //this.ssaaRenderPass.renderToScreen = true; 
                 //this.ssaaRenderPass.needsSwap = false
                 //见 https://threejs.org/examples/?q=AA#webgl_postprocessing_fxaa 效果和SSAA差不多,都对透明不太友好。
-                /* const renderPass = new RenderPass();
-				renderPass.clearColor = new THREE.Color( 0, 0, 0 );
-				renderPass.clearAlpha = 0;
-                this.composer.addPass( renderPass ); 
-                 
-                this.fxaaPass = new ShaderPass( FXAAShader );
-                 
-				this.composer.addPass( this.fxaaPass );
-                
-                this.fxaaPass.setSize = function(width, height){
-                    this.material.uniforms[ 'resolution' ].value.x = 1 / ( width );
-                    this.material.uniforms[ 'resolution' ].value.y = 1 / ( height );  
-                } 
-                this.fxaaPass.renderToScreen = true;  */ 
                  
-                /* this.fxaaPass = new ShaderPass( FXAAShader );
-                //this.fxaaPass.readTarget = true //add
-				this.composer.addPass( this.fxaaPass );
-                this.composer.readTarget = true
-                this.fxaaPass.setSize = function(width, height){
-                    this.material.uniforms[ 'resolution' ].value.x = 1 / ( width );
-                    this.material.uniforms[ 'resolution' ].value.y = 1 / ( height );  
-                } 
-                this.fxaaPass.renderToScreen = true;   */
-                
-                //for 融合页面
-                
-                
-                /* let outlinePass = this.outlinePass = new OutlinePass( );
-                //composer.addPass( outlinePass );
-                outlinePass.edgeStrength = 10
-                outlinePass.edgeGlow = 0 
-                outlinePass.visibleEdgeColor = new THREE.Color("#09a1b3")  
-                outlinePass.hiddenEdgeColor = new THREE.Color("#09a1b3") 
+                /* let outlinePass = this.outlinePass = new OutlinePass( ); 
                 this.ssaaRenderPass.addPass(outlinePass) 
                  */
                 
-                
+                //for 融合页面 
                 let outlinePass = this.outlinePass = new OutlinePass( );
                 outlinePass.renderToScreen = true  //这样更流畅,不用ssaa了,缺点是outline有锯齿
                 outlinePass.enabled = false
                 this.composer.addPass( outlinePass );
                 outlinePass.edgeStrength = 4
                 outlinePass.edgeGlow = 0 
-                outlinePass.visibleEdgeColor = new THREE.Color("#09a1b3")  
-                //outlinePass.hiddenEdgeColor = new THREE.Color("#09a1b3")  
-                 
-                  
+                outlinePass.visibleEdgeColor = new THREE.Color("#09a1b3")   
+                //--------------------------
+                
+                
+                /* this.composer2 = new EffectComposer( this.renderer );
+                //const renderPass = new RenderPass();
+				//renderPass.clearColor = new THREE.Color( 0, 0, 0 );
+				//renderPass.clearAlpha = 0;
+                //this.composer2.addPass( renderPass );  
+                this.fxaaPass = new ShaderPass( FXAAShader ); 
+                this.fxaaPass.readTarget = true //add 
+                this.fxaaPass.setSize = function(width, height){
+                    this.material.uniforms[ 'resolution' ].value.x = 1 / ( width );
+                    this.material.uniforms[ 'resolution' ].value.y = 1 / ( height );  
+                } 
+                this.fxaaPass.renderToScreen = true;
+                
+				this.composer2.addPass( this.fxaaPass ); 
+                this.composer2.readTarget = true
+                */ 
+                
             }
             
             
@@ -3336,7 +3321,7 @@ export class Viewer extends ViewerBase{
         let target  = new THREE.Vector3,  //相机focus的位置
             position = new THREE.Vector3, //相机最终位置
             dis;                          //相机距离目标
-        duration = duration == void 0 ? 1000 : duration;     
+        duration = duration == void 0 ? 1500 : duration;      
         let camera = viewer.scene.getActiveCamera()
         let cameraPos = camera.position.clone()
          
@@ -3578,7 +3563,7 @@ export class Viewer extends ViewerBase{
                     let dis1 = viewer.images360.currentPano.position.distanceTo(target)
                     let dis2 = position.distanceTo(target)
                     console.log('dis1 / dis2',dis1 / dis2, 'dis1-dis2', dis1-dis2)
-                    return {mag: (dis1 / dis2 > 1.5 && dis1-dis2>10)? 'tooFar' : 'posNoChange',  promise : deferred.promise()  }
+                    return {msg: (dis1 / dis2 > 1.5 && dis1-dis2>10)? 'tooFar' : 'posNoChange',  promise : deferred.promise()  }
                   
                 }else{
                     return {promise : deferred.promise()}
@@ -3623,7 +3608,9 @@ export class Viewer extends ViewerBase{
             
             }else if(Potree.settings.displayMode == 'showPanos'){
                 let pano = viewer.images360.fitPanoTowardPoint({
-                    point : target,
+                    point : target,  
+                    dir :  this.scene.view.direction, //尽量不改相机方向,避免镜头晃动
+                    checkIntersect: true,
                     bestDistance  //越近越好,但不要太近,bestDistance左右差不多
                 })
                 pano && viewer.images360.flyToPano({pano, target, duration, deferred, dontMoveMap:true , basePanoSize:o.basePanoSize })

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

@@ -72,7 +72,7 @@ export class MapLayer extends THREE.EventDispatcher{ // 包括了 MapLayerBase S
     
     addMapEntity(data, datasetId){ 
         if(!data || !data[0]){ 
-            Potree.Log('平面图无数据','red')
+            Potree.Log('平面图无数据',{font:'red'})
             return
         }
         
@@ -658,9 +658,9 @@ export class TiledMapOpenStreetMap extends TiledMapBase{
             maxDepth = 22           
         }else{
             projection = "EPSG:3857"
-            baseUrl = "https://wprd04.is.autonavi.com/appmaptile?lang=zh_cn&style=7&x=${x}&y=${y}&z=${z}"    //最高只到19
+            baseUrl = "https://wprd04.is.autonavi.com/appmaptile?lang=zh_cn&style=7&x=${x}&y=${y}&z=${z}"    // https://blog.csdn.net/fredricen/article/details/77189453
             attribution = "© PopSmart,  © 高德地图"
-            maxDepth = 19           
+            maxDepth = 19   
         }
         
         super('map', mapLayer, tileColor,  projection ) //EPSG projection

+ 2 - 2
src/custom/viewer/map/MapViewer.js

@@ -690,7 +690,7 @@ export class MapViewer extends ViewerBase{
         } 
                      
         if(needCopy || waitCopy){//使用缓存   ----当viewer的preserveDrawingBuffer为false的话,使用buffer
-            this.copyPass.render(null,null, renderer, params.target||null, this.copyBuffer)
+            this.copyPass.render(null,null, null, renderer, params.target||null, this.copyBuffer)
         }  
         this.needRender = false
         return true
@@ -726,7 +726,7 @@ export class MapViewer extends ViewerBase{
         }
         
         params.clear ? params.clear() : renderer.clear(); 
-        this.copyPass.render(null,null, renderer, params.target||null, this.copyBuffer) //拷贝地图背景
+        this.copyPass.render(null,null, null,renderer, params.target||null, this.copyBuffer) //拷贝地图背景
         renderer.clearDepth(); //防止地图遮挡其他物体
         
         

+ 2 - 6
src/custom/viewer/viewerBase.js

@@ -210,14 +210,10 @@ export class ViewerBase extends THREE.EventDispatcher{
         if(!onlyForTarget){//onlyForTarget表示不更改当前renderer,只是为了rendertarget才要改变viewport
                        
             this.renderer.setSize(width, height, null, devicePixelRatio); // resize之后会自动clear(似乎因为setScissor ),所以一定要立刻绘制,所以setSize要在cameraChanged、update之前
-              
-                                                     
-                                                                                                                                                                                 
-              
-                                                                        
+                                                                           
         }
        
-        this.composer && this.composer.setSize(width, height);
+        //this.composer && this.composer.setSize(width, height);
         
         if(this.viewports){
             this.viewports.forEach((view,i)=>{

+ 60 - 56
src/navigation/FirstPersonControlsNew.js

@@ -17,7 +17,7 @@ import * as THREE from "../../libs/three.js/build/three.module.js";
 import {Utils} from "../utils.js"; 
 import cameraLight from "../custom/utils/cameraLight.js"; 
 import Common from "../custom/utils/Common.js"; 
- 
+import math from "../custom/utils/math.js"; 
  
 let Buttons = Potree.defines.Buttons 
 export class FirstPersonControls extends THREE.EventDispatcher {
@@ -85,7 +85,7 @@ export class FirstPersonControls extends THREE.EventDispatcher {
                 if(e.touches.length == 1){
                     mode = (!e.dragViewport || e.dragViewport.name == 'MainView') ? 'rotate' : 'pan' 
                 }else if(e.touches.length == 2){
-                    mode = 'scale'
+                    mode = 'pan-scale'
                 }else{
                     mode = (!e.dragViewport || e.dragViewport.name == 'MainView') ? 'pan' : 'scale' 
                 } 
@@ -229,8 +229,7 @@ export class FirstPersonControls extends THREE.EventDispatcher {
                             
                         }else{ */
                             pointclouds = a && e.drag.intersectStart.pointcloud && [e.drag.intersectStart.pointcloud]
-                        //}
-                        
+                        //} 
                     }
                       
                     if(pointclouds){
@@ -246,30 +245,23 @@ export class FirstPersonControls extends THREE.EventDispatcher {
                             pointclouds, 
                             camera
                         }) 
-                    }else{ 
-                        
-                        this.translationWorldDelta.add(moveVec.negate()) 
-                        
+                    }else{  
+                        this.translationWorldDelta.add(moveVec.negate())  
                     }
-                    
-                    
-                    
-                }else{  
+                     
+                }else{ //perspectiveCamera:
                     if(e.drag.intersectStart){//如果拖拽着点云 
+                        let ifInit = e.drag.z == void 0
+                        let pointerStartPos2d = e.drag.intersectStart.location.clone().project(camera);//识别到的点云点的位置
+                            e.drag.z = pointerStartPos2d.z //记录z,保持拖拽物体到屏幕距离不变,所以z深度不变(如果拖拽过程中没有缩放,这个z其实不变)
                         
-                        if(e.drag.z == void 0){//拖拽开始
-                            let pointerStartPos2d = e.drag.intersectStart.location.clone().project(camera);//识别到的点云点的位置
-                            e.drag.z = pointerStartPos2d.z //记录z,保持拖拽物体到屏幕距离不变,所以z深度不变
+                        if(ifInit){//拖拽开始 
                             e.drag.projectionMatrixInverse = camera.projectionMatrixInverse.clone()
                             //防止吸附到最近点上(因为鼠标所在位置并非识别到的点云点的位置,需要得到鼠标所在位置的3d坐标。)
                             let pointerStartPos2dReal = new THREE.Vector3(this.pointerDragStart.x,this.pointerDragStart.y, e.drag.z);
                             e.drag.translateStartPos = pointerStartPos2dReal.clone().unproject(camera);
-                            /* this.viewer.dispatchEvent({ 
-                                type: 'dragPanBegin', 
-                                projectionMatrixInverse : e.drag.projectionMatrixInverse
-                            }); */
                             //console.log('开始拖拽', e.pointer.clone())
-                        }  
+                        }   
                         //拖拽的过程中将projectionMatrixInverse替换成开始拖拽时的,因为near、far一直在变,会导致unproject计算出的3d坐标改变很大而闪烁。
                         var _projectionMatrixInverse = camera.projectionMatrixInverse;
                         camera.projectionMatrixInverse = e.drag.projectionMatrixInverse;
@@ -281,16 +273,13 @@ export class FirstPersonControls extends THREE.EventDispatcher {
                         
                       
                         camera.projectionMatrixInverse = _projectionMatrixInverse
-                        this.translationWorldDelta.copy(moveVec.negate())  //这里没法用add,原因未知,会跳动
+                        this.translationWorldDelta.add(moveVec.negate())  //这里没法用add,原因未知,会跳动
                         //console.log('pan 1', this.translationWorldDelta.clone())   
                         
                          
                         
                         //四指松开剩三指时会偏移一下,暂不知道哪里的问题,或许跟开头防止点云吸附有关?
-                        
-                        
-                        
-                        
+                         
                     }else{ //如果鼠标没有找到和点云的交点,就假设移动整个模型(也可以去扩大范围寻找最近点云)
                          
                         /* let center = viewer.scene.pointclouds[0].position;
@@ -317,19 +306,17 @@ export class FirstPersonControls extends THREE.EventDispatcher {
 			}
             
             
-            if(mode.includes('scale')){
- 
+            if(mode.includes('scale')){//触屏缩放
+                
                 this.dollyEnd.subVectors(e.touches[0].pointer, e.touches[1].pointer);
                 //if(!this.dollyStart)return
                 var scale = this.dollyEnd.length() / this.dollyStart.length()
-
-                //console.log('scale ',scale)
-                 
+ 
                 let pointer = new THREE.Vector2().addVectors(e.touches[0].pointer, e.touches[1].pointer).multiplyScalar(0.5);//两个指头的中心点
                 
                 dolly({
                     pointer,
-                    scale, camera
+                    scale, camera, drag:e.drag
                 })
                 this.dollyStart.copy(this.dollyEnd);
                 
@@ -387,36 +374,49 @@ export class FirstPersonControls extends THREE.EventDispatcher {
                 this.translationWorldDelta.add(moveVec.negate()) 
                 this.useAttenuation = false
             }else{
-                let speed , direction
+                let speed = this.currentViewport.getMoveSpeed() * 15, direction
                  
                 
                 if(e.delta != void 0){//滚轮缩放 
-                    speed =  this.currentViewport.getMoveSpeed() * 15
-                    
-                    //var direction = this.currentViewport.view.direction.clone();
+                    if(e.delta == 0)return //mac
                     
-                    /* if(this.target && !e.intersect){//如果没有intersect点云且有target的话,就朝target的方向. 但无限靠近时有问题,且到背面时前进却是后退
+                    /*if(this.target && !e.intersect){//如果没有intersect点云且有target的话,就朝target的方向. 但无限靠近时有问题,且到背面时前进却是后退
                         direction = new THREE.Vector3().subVectors(this.target, camera.position).normalize()
                     }else{ */
-                        direction = this.viewer.inputHandler.getMouseDirection().direction  //定点缩放
-                    //}
-                    
-                    if(e.delta == 0){//mac
-                        return 
-                    }else if (e.delta < 0) {
+                    direction = this.viewer.inputHandler.getMouseDirection().direction  //定点缩放
+                     
+                    if(e.intersect){//和intersect的墙越接近,速度越慢,便于focus细节
+                        let dis = camera.position.distanceTo(e.intersect.location);
+                        
+                        speed = THREE.Math.clamp(dis * 0.1,  0.3, speed) 
+                    }     
+                    if (e.delta < 0) {
                         speed *= -1
-                    } 
-                }else{
-                    const constantDis =  this.currentViewport.getMoveSpeed() * 200 //constantDis = 10;//常量系数,当放大一倍时前进的距离。可以调整
-                    speed = (e.scale-1)*constantDis //触屏缩放
-                    //pointer = new THREE.Vector2().addVectors().multiplyScalar(0.5);//两个指头的中心点
+                    }
+                    this.useAttenuation = true
+                }else{//触屏缩放
                     direction = this.viewer.inputHandler.getMouseDirection(e.pointer).direction  //定点缩放
+               
+                    if(e.drag.intersectStart){//和intersect的墙越接近,速度越慢,便于focus细节
+                        let dis = camera.position.distanceTo(e.drag.intersectStart.location);
+                        
+                        let r = 1-1/e.scale 
+                        let closeMin = 0.1, standardMin = 0.001, disBound1 = 2, disBound2 = 5   
+                        let min = math.linearClamp(dis, disBound1, disBound2,  closeMin, standardMin) //触屏和滚轮不一样,触发较为连续,所以最小值设低一点。若要保持双指相对点云位置不变,理想最小值是0,但那样就无法穿越点云(最小值太小的话穿越密集点云如树丛很困难;太大会打滑)所以当离点云近时增大最小值 
+                        speed = Math.sign(r) * THREE.Math.clamp(dis * Math.abs(r),   min, speed) 
+                        
+                        console.log(speed, dis, e.scale)
+                        
+                    }else{  
+                        const constantDis =  this.currentViewport.getMoveSpeed() * 200 //constantDis = 10;//常量系数,当放大一倍时前进的距离。可以调整
+                        speed = (e.scale-1)*constantDis 
+                    } 
                 }
-                 
-                this.useAttenuation = true
+                  
                 var vec = direction.multiplyScalar(speed )
-                this.translationWorldDelta.copy(vec)
-                
+                //this.translationWorldDelta.copy(vec)
+                this.translationWorldDelta.add(vec)
+                //console.log(vec, speed)
             }
         }
 
@@ -453,6 +453,7 @@ export class FirstPersonControls extends THREE.EventDispatcher {
         
         let prepareScale = (e)=>{//触屏的scale 
             this.dollyStart.subVectors(e.touches[0].pointer, e.touches[1].pointer);
+            e.drag.camDisToPointStart = null
         }
         let prepareRotate = (e)=>{ 
             this.pointerDragStart = e.pointer.clone()
@@ -462,8 +463,8 @@ export class FirstPersonControls extends THREE.EventDispatcher {
             let rotAroundPoint = Potree.settings.rotAroundPoint && e.dragViewport.camera.type != 'OrthographicCamera' &&  (viewer.atDatasets.length == 0 || intersect) && this.canMovePos(viewport) && !viewer.images360.isAtPano() && !this.viewer.inputHandler.pressedKeys[32]
             let rotCenter2d, rotCenter
             if(rotAroundPoint){
-                let pivotType = this.target ? 'target' : viewer.atDatasets.length > 0 ? 'intersect' :  viewer.inputHandler.selection.length ? 'selection' : 'boundCenter'  
-                rotCenter = pivotType == 'target'? this.target :pivotType == 'intersect' ? intersect.location : pivotType == 'selection' ? viewer.inputHandler.selection[0].position : viewer.bound.center
+                let pivotType = this.target ? 'target' : viewer.atDatasets.length > 0 ? 'intersect' :  viewer.inputHandler.selection.length ? 'selection' : this.target2 ? 'target2' : 'boundCenter'  
+                rotCenter = pivotType == 'target'? this.target :pivotType == 'intersect' ? intersect.location : pivotType == 'selection' ? viewer.inputHandler.selection[0].position : pivotType == 'target2' ? this.target2 :viewer.bound.center
                 if(rotCenter){
                     rotCenter2d = rotCenter.clone().project(e.dragViewport.camera) //点在屏幕中的位置
                 }else{
@@ -500,14 +501,16 @@ export class FirstPersonControls extends THREE.EventDispatcher {
 
             if(e.touches.length==2){//只监听开头两个指头
                 prepareScale(e)
+                preparePan(e) 
             }else if(e.touches.length>=3){
                 preparePan(e)
             }
         })
-        this.viewer.addEventListener('global_touchend', (e)=>{
+        this.viewer.addEventListener('global_touchend', (e)=>{//e.touches是剩余的指头
             if(!this.enabled)return
             if(e.touches.length==2){//停止平移,开始scale
                 prepareScale(e)
+                preparePan(e) 
             }else if(e.touches.length==1){//停止scale,开始rotate
                 prepareRotate(e)
             }else if(e.touches.length>=3){//重新准备下平移(因为抬起的指头可能包含平移使用的数据),否则抬起时漂移
@@ -535,8 +538,9 @@ export class FirstPersonControls extends THREE.EventDispatcher {
         this.enabled = enabled;
          
     }
-    setTarget(target){//绕该点旋转,类似orbitControl
-        this.target = target
+    setTarget(target, index){//绕该点旋转,类似orbitControl
+        if(index == 2)this.target2 = target
+        else this.target = target
     }
     setFPCMoveSpeed(viewport){
         if(viewport.camera.type == 'OrthographicCamera'){

+ 28 - 18
src/navigation/InputHandlerNew.js

@@ -378,7 +378,7 @@ export class InputHandler extends THREE.EventDispatcher {
 
     dealPointerDown(e,isTouch){
         e.preventDefault(); 
-        
+         
         //重新获取一下pointer, 因点击了浏览器的按钮展开列表时 move回来不会触发onmousemove,所以pointer是旧的
         
         if(isTouch){
@@ -401,10 +401,25 @@ export class InputHandler extends THREE.EventDispatcher {
         if(isTouch || !Potree.settings.intersectWhenHover ){ 
             this.hoveredElements = this.getHoveredElements();
             this.intersect = this.getIntersect(viewport)
-            //this.intersect = this.getWholeIntersect() 
+            //this.intersect = this.getWholeIntersect()  
+        }
+        if(!viewport)return //why add this?
+        if (!this.drag) {
+            let target = (isTouch||e.button == THREE.MOUSE.LEFT) && this.hoveredElements.find(el => (//只有左键能拖拽
+                    el.object._listeners &&
+                    el.object._listeners['drag'] &&
+                    el.object._listeners['drag'].length > 0));
+
+            if (target) {
+                this.startDragging(target.object, {location: target.point});
+            } else {
+                this.startDragging(null);
+            }
         }
+        this.drag.intersectStart = this.intersect;
+        
+        
         
-        if(!viewport)return 
     
 		if(!isTouch || e.touches.length == 1){ 
        
@@ -434,21 +449,9 @@ export class InputHandler extends THREE.EventDispatcher {
         }
         
         
-        if (!this.drag) {
-            let target = (isTouch||e.button == THREE.MOUSE.LEFT) && this.hoveredElements.find(el => (//只有左键能拖拽
-                    el.object._listeners &&
-                    el.object._listeners['drag'] &&
-                    el.object._listeners['drag'].length > 0));
-
-            if (target) {
-                this.startDragging(target.object, {location: target.point});
-            } else {
-                this.startDragging(null);
-            }
-        }
+        
          
        
-        this.drag.intersectStart = this.intersect;
         this.mouseDownMouse = this.mouse.clone()
         
         this.pointerDownTime = Date.now()
@@ -1142,8 +1145,17 @@ export class InputHandler extends THREE.EventDispatcher {
             ));
               
 		}
+        
+        setTimeout(()=>{
+            this.dealPointerMove(e )//add 在更新完view后重新获取intersect 和 drag
+        },1)//只延迟1会崩溃吗
+        
+        
 	}
 
+
+
+
 	startDragging (object, args = null) {
 
 		let name = object ? object.name : "no name";
@@ -1171,8 +1183,6 @@ export class InputHandler extends THREE.EventDispatcher {
                 }
             )); 
         }
-         
-
 		
 	}
 

+ 2 - 2
src/utils/Box3Helper.js

@@ -11,7 +11,7 @@
 import * as THREE from "../../libs/three.js/build/three.module.js";
 
 export class Box3Helper extends THREE.LineSegments {
-	constructor (box, color) {
+	constructor (box, color, depthTest = true) {
 		if (color === undefined) color = 0xffff00;
 
 		let indices = new Uint16Array([ 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 ]);
@@ -30,7 +30,7 @@ export class Box3Helper extends THREE.LineSegments {
 		geometry.setIndex(new THREE.BufferAttribute(indices, 1));
 		geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
 
-		let material = new THREE.LineBasicMaterial({ color: color });
+		let material = new THREE.LineBasicMaterial({ color: color , depthTest});
 
 		super(geometry, material);
 	}

+ 10 - 4
src/viewer/EDLRendererNew.js

@@ -73,7 +73,7 @@ export class EDLRenderer{//Eye-Dome Lighting 眼罩照明
         if(Features.EXT_DEPTH.isSupported()){  
             let viewport = e.viewport
             let size = ( Potree.settings.displayMode == 'showPanos' ? Potree.settings.useRTskybox : Potree.settings.useRTPoint) ? viewport.resolution2 : viewport.resolution; //若要渲染skybox,需要和设备一样精度的rt
-            this.getRtEDL(viewport).setSize( size.x, size.y  );   //理论上可以是任意尺寸,但会影响精度,且aspect最好和渲染的一致
+            this.getRtEDL(viewport).setSize( size.x, size.y );   //理论上可以是任意尺寸,但会影响精度,且aspect最好和渲染的一致
         }
 	}
 
@@ -191,11 +191,16 @@ export class EDLRenderer{//Eye-Dome Lighting 眼罩照明
          
         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 = (Potree.settings.pointEnableRT || Potree.settings.displayMode == 'showPanos' || viewer.useEDL) && 
                     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
+        
+		const resolution = rtEDL ? new THREE.Vector2(rtEDL.width,rtEDL.height) : params.viewport ? params.viewport.resolution : this.viewer.renderer.getSize(new THREE.Vector2());//突然发现mobile用resolution2点云会放大
+        
+        
+        
         viewer.renderer.setRenderTarget(target);
         
         //viewer.dispatchEvent({type: "render.pass.begin",viewer: viewer});
@@ -326,8 +331,9 @@ export class EDLRenderer{//Eye-Dome Lighting 眼罩照明
                 if(this.recoverToScreenMat.defines.useDepth){
                     this.recoverToScreenMat.uniforms.depthTex.value = rtEDL.depthTexture; 
                 }
-                 
-                Utils.screenPass.render(viewer.renderer, this.recoverToScreenMat, target);
+                  
+                Utils.screenPass.render(viewer.renderer, this.recoverToScreenMat, target/* , Potree.settings.useFxaa && viewer.composer2 */);
+                
                 params.drawedModelOnRT = true
             }else{
                 //渲染点云 (直接用rtEDL上的会失去抗锯齿, 导致频闪、密集时出现条纹,  自己写抗锯齿也要渲染好几次。另外透明度也要处理下)