|
@@ -5,17 +5,17 @@ import ModelTextureMaterial from "../../materials/ModelTextureMaterial.js";
|
|
|
import Common from "../../utils/Common.js";
|
|
|
import math from "../../utils/math.js";
|
|
|
import cameraLight from "../../utils/cameraLight.js";
|
|
|
-import {MeshDraw } from '../../utils/DrawUtil'
|
|
|
+import {MeshDraw } from '../../utils/DrawUtil.js'
|
|
|
import Panorama from "./Panorama.js";
|
|
|
-import browser from '../../utils/browser'
|
|
|
-import QualityManager from './tile/QualityManager'
|
|
|
-import TileDownloader from './tile/TileDownloader'
|
|
|
-import PanoRenderer from './tile/PanoRenderer'
|
|
|
-import TilePrioritizer from './tile/TilePrioritizer'
|
|
|
-import { PanoSizeClass,Vectors,GLCubeFaces, PanoramaEvents} from '../../defines'
|
|
|
+import browser from '../../utils/browser.js'
|
|
|
+import QualityManager from './tile/QualityManager.js'
|
|
|
+import TileDownloader from './tile/TileDownloader.js'
|
|
|
+import PanoRenderer from './tile/PanoRenderer.js'
|
|
|
+import TilePrioritizer from './tile/TilePrioritizer.js'
|
|
|
+import { PanoSizeClass,Vectors,GLCubeFaces, PanoramaEvents} from '../../defines.js'
|
|
|
|
|
|
import {transitions, easing, lerp} from "../../utils/transitions.js";
|
|
|
-import DepthImageSampler from './DepthImageSampler'
|
|
|
+import DepthImageSampler from './DepthImageSampler.js'
|
|
|
|
|
|
|
|
|
|
|
@@ -38,7 +38,7 @@ let previousView = {
|
|
|
const HighMapCubeWidth = 1
|
|
|
|
|
|
|
|
|
-const directionFactor = 100 //原先10,几乎只往距离近的走了;设置太大楼梯上不去
|
|
|
+const directionFactor = 200 //原先10,几乎只往距离近的走了;设置太大楼梯上不去
|
|
|
|
|
|
|
|
|
export class Images360 extends THREE.EventDispatcher{
|
|
@@ -143,10 +143,11 @@ export class Images360 extends THREE.EventDispatcher{
|
|
|
let click = (e) => {//不用"mouseup" 是因为 mouseup有drag object时也会触发
|
|
|
if(Potree.settings.unableNavigate || this.flying || !e.isTouch && e.button != THREE.MOUSE.LEFT || e.drag && e.drag.object //拖拽结束时不算
|
|
|
|| Potree.settings.editType == 'pano' && viewer.modules.PanoEditor.activeViewName != 'mainView'
|
|
|
+ || Potree.settings.editType == 'merge' && !e.intersectPoint || viewer.inputHandler.hoveredElements[0] && viewer.inputHandler.hoveredElements[0].isModel && e.intersectPoint.distance > viewer.inputHandler.hoveredElements[0].distance
|
|
|
) return
|
|
|
|
|
|
|
|
|
- if(Potree.settings.editType != 'pano'){
|
|
|
+ if(Potree.settings.editType != 'pano' && Potree.settings.editType != 'merge'){
|
|
|
if( e.hoverViewport == viewer.mapViewer.viewports[0]){
|
|
|
return viewer.mapViewer.dispatchEvent(e/* {type:'global_click',e } */)
|
|
|
}
|
|
@@ -193,28 +194,28 @@ export class Images360 extends THREE.EventDispatcher{
|
|
|
this.elUnfocus = elUnfocus;
|
|
|
this.domRoot.appendChild(elUnfocus[0]);
|
|
|
|
|
|
-
|
|
|
-
|
|
|
- let elHide = $("<input type='button' value='隐藏点云'></input>")
|
|
|
- elHide.css({
|
|
|
- position : "absolute",
|
|
|
- right : '40%',
|
|
|
- bottom: '20px',
|
|
|
- zIndex: "10000",
|
|
|
- fontSize:'1em' ,color:"black",
|
|
|
- width : '100px',
|
|
|
- background:'rgba(255,255,255,0.8)',
|
|
|
- })
|
|
|
- this.domRoot.appendChild(elHide[0]);
|
|
|
- elHide.on("click", (e) => {
|
|
|
- let visi = viewer.getObjVisiByReason(viewer.scene.pointclouds[0], 'force')
|
|
|
- viewer.scene.pointclouds.forEach(e=>{
|
|
|
- viewer.updateVisible(e, 'force', !visi)
|
|
|
- })
|
|
|
- elHide.val(!visi ? "隐藏点云" : "显示点云")
|
|
|
- });
|
|
|
-
|
|
|
-
|
|
|
+ if(Potree.settings.editType != 'merge'){
|
|
|
+
|
|
|
+ let elHide = $("<input type='button' value='隐藏点云'></input>")
|
|
|
+ elHide.css({
|
|
|
+ position : "absolute",
|
|
|
+ right : '40%',
|
|
|
+ bottom: '20px',
|
|
|
+ zIndex: "10000",
|
|
|
+ fontSize:'1em' ,color:"black",
|
|
|
+ width : '100px',
|
|
|
+ background:'rgba(255,255,255,0.8)',
|
|
|
+ })
|
|
|
+ this.domRoot.appendChild(elHide[0]);
|
|
|
+ elHide.on("click", (e) => {
|
|
|
+ let visi = viewer.getObjVisiByReason(viewer.scene.pointclouds[0], 'force')
|
|
|
+ viewer.scene.pointclouds.forEach(e=>{
|
|
|
+ viewer.updateVisible(e, 'force', !visi)
|
|
|
+ })
|
|
|
+ elHide.val(!visi ? "隐藏点云" : "显示点云")
|
|
|
+ });
|
|
|
+
|
|
|
+ }
|
|
|
|
|
|
let elDisplayModel = $("<input type='button' value='>>全景'></input>")
|
|
|
elDisplayModel.css({
|
|
@@ -229,7 +230,8 @@ export class Images360 extends THREE.EventDispatcher{
|
|
|
|
|
|
this.domRoot.appendChild(elDisplayModel[0]);
|
|
|
elDisplayModel.on("click", (e) => {
|
|
|
- Potree.settings.displayMode = Potree.settings.displayMode == 'showPointCloud' ? 'showPanos' : 'showPointCloud'
|
|
|
+ if(Potree.settings.displayMode == 'showPointCloud' && this.panos.length == 0)return
|
|
|
+ Potree.settings.displayMode = Potree.settings.displayMode == 'showPointCloud' ? 'showPanos' : 'showPointCloud'
|
|
|
});
|
|
|
|
|
|
this.elDisplayModel = elDisplayModel
|
|
@@ -297,10 +299,8 @@ export class Images360 extends THREE.EventDispatcher{
|
|
|
}
|
|
|
|
|
|
|
|
|
-
|
|
|
- if(config2.showSkybox || config2.pointUsePanoTex){
|
|
|
- //this.currentPano.loadDepthImg()
|
|
|
- //this.updateDepthTex()
|
|
|
+
|
|
|
+ if(config2.showSkybox || config2.pointUsePanoTex){
|
|
|
let wait = ()=> {
|
|
|
setTimeout( ()=>{
|
|
|
if(latestRequestMode == mode ){
|
|
@@ -309,18 +309,16 @@ export class Images360 extends THREE.EventDispatcher{
|
|
|
},1)
|
|
|
this.removeEventListener('loadedDepthImg', wait)
|
|
|
}
|
|
|
- if(!this.currentPano.depthTex && Potree.settings.hasDepthTex){
|
|
|
+ if(!this.currentPano.depthTex && this.currentPano.pointcloud.hasDepthTex){
|
|
|
this.addEventListener('loadedDepthImg', wait)
|
|
|
return this.currentPano.loadDepthImg()
|
|
|
}
|
|
|
- //this.updateDepthTex()
|
|
|
-
|
|
|
+ //this.updateDepthTex()
|
|
|
if(this.checkAndWaitForPanoLoad(this.currentPano, this.basePanoSize, wait)){
|
|
|
return
|
|
|
- }
|
|
|
-
|
|
|
+ }
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
|
|
|
|
|
|
viewer.scene.pointclouds.forEach(e=>{
|
|
@@ -399,7 +397,7 @@ export class Images360 extends THREE.EventDispatcher{
|
|
|
|
|
|
|
|
|
if(this.elDisplayModel){
|
|
|
- this.elDisplayModel.value = mode == 'showPointCloud' ? ">>全景" : '>>点云'
|
|
|
+ this.elDisplayModel.val( mode == 'showPointCloud' ? ">>全景" : '>>点云')
|
|
|
}
|
|
|
|
|
|
/* this.panos.forEach(e=>{
|
|
@@ -503,10 +501,12 @@ export class Images360 extends THREE.EventDispatcher{
|
|
|
};
|
|
|
|
|
|
|
|
|
- updateDepthTex(pano){
|
|
|
+ updateDepthTex(pano){
|
|
|
if(this.currentPano != pano || !pano.depthTex)return
|
|
|
//this.depthSampler.changeImg(pano.depthTex.image); //pick sampler要飞到了才能切换图,而skybox贴图是随着全景图切换而切换的
|
|
|
- this.cube.material.updateDepthTex(pano) //确保一下
|
|
|
+ this.cube.material.updateDepthTex(pano) //确保一下
|
|
|
+
|
|
|
+
|
|
|
}
|
|
|
|
|
|
findNearestPano(pos){
|
|
@@ -622,14 +622,14 @@ export class Images360 extends THREE.EventDispatcher{
|
|
|
/* if(!this.currentPano){
|
|
|
return this.focusPano(toPano)
|
|
|
} */
|
|
|
- //console.log('flyToPano:', toPano.pano.id)
|
|
|
+
|
|
|
let done = (makeIt)=>{
|
|
|
//console.log('flyToPano done ', toPano.pano.id, makeIt )
|
|
|
if(makeIt || toPano.dealDoneWhenCancel) {
|
|
|
- toPano.callback && toPano.callback()
|
|
|
+ toPano.callback && toPano.callback()
|
|
|
+ this.flying = false
|
|
|
+ this.updateClosestPano(this.closestPano,false) //飞行结束后取消点击漫游点时得到的closestPano
|
|
|
}
|
|
|
- this.flying = false
|
|
|
- this.updateClosestPano(this.closestPano,false) //飞行结束后取消点击漫游点时得到的closestPano
|
|
|
//this.dispatchEvent('cameraMoveDone')
|
|
|
toPano.deferred && toPano.deferred.resolve(makeIt) //测量线截图时发现,resolve需要写在flying=false 后才行。
|
|
|
}
|
|
@@ -657,26 +657,28 @@ export class Images360 extends THREE.EventDispatcher{
|
|
|
|
|
|
this.nextPano = pano
|
|
|
//不飞的话是否不要执行这段?
|
|
|
- if(config.atPano.showSkybox || config.atPano.pointUsePanoTex){
|
|
|
+
|
|
|
+ {
|
|
|
let wait = ()=> {
|
|
|
setTimeout( ()=>{
|
|
|
this.flyToPano(toPano)
|
|
|
},1)
|
|
|
this.removeEventListener('loadedDepthImg', wait)
|
|
|
}
|
|
|
- if(!pano.depthTex && Potree.settings.hasDepthTex){
|
|
|
+ if(!pano.depthTex && pano.pointcloud.hasDepthTex){ //需要用到depthTex计算neighbour
|
|
|
this.addEventListener('loadedDepthImg', wait)
|
|
|
return pano.loadDepthImg()
|
|
|
- }
|
|
|
- this.updateCube(this.currentPano, toPano.pano)
|
|
|
+ }
|
|
|
|
|
|
- if(this.checkAndWaitForPanoLoad(pano, toPano.basePanoSize || this.basePanoSize, wait)){
|
|
|
- return
|
|
|
+ if(config.atPano.showSkybox || config.atPano.pointUsePanoTex){
|
|
|
+
|
|
|
+ this.updateCube(this.currentPano, toPano.pano)
|
|
|
+
|
|
|
+ if(this.checkAndWaitForPanoLoad(pano, toPano.basePanoSize || this.basePanoSize, wait)){
|
|
|
+ return
|
|
|
+ }
|
|
|
}
|
|
|
-
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
+ }
|
|
|
|
|
|
this.cube.visible = config.atPano.showSkybox
|
|
|
/* this.cube.visible && this.cube.material.setProjectedPanos(this.currentPano, pano, 0)
|
|
@@ -699,7 +701,7 @@ export class Images360 extends THREE.EventDispatcher{
|
|
|
viewer.updateVisible(e, 'displayMode', true)
|
|
|
})
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
if(config.transition.showSkybox || config.transition.pointUsePanoTex){
|
|
|
this.setProjectedPanos({
|
|
|
progress:0,
|
|
@@ -749,6 +751,8 @@ export class Images360 extends THREE.EventDispatcher{
|
|
|
//this.updateCube(this.currentPano)
|
|
|
this.updateDepthTex(this.currentPano)
|
|
|
|
|
|
+
|
|
|
+
|
|
|
}, onUpdate:(progress)=>{
|
|
|
this.cube.material.uniforms.progress.value = progress
|
|
|
|
|
@@ -772,7 +776,7 @@ export class Images360 extends THREE.EventDispatcher{
|
|
|
fly()
|
|
|
}
|
|
|
|
|
|
-
|
|
|
+ //console.log('flyToPano:', toPano.pano.id)
|
|
|
}
|
|
|
|
|
|
|
|
@@ -919,6 +923,9 @@ export class Images360 extends THREE.EventDispatcher{
|
|
|
|
|
|
|
|
|
updateCube(pano0, pano1){
|
|
|
+
|
|
|
+ if(!viewer.scene.pointclouds.some(e=>!e.hasDepthTex)) return this.updateCube2(pano0, pano1) //都hasDepthTex的话
|
|
|
+
|
|
|
if(Potree.settings.displayMode != 'showPanos')return
|
|
|
|
|
|
|
|
@@ -1260,14 +1267,15 @@ export class Images360 extends THREE.EventDispatcher{
|
|
|
} */
|
|
|
|
|
|
|
|
|
- updateCube2(pano0, pano1){//增加细分的版本,且垂直方向上取中位数
|
|
|
+
|
|
|
+ updateCube3(pano0, pano1){//增加细分的版本,且垂直方向上取中位数... 侧边只有一条
|
|
|
if(Potree.settings.displayMode != 'showPanos' || pano0 == pano1
|
|
|
|| this.cubePanos.includes(pano0) && this.cubePanos.includes(pano1)
|
|
|
) return
|
|
|
|
|
|
this.cubePanos = [pano0, pano1]
|
|
|
|
|
|
- console.log('updateCube',pano0.id, pano1&&pano1.id)
|
|
|
+ //console.log('updateCube',pano0.id, pano1&&pano1.id)
|
|
|
|
|
|
let f = (bound, size)=>{
|
|
|
size = size || bound.getSize(new THREE.Vector3)
|
|
@@ -1279,30 +1287,19 @@ export class Images360 extends THREE.EventDispatcher{
|
|
|
}
|
|
|
|
|
|
|
|
|
- //this.cube.geometry.dispose();
|
|
|
+ this.cube.geometry.dispose();
|
|
|
|
|
|
if(pano1){//过渡
|
|
|
- // if(this.update111)return
|
|
|
- // this.update111 = true
|
|
|
- this.cube.geometry.dispose();
|
|
|
-
|
|
|
- // this.cube.geometry = new THREE.BoxBufferGeometry(1,1,1,1);//new THREE.SphereBufferGeometry(1,10,10)
|
|
|
- //this.cube.scale.set(20,10,20);
|
|
|
- /// this.cube.position.copy(pano1.position)
|
|
|
-
|
|
|
|
|
|
- //f(pano0.pointcloud.bound)
|
|
|
|
|
|
- //return
|
|
|
-
|
|
|
-
|
|
|
- const half = Potree.settings.hasDepthTex ? ( browser.isMobile() ? 3 : 6 ) : (browser.isMobile() ? 2 : 3) //自行输入 (点云计算的慢,还不准)
|
|
|
+ const half = pano0.pointcloud.hasDepthTex && pano0.pointcloud.hasDepthTex ? ( browser.isMobile() ? 3 : 6 ) : (browser.isMobile() ? 2 : 3) //自行输入 (点云计算的慢,还不准)
|
|
|
let count1 = 2*half//偶数个 dir 个数
|
|
|
+
|
|
|
//奇数个的好处:在窄空间内能探测到最远距离,坏处是前方有尖角。偶数个的坏处就是可能检测距离太近。
|
|
|
let panoIndex = 0
|
|
|
|
|
|
let getIntersect = (pano, dir, origin)=>{
|
|
|
- if(Potree.settings.hasDepthTex && pano){
|
|
|
+ if(pano && pano.pointcloud.hasDepthTex ){
|
|
|
return this.depthSampler.sample( {dir }, pano, true )
|
|
|
}else{
|
|
|
origin = origin || pano.position
|
|
@@ -1336,7 +1333,7 @@ export class Images360 extends THREE.EventDispatcher{
|
|
|
return projectLen
|
|
|
})
|
|
|
disArr.sort((a,b)=>{return b-a}); //从大到小
|
|
|
- console.log(pano ? pano.id : 'side','disArr', disArr)
|
|
|
+ //console.log(pano ? pano.id : 'side','disArr', disArr)
|
|
|
let dis = disArr[Math.floor(count2/2-0.5)] //对半、取前(中位数)
|
|
|
|
|
|
|
|
@@ -1374,8 +1371,8 @@ export class Images360 extends THREE.EventDispatcher{
|
|
|
let min = pano.position.z + 1
|
|
|
maxZ = Math.max(min,maxZ)
|
|
|
pano.ceilZ = maxZ
|
|
|
- console.log(pano.id, 'maxZ:',maxZ )
|
|
|
- console.log(pano.id, 'minZ:',minZ )
|
|
|
+ //console.log(pano.id, 'maxZ:',maxZ )
|
|
|
+ //console.log(pano.id, 'minZ:',minZ )
|
|
|
}
|
|
|
[maxZ, minZ ].forEach(z=>{
|
|
|
posArr.push(pano.position.clone().setZ(z))
|
|
@@ -1387,7 +1384,7 @@ export class Images360 extends THREE.EventDispatcher{
|
|
|
//在画面上线条从左往右数
|
|
|
let dirs = [];
|
|
|
for(let i=0;i<count1;i++){
|
|
|
- dirs.push(getDir(Math.PI/2-i*angle, vec))
|
|
|
+ dirs.push(getDir(Math.PI/2-i*angle, vec))//正的在左边
|
|
|
}
|
|
|
|
|
|
|
|
@@ -1459,18 +1456,59 @@ export class Images360 extends THREE.EventDispatcher{
|
|
|
let sideMaxZ = (pano0.ceilZ + pano1.ceilZ)/2
|
|
|
let sideMinZ = (pano0.floorPosition.z+pano1.floorPosition.z)/2;
|
|
|
|
|
|
- let sideDis = [Math.min(sideDis0[0] , sideDis1[1]), Math.min(sideDis0[1] , sideDis1[0])]//[(sideDis0[0] + sideDis1[1])/2, (sideDis0[1] + sideDis1[0])/2];
|
|
|
+ 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 mid = new THREE.Vector3().addVectors(pano0.position, pano1.position).multiplyScalar(0.5)
|
|
|
-
|
|
|
let sideDirs = [getDir(-Math.PI/2, vec), getDir(Math.PI/2, vec)]
|
|
|
- sideDirs.forEach((dir_ ,index)=>{
|
|
|
- let dis = getFar(dir_, null, mid);
|
|
|
- dir_.multiplyScalar( Math.max(dis, sideDis[index]) );
|
|
|
- [sideMaxZ,sideMinZ].forEach(z=>{
|
|
|
- posArr.push(mid.clone().setZ(z).add(dir_))
|
|
|
+
|
|
|
+ if(pano0.pointcloud.hasDepthTex && pano0.pointcloud.hasDepthTex){
|
|
|
+ let panos = [pano0,pano1]
|
|
|
+ let vecs = [vec.negate(), vec]
|
|
|
+ let axis = [[-1,1],[1,-1]]
|
|
|
+ let dis2d = new THREE.Vector2().subVectors(pano0.position, pano1.position).length()//水平上的距离
|
|
|
+ let angles = [THREE.Math.degToRad(45), THREE.Math.degToRad(60)]
|
|
|
+ sideDirs.forEach((dir, index0)=>{
|
|
|
+ let disToSides = []
|
|
|
+ panos.forEach((pano,index)=>{
|
|
|
+ let dirs = [getDir(axis[index0][index]*angles[0], vecs[index]), getDir(axis[index0][index]*angles[1], vecs[index])];//一侧的若干角度
|
|
|
+ dirs.forEach((dir_,i)=>{
|
|
|
+ let dis1 = getFar(dir_, pano);
|
|
|
+ //dir_.multiplyScalar( dis1 );
|
|
|
+ let disToPano2d = dis1 * Math.cos(angles[i])
|
|
|
+ if(disToPano2d<dis2d){//超过的话都到另一半pano的半圆了,不计入
|
|
|
+ let disToSide = dis1 * Math.sin(angles[i])
|
|
|
+ disToSides.push(disToSide)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ })
|
|
|
+ let disToSide
|
|
|
+ if(disToSides.length){
|
|
|
+ disToSides.sort((a,b)=>{return b-a});//从大到小
|
|
|
+ disToSide = disToSides[0]
|
|
|
+ console.log('disToSides', index0, disToSides)
|
|
|
+ }else{
|
|
|
+ disToSide = sideDis[index0]
|
|
|
+ }
|
|
|
+ dir.multiplyScalar( disToSide );
|
|
|
+
|
|
|
+ [sideMaxZ,sideMinZ].forEach(z=>{
|
|
|
+ posArr.push(mid.clone().setZ(z).add(dir)) //是直接使用最长dis的那个intersect点好还是mid
|
|
|
+ })
|
|
|
})
|
|
|
- })
|
|
|
+
|
|
|
+ }else{
|
|
|
+
|
|
|
+ sideDirs.forEach((dir_ ,index)=>{
|
|
|
+ let dis = getFar(dir_, null, mid);
|
|
|
+ dir_.multiplyScalar( /* sideDis_[index] */ Math.max(dis, sideDis[index]) );
|
|
|
+
|
|
|
+
|
|
|
+ [sideMaxZ,sideMinZ].forEach(z=>{
|
|
|
+ posArr.push(mid.clone().setZ(z).add(dir_))
|
|
|
+ })
|
|
|
+ })
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
let posArr = [];
|
|
@@ -1498,7 +1536,346 @@ export class Images360 extends THREE.EventDispatcher{
|
|
|
this.cube.geometry = new THREE.BoxBufferGeometry(1,1,1,1)
|
|
|
f(pano0.pointcloud.bound)
|
|
|
}
|
|
|
- }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ updateCube2(pano0, pano1){//增加细分的版本,且垂直方向上取中位数 侧边多条
|
|
|
+ if(Potree.settings.displayMode != 'showPanos' || pano0 == pano1
|
|
|
+ || this.cubePanos.includes(pano0) && this.cubePanos.includes(pano1)
|
|
|
+ ) return
|
|
|
+
|
|
|
+ this.cubePanos = [pano0, pano1]
|
|
|
+
|
|
|
+ //console.log('updateCube',pano0.id, pano1&&pano1.id)
|
|
|
+
|
|
|
+ let useBound = (bound, size)=>{
|
|
|
+
|
|
|
+ size = size || bound.getSize(new THREE.Vector3)
|
|
|
+ let center = bound.getCenter(new THREE.Vector3)
|
|
|
+ size.max(new THREE.Vector3(HighMapCubeWidth,HighMapCubeWidth,HighMapCubeWidth))
|
|
|
+ this.cube.geometry = new THREE.BoxBufferGeometry(1,1,1,1)
|
|
|
+ this.cube.scale.copy(size)
|
|
|
+ this.cube.position.copy(center)
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ this.cube.geometry.dispose();
|
|
|
+
|
|
|
+ if(pano1){//过渡
|
|
|
+
|
|
|
+ if(pano0.pointcloud != pano1.pointcloud){ //距离太远的数据集,过渡会畸变。所以扩大skybox
|
|
|
+ let dis = pano0.position.distanceTo(pano1.position)
|
|
|
+ if(dis > 100){
|
|
|
+ let bound = pano0.pointcloud.bound.clone().union(pano1.pointcloud.bound)
|
|
|
+ let size = bound.getSize(new THREE.Vector3)
|
|
|
+ let max = Math.max(size.x, size.y, size.z)
|
|
|
+ size.set(max,max,max)
|
|
|
+ return useBound(bound, size)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ const half = pano0.pointcloud.hasDepthTex && pano0.pointcloud.hasDepthTex ? 6 : (browser.isMobile() ? 2 : 3) //自行输入 (点云计算的慢,还不准)
|
|
|
+ let count1 = 2*half//偶数个 每个pano向 外dir 个数
|
|
|
+ //奇数个的好处:在窄空间内能探测到最远距离,坏处是前方有尖角。偶数个的坏处就是可能检测距离太近。
|
|
|
+
|
|
|
+ //let panoIndex = 0
|
|
|
+
|
|
|
+ let getIntersect = (pano, dir, origin)=>{
|
|
|
+ if(pano && pano.pointcloud.hasDepthTex ){
|
|
|
+ return this.depthSampler.sample( {dir }, pano, true )
|
|
|
+ }else{
|
|
|
+ origin = origin || pano.position
|
|
|
+ return viewer.inputHandler.getIntersect(viewer.inputHandler.hoverViewport, true, null, null, true, {
|
|
|
+ point: origin.clone().add(dir),
|
|
|
+ cameraPos: origin
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ let getDir = (angle_, vec)=>{ //旋转获得水平向量
|
|
|
+ let rotMat = new THREE.Matrix4().makeRotationZ(angle_)
|
|
|
+ return vec.clone().applyMatrix4(rotMat)
|
|
|
+ }
|
|
|
+ let getFar = (dir, pano, origin)=>{//获取在这个方向上和墙体intersect的距离
|
|
|
+ //在垂直方向上分出多个方向,取一个最可能的接近真实的距离
|
|
|
+ let dirs_ = [
|
|
|
+ //注意:角度太大会碰到天花板或地板,越远越容易碰到, 在地下停车场就会伸展不开。 户外时需要更多向上的方向,所以上方向多一个
|
|
|
+ dir.clone().setZ(Math.tan(THREE.Math.degToRad(30))).normalize(),
|
|
|
+ dir.clone().setZ(Math.tan(THREE.Math.degToRad(7))).normalize(),
|
|
|
+ dir.clone(), // 水平方向
|
|
|
+ dir.clone().setZ(-Math.tan(THREE.Math.degToRad(5))).normalize(),
|
|
|
+ //dir.clone().setZ(-Math.tan(THREE.Math.degToRad(30))).normalize(),
|
|
|
+ ];
|
|
|
+
|
|
|
+ let max = 50
|
|
|
+ let count2 = dirs_.length
|
|
|
+ let disArr = dirs_.map((dir_, i) =>{
|
|
|
+ let intersect = getIntersect(pano, dir_, origin)
|
|
|
+ let projectLen = intersect && intersect.distance ? dir_.dot(dir)*intersect.distance : max; //得到project在dir的长度
|
|
|
+ return projectLen //得水平距离
|
|
|
+ })
|
|
|
+ disArr.sort((a,b)=>{return b-a}); //从大到小
|
|
|
+ //console.log(pano ? pano.id : 'side','disArr', disArr)
|
|
|
+ let dis = disArr[Math.floor(count2/2-0.5)] //对半、取前(中位数)
|
|
|
+ return dis
|
|
|
+ }
|
|
|
+
|
|
|
+ let sideCount = []
|
|
|
+
|
|
|
+ let addPos = (pano, vec )=>{//添加这个pano这一侧向外半圆的顶点
|
|
|
+ //添加pano位置对应的最高点最低点:
|
|
|
+ let minZ, maxZ
|
|
|
+ minZ = pano.floorPosition.z
|
|
|
+
|
|
|
+ if(pano.ceilZ != void 0){
|
|
|
+ maxZ = pano.ceilZ
|
|
|
+ }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 dir2 = dir1.clone().applyMatrix4(rotMat1)
|
|
|
+ let dir3 = dir1.clone().applyMatrix4(rotMat2)
|
|
|
+ let skyHeight = 50
|
|
|
+ let zs = [dir1,dir2,dir3].map(dir_=>{
|
|
|
+ let intersect = getIntersect(pano, dir_)
|
|
|
+ let z = intersect ? intersect.location.z : pano.position.z+skyHeight //没有intersect代表可能是天空
|
|
|
+ return z
|
|
|
+ })
|
|
|
+ zs.sort((a,b)=>{return b-a});//得最大值 (不用中位数的原因:在屋檐处,如果仅有一个intersect是天空,因到了室外所以也用天空高度)
|
|
|
+ maxZ = zs[0]
|
|
|
+
|
|
|
+ let min = pano.position.z + 1 // 防止意外太低
|
|
|
+ maxZ = Math.max(min,maxZ)
|
|
|
+ pano.ceilZ = maxZ
|
|
|
+ //console.log(pano.id, 'maxZ:',maxZ )
|
|
|
+ //console.log(pano.id, 'minZ:',minZ )
|
|
|
+ }
|
|
|
+ [maxZ, minZ ].forEach(z=>{
|
|
|
+ posArr.push(pano.position.clone().setZ(z))
|
|
|
+ })
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ //在画面上线条从左往右数
|
|
|
+ const angle = Math.PI/(count1-1)
|
|
|
+ const dirs = []; //平分这半边180度
|
|
|
+ for(let i=0;i<count1;i++){
|
|
|
+ dirs.push(getDir(Math.PI/2-i*angle, vec))//正的在左边
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ // let sideDis = []
|
|
|
+ dirs.forEach((dir, index)=>{
|
|
|
+ let dis = getFar(dir, pano);
|
|
|
+ // if(index == 0 || index == count1-1){
|
|
|
+ // sideDis.push(dis)
|
|
|
+ // }
|
|
|
+ dir.multiplyScalar( dis );
|
|
|
+
|
|
|
+ [maxZ,minZ].forEach(z=>{
|
|
|
+ posArr.push(pano.position.clone().setZ(z).add(dir)) //获取到外墙点
|
|
|
+ })
|
|
|
+
|
|
|
+
|
|
|
+ });
|
|
|
+
|
|
|
+ //panoIndex ++
|
|
|
+ //return sideDis;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ let addSide = ()=>{//两个漫游点间两边各加一些侧线
|
|
|
+ //中点处的
|
|
|
+ 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])]//
|
|
|
+ */
|
|
|
+
|
|
|
+
|
|
|
+ if(pano0.pointcloud.hasDepthTex && pano0.pointcloud.hasDepthTex){
|
|
|
+ let panos = [pano0,pano1]
|
|
|
+ let vecs = [vec.clone().negate(), vec]
|
|
|
+ let axis = [[-1,1],[1,-1]]
|
|
|
+ let dis2d = new THREE.Vector2().subVectors(pano0.position, pano1.position).length()//水平上的距离
|
|
|
+ let angles = [THREE.Math.degToRad(40), THREE.Math.degToRad(70)] //正的在左边 尽量能够平分中间这段墙体
|
|
|
+ axis.forEach((axis_, index0)=>{
|
|
|
+ let disToSides = []
|
|
|
+ let accordingPano = index0 == 0 ? pano0 : pano1; //根据离该点在vec方向上的距离顺序来存顶点
|
|
|
+ panos.forEach((pano,index)=>{
|
|
|
+ let dirs = [getDir(axis_[index]*angles[0], vecs[index]), getDir(axis_[index]*angles[1], vecs[index])];//一侧的若干角度
|
|
|
+
|
|
|
+ dirs.forEach((dir_,i)=>{
|
|
|
+ let dis1 = getFar(dir_, pano);
|
|
|
+
|
|
|
+ let disToPano2d = dis1 * Math.cos(angles[i])
|
|
|
+ if(disToPano2d<dis2d){//超过的话都到另一半pano的半圆了,不计入
|
|
|
+ let disToSide = dis1 * Math.sin(angles[i])
|
|
|
+
|
|
|
+ if(pano != accordingPano){
|
|
|
+ disToPano2d = dis2d - disToPano2d //反一下
|
|
|
+ }
|
|
|
+
|
|
|
+ dir_.multiplyScalar( dis1 );
|
|
|
+ disToSides.push({disToSide,disToPano2d, pano, dir_})
|
|
|
+ }
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+
|
|
|
+ sideCount[index0] = disToSides.length //记录侧边个数
|
|
|
+
|
|
|
+ if(disToSides.length){
|
|
|
+ //disToSides.sort((a,b)=>{return b-a});//从大到小
|
|
|
+ //由距离accordingPano的近到远:
|
|
|
+ disToSides.sort((a,b)=>{return a.disToPano2d-b.disToPano2d})
|
|
|
+
|
|
|
+ //console.log('disToSides', index0, disToSides)
|
|
|
+
|
|
|
+
|
|
|
+ disToSides.forEach(e=>{//求z
|
|
|
+ let ratio = e.disToPano2d / dis2d
|
|
|
+ let r = accordingPano == pano0 ? (1-ratio) : ratio
|
|
|
+ let sideMaxZ_ = pano0.ceilZ * r + pano1.ceilZ * (1-r);
|
|
|
+ let sideMinZ_ = pano0.floorPosition.z * r + pano1.floorPosition.z * (1-r);
|
|
|
+ [sideMaxZ_,sideMinZ_].forEach(z=>{
|
|
|
+ posArr.push(e.pano.position.clone().setZ(z).add(e.dir_)) //是直接使用最长dis的那个intersect点好还是mid
|
|
|
+ })
|
|
|
+
|
|
|
+ })
|
|
|
+
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ }else{
|
|
|
+ //这段针对点云时,仅测试才会执行到
|
|
|
+ sideCount = [1,1]
|
|
|
+ let sideDirs = [getDir(Math.PI/2, vec), getDir(-Math.PI/2, vec)]
|
|
|
+ sideDirs.forEach((dir_ ,index)=>{
|
|
|
+ let dis = getFar(dir_, null, mid); //直接从中点求两侧的距离
|
|
|
+ dir_.multiplyScalar( /* Math.max( */dis/* , sideDis[index]) */ );
|
|
|
+ [midMaxZ,midMinZ].forEach(z=>{
|
|
|
+ posArr.push(mid.clone().setZ(z).add(dir_))
|
|
|
+ })
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ //中心:
|
|
|
+ [midMaxZ,midMinZ].forEach(z=>{
|
|
|
+ posArr.push(mid.clone().setZ(z))
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ //positions存放顺序:pano的每边的 zMax和zMin 、count1个dir的点 ;侧边的点 ;连接处顶底的中点
|
|
|
+ let addFaces = ()=>{
|
|
|
+
|
|
|
+ let getPI = function(index, posType, panoIndex){//获取顶点序号
|
|
|
+ return 2 + (count1*2 + 2 ) * panoIndex + index*2 + (posType == 'top' ? 0 : 1)
|
|
|
+ }
|
|
|
+ let getSidePI = function(index, posType, panoIndex){//获取侧边顶点序号
|
|
|
+ if(panoIndex == 1) index += sideCount[0]
|
|
|
+ return getPI(index, posType, 2)-2
|
|
|
+ }
|
|
|
+ let getPanoPI = function(posType, panoIndex){//获取pano处对应的点序号
|
|
|
+ return getPI(-1, posType, panoIndex)
|
|
|
+ }
|
|
|
+ let topCenter = posArr.length-2; //最后添加的两个中心点
|
|
|
+ let btmCenter = posArr.length-1;
|
|
|
+
|
|
|
+ for(let i=0;i<2;i++){
|
|
|
+ for(let index=1; index<count1; index++){
|
|
|
+ //pano外侧半圆围墙
|
|
|
+ faceArr.push([getPI(index,'top',i), getPI(index-1,'btm',i), getPI(index-1,'top',i)],//加入一块四方面
|
|
|
+ [getPI(index,'top',i), getPI(index,'btm',i), getPI(index-1,'btm',i)])
|
|
|
+
|
|
|
+ faceArr.push([getPI(index,'top',i), getPI(index-1,'top',i), getPanoPI('top',i)])//天花板扇形
|
|
|
+ faceArr.push([getPI(index,'btm',i), getPI(index-1,'btm',i), getPanoPI('btm',i)])//地板扇形
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ let j = (i + 1) % 2; //另一个pano
|
|
|
+
|
|
|
+
|
|
|
+ //侧边
|
|
|
+
|
|
|
+ for(let u=0; u<=sideCount[i]; u++){
|
|
|
+ //侧边每个四方的左上右上左下右下四个点
|
|
|
+ let pLT = u == 0 ? getPI(0,'top',i) : getSidePI(u-1, 'top',i)
|
|
|
+ let pRT = u == sideCount[i] ? getPI(count1-1,'top',j) : getSidePI(u, 'top',i)
|
|
|
+ let pLB = u == 0 ? getPI(0,'btm',i) : getSidePI(u-1, 'btm',i)
|
|
|
+ let pRB = u == sideCount[i] ? getPI(count1-1,'btm',j) : getSidePI(u, 'btm',i)
|
|
|
+
|
|
|
+ faceArr.push([pLT,pLB,pRB],[pLT,pRB,pRT])//外侧四方面
|
|
|
+ faceArr.push([pLT,topCenter,pRT] ,[pLB,btmCenter,pRB] )//顶部和底部到整体中心的扇形(由于点的顺序是根据和两个pano的距离,因此到中心的夹角并没按顺序排列,所以可能会重叠)
|
|
|
+
|
|
|
+ if(i==0){//只需要算一次
|
|
|
+ //顶部和底部中心与两个pano边构成的三角形
|
|
|
+ if(u == 0){
|
|
|
+ faceArr.push([pLT,getPI(count1-1,'top',i),topCenter],
|
|
|
+ [pLB,getPI(count1-1,'btm',i),btmCenter],
|
|
|
+ )
|
|
|
+ }
|
|
|
+ //不能用else 因为当length==0时u==0也==sideCount[i],此时就是要两个面
|
|
|
+ if(u == sideCount[i]){
|
|
|
+ faceArr.push([pRT,getPI(0,'top',j),topCenter],
|
|
|
+ [pRB,getPI(0,'btm',j),btmCenter],
|
|
|
+ )
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ let posArr = [];
|
|
|
+ let faceArr = []
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ //两点连线的水平向量
|
|
|
+ let vec = new THREE.Vector3().subVectors(pano0.position, pano1.position).setZ(0).normalize()
|
|
|
+
|
|
|
+ /* let sideDis0 = */addPos(pano0, vec)
|
|
|
+ /* let sideDis1 = */addPos(pano1, vec.clone().negate())
|
|
|
+ addSide()
|
|
|
+ addFaces()
|
|
|
+
|
|
|
+ //MeshDraw.updateGeometry(this.cube.geometry, posArr, faceArr)
|
|
|
+ let geo = MeshDraw.createGeometry(posArr, faceArr)
|
|
|
+ this.cube.geometry = geo
|
|
|
+ this.cube.scale.set(1,1,1);
|
|
|
+ this.cube.position.set(0,0,0)
|
|
|
+
|
|
|
+
|
|
|
+ //this.cube.scale.set(100,100,100);
|
|
|
+ //this.cube.position.copy(pano1.position).multiplyScalar(-100)
|
|
|
+ }else{
|
|
|
+
|
|
|
+ useBound(pano0.pointcloud.bound)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
/*
|
|
|
注: 修改skybox,若不准的话,会遮住其他mesh,比如marker。尤其在没有深度贴图时。
|
|
|
|
|
@@ -1516,7 +1893,7 @@ export class Images360 extends THREE.EventDispatcher{
|
|
|
if (!this.flying) {
|
|
|
|
|
|
console.log('bump')
|
|
|
- let distance = Potree.settings.displayMode == 'showPanos' ? 0.4 : 0.2;//感觉点云模式比全景模式更明显,所以降低
|
|
|
+ let distance = Potree.settings.displayMode == 'showPanos' ? 0.3 : 0.2;//感觉点云模式比全景模式更明显,所以降低
|
|
|
let currentPos = this.position.clone()
|
|
|
let endPosition = new THREE.Vector3().addVectors(this.position, direction.clone().multiplyScalar(distance))
|
|
|
|
|
@@ -1672,16 +2049,16 @@ export class Images360 extends THREE.EventDispatcher{
|
|
|
}
|
|
|
} */
|
|
|
];
|
|
|
- /* if(viewer.inputHandler.intersectPoint){//方便上楼
|
|
|
+ if(viewer.inputHandler.intersectPoint){//方便上下楼, 考虑panos之间的角度差
|
|
|
let pos1 = this.currentPano.floorPosition
|
|
|
- let vec1 = new THREE.Vector3().sub(viewer.inputHandler.intersectPoint.location, pos1 ).normalize()//应该只有atPano时才会执行到这吧?
|
|
|
+ let vec1 = new THREE.Vector3().subVectors(viewer.inputHandler.intersectPoint.location, pos1 ).normalize()//应该只有atPano时才会执行到这吧?
|
|
|
list.push( function(pano) {
|
|
|
var pos2 = pano.floorPosition;
|
|
|
var vec2 = pos2.clone().sub(pos1).normalize();
|
|
|
- console.log('direction2', pano.id, vec2.dot(vec1) * directionFactor * 1 );
|
|
|
+ //console.log('direction2', pano.id, vec2.dot(vec1) * directionFactor * 1 );
|
|
|
return vec2.dot(vec1) * directionFactor * 1
|
|
|
})
|
|
|
- } */
|
|
|
+ }
|
|
|
|
|
|
this.findRankedByScore(t,request,list,panoSet);
|
|
|
|
|
@@ -1737,9 +2114,9 @@ export class Images360 extends THREE.EventDispatcher{
|
|
|
ifNeighbour = false
|
|
|
}
|
|
|
}else{
|
|
|
- //使用点云判断
|
|
|
+ //使用点云判断(有深度贴图时不会执行到这)
|
|
|
ifNeighbour = !viewer.inputHandler.ifBlockedByIntersect(pano1.position, margin, true, pano0.position)
|
|
|
-
|
|
|
+ console.log('使用点云判断')
|
|
|
if(ifNeighbour){//点云模式下未加载的点云会判断为true
|
|
|
let dir = new THREE.Vector3().subVectors(pano1.position,pano0.position).normalize()
|
|
|
let dis = pano1.position.distanceTo(pano0.position)
|
|
@@ -2352,7 +2729,12 @@ export class Images360 extends THREE.EventDispatcher{
|
|
|
|
|
|
/* pano.mesh.layers.set(Potree.config.renderLayers.marker)
|
|
|
pano.marker.layers.set(Potree.config.renderLayers.marker) */
|
|
|
-
|
|
|
+
|
|
|
+
|
|
|
+ pano.addEventListener('dispose',(e)=>{
|
|
|
+ if(this.closestPano == pano) this.closestPano = null
|
|
|
+ })
|
|
|
+
|
|
|
this.panos.push(pano);
|
|
|
if(Potree.settings.editType == 'pano'){
|
|
|
Potree.settings.datasetsPanos[datasetId].panos.push(pano);
|
|
@@ -2536,7 +2918,7 @@ Images360.filters = {
|
|
|
Images360.scoreFunctions = {
|
|
|
direction: function(curPos, dir, ifLog) {
|
|
|
return function(pano) {
|
|
|
- var pos1 = pano.floorPosition //pano.position 改为权重放在marker上,这样对有斜坡的更准确,如上楼
|
|
|
+ var pos1 = /* pano.floorPosition */ pano.position //旧:改为权重放在marker上,这样对有斜坡的更准确,如上楼, 但这样近距离的pano角度就会向下了,以致于走不到
|
|
|
var n = pos1.clone().sub(curPos).normalize();
|
|
|
//ifLog && console.log('direction', pano.id, n.dot(dir) * directionFactor )
|
|
|
return n.dot(dir) * directionFactor
|