SplitScreen4Views.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. import * as THREE from "../../../libs/three.js/build/three.module.js";
  2. import SplitScreen from "./SplitScreen.js";
  3. const viewportProps = [
  4. {
  5. left:0.5,
  6. bottom:0.5,
  7. width: 0.5,height:0.5,
  8. name : 'MainView',
  9. //view: viewer.scene.view,
  10. active: true,
  11. },
  12. {
  13. left:0,
  14. bottom:0.5,
  15. width: 0.5,height:0.5,
  16. name : 'top',
  17. name2 : 'mapViewport',
  18. axis:["x","y"],
  19. direction : new THREE.Vector3(0,0,-1), //镜头朝向
  20. //axisSign:[1,1],
  21. active: true,
  22. //相机位置在z轴正向
  23. },
  24. {
  25. left:0.5,
  26. bottom:0,
  27. width: 0.5,height:0.5,
  28. name : 'right',
  29. axis:["y","z"],
  30. direction : new THREE.Vector3(1,0,0),
  31. //axisSign:[1,1],
  32. active: true,
  33. //相机位置在x轴负向 右下角屏
  34. },
  35. {
  36. left:0,
  37. bottom:0,
  38. width: 0.5,height:0.5,
  39. name : 'back',
  40. axis:["x","z"],
  41. direction : new THREE.Vector3(0,-1,0),
  42. //axisSign:[-1,1], // 从镜头方向看 x向左 所以取负
  43. active: true,
  44. //相机位置在y轴正向 左下角屏
  45. },
  46. ]
  47. var SplitScreen4Views = new SplitScreen()
  48. SplitScreen4Views.split = function(o={}){
  49. var defaultCamera = viewer.scene.getActiveCamera()
  50. let {boundSize, center} = viewer.bound
  51. viewer.setLimitFar(false)
  52. viewer.mapViewer.attachToMainViewer(true,'split4Screens','dontSet')
  53. let viewports = this.splitStart(viewportProps)
  54. //覆盖在map上、点云等其他物体之下的一层背景
  55. let mapViewport = viewer.mapViewer.viewports[0]
  56. mapViewport.noPointcloud = false
  57. //隐藏地图游标
  58. //Potree.Utils.updateVisible(viewer.mapViewer.cursor, 'split4Screens', false)
  59. /* viewer.images360.panos.forEach(pano=>{
  60. Potree.Utils.updateVisible(pano.mapMarker, 'split4Screens', false) //希望这时候mapMarker已经建好了吧
  61. }) */
  62. /* viewer.images360.panos.forEach(pano=>{
  63. pano.addLabel2()
  64. Potree.Utils.updateVisible(pano.label2, 'notDisplay', true)
  65. pano.dispatchEvent({type:'changeMarkerTex',name:'ring'})
  66. }) */
  67. //材质
  68. this.statesBefore = {
  69. pointDensity : Potree.settings.pointDensity,
  70. displayMode : Potree.settings.displayMode,
  71. position: viewer.images360.position,
  72. target: viewer.scene.view.getPivot(),
  73. currentPano: viewer.images360.currentPano,
  74. //---
  75. //ifShowMarker : Potree.settings.ifShowMarker,
  76. }
  77. viewer.setPointStandardMat(true,null,true) //切换到标准模式(主要为了mainViewport) 点云使用标准大小
  78. var matBefore = {
  79. opacity : new Map()
  80. }
  81. var newOpacityMap = new Map()
  82. viewer.scene.pointclouds.forEach(e=>{
  83. matBefore.opacity.set(e, e.temp.pointOpacity)
  84. matBefore.colorType = e.material.activeAttributeName
  85. /* {
  86. var map = new Map()
  87. newOpacityMap.set(e, map )
  88. var size = e.bound.getSize()
  89. viewports.forEach(viewport=>{//根据bound设置opacity,越小的要靠越近,需要大的opacity。但似乎影响太大了
  90. if(viewport.name == 'MainView')return;
  91. var prop = viewportProps.find(v => viewport.name == v.name2||viewport.name == v.name)
  92. let axis = prop.axis
  93. var width = size[axis[0]]
  94. var height = size[axis[1]]
  95. var area = width * height
  96. map.set(viewport, 5000/area);
  97. })
  98. } */
  99. })
  100. let beforeRender = function(){
  101. viewer.scene.pointclouds.forEach(e=>{
  102. if(this.name == "MainView"){
  103. e.material.activeAttributeName = matBefore.colorType // 'rgba'
  104. e.material.useFilterByNormal = false
  105. e.changePointOpacity(matBefore.opacity.get(e)) //1 //恢复下 e.temp.pointOpacity 其实就是1
  106. Potree.settings.pointDensity = 'fourViewportsMain'/* 'fourViewports' */ //本来想比另外三屏高一点质量,结果发现会闪烁,因为点云加载需要时间 (navvis仿版也是一样,以后看看能否优化)
  107. }else{
  108. e.material.activeAttributeName = "color"
  109. e.material.useFilterByNormal = true
  110. Potree.settings.pointDensity = 'fourViewports' //强制降低点云质量
  111. //侧面重叠概率更大,所以透明度调小
  112. e.changePointOpacity(this.name == "mapViewport" ? 0.2 : 0.06/* newOpacityMap.get(e).get(viewport), true */); //多数据集有的数据集很小,放大后显示特别淡
  113. //console.log(e.name, viewport.name, e.temp.pointOpacity, e.material.opacity)
  114. }
  115. viewer.images360.panos.forEach(pano=>{
  116. if(this.name == 'mapViewport'){
  117. Potree.Utils.updateVisible(pano.marker, 'showOnMap', true, 1, 'add' )
  118. }else{
  119. Potree.Utils.updateVisible(pano.marker, 'showOnMap', false, 1, 'cancel' )
  120. }
  121. })
  122. })
  123. }
  124. viewports.forEach(viewport=>{viewport.beforeRender = beforeRender})
  125. this.enableMap(false)
  126. this.enableFloorplan(false)
  127. viewer.mapViewer.setViewLimit('expand') //多数据集距离远时可以任意远,所以不限制了。但是这样就会看到地图边界了怎么办?
  128. //viewer.dispatchEvent({'type': 'beginSplitView' })
  129. //viewer.updateScreenSize({forceUpdateSize:true})
  130. //this.viewportFitBound(mapViewport, boundSize, center)
  131. //Potree.settings.ifShowMarker = false
  132. Potree.settings.displayMode = 'showPointCloud'
  133. }
  134. SplitScreen4Views.recover = function(){
  135. this.unSplit()
  136. viewer.mapViewer.viewports[0].beforeRender = null;
  137. /* const {width, height} = viewer.renderer.getSize(new THREE.Vector2());
  138. viewer.renderer.setViewport(0,0,width,height)
  139. viewer.renderer.setScissorTest( false ); */
  140. viewer.setView({
  141. position: this.statesBefore.position,
  142. target: this.statesBefore.target,
  143. currentPano: this.statesBefore.currentPano,
  144. duration:300,
  145. callback:function(){
  146. }
  147. })
  148. viewer.mainViewport.beforeRender = null
  149. viewer.setLimitFar(true)
  150. let mapViewport = viewer.mapViewer.viewports[0]
  151. viewer.mapViewer.attachToMainViewer(false)
  152. //Potree.Utils.updateVisible(viewer.mapViewer.cursor, 'split4Screens', true)
  153. /* viewer.images360.panos.forEach(pano=>{
  154. Potree.Utils.updateVisible(pano.mapMarker, 'split4Screens', true)
  155. }) */
  156. /* viewer.images360.panos.forEach(pano=>{
  157. Potree.Utils.updateVisible(pano.label2, 'notDisplay', false )
  158. pano.dispatchEvent({type:'changeMarkerTex',name:'default'})
  159. }) */
  160. mapViewport.noPointcloud = true
  161. {
  162. this.enableMap(Potree.settings.mapEnable)
  163. this.enableFloorplan(Potree.settings.floorplanEnable)
  164. if(this.floorplanListener){
  165. viewer.mapViewer.mapLayer.removeEventListener( 'floorplanLoaded', this.floorplanListener )
  166. this.floorplanListener = null
  167. }
  168. }
  169. Potree.settings.pointDensity = this.statesBefore.pointDensity
  170. if(!Potree.settings.isOfficial){
  171. Potree.settings.displayMode = this.statesBefore.displayMode
  172. }
  173. viewer.scene.pointclouds.forEach(e=>{
  174. //e.material.color.set(this.statesBefore.mat.color)
  175. //e.material.activeAttributeName = this.statesBefore.mat.colorType
  176. e.material.useFilterByNormal = false
  177. //e.material.opacity = this.statesBefore.mat.opacity
  178. })
  179. viewer.setPointStandardMat(false)
  180. viewer.mapViewer.setViewLimit('standard')
  181. viewer.images360.panos.forEach(pano=>{
  182. Potree.Utils.updateVisible(pano.marker, 'showOnMap', false, 1, 'cancel' )
  183. })
  184. //Potree.settings.ifShowMarker = this.statesBefore.ifShowMarker
  185. //viewer.dispatchEvent({'type': 'finishSplitView' })
  186. //viewer.updateScreenSize({forceUpdateSize:true})
  187. }
  188. SplitScreen4Views.updateMapViewerBG = function(){
  189. let mapViewport = viewer.mapViewer.viewports[0]
  190. if( this.floorplanEnabled || this.mapEnabled){
  191. mapViewport.background = 'overlayColor'
  192. mapViewport.backgroundColor = new THREE.Color(0,0,0)
  193. mapViewport.backgroundOpacity = 0.5;
  194. }else{
  195. mapViewport.background = null
  196. mapViewport.backgroundColor = null
  197. mapViewport.backgroundOpacity = null
  198. }
  199. viewer.mapViewer.mapChanged = true
  200. viewer.mapViewer.needUpdate = true
  201. }
  202. SplitScreen4Views.setFloorplanDisplay = function(e, show=false){
  203. e.floorplan.setEnable(show)
  204. }
  205. SplitScreen4Views.enableMap = function(enable){
  206. let map = viewer.mapViewer.mapLayer.maps.find(e=>e.name == 'map')
  207. map.setEnable(!!enable)
  208. //viewer.mapViewer.mapGradientBG = viewer.background == 'gradient' && !enable
  209. this.mapEnabled = enable
  210. this.updateMapViewerBG()
  211. },
  212. //直接覆盖原设置
  213. SplitScreen4Views.enableFloorplan = function(enable){ //是否让自定义的平面图显示
  214. let floorplans = viewer.mapViewer.mapLayer.maps.filter(e=>e.name.includes('floorplan'))
  215. if(this.floorplanListener){
  216. viewer.mapViewer.mapLayer.removeEventListener( 'floorplanLoaded', this.floorplanListener )
  217. }
  218. this.floorplanListener = (e)=>{
  219. this.setFloorplanDisplay(e, enable)
  220. }
  221. viewer.mapViewer.mapLayer.addEventListener( 'floorplanLoaded', this.floorplanListener ) //万一之后才加载
  222. if(!enable){
  223. //隐藏平面图
  224. floorplans.forEach(floorplan=>this.setFloorplanDisplay({floorplan},false))
  225. }else{
  226. floorplans.forEach(floorplan=>this.setFloorplanDisplay({floorplan},true))
  227. }
  228. if (enable && floorplans.length == 0) Potree.loadMapEntity('all',true)
  229. this.floorplanEnabled = enable
  230. this.updateMapViewerBG()
  231. },
  232. /* viewportFitBound:function(viewport, boundSize, center){ //使一个viewport聚焦在某个范围
  233. var prop = viewportProps.find(v => viewport.name == v.name2||viewport.name == v.name)
  234. let axis = prop.axis
  235. let expand = 10;
  236. let position = center.clone()
  237. var moveAtAxis = ['x','y','z'].find(e=>!(axis.includes(e)))
  238. if(viewport.name == 'mapViewport'){
  239. let ori = viewport.view.position[moveAtAxis]
  240. position[moveAtAxis] = ori //不改变这个值,尤其是mapViewer中的z
  241. }else{
  242. position[moveAtAxis] += boundSize[moveAtAxis]/2+expand//移动到bounding边缘外
  243. }
  244. viewport.view.position.copy(position)
  245. var width = Math.max(boundSize[axis[0]], boundSize[axis[1]] * viewport.camera.aspect)//视口宽度(米)
  246. var margin = 50 //px
  247. viewport.camera.zoom = (viewport.resolution.x - margin) / width
  248. viewport.camera.updateProjectionMatrix()
  249. },
  250. */
  251. SplitScreen4Views.focusOnPointCloud = function(pointcloud){//三个屏都聚焦在这个点云
  252. var boundSize = pointcloud.bound.getSize(new THREE.Vector3);
  253. var center = pointcloud.bound.getCenter(new THREE.Vector3);
  254. let target = pointcloud.panosBound && pointcloud.panosBound.center //看向pano集中的地方,也就是真正有点云的地方。(因为需要展示所有点云,所以没办法用这个做为center)
  255. this.focusOnObject(pointcloud.bound, center,target)
  256. viewer.flyToDataset({pointcloud, dontMoveMap:true, duration:0})
  257. }
  258. SplitScreen4Views.focusOnObject = function(bound, center, target, duration=0){
  259. viewer.viewports.forEach(e=>{
  260. if(e.name == 'MainView'){
  261. /* let len = boundSize.length()
  262. let distance = THREE.Math.clamp(e.view.position.distanceTo(center), len * 0.01, len*0.3 ) //距离限制
  263. //viewer.focusOnObject({position:center}, 'point', duration, {distance, direction: e.view.direction,dontMoveMap:true} )//平移镜头
  264. //为了方便定位,直接飞到中心位置:
  265. e.view.setView({
  266. position:center, duration, target
  267. }) */
  268. }else{
  269. this.viewportFitBound(e, bound, center)
  270. }
  271. })
  272. }
  273. export default SplitScreen4Views