|
@@ -58,7 +58,7 @@ import {OBJLoader} from "../../../libs/three.js/loaders/OBJLoader.js";
|
|
|
import {MTLLoader} from "../../../libs/three.js/loaders/MTLLoader.js";
|
|
|
import {GLTFLoader} from "../../../libs/three.js/loaders/GLTFLoader.js";
|
|
|
import {Loader3DTiles} from '../../../libs/three.js/3dtiles/three-loader-3dtiles.esm.js';
|
|
|
-
|
|
|
+import {PLYLoader} from "../../../libs/three.js/loaders/PLYLoader.js";
|
|
|
|
|
|
|
|
|
import SSAARenderPass from "../materials/postprocessing/SSAARenderPass.js"
|
|
@@ -82,7 +82,7 @@ const manager = new THREE.LoadingManager();
|
|
|
let loaders = {}
|
|
|
|
|
|
let mapArea;
|
|
|
-let blockedByIntersectHistory = new Map();
|
|
|
+let shelterHistory = []
|
|
|
|
|
|
|
|
|
|
|
@@ -124,12 +124,20 @@ export class Viewer extends ViewerBase{
|
|
|
}
|
|
|
{
|
|
|
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;
|
|
|
+ depthSampler : {minCount:400, median: 25}, //median预置一个中等值,以防止cpu过低的设备首次卡顿
|
|
|
+
|
|
|
}
|
|
|
+
|
|
|
+ setTimeout(()=>{
|
|
|
+ for(let i in Potree.timeCollect){
|
|
|
+ Potree.timeCollect[i].measures = [];
|
|
|
+ Potree.timeCollect[i].sum = 0;
|
|
|
+ Potree.timeCollect[i].start = true
|
|
|
+ }
|
|
|
+ /* setTimeout(()=>{
|
|
|
+ console.log('timeCollect', Potree.timeCollect.depthSampler.median, Potree.timeCollect.depthSampler.ave, Potree.timeCollect.depthSampler.measures.length)
|
|
|
+ },10000) */
|
|
|
+ },2000)
|
|
|
}
|
|
|
|
|
|
|
|
@@ -535,8 +543,8 @@ export class Viewer extends ViewerBase{
|
|
|
loaders = {
|
|
|
objLoader : new OBJLoader( manager ),
|
|
|
mtlLoader : new MTLLoader( manager ),
|
|
|
- glbLoader : new GLTFLoader(undefined, this.renderer, Potree.settings.libsUrl )
|
|
|
-
|
|
|
+ glbLoader : new GLTFLoader(undefined, this.renderer, Potree.settings.libsUrl ),
|
|
|
+ plyLoader : new PLYLoader( manager ),
|
|
|
}
|
|
|
//add test
|
|
|
/* const environment = new RoomEnvironment();
|
|
@@ -713,24 +721,16 @@ export class Viewer extends ViewerBase{
|
|
|
this.addEventListener('camera_changed', e => {
|
|
|
|
|
|
if(e.viewport == this.mainViewport && (e.changeInfo.positionChanged || zoomLevel != this.images360.zoomLevel)){
|
|
|
- zoomLevel = this.images360.zoomLevel
|
|
|
- blockedByIntersectHistory.clear() //清空
|
|
|
- this.updateDatasetAt() //更新所在数据集
|
|
|
+ zoomLevel = this.images360.zoomLevel //对updateMarkerVisibles有影响
|
|
|
+ //e.changeInfo.positionChanged && shelterHistory.clear() //清空
|
|
|
+ e.changeInfo.positionChanged && this.updateDatasetAt() //更新所在数据集
|
|
|
|
|
|
if(Potree.settings.ifShowMarker && Potree.settings.editType != 'merge'){
|
|
|
- updated = true
|
|
|
-
|
|
|
- Common.intervalTool.isWaiting('updateMarkerVisibles', ()=>{
|
|
|
-
|
|
|
- if(!updated)return
|
|
|
-
|
|
|
+
|
|
|
+ Common.intervalTool.isWaiting('updateMarkerVisibles', ()=>{
|
|
|
if(!this.mainViewport.view.isFlying() ){
|
|
|
- this.updateMarkerVisibles()
|
|
|
- updated = false
|
|
|
- }
|
|
|
-
|
|
|
- return true
|
|
|
-
|
|
|
+ this.updateMarkerVisibles()
|
|
|
+ }
|
|
|
},500)
|
|
|
}
|
|
|
}
|
|
@@ -741,6 +741,25 @@ export class Viewer extends ViewerBase{
|
|
|
})
|
|
|
|
|
|
|
|
|
+
|
|
|
+ /* if(!Potree.Features.EXT_DEPTH.isSupported()){
|
|
|
+
|
|
|
+ this.images360.addEventListener('endChangeMode',(e)=>{
|
|
|
+ if(e.mode == 'showPanos'){
|
|
|
+ this.updateMarkerVisibles()
|
|
|
+ }
|
|
|
+ }) */
|
|
|
+ this.images360.addEventListener('getNeighbourAuto',(e)=>{
|
|
|
+ if(/* Potree.settings.displayMode == 'showPanos' && */e.panos.includes(this.images360.currentPano)){
|
|
|
+ Common.intervalTool.isWaiting('updateMarkerVisibles', ()=>{
|
|
|
+ this.updateMarkerVisibles()
|
|
|
+ },500)
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ /* } */
|
|
|
+
|
|
|
+
|
|
|
}
|
|
|
|
|
|
|
|
@@ -748,17 +767,208 @@ export class Viewer extends ViewerBase{
|
|
|
}
|
|
|
|
|
|
|
|
|
- ifPointBlockedByIntersect(pos3d, object){//点是否被遮挡
|
|
|
+
|
|
|
+
|
|
|
+ ifPointBlockedByIntersect(pos3d , panoId, soon ){//点是否被遮挡
|
|
|
let ifShelter
|
|
|
- let shelter = blockedByIntersectHistory.get(object || pos3d);
|
|
|
- if(shelter){
|
|
|
- ifShelter = shelter.ifShelter
|
|
|
- }else{
|
|
|
- ifShelter = viewer.inputHandler.ifBlockedByIntersect(pos3d, 0.3, true)//由于热点都是使用点云得到的位置,所以判断遮挡时也用点云
|
|
|
- blockedByIntersectHistory.set(object || pos3d, {ifShelter})
|
|
|
+ let now = Date.now()
|
|
|
+ let extraPanoId = panoId != void 0
|
|
|
+ if(!this.shelterCount)return
|
|
|
+
|
|
|
+ let history = shelterHistory.find(e=>e.pos3d.equals(pos3d))
|
|
|
+ let cameraPos = this.mainViewport.view.position.clone()
|
|
|
+ if(panoId == void 0){
|
|
|
+ if(this.images360.isAtPano(0.05)){
|
|
|
+ panoId = this.images360.currentPano.id
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ if(history){
|
|
|
+ if(panoId != void 0){
|
|
|
+ ifShelter = history.panos[panoId];
|
|
|
+ }else{
|
|
|
+ if(history.notAtPano.cameraPos && history.notAtPano.cameraPos.equals(cameraPos)){
|
|
|
+ ifShelter = history.notAtPano.ifShelter
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ let index = shelterHistory.indexOf(history) //先取出,稍后放回
|
|
|
+ shelterHistory.splice(index, 1)
|
|
|
+
|
|
|
+ }else{//新增
|
|
|
+ history = {pos3d, panos:{}, notAtPano:{}}
|
|
|
+
|
|
|
+ const minCount = 100
|
|
|
+ if(shelterHistory.length > minCount){//去除最早的
|
|
|
+ let old
|
|
|
+ while(old = shelterHistory[0], now - old.lastTime > 1000){//因为不知热点个数,所以需要加上时间限制,超过时间才能删。
|
|
|
+ if(old == history || shelterHistory.length == minCount)break;
|
|
|
+ shelterHistory.splice(0,1)
|
|
|
+ //console.log('delete')
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ if(ifShelter == void 0){
|
|
|
+ delete history.waitCompute
|
|
|
+
|
|
|
+ if(this.mainViewport.view.isFlying()){
|
|
|
+ return useLastResult()
|
|
|
+ }
|
|
|
+
|
|
|
+ if(panoId != void 0){
|
|
|
+ let pano = this.images360.getPano(panoId)
|
|
|
+ if((soon || this.shelterCount.byTex<this.shelterCount.maxByTex) && pano.depthTex){
|
|
|
+ ifShelter = !!viewer.inputHandler.ifBlockedByIntersect({pos3d, margin:Potree.config.shelterMargin, useDepthTex:true, pano } )
|
|
|
+ history.panos[panoId] = ifShelter
|
|
|
+ this.shelterCount.byTex ++ ;
|
|
|
+ //console.log('computeByTex direct', panoId, pos3d, ifShelter)
|
|
|
+ }else{
|
|
|
+ //console.log('延迟tex',panoId, pos3d )
|
|
|
+ history.waitCompute = {panoId, forceGet:extraPanoId }
|
|
|
+ return useLastResult()
|
|
|
+ }
|
|
|
+ }else{
|
|
|
+ if(/* history.ifShelter == void 0 || */ this.shelterCount.byCloud<this.shelterCount.maxByCloud){//弊端:第一个总是直接计算,后面的都是延后。但无法改进,因是一个个传进来的,无法预测。
|
|
|
+ ifShelter = !!viewer.inputHandler.ifBlockedByIntersect({pos3d, margin:Potree.config.shelterMargin, pickWindowSize:3} )
|
|
|
+ history.notAtPano = {cameraPos , ifShelter }
|
|
|
+ this.shelterCount.byCloud ++ ;
|
|
|
+ //console.log('computeByCloud direct', pos3d.toArray())
|
|
|
+ }else{
|
|
|
+ //console.log('延迟cloud' )
|
|
|
+ history.waitCompute = {cameraPos}
|
|
|
+ return useLastResult()
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
}
|
|
|
+
|
|
|
+
|
|
|
+ history.ifShelter = ifShelter
|
|
|
+ history.lastTime = now
|
|
|
+ shelterHistory.push(history) //最新使用的保持在最后一个,使队列按照从旧到新排列
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ function useLastResult(){//暂时先用上一次的值
|
|
|
+ shelterHistory.push(history)
|
|
|
+ history.lastTime = now
|
|
|
+ return history.ifShelter
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
return ifShelter
|
|
|
}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ computeShelter(){
|
|
|
+ //先算用深度图的,然后再点云;
|
|
|
+
|
|
|
+ let depthTiming = Potree.timeCollect.depthSampler.median
|
|
|
+ let byTex=0, byCloud=0;
|
|
|
+ let len = shelterHistory.length;
|
|
|
+ let waitCloud = []
|
|
|
+ let max = this.mainViewport.view.isFlying() ? 1 : Math.min(1/depthTiming, 10); //起飞时lastFrameChanged还是false,所以不用lastFrameChanged
|
|
|
+ let maxTexCount = Common.getBestCount('shelterMaxDepthSample', 1, max, 1, 13 /* ,true */ )
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ for(let i=len-1; i>=0; i--){
|
|
|
+ let history = shelterHistory[i];
|
|
|
+
|
|
|
+ if(history.waitCompute){
|
|
|
+ if(history.waitCompute.panoId != void 0){
|
|
|
+ if(!history.waitCompute.forceGet && (history.waitCompute.panoId != this.images360.currentPano.id || !this.images360.isAtPano(0.1))){
|
|
|
+ delete history.waitCompute //取消计算
|
|
|
+ }else{
|
|
|
+ if(this.images360.currentPano.depthTex){
|
|
|
+ if(byTex >= maxTexCount)break
|
|
|
+
|
|
|
+ byTex ++
|
|
|
+ let ifShelter = !!viewer.inputHandler.ifBlockedByIntersect({pos3d:history.pos3d, margin:Potree.config.shelterMargin, useDepthTex:true } )
|
|
|
+ history.panos[this.images360.currentPano.id] = ifShelter
|
|
|
+ history.ifShelter = ifShelter
|
|
|
+ delete history.waitCompute
|
|
|
+ //console.log('补1', history.pos3d.toArray())
|
|
|
+ }else{
|
|
|
+ if(this.images360.currentPano.pointcloud.hasDepthTex){
|
|
|
+ //先等待加载完深度图
|
|
|
+ }else{
|
|
|
+ waitCloud.push(history)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }else{
|
|
|
+ waitCloud.push(history)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ let maxCloudCount
|
|
|
+ if(byTex < maxTexCount && waitCloud.length){
|
|
|
+ maxCloudCount = this.lastFrameChanged ? Common.getBestCount('shelterMaxCloud', 0, 2, 4, 8 /* ,true */ ) : 5;
|
|
|
+ let waitCloud2 = []
|
|
|
+ if(maxCloudCount){
|
|
|
+ for(let i=0; i<waitCloud.length; i++){
|
|
|
+
|
|
|
+ let history = waitCloud[i];
|
|
|
+ if(history.waitCompute.cameraPos){
|
|
|
+ if(!viewer.mainViewport.view.position.equals(history.waitCompute.cameraPos)){
|
|
|
+ delete history.waitCompute
|
|
|
+ //console.log('delete history.waitCompute', history)
|
|
|
+ continue; //取消计算
|
|
|
+ }else{
|
|
|
+ waitCloud2.push(history)
|
|
|
+ }
|
|
|
+ }else{
|
|
|
+ waitCloud2.push(history)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ let list = waitCloud2.map(e=>e.pos3d)
|
|
|
+ let result = Common.batchHandling.getSlice('shelterByCloud', list, {maxUseCount:maxCloudCount,useEquals:true, stopWhenAllUsed:true} ) //iphonex稳定后大概在7-10。
|
|
|
+ //list.length>0 && console.log('list',list, maxCloudCount)
|
|
|
+
|
|
|
+ result.list.forEach(e=>{
|
|
|
+ let history = waitCloud2.find(a=>a.pos3d.equals(e))
|
|
|
+
|
|
|
+ let ifShelter = !!viewer.inputHandler.ifBlockedByIntersect({pos3d:history.pos3d, margin: Potree.config.shelterMargin , pickWindowSize:3} )
|
|
|
+
|
|
|
+ if(history.waitCompute.cameraPos){
|
|
|
+ history.notAtPano = {cameraPos: history.waitCompute.cameraPos , ifShelter }
|
|
|
+ }else{
|
|
|
+ history.panos[this.images360.currentPano.id] = ifShelter
|
|
|
+ }
|
|
|
+ history.ifShelter = ifShelter
|
|
|
+ byCloud++
|
|
|
+ //console.log('补2', history.pos3d.toArray())
|
|
|
+ delete history.waitCompute
|
|
|
+ })
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ if(byTex || byCloud){
|
|
|
+ //console.log('shelterComputed',byTex,byCloud, maxTexCount, maxCloudCount)
|
|
|
+ Common.intervalTool.isWaiting('shelterComputed', ()=>{
|
|
|
+ //console.log('shelterComputed update')
|
|
|
+ this.dispatchEvent('shelterComputed')
|
|
|
+ },340)
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
|
|
|
updateDatasetAt(force){//更新所在数据集
|
|
|
|
|
@@ -780,9 +990,9 @@ export class Viewer extends ViewerBase{
|
|
|
this.dispatchEvent({type:'pointcloudAtChange',pointclouds:at})
|
|
|
}
|
|
|
force = false
|
|
|
- return true
|
|
|
- //}
|
|
|
- }
|
|
|
+
|
|
|
+ }
|
|
|
+ //}
|
|
|
if(force)fun()
|
|
|
else Common.intervalTool.isWaiting('atWhichDataset', fun , 300)
|
|
|
|
|
@@ -799,22 +1009,29 @@ export class Viewer extends ViewerBase{
|
|
|
|
|
|
updateMarkerVisibles(){//限制显示的marker个数,因镜头内marker多的时候可能会卡
|
|
|
if(!Potree.settings.ifShowMarker)return
|
|
|
-
|
|
|
+
|
|
|
|
|
|
const minRadius = 8 * this.images360.zoomLevel, //当视线垂直于marker时的最小可见距离,此范围内可见的pano绝对可见
|
|
|
maxRadius = 50 * this.images360.zoomLevel, //当视线垂直于marker时的最大可见距离,此范围外绝对不可见
|
|
|
hopeCount = browser.isMobile() ? 8 : 15 //期望达到的真实可见的marker数
|
|
|
-
|
|
|
- let panoMap = new Map
|
|
|
|
|
|
- let set = ()=>{
|
|
|
+
|
|
|
+ let sheltered = (pano)=>{
|
|
|
+ if(/* Potree.settings.displayMode == 'showPanos' && !Potree.Features.EXT_DEPTH.isSupported() && */this.images360.isAtPano() && !this.mainViewport.view.isFlying()){
|
|
|
+ return !this.images360.currentPano.neighbours.includes(pano) && this.images360.currentPano != pano //起初因不支持EXT_DEPTH时无法用depthTex遮住marker, 后为了减少绘制,都判断
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ let panoMap = new Map //先记录想要设置为可见的
|
|
|
+
|
|
|
+ let set = ()=>{//最后确定设置
|
|
|
let count = 0
|
|
|
viewer.images360.panos.forEach(pano=>{
|
|
|
let v = panoMap.get(pano).visible
|
|
|
v && count++
|
|
|
Potree.Utils.updateVisible(pano.marker, 'limitMarkerShow', v )
|
|
|
})
|
|
|
- //console.log('marker显示个数', count)
|
|
|
+ //console.log('updateMarkerVisibles marker显示个数', count)
|
|
|
}
|
|
|
let isWithinDis = (pano,maxDis)=>{//是否marker到相机的距离 没有超出可视距离。可视距离考虑上倾斜角,倾斜越大可视距离越短
|
|
|
let camPos = viewer.mainViewport.camera.position
|
|
@@ -824,24 +1041,25 @@ export class Viewer extends ViewerBase{
|
|
|
return o.dis < maxDis * o.sin
|
|
|
}
|
|
|
|
|
|
+
|
|
|
viewer.images360.panos.forEach(pano=>{//minRadius内的记录为可见
|
|
|
let o = {}
|
|
|
panoMap.set(pano, o)
|
|
|
- if(pano.visible && isWithinDis(pano, minRadius)){
|
|
|
+ if(pano.visible && !sheltered(pano) && isWithinDis(pano, minRadius)){
|
|
|
o.visible = true;
|
|
|
}
|
|
|
})
|
|
|
- //真正可见的要过滤本来pano就不可见的
|
|
|
+ //不超过hopeCount的话,可以直接确定设置
|
|
|
if(viewer.images360.panos.filter(pano=> panoMap.get(pano).visible ).length >= hopeCount)return set()
|
|
|
|
|
|
//距离超过maxRadius就绝对不可见
|
|
|
- let insideOutCirle = viewer.images360.panos.filter(pano=> pano.visible && isWithinDis(pano, maxRadius))
|
|
|
+ let insideOutCirle = viewer.images360.panos.filter(pano=> pano.visible && !sheltered(pano) && isWithinDis(pano, maxRadius))
|
|
|
if(insideOutCirle.length <= hopeCount){
|
|
|
insideOutCirle.forEach(pano=>panoMap.get(pano).visible = true )
|
|
|
return set()
|
|
|
}
|
|
|
|
|
|
- //数量超过minCount时,根据距离排序
|
|
|
+ //数量超过hopeCount时,根据距离排序
|
|
|
insideOutCirle.sort((a,b)=>{return panoMap.get(a).dis - panoMap.get(b).dis })
|
|
|
let slice = insideOutCirle.slice(0,hopeCount)
|
|
|
slice.forEach(pano=>panoMap.get(pano).visible = true )
|
|
@@ -994,6 +1212,7 @@ export class Viewer extends ViewerBase{
|
|
|
else {
|
|
|
this.removeEventListener('camera_changed',test)
|
|
|
console.log('testPointcloudsMaxLevel结束')
|
|
|
+
|
|
|
}
|
|
|
|
|
|
}, count<10 ? 250 : 500)
|
|
@@ -2235,7 +2454,11 @@ export class Viewer extends ViewerBase{
|
|
|
update(delta, timestamp){
|
|
|
|
|
|
viewer.addTimeMark('update','start')
|
|
|
-
|
|
|
+ TWEEN.update(timestamp);
|
|
|
+ transitions.update(delta);//写在开头,因为这时候最为固定,计时准确
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
this.dispatchEvent({
|
|
|
type: 'update_start',
|
|
|
delta: delta,
|
|
@@ -2389,8 +2612,7 @@ export class Viewer extends ViewerBase{
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- TWEEN.update(timestamp);
|
|
|
- transitions.update(delta);
|
|
|
+
|
|
|
this.transformationTool.update();
|
|
|
|
|
|
|
|
@@ -2789,7 +3011,7 @@ export class Viewer extends ViewerBase{
|
|
|
if(view.render){
|
|
|
if(!view.render($.extend({}, params, {
|
|
|
renderer:this.renderer, clear:this.clear.bind(this), resize:null,
|
|
|
- renderBG:this.renderBG.bind(this), force:!view.noPointcloud //如果要渲染点云,必须也一直渲染地图,否则地图会被覆盖(点云目前未能获取是否改变,也可能有其他动态物体,所以还是一直渲染的好)
|
|
|
+ renderBG:this.renderBG.bind(this), force:true //viewer content_change时map也直接渲染吧 //!view.noPointcloud //如果要渲染点云,必须也一直渲染地图,否则地图会被覆盖(点云目前未能获取是否改变,也可能有其他动态物体,所以还是一直渲染的好)
|
|
|
})))return
|
|
|
}else{
|
|
|
this.clear(params)
|
|
@@ -2839,7 +3061,7 @@ export class Viewer extends ViewerBase{
|
|
|
|
|
|
|
|
|
this.renderer.setRenderTarget(null)
|
|
|
- this.needRender = false
|
|
|
+
|
|
|
|
|
|
viewer.scene.pointclouds[0] && this.addFakeMeasure('visibleNodes', viewer.scene.pointclouds[0].visibleNodes.length )//
|
|
|
this.addFakeMeasure('numVisiblePoints', Potree.numVisiblePoints/100000)//十万 numVisiblePoints和帧率成反比(若每一帧都render的话),和render用时成正比 (y=kn+b)。但visibleNodes个数也影响,多的话也更卡。visibleNodes和numVisiblePoints不成正比,少的visibleNodes可能numVisiblePoints多
|
|
@@ -3061,6 +3283,7 @@ export class Viewer extends ViewerBase{
|
|
|
if(vrActive){
|
|
|
this.renderVR();
|
|
|
}else{
|
|
|
+ let specialRender = !!params.viewports
|
|
|
let viewports = params.viewports || this.viewports
|
|
|
|
|
|
if(!this.needRender){
|
|
@@ -3068,15 +3291,15 @@ export class Viewer extends ViewerBase{
|
|
|
}
|
|
|
viewports = viewports.filter(v=>v.active)
|
|
|
if(viewports.length > 0){
|
|
|
- params.viewports = viewports
|
|
|
-
|
|
|
+ params.viewports = viewports
|
|
|
if(this.outlinePass.selectedObjects.length && this.outlinePass.edgeStrength > 0 && !params.screenshot){
|
|
|
let scenes = this.inputHandler.interactiveScenes.concat(this.scene.scene).concat(viewer.scene.scenePointCloud)
|
|
|
this.composer.render(scenes, null, this.viewports, this.renderDefault.bind(this));
|
|
|
}else{
|
|
|
this.renderDefault(params);
|
|
|
}
|
|
|
- }
|
|
|
+ }
|
|
|
+ if(!specialRender) this.needRender = false
|
|
|
}
|
|
|
viewer.addTimeMark('render','end')
|
|
|
}
|
|
@@ -3333,7 +3556,7 @@ export class Viewer extends ViewerBase{
|
|
|
let target = new THREE.Vector3, //相机focus的位置
|
|
|
position = new THREE.Vector3, //相机最终位置
|
|
|
dis; //相机距离目标
|
|
|
- duration = duration == void 0 ? 1500 : duration;
|
|
|
+ duration = duration == void 0 ? 1200 : duration;
|
|
|
let camera = viewer.scene.getActiveCamera()
|
|
|
let cameraPos = camera.position.clone()
|
|
|
|
|
@@ -3499,12 +3722,12 @@ export class Viewer extends ViewerBase{
|
|
|
|
|
|
//if(o.checkIntersect){
|
|
|
let checkIntersect = ( )=>{
|
|
|
- let intersect = this.inputHandler.ifBlockedByIntersect(position, null , true, target)// 不一定准确
|
|
|
+ let intersect = this.inputHandler.ifBlockedByIntersect({pos3d:position, cameraPos: target})// 不一定准确
|
|
|
if(intersect){
|
|
|
let blockCount = 0, unblockCount = 0, visi;
|
|
|
for(let i=0;i<object.points.length;i++){ //如果顶点超过一半不可见,就要更改位置
|
|
|
let p = object.points[i]
|
|
|
- let blocked = this.inputHandler.ifBlockedByIntersect(p, 0.3 , true, position, 4);
|
|
|
+ let blocked = this.inputHandler.ifBlockedByIntersect({pos3d:p, margin:0.3 , cameraPos:position, pickWindowSize:4});
|
|
|
if(blocked){
|
|
|
blockCount ++;
|
|
|
if(blockCount / object.points.length >= 0.5){
|
|
@@ -3535,7 +3758,7 @@ export class Viewer extends ViewerBase{
|
|
|
let position1 = position.clone()
|
|
|
let dir = new THREE.Vector3().subVectors(position, target)
|
|
|
position.copy(target).sub(dir)
|
|
|
- let intersect2 = this.inputHandler.ifBlockedByIntersect(position, null , true, target)// 不一定准确
|
|
|
+ let intersect2 = this.inputHandler.ifBlockedByIntersect({pos3d: position, cameraPos:target})// 不一定准确
|
|
|
if(intersect2){
|
|
|
if(intersect2.distance < intersect.distance ){
|
|
|
position.copy(position1)//恢复
|
|
@@ -3594,6 +3817,7 @@ export class Viewer extends ViewerBase{
|
|
|
this.mapViewer.moveTo(target.clone(), null, duration)
|
|
|
}
|
|
|
|
|
|
+
|
|
|
if(Potree.settings.displayMode == 'showPointCloud'){
|
|
|
if(o.dontChangePos){
|
|
|
position.copy(cameraPos)
|
|
@@ -3603,30 +3827,56 @@ export class Viewer extends ViewerBase{
|
|
|
if(o.dontLookUp && dir.z<0) dir.z *= -1
|
|
|
position.copy(target).add(dir.multiplyScalar(dis))
|
|
|
}
|
|
|
- /* if(o.checkIntersect){//识别被点云遮住的话
|
|
|
- let ifShelter
|
|
|
-
|
|
|
- while(1){
|
|
|
- ifShelter = this.inputHandler.ifBlockedByIntersect(target, o.checkMargin, true, position)
|
|
|
- if(ifShelter){
|
|
|
- if(dis > 0.5){
|
|
|
- dis --
|
|
|
- dir.dot(ifShelter.normal)>0 ? dir.copy(ifShelter.normal).negate() : dir.copy(ifShelter.normal);
|
|
|
- position.copy(target).add(dir.multiplyScalar(dis))
|
|
|
+
|
|
|
+ if(o.sameFloor){//需要在同一楼层
|
|
|
+ let atFloor = this.modules.SiteModel.pointInWhichEntity(target, 'floor')
|
|
|
+ if(atFloor){
|
|
|
+ let camFloor = this.modules.SiteModel.pointInWhichEntity(position, 'floor')
|
|
|
+ if(camFloor != atFloor){
|
|
|
+ let raycaster = new THREE.Raycaster();
|
|
|
+ let origin = target
|
|
|
+ let dir = new THREE.Vector3().subVectors( position, target ).normalize()
|
|
|
+ raycaster.set(origin, dir)
|
|
|
+ let intersect = Potree.Utils.getIntersect(null, [atFloor.box], null, raycaster)
|
|
|
+ if(intersect){
|
|
|
+ let dis = THREE.Math.clamp(intersect.distance - 0.2, camera.near, intersect.distance)
|
|
|
+ position.addVectors(origin, dir.multiplyScalar(dis))
|
|
|
+ console.log('移动到楼层')
|
|
|
+ }else{
|
|
|
+ console.error('?no intersect?')
|
|
|
}
|
|
|
- }
|
|
|
+
|
|
|
+ }
|
|
|
}
|
|
|
- } */
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ if(o.checkIntersect){//识别被点云遮住的话
|
|
|
+ let intersect //反向查找从target到相机的第一个intersect
|
|
|
+ intersect = this.inputHandler.ifBlockedByIntersect({pos3d:position, margin:0, cameraPos:target} /* {pos3d:target, margin: 0.2, cameraPos:position} */)
|
|
|
+
|
|
|
+ if(intersect){
|
|
|
+ position.copy(intersect.location)
|
|
|
+ console.log('移近')
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
|
|
|
}else if(Potree.settings.displayMode == 'showPanos'){
|
|
|
let pano = viewer.images360.fitPanoTowardPoint({
|
|
|
point : target,
|
|
|
dir : this.scene.view.direction, //尽量不改相机方向,避免镜头晃动
|
|
|
- checkIntersect: true,
|
|
|
+ checkIntersect: o.checkIntersect, sameFloor:o.sameFloor,
|
|
|
bestDistance, maxDis: o.maxDis //越近越好,但不要太近,bestDistance左右差不多
|
|
|
})
|
|
|
+ let result = {promise:deferred.promise() }
|
|
|
+ if(pano && pano.msg){
|
|
|
+ pano = pano.pano
|
|
|
+ result.msg = pano.msg
|
|
|
+ }
|
|
|
pano && viewer.images360.flyToPano({pano, target, duration, deferred, dontMoveMap:true , basePanoSize:o.basePanoSize })
|
|
|
- return {promise:deferred.promise() }
|
|
|
+
|
|
|
+ return result
|
|
|
}
|
|
|
}else if(object.boundingBox && type == 'boundingBox'){//使屏幕刚好看全boundingBox
|
|
|
target = object.boundingBox.getCenter(new THREE.Vector3)
|
|
@@ -3694,7 +3944,7 @@ export class Viewer extends ViewerBase{
|
|
|
Images360.scoreFunctions.distanceSquared({position: center})
|
|
|
]
|
|
|
let r = Common.sortByScore(pointcloud.panos, request, rank);
|
|
|
- if(r && r.length){
|
|
|
+ if(r.length){
|
|
|
return r[0].item
|
|
|
}
|
|
|
}
|
|
@@ -3746,7 +3996,7 @@ export class Viewer extends ViewerBase{
|
|
|
|
|
|
addTimeMark(name, type){
|
|
|
let record = Potree.timeCollect[name]
|
|
|
- let needRecord = record && record.measures.length < record.minCount
|
|
|
+ let needRecord = record && record.start && record.measures.length < record.minCount
|
|
|
|
|
|
if(needRecord || Potree.measureTimings){
|
|
|
performance.mark(name+"-"+type)
|
|
@@ -3756,7 +4006,7 @@ export class Viewer extends ViewerBase{
|
|
|
if(needRecord){
|
|
|
record.measures.push( measure.duration )
|
|
|
record.sum += measure.duration;
|
|
|
- record.mean = record.sum / record.measures.length;
|
|
|
+ record.ave = record.sum / record.measures.length;
|
|
|
record.measures.sort( (a, b) => a - b );
|
|
|
record.median = record.measures[parseInt(record.measures.length / 2)]
|
|
|
|
|
@@ -3913,15 +4163,21 @@ export class Viewer extends ViewerBase{
|
|
|
}
|
|
|
|
|
|
performance.mark('loop-start') ;// 无论有没有reportTimings都要获取,因为getBestCound需要
|
|
|
+
|
|
|
+ let depthTiming = Potree.timeCollect.depthSampler.median
|
|
|
+ this.shelterCount = {byTex:0, byCloud:0, maxByTex: THREE.Math.clamp(0.2/depthTiming, 1, 10), maxByCloud:0 } //清空 因ifPointBlockedByIntersect可能在任何时候触发,所以需要一开始就定义这个,且每次计算最大可计算次数太麻烦了就定义一个吧。
|
|
|
+
|
|
|
+
|
|
|
|
|
|
- this.update(this.clock.getDelta(), timestamp);
|
|
|
+ let deltaTime = this.clock.getDelta()
|
|
|
+ this.update(deltaTime, timestamp);
|
|
|
this.magnifier.render();
|
|
|
this.render();
|
|
|
|
|
|
-
|
|
|
+
|
|
|
this.objs.children.forEach(e=>{
|
|
|
- if(e.name == '3dTiles'){
|
|
|
- e.runtime.update(this.clock.getDelta(), this.renderer, this.mainViewport.camera)
|
|
|
+ if(e.fileType == '3dTiles'){
|
|
|
+ e.runtime.update(deltaTime, this.renderer, this.mainViewport.camera)
|
|
|
}
|
|
|
})
|
|
|
|
|
@@ -3944,9 +4200,8 @@ export class Viewer extends ViewerBase{
|
|
|
//-------------
|
|
|
this.images360.tileDownloader.update()
|
|
|
this.images360.panoRenderer.update()
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
+ this.images360.getNeighbours()
|
|
|
+ this.computeShelter()
|
|
|
//-------------
|
|
|
if(this.stats){
|
|
|
this.stats.end();
|
|
@@ -3956,7 +4211,7 @@ export class Viewer extends ViewerBase{
|
|
|
viewer.addTimeMark('loop','end')
|
|
|
viewer.addTimeMark('loopWaitNext','start')
|
|
|
this.resolveTimings(timestamp, Potree.measureTimings);
|
|
|
-
|
|
|
+ //Potree.measureTimings = 1
|
|
|
}
|
|
|
|
|
|
postError(content, params = {}){
|
|
@@ -4183,8 +4438,8 @@ export class Viewer extends ViewerBase{
|
|
|
}
|
|
|
])
|
|
|
//若要求更准确的话,可以使用ifContainsPoint判断一下是否在bound中
|
|
|
- let r = result && result[0];
|
|
|
- return r.score > 1 ? result[0].item : null
|
|
|
+ let r = result[0];
|
|
|
+ return r && r.score > 1 ? result[0].item : null
|
|
|
}
|
|
|
|
|
|
/* addObjectTest1(){//加水管
|
|
@@ -4257,7 +4512,7 @@ export class Viewer extends ViewerBase{
|
|
|
*/
|
|
|
|
|
|
async loadModel(fileInfo, done, onProgress_, onError){
|
|
|
-
|
|
|
+ console.log('开始加载', Common.getNameFromURL(fileInfo.name) )
|
|
|
|
|
|
let boundingBox = new THREE.Box3()
|
|
|
/* if(!Potree.settings.boundAddObjs){
|
|
@@ -4282,15 +4537,13 @@ export class Viewer extends ViewerBase{
|
|
|
return
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
-
|
|
|
+ fileInfo.url = Common.dealURL(fileInfo.url) //去除'+'
|
|
|
+ fileInfo.loadStartTime = Date.now()
|
|
|
//let fileType = fileInfo.tilesUrl ? '3dTiles' : fileInfo.objurl ? 'obj' : 'glb'
|
|
|
|
|
|
|
|
|
let loadDone = (object, fileInfo_ /* , total, url */)=>{
|
|
|
- /* let weight = Math.round((total / 1024 / 1024) * 100) / 100;
|
|
|
- url && console.log(url.split('/').pop() , '加载完毕, 模型数据量:' + weight + 'M')
|
|
|
- */
|
|
|
+
|
|
|
fileInfo_ = fileInfo_ || fileInfo
|
|
|
if(fileInfo_.parentInfo){
|
|
|
object.name = fileInfo_.name
|
|
@@ -4304,6 +4557,7 @@ export class Viewer extends ViewerBase{
|
|
|
}
|
|
|
|
|
|
object.name = fileInfo_.name != void 0 ? fileInfo_.name : fileInfo_.type
|
|
|
+ object.fileType = fileInfo_.fileType
|
|
|
object.boundingBox = boundingBox //未乘上matrixWorld的本地boundingBox
|
|
|
//object.scale.set(1,1,1);//先获取原始的大小时的boundingBox
|
|
|
object.opacity = 1 //初始化 记录
|
|
@@ -4312,6 +4566,11 @@ export class Viewer extends ViewerBase{
|
|
|
if(fileInfo_.id != void 0)object.dataset_id = fileInfo_.id
|
|
|
|
|
|
|
|
|
+ fileInfo_.loadCostTime = Date.now() - fileInfo_.loadStartTime
|
|
|
+ /* let weight = Math.round((total / 1024 / 1024) * 100) / 100;*/
|
|
|
+ console.log( '加载完毕:', Common.getNameFromURL(fileInfo_.name), '耗时(ms)', fileInfo_.loadCostTime, /* 模型数据量:' + weight + 'M' */)
|
|
|
+
|
|
|
+
|
|
|
if(fileInfo_.fileType == '3dTiles'){
|
|
|
let tileset = object.runtime.getTileset()
|
|
|
|
|
@@ -4345,12 +4604,12 @@ export class Viewer extends ViewerBase{
|
|
|
|
|
|
json.root.refine = 'ADD';
|
|
|
json.refine = 'ADD';
|
|
|
- }else{
|
|
|
+ }else {
|
|
|
Potree.Utils.setObjectLayers(object,'model')
|
|
|
|
|
|
|
|
|
object.traverse( ( child )=>{
|
|
|
- if ( child instanceof THREE.Mesh ) {
|
|
|
+ if ( child instanceof THREE.Mesh || child instanceof THREE.Points ) {
|
|
|
child.renderOrder = Potree.config.renderOrders.model;
|
|
|
if(Potree.settings.boundAddObjs){
|
|
|
child.geometry.computeBoundingBox()
|
|
@@ -4431,6 +4690,19 @@ export class Viewer extends ViewerBase{
|
|
|
loadDone(gltf.scene/* , total, fileInfo.url */)
|
|
|
}, onProgress, onError)
|
|
|
|
|
|
+ }else if(fileInfo.fileType == 'ply'){
|
|
|
+ loaders.plyLoader.load( fileInfo.url, (geometry) => {
|
|
|
+ let object
|
|
|
+ console.log('ply加载完毕', geometry)
|
|
|
+ if(!geometry.index){//点云
|
|
|
+ object = new THREE.Points(geometry, new THREE.PointsMaterial({vertexColors:true, size:0.02}))
|
|
|
+ //141M的点云,intersect费时300ms以上
|
|
|
+ }else{//mesh
|
|
|
+ object = new THREE.Mesh(geometry)
|
|
|
+ }
|
|
|
+ loadDone(object)
|
|
|
+ })
|
|
|
+
|
|
|
}else if(fileInfo.fileType == '3dTiles'){
|
|
|
|
|
|
let result = await Loader3DTiles.load({
|
|
@@ -4440,9 +4712,11 @@ export class Viewer extends ViewerBase{
|
|
|
options: {
|
|
|
//dracoDecoderPath: '../utils/loaders/DRACOLoader/draco',
|
|
|
//basisTranscoderPath: '../utils/loaders/KTX2Loader/basis',
|
|
|
- maximumScreenSpaceError: 48,
|
|
|
- maxDepth: 100,
|
|
|
- showAllTile: true,
|
|
|
+ maximumScreenSpaceError: 50,
|
|
|
+ maxDepth: 100,
|
|
|
+ maximumMemoryUsage: 700, //缓存大小。 若太小,密集的tile反复加载很卡
|
|
|
+ //debug:true,
|
|
|
+ parent: this.scene.scene
|
|
|
},
|
|
|
})
|
|
|
console.log(result)
|
|
@@ -4450,7 +4724,7 @@ export class Viewer extends ViewerBase{
|
|
|
loadDone(result.model/* , null, fileInfo.url */)
|
|
|
|
|
|
|
|
|
-
|
|
|
+
|
|
|
let loaded = false
|
|
|
let tileset = result.runtime.getTileset()
|
|
|
tileset.addEventListener('endTileLoading', function (data) {//Tileset3D
|
|
@@ -4647,6 +4921,9 @@ export class Viewer extends ViewerBase{
|
|
|
})
|
|
|
|
|
|
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
|
|
|
/* this.images360.addEventListener('flyToPano' ,(e)=>{//飞之前
|
|
|
if(Potree.settings.displayMode != 'showPanos') return
|