SplitScreen.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. import {View} from "../viewer/View.js";
  2. import Viewport from "../viewer/Viewport.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. //axisSign:[1,1],
  20. active: true,
  21. },
  22. {
  23. left:0.5,
  24. bottom:0,
  25. width: 0.5,height:0.5,
  26. name : 'Right',
  27. axis:["y","z"],
  28. //axisSign:[1,1],
  29. active: true,
  30. },
  31. {
  32. left:0,
  33. bottom:0,
  34. width: 0.5,height:0.5,
  35. name : 'Back',
  36. axis:["x","z"],
  37. //axisSign:[-1,1], // 从镜头方向看 x向左 所以取负
  38. active: true,
  39. },
  40. ]
  41. var SplitScreen = {
  42. //viewer.modules.Alignment.SplitScreen.viewportFitBound(viewer.mapViewer.viewports[0],viewer.bound.boundSize, viewer.bound.center)
  43. splitScreen4Views : function(o={}){
  44. var defaultCamera = viewer.scene.getActiveCamera()
  45. let {boundSize, center} = viewer.bound
  46. var getOrthographicCamera = function(widthRatio, heightRatio, axis){
  47. var widthPX = viewer.renderArea.clientWidth * widthRatio;
  48. var heightPX = viewer.renderArea.clientHeight * heightRatio;
  49. var aspect = widthPX/heightPX
  50. console.log(viewer.renderArea.clientWidth,viewer.renderArea.clientHeight,aspect)
  51. var width = Math.max(boundSize[axis[0]], boundSize[axis[1]] * aspect)
  52. var orthographicCamera = new THREE.OrthographicCamera(-widthPX/2, widthPX/2, heightPX/2, -heightPX/2, 0.01, 10000);
  53. var margin = 50 //px
  54. orthographicCamera.zoom = (widthPX - margin) / width//zoom越大视野越小
  55. var moveAtAxis = ['x','y','z'].find(e=>!(axis.includes(e)))
  56. orthographicCamera.up.set(0,0,1)
  57. orthographicCamera.position.copy(center)
  58. orthographicCamera.position[moveAtAxis] += 1000;//偏移一些 在模型外即可
  59. return orthographicCamera
  60. }
  61. //材质
  62. let material = viewer.scene.pointclouds[0].material
  63. this.statesBefore = {
  64. mat : {
  65. colorType : material.activeAttributeName,
  66. color : material.color.clone(),
  67. opacity : material.opacity,
  68. },
  69. pointDensity : Potree.settings.pointDensity,
  70. displayMode : Potree.settings.displayMode,
  71. }
  72. let beforeRender = function(viewport){
  73. viewer.scene.pointclouds.forEach(e=>{
  74. if(viewport.name == "MainView"){
  75. e.material.activeAttributeName = SplitScreen.statesBefore.mat.colorType
  76. e.material.color.copy(SplitScreen.statesBefore.mat.color)
  77. e.material.useFilterByNormal = false
  78. e.material.opacity = SplitScreen.statesBefore.mat.opacity
  79. Potree.settings.pointDensity = 'fourViewports' //本来想比另外三屏高一点质量,结果发现会闪烁,因为点云加载需要时间 (navvis仿版也是一样,以后看看能否优化)
  80. }else{
  81. e.material.activeAttributeName = "color"
  82. e.material.color.set(e.color)
  83. e.material.useFilterByNormal = true
  84. e.material.opacity = /* THREE.Math.clamp( */e.material.spacing /* , 0.01,100); */ //0.09 //越稀疏给的opacity应该越高,支持超过1(隧道场景 spacing达9之多)
  85. Potree.settings.pointDensity = 'fourViewports' //强制降低点云质量
  86. }
  87. })
  88. }
  89. let viewports = []
  90. //更改mainViewport参数
  91. viewports.push(viewer.mainViewport)
  92. let mapViewport = viewer.mapViewer.viewports[0]
  93. viewports.push(mapViewport)
  94. for(let i=0;i<4;i++){
  95. let prop = viewportProps[i];
  96. let viewport;
  97. let v = viewports.find(e=>e.name == (prop.name2||prop.name))
  98. if(v){
  99. viewport = v
  100. viewport.left = prop.left; viewport.bottom = prop.bottom; viewport.width = prop.width; viewport.height = prop.height;
  101. }
  102. if(!viewport){
  103. viewport = new Viewport( new View(), getOrthographicCamera(prop.width, prop.height, prop.axis), prop )
  104. viewports.push(viewport)
  105. }
  106. viewport.beforeRender = beforeRender;
  107. if(viewport.name != 'MainView'){
  108. viewport.view.setCubeView(viewport.name)
  109. viewport.view.position.copy(viewport.camera.position)
  110. }
  111. }
  112. viewer.viewports = viewports;
  113. viewer.setLimitFar(false)
  114. viewer.mapViewer.attachToMainViewer(true,'split4Screens','dontSet')
  115. //覆盖在map上、点云等其他物体之下的一层背景
  116. mapViewport.noPointcloud = false
  117. //隐藏地图游标
  118. viewer.updateVisible(viewer.mapViewer.cursor, 'split4Screens', false)
  119. viewer.images360.panos.forEach(pano=>{
  120. viewer.updateVisible(pano.mapMarker, 'split4Screens', false) //希望这时候mapMarker已经建好了吧
  121. })
  122. this.enableMap(false)
  123. this.enableFloorplan(false)
  124. //viewer.dispatchEvent({'type': 'beginSplitView' })
  125. viewer.updateScreenSize({forceUpdateSize:true})
  126. this.viewportFitBound(mapViewport, boundSize, center)
  127. Potree.settings.displayMode = 'showPointCloud'
  128. },
  129. recoverFrom4Views: function(){
  130. this.unfocusViewport()
  131. const {width, height} = viewer.renderer.getSize(new THREE.Vector2());
  132. viewer.renderer.setViewport(0,0,width,height)
  133. viewer.renderer.setScissorTest( false );
  134. viewer.scene.pointclouds.forEach(e=>{
  135. e.material.color.set(SplitScreen.statesBefore.mat.color)
  136. e.material.activeAttributeName = SplitScreen.statesBefore.mat.colorType
  137. e.material.useFilterByNormal = false
  138. e.material.opacity = SplitScreen.statesBefore.mat.opacity
  139. })
  140. viewer.viewports = [viewer.mainViewport]
  141. viewer.mainViewport.width = 1;
  142. viewer.mainViewport.height = 1;
  143. viewer.mainViewport.left = 0
  144. viewer.mainViewport.bottom = 0;
  145. viewer.mainViewport.beforeRender = null
  146. viewer.setLimitFar(true)
  147. let mapViewport = viewer.mapViewer.viewports[0]
  148. viewer.mapViewer.attachToMainViewer(false)
  149. viewer.updateVisible(viewer.mapViewer.cursor, 'split4Screens', true)
  150. viewer.images360.panos.forEach(pano=>{
  151. viewer.updateVisible(pano.mapMarker, 'split4Screens', true)
  152. })
  153. mapViewport.noPointcloud = true
  154. this.enableMap(true)
  155. this.enableFloorplan(true)
  156. Potree.settings.pointDensity = SplitScreen.statesBefore.pointDensity
  157. Potree.settings.displayMode = SplitScreen.statesBefore.displayMode
  158. //viewer.dispatchEvent({'type': 'finishSplitView' })
  159. viewer.updateScreenSize({forceUpdateSize:true})
  160. },
  161. focusOnViewport : function(name){//全屏
  162. viewer.viewports.forEach((viewport, i )=>{
  163. if(viewport.name == name){
  164. this.focusInfo = {
  165. name,
  166. left : viewport.left, bottom : viewport.bottom, height : viewport.height, width : viewport.width
  167. }
  168. viewport.left = 0; viewport.bottom = 0; viewport.height = 1; viewport.width = 1
  169. }else{
  170. viewport.active = false
  171. }
  172. })
  173. viewer.updateScreenSize({forceUpdateSize:true})
  174. },
  175. unfocusViewport:function(){
  176. if(!this.focusInfo)return
  177. viewer.viewports.forEach((viewport, i )=>{
  178. if(this.focusInfo.name == viewport.name){//全屏的恢复
  179. viewport.left = this.focusInfo.left;
  180. viewport.bottom = this.focusInfo.bottom;
  181. viewport.height = this.focusInfo.height;
  182. viewport.width = this.focusInfo.width;
  183. }
  184. viewport.active = true
  185. })
  186. viewer.updateScreenSize({forceUpdateSize:true})
  187. this.focusInfo = null
  188. },
  189. updateMapViewerBG(){
  190. let mapViewport = viewer.mapViewer.viewports[0]
  191. if(this.floorplanEnabled || this.mapEnabled){
  192. mapViewport.background = 'overlayColor'
  193. mapViewport.backgroundColor = new THREE.Color(0,0,0)
  194. mapViewport.backgroundOpacity = 0.5;
  195. }else{
  196. mapViewport.background = null
  197. mapViewport.backgroundColor = null
  198. mapViewport.backgroundOpacity = null
  199. }
  200. },
  201. setFloorplanDisplay: function(e, show=false){
  202. viewer.updateVisible(e.floorplan.objectGroup, 'splitScreen', !!show)
  203. },
  204. enableMap(enable){
  205. let map = viewer.mapViewer.mapLayer.maps.find(e=>e.name == 'map')
  206. viewer.updateVisible(map.objectGroup, 'splitScreen', !!enable)
  207. //viewer.mapViewer.mapGradientBG = viewer.background == 'gradient' && !enable
  208. this.mapEnabled = enable
  209. this.updateMapViewerBG()
  210. if(enable)viewer.mapViewer.mapLayer.needUpdate = true //加载地图
  211. },
  212. enableFloorplan(enable){ //是否让自定义的平面图显示
  213. let floorplan = viewer.mapViewer.mapLayer.maps.find(e=>e.name == 'floorplan')
  214. if(!enable){
  215. //隐藏平面图
  216. if(floorplan){
  217. //console.log('已经有floorplan')
  218. this.setFloorplanDisplay({floorplan},false)
  219. }else{
  220. viewer.mapViewer.mapLayer.addEventListener( 'floorplanLoaded', this.setFloorplanDisplay ) //万一之后才加载
  221. }
  222. }else{
  223. if(!floorplan){
  224. //???
  225. }else{
  226. this.setFloorplanDisplay({floorplan},true)
  227. }
  228. }
  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. var moveAtAxis = ['x','y','z'].find(e=>!(axis.includes(e)))
  236. let ori = viewport.view.position[moveAtAxis]
  237. viewport.view.position.copy(center)
  238. viewport.view.position[moveAtAxis] = ori //不改变这个值,尤其是mapViewer中的z
  239. var width = Math.max(boundSize[axis[0]], boundSize[axis[1]] * viewport.camera.aspect)//视口宽度(米)
  240. var margin = 50 //px
  241. viewport.camera.zoom = (viewport.resolution.x - margin) / width
  242. viewport.camera.updateProjectionMatrix()
  243. },
  244. focusOnPointCloud:function(pointcloud){//三个屏都聚焦在这个点云
  245. var boundSize = pointcloud.bound.getSize(new THREE.Vector3);
  246. var center = pointcloud.bound.getCenter(new THREE.Vector3);
  247. viewer.viewports.forEach(e=>{
  248. if(e.name == 'MainView')return
  249. this.viewportFitBound(e, boundSize, center)
  250. })
  251. }
  252. }
  253. export default SplitScreen