Magnifier.js 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. import * as THREE from "../../libs/three.js/build/three.module.js";
  2. import math from './math'
  3. import Viewport from '../viewer/Viewport'
  4. let texLoader = new THREE.TextureLoader()
  5. let circleGeo = new THREE.CircleGeometry(1.45,100);
  6. const magDistance_ = 2;//相机离目标位置的距离的分界线,当离得远时要缩小fov以使看到的视野固定(望远镜效果)
  7. const radius_ = 0.2; //当相机离目标位置的距离>magDistance_时,希望看到的视野的半径
  8. const maxFov = THREE.Math.radToDeg(Math.atan(radius_ / magDistance_ )) * 2//提前计算出当相机离目标位置的距离<magDistance_时的fov,均使用=magDistance_时的fov。只要保证该fov大于主相机的fov就会有放大效果
  9. const width2dPX = 200/1.4;//px
  10. const sphereGeo = new THREE.SphereBufferGeometry(0.02,10,10);
  11. export default class Magnifier extends THREE.Object3D {//放大镜or望远镜
  12. constructor (viewer) {
  13. super()
  14. this.width = this.height = 256;
  15. this.camera = new THREE.PerspectiveCamera(50, 1, 0.1, 10000); //fov aspect near far
  16. this.camera.up = new THREE.Vector3(0,0,1)
  17. this.viewport = new Viewport( null, this.camera, {
  18. left:0, bottom:0, width:1, height: 1, name:'magnifier' , cameraLayers:['magnifierContent']
  19. })
  20. this.viewport.setResolution(this.width, this.height,0,0)
  21. this.renderTarget = new THREE.WebGLRenderTarget(this.width,this.height, {
  22. minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter,
  23. format: THREE.RGBAFormat ,
  24. /* type: THREE.FloatType,
  25. minFilter: THREE.NearestFilter,
  26. magFilter: THREE.NearestFilter,
  27. */
  28. } )
  29. this.rtEDL = new THREE.WebGLRenderTarget(this.width, this.height, {
  30. minFilter: THREE.NearestFilter,
  31. magFilter: THREE.NearestFilter,
  32. format: THREE.RGBAFormat,
  33. type: THREE.FloatType,
  34. depthTexture: new THREE.DepthTexture(undefined, undefined, THREE.UnsignedIntType)
  35. });
  36. this.mesh = new THREE.Mesh(circleGeo, new THREE.MeshBasicMaterial({
  37. side: THREE.DoubleSide ,
  38. map: this.renderTarget.texture ,
  39. transparent:true,
  40. depthTest: !1,
  41. //depthWrite: !1,
  42. }))
  43. this.overlayMesh = new THREE.Mesh(circleGeo, new THREE.MeshBasicMaterial({
  44. side: THREE.DoubleSide ,
  45. map:texLoader.load(Potree.resourcePath+'/textures/crosshair.png') ,
  46. transparent:true,
  47. depthTest: !1,
  48. //depthWrite: !1,
  49. }))
  50. this.targetPoint = new THREE.Mesh(sphereGeo, new THREE.MeshBasicMaterial({
  51. color:"#ff0000",
  52. transparent:true,
  53. opacity:0.7,
  54. }))
  55. this.targetPoint.name = 'magnifierPointTarget'
  56. viewer.scene.scene.add(this.targetPoint)
  57. viewer.setObjectLayers(this.targetPoint, 'magnifierContent' )
  58. this.add(this.mesh)
  59. this.add(this.overlayMesh)
  60. this.position.set(-1000,-1000,-100000)//令它看不见
  61. this.mesh.renderOrder = 10;
  62. this.overlayMesh.renderOrder = 11;
  63. this.aimPos
  64. viewer.setObjectLayers(this, 'magnifier' )
  65. //viewer.inputHandler.addInputListener(this)
  66. viewer.addEventListener('camera_changed',(e)=>{ // 平移、滚轮时更新
  67. if(e.viewport == viewer.mainViewport) this.update()
  68. })
  69. this.mesh.layers.set(Potree.config.renderLayers.magnifier);
  70. this.overlayMesh.layers.set(Potree.config.renderLayers.magnifier);
  71. //this.layers.set(Potree.config.renderLayers.magnifier);//这句在外层写没用
  72. this.dontRender = false
  73. viewer.addEventListener('global_drag', (e)=>{//拖拽时不渲染。主要是右键平移时渲染延迟了,会闪烁。
  74. this.dontRender = true
  75. })
  76. viewer.addEventListener('global_drop', (e)=>{
  77. this.dontRender = false
  78. })
  79. viewer.addEventListener('global_mouseup', (e)=>{//测量时拖拽场景再mouseup
  80. this.dontRender = false
  81. })
  82. var updateVisi = (e)=>{
  83. if(e.hoverViewport == viewer.mainViewport){
  84. viewer.updateVisible(this,"atViewport", true)
  85. this.update(e.intersectPoint && e.intersectPoint.location)
  86. }else{
  87. viewer.updateVisible(this,"atViewport", false) //小地图不显示
  88. }
  89. }
  90. viewer.addEventListener('global_mousemove', updateVisi)
  91. viewer.addEventListener('global_touchstart', updateVisi)
  92. /* viewer.addEventListener("beginSplitView",()=>{
  93. this.updateVisible("splitView", false)
  94. })
  95. viewer.addEventListener("finishSplitView",()=>{
  96. this.updateVisible("splitView", true)
  97. }) */
  98. this.addEventListener("setEnable",(e)=>{
  99. viewer.updateVisible(this, "enable", e.value) //界面开关
  100. })
  101. if(Potree.settings.isOfficial){
  102. viewer.updateVisible(this, "enable", false)
  103. }else{
  104. viewer.updateVisible(this, "measure", false)
  105. viewer.addEventListener("measureMovePoint",()=>{//测量开始
  106. viewer.updateVisible(this, "measure", true)
  107. })
  108. viewer.addEventListener("endMeasureMove",()=>{
  109. viewer.updateVisible(this, "measure", false)
  110. })
  111. }
  112. }
  113. /* updateVisible(reason, ifShow){//当所有加入的条件都不为false时才显示
  114. if(ifShow){
  115. var index = this.unvisibleReasons.indexOf(reason)
  116. index > -1 && this.unvisibleReasons.splice(index, 1)
  117. if(this.unvisibleReasons.length == 0)this.visible = true
  118. }else{
  119. if(!this.unvisibleReasons.includes(reason)) this.unvisibleReasons.push(reason)
  120. this.visible = false
  121. }
  122. } */
  123. update(aimPos){
  124. aimPos = aimPos instanceof THREE.Vector3 ? aimPos : this.aimPos
  125. if(!aimPos || !this.visible)return
  126. //console.log(aimPos)
  127. //相机位置
  128. var playerCamera = viewer.scene.getActiveCamera()
  129. var playerPos = playerCamera.position;//viewer.scene.view.getPivot()
  130. var dis = playerPos.distanceTo(aimPos);
  131. /* var vec = playerPos.clone().sub(aimPos).normalize().multiplyScalar(dis > magDistance_ ? magDistance_ : magDistance_/2)
  132. this.camera.position.copy(aimPos.clone().add(vec))
  133. this.camera.lookAt(aimPos) */
  134. if(dis<magDistance_){
  135. this.camera.fov = maxFov
  136. }else{
  137. this.camera.fov = THREE.Math.radToDeg(Math.atan(radius_ / dis )) * 2 //radius_是能看到的范围半径。当dis大于magDistance_时就放大,否则维持fov为maxFov
  138. }
  139. this.camera.updateProjectionMatrix()
  140. this.camera.position.copy(playerPos)
  141. this.camera.lookAt(aimPos)
  142. this.quaternion.copy(playerCamera.quaternion);
  143. //mesh位置
  144. let screenPos = viewer.inputHandler.mouse.clone();
  145. let clientWidth = viewer.inputHandler.domElement.clientWidth * viewer.mainViewport.width;
  146. let clientHeight = viewer.inputHandler.domElement.clientHeight * viewer.mainViewport.height;
  147. screenPos.x = screenPos.x / clientWidth * 2 - 1;
  148. screenPos.y = -((screenPos.y < 300 ? 200 : -200) + screenPos.y) / clientHeight * 2 + 1;
  149. let newPos = new THREE.Vector3(screenPos.x,screenPos.y,0.8).unproject(playerCamera); //z:-1朝外
  150. let dir = newPos.clone().sub(playerPos).normalize().multiplyScalar(10);//这个数值要大于playerCamera.near
  151. this.position.copy(playerPos.clone().add(dir))
  152. this.aimPos = aimPos
  153. this.targetPoint.position.copy(aimPos);
  154. var scale = math.getScaleForConstantSize({//
  155. width2d : width2dPX,
  156. camera:viewer.scene.getActiveCamera(), position: this.getWorldPosition(new THREE.Vector3()),
  157. resolution: viewer.mainViewport.resolution2
  158. })
  159. this.scale.set(scale, scale, scale);
  160. if(!this.dontRender){
  161. this.waitRender = true
  162. }
  163. }//位置需要计算,不仅仅是点云,所以需要深度图
  164. render(){
  165. if(!this.waitRender)return
  166. //this.visible = false;//防止放大镜里有自己
  167. viewer.render({
  168. target : this.renderTarget,
  169. viewports : [this.viewport],
  170. camera : this.camera,
  171. magnifier : true,
  172. rtEDL: this.rtEDL
  173. /* width :this.renderTarget.width,
  174. height: this.renderTarget.height, */
  175. })
  176. //this.visible = true;
  177. this.waitRender = false
  178. }
  179. }