SplitScreen.js 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. import {ExtendView} from "../../viewer/ExtendView.js";
  2. import Viewport from "../viewer/Viewport.js";
  3. import * as THREE from "../../../libs/three.js/build/three.module.js";
  4. class SplitScreen extends THREE.EventDispatcher{
  5. constructor (args = {}) {
  6. super();
  7. }
  8. /*
  9. viewport.targetPlane // bound中心点处的plane,方向和view一致
  10. viewport.shiftTarget // camera的位置project在targetPlane上的位置
  11. 这两个参数的主要目的是为了getPosOutOfModel,以及rotateSideCamera时保持相对位置
  12. */
  13. splitStart(cameraProps){
  14. this.splited = true
  15. let viewports = []
  16. let subViewports = [viewer.mainViewport]
  17. if(viewer.mapViewer){
  18. subViewports.push(viewer.mapViewer.viewports[0])
  19. }
  20. let length = cameraProps.length
  21. for(let i=0;i<length;i++){
  22. let prop = cameraProps[i];
  23. let viewport;
  24. let v = subViewports.find(e=>e.name == (prop.name2||prop.name))
  25. if(v){
  26. viewport = v
  27. viewport.left = prop.left; viewport.bottom = prop.bottom; viewport.width = prop.width; viewport.height = prop.height;
  28. }
  29. if(!viewport){
  30. let view = new ExtendView()
  31. if(prop.limitBound)view.limitBound = prop.limitBound
  32. prop.direction && (view.direction = prop.direction)
  33. viewport = new Viewport(view , this.getOrthoCamera(), prop )
  34. if(prop.viewContainsPoints)viewport.viewContainsPoints = prop.viewContainsPoints
  35. //viewport.unableDepth = true //depthBasicMaterial等在此viewport中不开启depth
  36. }
  37. if(viewport.camera.type == 'OrthographicCamera' ){
  38. viewport.targetPlane = new THREE.Plane()
  39. viewport.shiftTarget = new THREE.Vector3 //project在targetPlane上的位置
  40. }
  41. viewport.fitMargin = prop.margin
  42. viewports.push(viewport)
  43. }
  44. viewer.viewports = viewports;
  45. viewer.updateScreenSize({forceUpdateSize:true})
  46. viewports.forEach(viewport=>{
  47. if(viewport.name == 'MainView')return
  48. this.viewportFitBound(viewport, viewer.bound.boundingBox , viewer.bound.center , 0, viewport.fitMargin)
  49. })
  50. return viewports
  51. }
  52. unSplit(){
  53. this.splited = false
  54. this.unfocusViewport()
  55. viewer.inputHandler.hoverViewport = null //清空
  56. viewer.viewports = [viewer.mainViewport]
  57. viewer.mainViewport.width = 1;
  58. viewer.mainViewport.height = 1;
  59. viewer.mainViewport.left = 0
  60. viewer.mainViewport.bottom = 0;
  61. viewer.updateScreenSize({forceUpdateSize:true})
  62. }
  63. viewportFitBound(viewport, bound, center, duration=0, margin){
  64. let view = viewport.view
  65. let info = {bound}
  66. let {boundSize, boundCenter} = this.getViewBound(viewport, bound )
  67. //this.setShiftTarget(viewport, boundCenter)
  68. viewport.targetPlane.setFromNormalAndCoplanarPoint( view.direction.clone(), boundCenter )
  69. viewport.targetPlane.projectPoint(center, viewport.shiftTarget) //target转换到过模型中心的平面,以保证镜头一定在模型外 this.shiftTarget是得到的
  70. info.endPosition = this.getPosOutOfModel(viewport, boundSize)
  71. //if(viewport.name == 'mapViewport')info.endPosition.z = Math.max(Potree.config.map.cameraHeight, info.endPosition.z)
  72. info.margin = margin || {x:30, y:30}
  73. view.moveOrthoCamera(viewport, info , duration )
  74. }
  75. getViewBound(viewport, boundingBox){
  76. if(boundingBox){
  77. boundSize = boundingBox.getSize(new THREE.Vector3)
  78. center = boundingBox.getCenter(new THREE.Vector3)
  79. }else{
  80. var {boundSize, center, boundingBox} = viewer.bound
  81. }
  82. let containsPoints = []
  83. this.focusCenter && containsPoints.push(this.focusCenter)
  84. viewport.viewContainsPoints && containsPoints.push(...viewport.viewContainsPoints)
  85. if(containsPoints.length){//视野范围内必须要包含的点,直接算入模型区域。这时候得到的boundCenter和模型中心不重合
  86. boundingBox = boundingBox.clone()
  87. containsPoints.forEach(point=>{
  88. boundingBox.expandByPoint(point)
  89. })
  90. boundSize = boundingBox.getSize(new THREE.Vector3)
  91. center = boundingBox.getCenter(new THREE.Vector3)
  92. }
  93. return {boundSize, boundCenter:center }
  94. }
  95. getPosOutOfModel(viewport, boundSize){
  96. //let {boundSize, center} = viewer.bound
  97. boundSize = boundSize || this.getViewBound(viewport).boundSize
  98. let expand = 10;
  99. let radius = boundSize.length() * 2
  100. let position = viewport.shiftTarget.clone().sub(viewport.view.direction.clone().multiplyScalar(radius + expand))
  101. return position
  102. }
  103. updateCameraOutOfModel(){//因为移动模型导致模型超出相机外,所以更新位置
  104. viewer.viewports.forEach((viewport, i )=>{
  105. if(viewport.camera.isOrthographicCamera){ //or if(viewport.targetPlane)
  106. let {boundSize, boundCenter} = this.getViewBound(viewport)
  107. /* viewport.targetPlane.setFromNormalAndCoplanarPoint( viewport.view.direction.clone(), boundCenter)
  108. viewport.targetPlane.projectPoint(viewport.view.position, viewport.shiftTarget) //target转换到过模型中心的平面,以保证镜头一定在模型外 this.shiftTarget是得到的
  109. */
  110. this.setShiftTarget(viewport, boundCenter)
  111. let endPosition = this.getPosOutOfModel(viewport, boundSize)
  112. //if(viewport.name == 'mapViewport')endPosition.z = Math.max(Potree.config.map.cameraHeight, endPosition.z)
  113. viewport.view.position.copy(endPosition)
  114. }
  115. })
  116. }
  117. setShiftTarget(viewport, center){
  118. if(!viewport.targetPlane ){
  119. viewport.targetPlane = new THREE.Plane()
  120. viewport.shiftTarget = new THREE.Vector3 //project在targetPlane上的位置
  121. }
  122. viewport.targetPlane.setFromNormalAndCoplanarPoint(viewport.view.direction, center )
  123. viewport.targetPlane.projectPoint(viewport.view.position, viewport.shiftTarget ) //target转换到过模型中心的平面,以保证镜头一定在模型外
  124. }
  125. rotateSideCamera(viewport, angle){//侧视图或俯视图绕模型中心水平旋转
  126. //let {boundSize, center} = viewer.bound
  127. let {boundSize, boundCenter } = this.getViewBound(viewport)
  128. let center = this.focusCenter || boundCenter //旋转中心,一般是所有模型的中心,除非想指定中心点
  129. this.setShiftTarget(viewport, center)
  130. //找到平移向量
  131. let vec = new THREE.Vector3().subVectors(center, viewport.shiftTarget)//相对于中心的偏移值,旋转后偏移值也旋转
  132. //旋转
  133. var rotMatrix = new THREE.Matrix4().makeRotationAxis(new THREE.Vector3(0,0,1), angle)
  134. viewport.view.direction = viewport.view.direction.applyMatrix4(rotMatrix)
  135. vec.applyMatrix4(rotMatrix)
  136. viewport.shiftTarget.subVectors(center,vec) //新的
  137. viewport.view.position = this.getPosOutOfModel(viewport, boundSize)
  138. }
  139. getOrthoCamera(){
  140. let camera = new THREE.OrthographicCamera(-100, 100, 100, 100, 0.01, 10000)
  141. camera.up.set(0,0,1)
  142. return camera
  143. }
  144. focusOnViewport(name){//全屏
  145. viewer.viewports.forEach((viewport, i )=>{
  146. if(viewport.name == name){
  147. this.focusInfo = {
  148. name,
  149. left : viewport.left, bottom : viewport.bottom, height : viewport.height, width : viewport.width
  150. }
  151. viewport.left = 0; viewport.bottom = 0; viewport.height = 1; viewport.width = 1
  152. }else{
  153. viewport.active = false
  154. }
  155. })
  156. viewer.updateScreenSize({forceUpdateSize:true})
  157. }
  158. unfocusViewport(){
  159. if(!this.focusInfo)return
  160. viewer.viewports.forEach((viewport, i )=>{
  161. if(this.focusInfo.name == viewport.name){//全屏的恢复
  162. viewport.left = this.focusInfo.left;
  163. viewport.bottom = this.focusInfo.bottom;
  164. viewport.height = this.focusInfo.height;
  165. viewport.width = this.focusInfo.width;
  166. }
  167. viewport.active = true
  168. })
  169. viewer.updateScreenSize({forceUpdateSize:true})
  170. this.focusInfo = null
  171. }
  172. }
  173. export default SplitScreen