import * as THREE from "../../../libs/three.js/build/three.module.js"; import SplitScreen from "./SplitScreen.js"; import AxisViewer from "../objects/tool/AxisViewer.js"; const viewportProps = [ { left:0.5, bottom:0.5, width: 0.5,height:0.5, name : 'MainView', //view: viewer.scene.view, active: true, }, { left:0, bottom:0.5, width: 0.5,height:0.5, name : 'top', name2 : 'mapViewport', axis:["x","y"], direction : new THREE.Vector3(0,0,-1), //镜头朝向 //axisSign:[1,1], active: true, //相机位置在z轴正向 }, { left:0.5, bottom:0, width: 0.5,height:0.5, name : 'right', axis:["y","z"], direction : new THREE.Vector3(1,0,0), //axisSign:[1,1], active: true, //相机位置在x轴负向 右下角屏 }, { left:0, bottom:0, width: 0.5,height:0.5, name : 'back', axis:["x","z"], direction : new THREE.Vector3(0,-1,0), //axisSign:[-1,1], // 从镜头方向看 x向左 所以取负 active: true, //相机位置在y轴正向 左下角屏 }, ] var SplitScreen4Views = new SplitScreen({noRotSide:true}) SplitScreen4Views.split = function(o={}){ var defaultCamera = viewer.scene.getActiveCamera() let {boundSize, center} = viewer.bound viewer.setLimitFar(false) viewer.mapViewer.attachToMainViewer(true,'split4Screens','dontSet') viewer.renderer.clear() //clear back的viewport左边的1px宽的部分,因setScissor的bug let viewports = this.splitStart(viewportProps) //覆盖在map上、点云等其他物体之下的一层背景 let mapViewport = viewer.mapViewer.viewports[0] mapViewport.noPointcloud = false //隐藏地图游标 //Potree.Utils.updateVisible(viewer.mapViewer.cursor, 'split4Screens', false) /* viewer.images360.panos.forEach(pano=>{ Potree.Utils.updateVisible(pano.mapMarker, 'split4Screens', false) //希望这时候mapMarker已经建好了吧 }) */ /* viewer.images360.panos.forEach(pano=>{ pano.addLabel2() Potree.Utils.updateVisible(pano.label2, 'notDisplay', true) pano.dispatchEvent({type:'changeMarkerTex',name:'ring'}) }) */ //材质 this.statesBefore = { pointDensity : Potree.settings.pointDensity, displayMode : Potree.settings.displayMode, position: viewer.images360.position, target: viewer.scene.view.getPivot(), currentPano: viewer.images360.currentPano, //--- //ifShowMarker : Potree.settings.ifShowMarker, } viewer.setPointStandardMat(true,null,true) //切换到标准模式(主要为了mainViewport) 点云使用标准大小 var matBefore = { opacity : new Map() } var newOpacityMap = new Map() viewer.scene.pointclouds.forEach(e=>{ matBefore.opacity.set(e, e.temp.pointOpacity) matBefore.colorType = e.material.activeAttributeName /* { var map = new Map() newOpacityMap.set(e, map ) var size = e.bound.getSize() viewports.forEach(viewport=>{//根据bound设置opacity,越小的要靠越近,需要大的opacity。但似乎影响太大了 if(viewport.name == 'MainView')return; var prop = viewportProps.find(v => viewport.name == v.name2||viewport.name == v.name) let axis = prop.axis var width = size[axis[0]] var height = size[axis[1]] var area = width * height map.set(viewport, 5000/area); }) } */ }) let beforeRender = function(){ viewer.dealBeforeRender = true //使不全部渲染 viewer.scene.pointclouds.forEach(e=>{ if(this.name == "MainView"){ e.material.activeAttributeName = matBefore.colorType // 'rgba' e.material.useFilterByNormal = false //e.material.pointSizeType = Potree.config.material.pointSizeType e.changePointOpacity(matBefore.opacity.get(e)) //1 //恢复下 e.temp.pointOpacity 其实就是1 Potree.settings.pointDensity = 'fourViewportsMain'/* 'fourViewports' */ //本来想比另外三屏高一点质量,结果发现会闪烁,因为点云加载需要时间 (navvis仿版也是一样,以后看看能否优化) }else{ e.material.activeAttributeName = "color" e.material.useFilterByNormal = true //e.material.pointSizeType = 'ADAPTIVE' Potree.settings.pointDensity = 'fourViewports' //强制降低点云质量 //侧面重叠概率更大,所以透明度调小 e.changePointOpacity(this.name == "mapViewport" ? 0.5 : 0.1/* newOpacityMap.get(e).get(viewport), true */); //多数据集有的数据集很小,放大后显示特别淡 //console.log(e.name, viewport.name, e.temp.pointOpacity, e.material.opacity) } viewer.images360.panos.forEach(pano=>{ if(this.name == 'mapViewport'){ Potree.Utils.updateVisible(pano.marker, 'showOnMap', true, 1, 'add' ) }else{ Potree.Utils.updateVisible(pano.marker, 'showOnMap', false, 1, 'cancel' ) } }) }) viewer.dealBeforeRender = false } viewports.forEach(viewport=>{ viewport.beforeRender = beforeRender new AxisViewer(viewport, viewer.renderArea,{domStyle:{ top: '22px',//viewport.name == 'mapViewport' ? '2px' : '-25px', right: (viewport.name == 'mapViewport') ? '30px' : '2px', width:'80px',height:'80px'} }) }) this.enableMap(false) this.enableFloorplan(false) viewer.mapViewer.setViewLimit('null') //多数据集距离远时可以任意远,所以不限制了。但是这样就会看到地图边界了怎么办?超出后让地图隐藏? //viewer.dispatchEvent({'type': 'beginSplitView' }) //viewer.updateScreenSize({forceUpdateSize:true}) //this.viewportFitBound(mapViewport, boundSize, center) //Potree.settings.ifShowMarker = false Potree.settings.displayMode = 'showPointCloud' } SplitScreen4Views.recover = function(){ viewer.viewports.forEach(e=>{e.axis.dispose()}) this.unSplit() viewer.mapViewer.viewports[0].beforeRender = null; /* const {width, height} = viewer.renderer.getSize(new THREE.Vector2()); viewer.renderer.setViewport(0,0,width,height) viewer.renderer.setScissorTest( false ); */ viewer.setView({ position: this.statesBefore.position, target: this.statesBefore.target, currentPano: this.statesBefore.currentPano, duration:300, callback:function(){ } }) viewer.mainViewport.beforeRender = null viewer.setLimitFar(true) let mapViewport = viewer.mapViewer.viewports[0] viewer.mapViewer.attachToMainViewer(false) //Potree.Utils.updateVisible(viewer.mapViewer.cursor, 'split4Screens', true) /* viewer.images360.panos.forEach(pano=>{ Potree.Utils.updateVisible(pano.mapMarker, 'split4Screens', true) }) */ /* viewer.images360.panos.forEach(pano=>{ Potree.Utils.updateVisible(pano.label2, 'notDisplay', false ) pano.dispatchEvent({type:'changeMarkerTex',name:'default'}) }) */ mapViewport.noPointcloud = true { this.enableMap(Potree.settings.mapEnable) this.enableFloorplan(Potree.settings.floorplanEnable) if(this.floorplanListener){ viewer.mapViewer.mapLayer.removeEventListener( 'floorplanLoaded', this.floorplanListener ) this.floorplanListener = null } } Potree.settings.pointDensity = this.statesBefore.pointDensity if(!Potree.settings.isOfficial){ Potree.settings.displayMode = this.statesBefore.displayMode } viewer.scene.pointclouds.forEach(e=>{ e.material.useFilterByNormal = false //e.material.pointSizeType = Potree.config.material.pointSizeType }) viewer.setPointStandardMat(false) viewer.mapViewer.setViewLimit('standard') viewer.images360.panos.forEach(pano=>{ Potree.Utils.updateVisible(pano.marker, 'showOnMap', false, 1, 'cancel' ) }) //Potree.settings.ifShowMarker = this.statesBefore.ifShowMarker //viewer.dispatchEvent({'type': 'finishSplitView' }) //viewer.updateScreenSize({forceUpdateSize:true}) } SplitScreen4Views.updateMapViewerBG = function(){ let mapViewport = viewer.mapViewer.viewports[0] if(this.splited && (this.floorplanEnabled || this.mapEnabled)){ mapViewport.background = 'overlayColor' mapViewport.backgroundColor = new THREE.Color(0,0,0) mapViewport.backgroundOpacity = 0.5; }else{ mapViewport.background = null mapViewport.backgroundColor = null mapViewport.backgroundOpacity = null } viewer.mapViewer.mapChanged = true viewer.mapViewer.needUpdate = true } SplitScreen4Views.setFloorplanDisplay = function(e, show=false){ e.floorplan.setEnable(show) } SplitScreen4Views.enableMap = function(enable){ let map = viewer.mapViewer.mapLayer.maps.find(e=>e.name == 'map') map.setEnable(!!enable) //viewer.mapViewer.mapGradientBG = viewer.background == 'gradient' && !enable this.mapEnabled = enable this.updateMapViewerBG() }, //直接覆盖原设置 SplitScreen4Views.enableFloorplan = function(enable){ //是否让自定义的平面图显示 let floorplans = viewer.mapViewer.mapLayer.maps.filter(e=>e.name.includes('floorplan')) if(this.floorplanListener){ viewer.mapViewer.mapLayer.removeEventListener( 'floorplanLoaded', this.floorplanListener ) } this.floorplanListener = (e)=>{ this.setFloorplanDisplay(e, enable) } viewer.mapViewer.mapLayer.addEventListener( 'floorplanLoaded', this.floorplanListener ) //万一之后才加载 if(!enable){ //隐藏平面图 floorplans.forEach(floorplan=>this.setFloorplanDisplay({floorplan},false)) }else{ floorplans.forEach(floorplan=>this.setFloorplanDisplay({floorplan},true)) } if (enable && floorplans.length == 0) Potree.loadMapEntity('all',true) this.floorplanEnabled = enable this.updateMapViewerBG() }, /* viewportFitBound:function(viewport, boundSize, center){ //使一个viewport聚焦在某个范围 var prop = viewportProps.find(v => viewport.name == v.name2||viewport.name == v.name) let axis = prop.axis let expand = 10; let position = center.clone() var moveAtAxis = ['x','y','z'].find(e=>!(axis.includes(e))) if(viewport.name == 'mapViewport'){ let ori = viewport.view.position[moveAtAxis] position[moveAtAxis] = ori //不改变这个值,尤其是mapViewer中的z }else{ position[moveAtAxis] += boundSize[moveAtAxis]/2+expand//移动到bounding边缘外 } viewport.view.position.copy(position) var width = Math.max(boundSize[axis[0]], boundSize[axis[1]] * viewport.camera.aspect)//视口宽度(米) var margin = 50 //px viewport.camera.zoom = (viewport.resolution.x - margin) / width viewport.camera.updateProjectionMatrix() }, */ SplitScreen4Views.focusOnPointCloud = function(pointcloud){//三个屏都聚焦在这个点云 var boundSize = pointcloud.bound.getSize(new THREE.Vector3); var center = pointcloud.bound.getCenter(new THREE.Vector3); let target = pointcloud.panosBound && pointcloud.panosBound.center //看向pano集中的地方,也就是真正有点云的地方。(因为需要展示所有点云,所以没办法用这个做为center) this.focusOnObject(pointcloud.bound, center,target) viewer.flyToDataset({pointcloud, dontMoveMap:true, duration:0}) } SplitScreen4Views.focusOnObject = function(bound, center, target, duration=0){ viewer.viewports.forEach(e=>{ if(e.name == 'MainView'){ /* let len = boundSize.length() let distance = THREE.Math.clamp(e.view.position.distanceTo(center), len * 0.01, len*0.3 ) //距离限制 //viewer.focusOnObject({position:center}, 'point', duration, {distance, direction: e.view.direction,dontMoveMap:true} )//平移镜头 //为了方便定位,直接飞到中心位置: e.view.setView({ position:center, duration, target }) */ }else{ this.viewportFitBound(e, bound, center) } }) } export default SplitScreen4Views