Sprite.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  1. import * as THREE from "../../../libs/three.js/build/three.module.js";
  2. import DepthBasicMaterial from "../materials/DepthBasicMaterial.js";
  3. import math from "../utils/math.js";
  4. const geo = new THREE.PlaneBufferGeometry(1,1)
  5. export default class Sprite extends THREE.Mesh{
  6. constructor(options={}){
  7. super(geo, options.mat || new DepthBasicMaterial(options))/* ({map:options.map, useDepth:options.useDepth})) */
  8. this.root = options.root || this;
  9. this.renderOrder = options.renderOrder != void 0 ? options.renderOrder : 4;
  10. this.pickOrder = options.pickOrder || 0
  11. this.sizeInfo = options.sizeInfo
  12. this.dontFixOrient = options.dontFixOrient
  13. this.options = options
  14. this.position.y = options.disToLine || 0 //离线距离
  15. this.matrixAutoUpdate = false;
  16. this.matrixMap = new Map()
  17. if(this.root != this){
  18. this.matrixMapRoot = new Map()
  19. this.root.matrixAutoUpdate = false;
  20. }
  21. this.visiMap = new Map()
  22. this.name = options.name || 'sprite'
  23. this.useViewport = null
  24. this.viewports = options.viewports//指定更新的viewports
  25. this.visible_ = true
  26. let clear = (e)=>{
  27. this.matrixMap.clear()//清空后在所有viewport上都必须更新才能渲染 //this.needsUpdate = true
  28. }
  29. viewer.mapViewer && viewer.mapViewer.addEventListener("camera_changed", clear)
  30. viewer.addEventListener("camera_changed", clear)
  31. /* if(viewer.viewports.length == 1){//直接更新。如果有多个不在这更新,在"render.begin"
  32. this.update(e)
  33. } */
  34. let applyMatrix = (e)=>{
  35. this.applyMatrix(e)
  36. }
  37. viewer.addEventListener("raycaster", applyMatrix) //before render
  38. viewer.addEventListener("render.begin", applyMatrix) //before render
  39. viewer.addEventListener("render.begin2", applyMatrix)
  40. viewer.addEventListener("cameraSetLayers", applyMatrix)
  41. this.addEventListener('dispose', ()=>{
  42. viewer.mapViewer && viewer.mapViewer.removeEventListener("camera_changed", clear)
  43. viewer.removeEventListener("camera_changed", clear)
  44. viewer.removeEventListener("raycaster", applyMatrix) //before render
  45. viewer.removeEventListener("render.begin", applyMatrix)
  46. viewer.removeEventListener("render.begin2", applyMatrix)
  47. this.dispose()
  48. })
  49. }
  50. set visible(v){
  51. let oldV = this.visible_
  52. this.visible_ = v
  53. if(v && !oldV){
  54. this.matrixMap && this.matrixMap.clear() //this.update() //update内有unableCompute会无限回调
  55. }
  56. }
  57. get visible(){
  58. return this.visible_
  59. }
  60. realVisible(viewport, interactables/* , raycaster */){
  61. if(interactables){
  62. if(!interactables.some((object)=>{//interactables中是否能找到this
  63. let finded
  64. object.traverse((object)=>{
  65. if(object == this){
  66. finded = true
  67. return {stopContinue:true}
  68. }
  69. })
  70. return finded
  71. }))return
  72. }
  73. /* if(interactables && viewport.name == 'mapViewport'){
  74. console.log(this)
  75. } */
  76. if(!(/* raycaster || */viewport.camera).layers.test(this.layers)){//如地图上一般不可见测量线
  77. return false
  78. }
  79. if(!this.visible && this.unvisibleReasons && this.unvisibleReasons.some(e=>e.reason != 'unableCompute')){
  80. return false
  81. }
  82. let v = true
  83. let parent = this.parent
  84. let lastParent = this
  85. while(parent){
  86. if(parent.visible === false){
  87. v = false
  88. break;
  89. }
  90. lastParent = parent
  91. parent = parent.parent
  92. }
  93. if(v && !(lastParent instanceof THREE.Scene)){//已被删除
  94. v = false
  95. }
  96. /* if(!this.latestRealVisi && v){//变为可见后先update
  97. this.latestRealVisi = true
  98. setTimeout(()=>{
  99. this.update()
  100. },1)//延迟 防止无限调用
  101. return false
  102. }
  103. this.latestRealVisi = v */
  104. return v;
  105. }
  106. waitUpdate(){
  107. this.matrixMap.clear()//清空后在所有viewport上都必须更新才能渲染
  108. //viewer.dispatchEvent('content_changed')
  109. }
  110. update(e={}){
  111. if(!e.viewport){
  112. let viewports = this.viewports || viewer.viewports
  113. if(!viewports)return
  114. viewports.forEach(view=>{
  115. this.update({viewport:view})
  116. })
  117. return;
  118. }
  119. if(!this.root || ! this.realVisible(e.viewport, e.interactables) /* this.visible */ )return
  120. if(this.viewports && !this.viewports.includes(e.viewport) )return
  121. if(e.viewport.name == 'magnifier')return
  122. let camera = e.viewport.camera
  123. //rotation
  124. if(!this.dontFixOrient){ //orthoCamera一般要加dontFixOrient
  125. let orient2dAngle
  126. if(this.root.lineDir){
  127. this.root.updateMatrix();//先更新,getWorldPosition才能得到正确的
  128. this.root.updateMatrixWorld(true)
  129. let center = this.root.getWorldPosition(new THREE.Vector3())
  130. //由于两个端点容易在屏幕外,所以使用center和center加dir
  131. let setVisi = (state)=>{
  132. this.visiMap.set(e.viewport, state)
  133. Potree.Utils.updateVisible(this, 'unableCompute', !!state)
  134. }
  135. let r1 = Potree.Utils.getPos2d(center, e.viewport, viewer.renderArea, viewer.renderer);
  136. if(!r1.trueSide)return setVisi(false);// 但这句会使realVisible为false从而无法更新//console.error('!r1.trueSide') //中心点如果在背面直接不渲染了
  137. let r2, point2
  138. let p2State = '', len=1, p2StateHistory = []
  139. while(p2State != 'got' && p2StateHistory.length<10){
  140. point2 = center.clone().add(this.root.lineDir.clone().multiplyScalar(len));
  141. r2 = Potree.Utils.getPos2d(point2, e.viewport , viewer.renderArea, viewer.renderer );
  142. if(!r2.trueSide){ //很少遇到点2在背面的
  143. if(!p2StateHistory.includes('tooLong-reverse')){
  144. p2State = 'tooLong-reverse' //先尝试反向
  145. len = -len
  146. }else{
  147. p2State = 'tooLong'
  148. len = len / 2
  149. }
  150. }else{
  151. let dis = r2.pos.distanceTo(r1.pos)
  152. if(math.closeTo(dis,0)){
  153. //console.log('dis == 0')
  154. setVisi(false)
  155. return
  156. break
  157. }
  158. if(dis<10 && !p2StateHistory.includes('tooLong')){//和r1的屏幕距离太近,要加长,否则精度过低
  159. p2State = 'tooShort'
  160. len = 100/dis * len
  161. }else{
  162. p2State = 'got'; break;
  163. }
  164. }
  165. p2StateHistory.push(p2State)
  166. }
  167. //console.log(p2StateHistory,len)
  168. if(!r2.trueSide){
  169. return setVisi(false)//, console.log(' !r2.trueSide', )
  170. }
  171. let p1 = r1.pos, p2 = r2.pos
  172. if(p2StateHistory.filter(e=>e == 'tooLong-reverse').length%2 == 1){//反,for marker
  173. p2 = r1.pos, p1 = r2.pos
  174. }
  175. let vec = new THREE.Vector2().subVectors(p1,p2);
  176. orient2dAngle = -vec.angle() //根据测量线在屏幕上的角度在旋转label,使之和屏幕上的二维线平行。
  177. let y = Math.abs(this.position.y)
  178. let facePlane = this.root.measure && this.root.measure.facePlane
  179. let eyeDir = new THREE.Vector3().subVectors(center,camera.position)
  180. let clockWise = facePlane && facePlane.normal.dot(eyeDir/* e.viewport.view.direction */) < 0
  181. if(p1.x < p2.x){
  182. orient2dAngle += Math.PI //避免字是倒着的情况。(使字一直在线的下方)
  183. clockWise != void 0 && (this.position.y = clockWise ? y : -y)
  184. }else{
  185. clockWise != void 0 && (this.position.y = clockWise ? -y : y) //使area类型的edgeLabel都在外侧
  186. }
  187. //this.parent.text && console.log(this.parent.text, clockWise, this.position.y, e.viewport.name /* THREE.Math.radToDeg(angle), p1.x < p2.x */ )
  188. setVisi(true)
  189. }
  190. let parentQua = this.root.parent.getWorldQuaternion(new THREE.Quaternion)
  191. this.root.quaternion.multiplyQuaternions(parentQua.invert(),camera.quaternion) //乘上parentQua.invert()是为了中和掉父结点的qua,使只剩下camera.quaternion
  192. if(orient2dAngle){
  193. let qua = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0,0,1), orient2dAngle)
  194. this.root.quaternion.multiply(qua)
  195. }
  196. }
  197. //scale
  198. var info = this.sizeInfo
  199. if(info){
  200. this.root.updateMatrix();//先更新,getWorldPosition才能得到正确的
  201. this.root.updateMatrixWorld(true)
  202. var scale
  203. if(info.nearBound == void 0 && info.farBound != void 0 || info.nearBound != void 0 && info.farBound == void 0){//仅限制最大或最小的话,不判断像素大小,直接限制mesh的scale
  204. //这个判断也可以写到getScaleForConstantSize里,可以更严谨控制像素宽度,这里只简单计算大小
  205. var dis = camera.position.distanceTo(this.root.getWorldPosition(new THREE.Vector3()))
  206. if(info.farBound == void 0 && dis < info.nearBound){
  207. scale = info.scale * dis / info.nearBound
  208. }else if(info.nearBound == void 0 && dis > info.farBound){
  209. scale = info.scale * dis / info.farBound
  210. }else{
  211. scale = info.scale
  212. }
  213. }else{
  214. scale = math.getScaleForConstantSize($.extend(info,{//规定下最小最大像素
  215. camera , position:this.root.getWorldPosition(new THREE.Vector3()) ,
  216. resolution: e.viewport.resolution//2
  217. }))
  218. }
  219. if(!isNaN(scale)){
  220. this.root.scale.set(scale, scale, scale);
  221. }
  222. }
  223. this.updateMatrix();
  224. //this.root.updateMatrixWorld(true)
  225. //console.log(this.root.text, this.root.matrix.elements)
  226. this.matrixMap.set(e.viewport, this.matrix.clone())
  227. if(this.root != this){
  228. this.root.updateMatrix(); //因this.position可能在两个viewport不同
  229. this.matrixMapRoot.set(e.viewport, this.root.matrix.clone())
  230. }
  231. this.needsUpdate = false
  232. this.useViewport = e.viewport
  233. }
  234. applyMatrix(e){
  235. if(!e)e = {viewport:viewer.mainViewport}//随便写一个viewport
  236. let visi = this.visiMap.get(e.viewport) //还原可见性
  237. Potree.Utils.updateVisible(this, 'unableCompute', visi == false ? false : true );
  238. /* if(e.viewport.name == 'mapViewport' && visi && this.visiMap.get(viewer.mainViewport) == false){
  239. console.log(1)
  240. } */
  241. if(e.viewport.name == 'magnifier')return
  242. if(this.viewports && !this.viewports.includes(e.viewport) )return
  243. if( !this.root || !this.realVisible(e.viewport, e.interactables) )return
  244. var matrix = this.matrixMap.get(e.viewport);
  245. if(!matrix){
  246. this.update(e)
  247. matrix = this.matrixMap.get(e.viewport);
  248. if(!matrix)return
  249. }
  250. if(e.viewport == this.useViewport){
  251. return
  252. }
  253. this.useViewport = e.viewport
  254. this.matrix.copy(matrix)
  255. if(this.root != this){
  256. var matrix2 = this.matrixMapRoot.get(e.viewport);
  257. this.root.matrix.copy(matrix2)
  258. }
  259. e.raycaster && this.root.updateMatrixWorld(true)//渲染前会自动updateMatrixWorld,但raycaster不会
  260. //console.log(this.root.name + e.viewport.name + " : "+this.root.matrixWorld.elements)
  261. }
  262. setUniforms(name,value){
  263. this.material.setUniforms(name,value)
  264. }
  265. dispose(){
  266. this.removeAllListeners()
  267. this.parent && this.parent.remove(this)
  268. }
  269. }
  270. /*
  271. let orient2d
  272. if(this.lineDir){
  273. this.root.updateMatrix();//先更新,getWorldPosition才能得到正确的
  274. this.root.updateMatrixWorld(true)
  275. let center = this.root.getWorldPosition(new THREE.Vector3())
  276. //由于两个端点容易在屏幕外,所以使用center和center加dir
  277. let lineDir = this.lineDir.clone();
  278. let r1 = Potree.Utils.getPos2d(center, camera, viewer.renderArea, e.viewport);
  279. if(!r1.trueSide)return Potree.Utils.updateVisible(this, 'unableCompute', false);// 但这句会使realVisible为false从而无法更新//console.error('!r1.trueSide') //中心点如果在背面直接不渲染了
  280. let r2, point2
  281. let p2State = '', len=1, p2StateHistory = []
  282. while(p2State != 'got' && p2StateHistory.length<10){
  283. point2 = center.clone().add(lineDir.multiplyScalar(len));
  284. r2 = Potree.Utils.getPos2d(point2, camera, viewer.renderArea, e.viewport);
  285. if(!r2.trueSide){ //很少遇到点2在背面的
  286. if(!p2StateHistory.includes('tooLong-reverse')){
  287. p2State = 'tooLong-reverse' //先尝试反向
  288. len = -len
  289. }else{
  290. p2State = 'tooLong'
  291. len = len / 2
  292. }
  293. }else{
  294. let dis = r2.pos.distanceTo(r1.pos)
  295. if(dis == 0){
  296. //console.log('dis == 0')
  297. Potree.Utils.updateVisible(this, 'unableCompute', false)
  298. return
  299. break
  300. }
  301. if(dis<10 && !p2StateHistory.includes('tooLong')){//和r1的屏幕距离太近,要加长,否则精度过低
  302. p2State = 'tooShort'
  303. len = 100/dis * len
  304. }else{
  305. p2State = 'got'; break;
  306. }
  307. }
  308. p2StateHistory.push(p2State)
  309. }
  310. //console.log(p2StateHistory,len)
  311. if(!r2.trueSide){
  312. return Potree.Utils.updateVisible(this, 'unableCompute', false)//, console.log(' !r2.trueSide', )
  313. }
  314. Potree.Utils.updateVisible(this, 'unableCompute', true)
  315. let p1 = r1.pos, p2 = r2.pos
  316. let vec = new THREE.Vector2().subVectors(p1,p2);
  317. let angle = -vec.angle() //根据测量线在屏幕上的角度在旋转label,使之和屏幕上的二维线平行。
  318. if(p1.x < p2.x) angle += Math.PI //避免字是倒着的情况
  319. orient2d = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0,0,1), angle)
  320. //console.log(this.parent.text, THREE.Math.radToDeg(angle), p1.x < p2.x )
  321. }
  322. let parentQua = this.root.parent.getWorldQuaternion(new THREE.Quaternion)
  323. this.root.quaternion.multiplyQuaternions(parentQua.invert(),camera.quaternion) //乘上parentQua.invert()是为了中和掉父结点的qua,使只剩下camera.quaternion
  324. if(this.lineDir){
  325. this.root.quaternion.multiply(orient2d)
  326. }
  327. */