DepthImageSampler.js 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. import * as THREE from "../../../../libs/three.js/build/three.module.js";
  2. import math from "../../utils/math.js";
  3. import browser from "../../utils/browser.js";
  4. class DepthImageSampler extends THREE.EventDispatcher{
  5. constructor(){
  6. super()
  7. var canvas = document.createElement("canvas");
  8. this.canvas = canvas
  9. this.context = canvas.getContext("2d")
  10. this.imgDatas = []
  11. /* document.getElementsByTagName('body')[0].appendChild(canvas);
  12. canvas.style.position = 'fixed';
  13. canvas.style.width = '1024px';
  14. canvas.style.top = canvas.style.left = 0
  15. canvas.style['z-index'] = 100
  16. */
  17. this.maxDataCount = browser.isMobile() ? 6 : 20; //手机会崩溃. 平均每张图为8M数据量(以200个点的园区为例,加载时间久一些后,总内存=700 + 每张图的8M * maxDataCount)
  18. this.maxNeighCount = browser.isMobile() ? 3 : 14; //包含在maxDataCount内的nearPanos最大个数.至少比maxDataCount少3个,留出空位给最近更新的pano
  19. this.nearPanos = []
  20. }
  21. updateNearPanos(panos){
  22. this.nearPanos = panos.slice(0,this.maxNeighCount)
  23. }
  24. changeImg(img, pano){
  25. this.pano = pano
  26. let item = this.imgDatas.find(p=>p.pano == pano)
  27. if(/* this.img == img || */item){
  28. //最新的在末尾,所以换到末尾
  29. let index = this.imgDatas.indexOf(item)
  30. this.imgDatas.splice(index,1)
  31. this.imgDatas.push(item)
  32. //console.log('重复使用',item.pano.id)
  33. return
  34. }
  35. viewer.addTimeMark('depthSampler','start')
  36. this.canvas.width = img.width
  37. this.canvas.height = img.height
  38. this.context.drawImage(img, 0, 0)
  39. let data = this.context.getImageData(0, 0, img.width , img.height ).data; //getImageData 1px时 : pc chrome 耗时0.01毫秒左右(排除第一次的50) , 但firefox: 4。但换贴图之后就多达5甚至几十
  40. //console.log('changeImg',pano.id )
  41. //this.img = img
  42. if(this.imgDatas.length >= this.maxDataCount){
  43. let old = this.imgDatas.find(e=>!this.nearPanos.includes(e.pano))
  44. //console.log('推出',old.pano.id)
  45. this.imgDatas.splice(this.imgDatas.indexOf(old), 1)//推出使用时间最早的一个非nearPano
  46. }
  47. this.imgDatas.push({pano, data})
  48. this.dispatchEvent({type:'changeImg',pano})
  49. viewer.addTimeMark('depthSampler','end') //耗时chrome 25ms,firefox: 38ms, iphoneX:33ms
  50. /* pano.depthData = {}
  51. for(let h=0; h<img.height; h++){
  52. for(let w=0; w<img.width; w++){
  53. let blockIndex = img.width * h + w
  54. let r = data.slice(blockIndex*4, (blockIndex+1)*4)
  55. let depth = r[1] + r[0] / 256
  56. if(depth>0) pano.depthData[h+'|'+w] = depth
  57. }
  58. } */
  59. }
  60. getDepth( UVx, UVy) {//根据图片像素获取深度值
  61. var x = Math.round(UVx * (this.canvas.width - 1))
  62. , y = Math.round(UVy * (this.canvas.height - 1));
  63. if (!(x < 0 || y < 0 || x >= this.canvas.width || y >= this.canvas.height)) {
  64. /* viewer.addTimeMark('depthSampler','start')
  65. var r = this.context.getImageData(x, y, 1, 1).data; //pc chrome 耗时0.01毫秒左右(排除第一次的50) , 但firefox: 4。但换贴图之后就多达5甚至几十
  66. viewer.addTimeMark('depthSampler','end')
  67. //console.log('color', r, x,y)
  68. return r[1] + r[0] / 256 */
  69. let imgData = this.imgDatas.find(p=>p.pano == this.pano)
  70. let blockIndex = this.canvas.width * y + x
  71. let color = imgData.data.slice(blockIndex*4, (blockIndex+1)*4)
  72. return color[1] + color[0] / 256
  73. }
  74. }
  75. sample( intersect, currentPano, onlyPos ) {//通过和skybox的intersect得到真实的intersect的位置
  76. if(!intersect)return
  77. let location = new THREE.Vector3
  78. let normal
  79. currentPano = currentPano || viewer.images360.currentPano
  80. //let markName
  81. if(currentPano != this.currentPano){
  82. if(!currentPano.depthTex/* || !currentPano.depthTex.image */) return //未加载
  83. /* markName = 'depthSampleChangeTex'
  84. viewer.addTimeMark(markName,'start') */
  85. this.changeImg(currentPano.depthTex.image, currentPano)
  86. this.currentPano = currentPano
  87. }/* else{
  88. markName = 'depthSampleSame'
  89. viewer.addTimeMark(markName,'start')
  90. } */
  91. let origin = currentPano.position
  92. let dir = intersect.dir || new THREE.Vector3().subVectors(intersect.point, origin).normalize()
  93. //var uv = intersect.uv
  94. //let dirInPano = math.getNormalDir(dir, currentPano)//转化为考虑漫游点旋转的方向
  95. let dirInPano = dir.clone().applyMatrix4(currentPano.panoMatrix2Inverse).normalize(); //转化为考虑漫游点旋转的方向
  96. let uv = math.getUVfromDir(dirInPano)//转化为uv
  97. let distance = this.getDepth( uv.x, uv.y);
  98. //viewer.addTimeMark(markName,'end')
  99. if (!distance){
  100. const margin = 0.1
  101. if(uv.y > 1-Potree.config.depthTexUVyLimit){//漫游点底部识别不到的区域,给一个地板高度
  102. distance = (currentPano.floorPosition.z - origin.z - margin) / dir.z
  103. location.copy(dir).multiplyScalar(distance).add(origin);
  104. let normal = new THREE.Vector3(0,0,1)
  105. return {location, normal, distance}
  106. }else if(uv.y < Potree.config.depthTexUVyLimit){
  107. let ceilZ = currentPano.getCeilHeight()
  108. if(ceilZ == Infinity)return !1
  109. else{
  110. distance = (ceilZ - origin.z - margin) / dir.z
  111. location.copy(dir).multiplyScalar(distance).add(origin);
  112. let normal = new THREE.Vector3(0,0,-1)
  113. return {location, normal, distance}
  114. }
  115. }
  116. //console.log('无穷远')
  117. return !1; //应该是天空或模型外 , 因为很少有漫游点的地方还拍不到地板
  118. }
  119. //console.log('distance', distance, dirInPano.clone().multiplyScalar(distance))
  120. location.copy(dir).multiplyScalar(distance).add(origin);
  121. if(!onlyPos){
  122. var pL = this.getNearbyPoint(origin, uv, -1, 0)
  123. , pR = this.getNearbyPoint(origin, uv, 1, 0)
  124. , pB = this.getNearbyPoint(origin, uv, 0, -1)
  125. , pT = this.getNearbyPoint(origin, uv, 0, 1);
  126. normal = this.planeFit(dir,location, pL,pR,pB,pT )
  127. }
  128. /* if(normal.x != normal.x ){
  129. console.log('NAN', normal)
  130. var pL = this.getNearbyPoint(origin, uv, -1, 0)
  131. , pR = this.getNearbyPoint(origin, uv, 1, 0)
  132. , pB = this.getNearbyPoint(origin, uv, 0, -1)
  133. , pT = this.getNearbyPoint(origin, uv, 0, 1);
  134. } */
  135. //console.log(location, normal, distance)
  136. return {location, normal, distance}
  137. }
  138. getNearbyPoint( origin, uv, x, y) { //获取附近的若干像素距离的点
  139. let uv2 = uv.clone()
  140. uv2.x += x/(this.canvas.width-1);
  141. uv2.x = this.clampUV(uv2.x)
  142. uv2.y += y/(this.canvas.height-1);
  143. uv2.y = this.clampUV(uv2.y)
  144. /* if(uv2.x < 0 || uv2.y < 0 || uv2.x > 1 || uv2.y > 1){
  145. console.log('will nan')
  146. } */
  147. let dir = math.getDirFromUV(uv2)//从uv获取到方向
  148. dir.applyMatrix4(viewer.images360.currentPano.panoMatrix2)
  149. let depth = this.getDepth(uv2.x, uv2.y);
  150. /* if(Math.abs(depth - this.mainDepth) > 0.3){
  151. console.log('Math.abs(depth - this.mainDepth) > 0.3')
  152. } */
  153. //let dir = new THREE.Vector3().subVectors(intersect.point, origin).normalize()
  154. let position = new THREE.Vector3().copy(dir).multiplyScalar(depth).add(origin);
  155. //console.log('getNearbyPoint', uv2, depth, dir, position )
  156. return position
  157. }
  158. clampUV(v){
  159. return (v + 1) % 1; // 使输出在 0-1
  160. }
  161. planeFit(dir, position, pL,pR,pB,pT ) {//求平均法线
  162. let normal = new THREE.Vector3
  163. let plane = new THREE.Plane;
  164. function addNormal(p1, p2) {//根据临接的四个点,分别求法线,然后法线相加能得到平均法线
  165. if(!p1 || !p2)return
  166. plane.setFromCoplanarPoints(position, p1, p2)
  167. //console.log('normalSub', plane.normal)
  168. normal.addScaledVector(plane.normal, dir.dot(plane.normal) < 0 ? 1 : -1)//根据面的朝向判断加还是减
  169. }
  170. addNormal(pL, pB)
  171. addNormal(pL, pT)
  172. addNormal(pR, pB)
  173. addNormal(pR, pT)
  174. if(0 !== normal.x || 0 !== normal.y || 0 !== normal.z){
  175. normal.normalize()
  176. //console.log(normal)
  177. return normal
  178. }
  179. /* 四个面拼成一个菱形 */
  180. }
  181. }
  182. /*
  183. 注:
  184. 由于有时候获取intersect需要知道是哪个点云,所以还是不能用这个。如加测量线。
  185. */
  186. export default DepthImageSampler