TileUtils.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. import {GLCubeFaces} from '../../../defines'
  2. import MathLight from '../../../utils/MathLight'
  3. import * as THREE from "../../../../libs/three.js/build/three.module.js";
  4. var TileUtils = {};
  5. TileUtils.TILE_SIZE = 512,
  6. TileUtils.FACES_PER_PANO = 6,
  7. TileUtils.LocationOnTile = {
  8. Center: 0,
  9. UpperLeft: 1,
  10. UpperRight: 2,
  11. LowerRight: 3,
  12. LowerLeft: 4
  13. },
  14. /*
  15. * 获取某tile在cube中的方向 direction (向量起点在cube中心,终点在tile图的指定位置)。spherical通过先求uv,再直接得到dir
  16. * @param {*} size 面分辨率
  17. * @param {*} cubeFace 所在面
  18. * @param {*} Center 在tile上的目标位置,默认为中心,其他位置就是四个顶点
  19. * @param {*} c 似乎是在tile的缩进百分比,根据所在面的不同,分别向不同方向缩进,但都是向tile的中心
  20. * @param {*} dir 所求方向
  21. */
  22. TileUtils.getTileVector = function() {//获取某tile在cube中的方向 direction (向量起点在cube中心,终点在tile图的中心)
  23. return function(size, tileSize, cubeFace, tileX, tileY, Center, c, dir) {//c似乎是缩进百分比
  24. Center = Center || TileUtils.LocationOnTile.Center;
  25. //假设该cube边长为2:
  26. var u = size / tileSize
  27. , d = tileX / u;
  28. tileY = -tileY + (u - 1);
  29. var p = tileY / u
  30. , f = tileSize / size
  31. , g = 2 * f //一个tile的宽度 (乘以2是因为cube边长是2)
  32. , m = g / 2
  33. , v = 2 * d - 1 + m
  34. , A = 2 * p - 1 + m;
  35. switch (Center) {//计算在tile中指定位置带来的偏移
  36. case TileUtils.LocationOnTile.UpperLeft: //1
  37. v -= m,
  38. A += m,
  39. v += c * g; //似乎是向内缩进
  40. break;
  41. case TileUtils.LocationOnTile.UpperRight:
  42. v += m,
  43. A += m,
  44. A -= c * g;
  45. break;
  46. case TileUtils.LocationOnTile.LowerRight:
  47. v += m,
  48. A -= m,
  49. v -= c * g;
  50. break;
  51. case TileUtils.LocationOnTile.LowerLeft:
  52. v -= m,
  53. A -= m,
  54. A += c * g;
  55. break;
  56. case TileUtils.LocationOnTile.Center: //0
  57. }
  58. switch (cubeFace) {
  59. case GLCubeFaces.GL_TEXTURE_CUBE_MAP_POSITIVE_X:
  60. MathLight.setVector(dir, -1, A, -v);
  61. break;
  62. case GLCubeFaces.GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
  63. MathLight.setVector(dir, 1, A, v);
  64. break;
  65. case GLCubeFaces.GL_TEXTURE_CUBE_MAP_POSITIVE_Y: //顶面
  66. MathLight.setVector(dir, -v, 1, -A);
  67. break;
  68. case GLCubeFaces.GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
  69. MathLight.setVector(dir, -v, -1, A);
  70. break;
  71. case GLCubeFaces.GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
  72. MathLight.setVector(dir, -v, A, 1);
  73. break;
  74. case GLCubeFaces.GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
  75. MathLight.setVector(dir, v, A, -1)
  76. }
  77. MathLight.normalize(dir)
  78. }
  79. }(),
  80. /*
  81. * 获取该tile在第几个面(简易装载法)
  82. */
  83. TileUtils.getFaceForTile = function(size, index) {//获取该tile在第几个面
  84. var tileSize = TileUtils.TILE_SIZE;
  85. size < TileUtils.TILE_SIZE && (tileSize = size);
  86. var n = Math.floor(size / tileSize)
  87. , sum = n * n; //得每个面tile总数
  88. return Math.floor(index / sum)
  89. }
  90. ,
  91. TileUtils.getTileLocation = function(size, t, result) {
  92. var tileSize = TileUtils.TILE_SIZE;
  93. size < TileUtils.TILE_SIZE && (tileSize = size);
  94. var r = TileUtils.getFaceForTile(size, t)
  95. , a = Math.floor(size / tileSize)
  96. , s = a * a
  97. , l = t - r * s;
  98. result.tileX = l % a;
  99. result.tileY = Math.floor(l / a);
  100. result.face = r;
  101. result.faceTileIndex = l;
  102. return result
  103. }
  104. ,
  105. /*
  106. * 求size分辨率需要多少张tile
  107. */
  108. TileUtils.getTileCountForSize = function(e) {
  109. if (e <= TileUtils.TILE_SIZE)
  110. return TileUtils.FACES_PER_PANO;
  111. var t = Math.floor(e / TileUtils.TILE_SIZE)
  112. , i = t * t
  113. , n = i * TileUtils.FACES_PER_PANO;
  114. return n
  115. }
  116. ,
  117. TileUtils.getRelativeDirection = function() {
  118. var e = new MathLight.Matrix4
  119. , t = new MathLight.Quaternion;
  120. return function(i, n) {//i是pano.quaternion, n是camera的direction
  121. t.copy(i),
  122. t.inverse(),
  123. e.makeRotationFromQuaternion(t),
  124. e.applyToVector3(n),
  125. MathLight.normalize(n)
  126. }
  127. }(),
  128. /*
  129. * 根据方向寻找合适的tile加载
  130. */
  131. TileUtils.matchingTilesInDirection = function() {
  132. var e = new MathLight.Vector3
  133. , t = new MathLight.Vector3(0,0,-1)
  134. , i = new MathLight.Quaternion
  135. , n = function(e, t) {
  136. e.push({
  137. face: t.face,
  138. faceTileIndex: t.faceTileIndex,
  139. tileX: t.tileX,
  140. tileY: t.tileY
  141. })
  142. }
  143. , a = function() {
  144. var e = {
  145. face: -1,
  146. faceTileIndex: -1,
  147. tileX: -1,
  148. tileY: -1
  149. };
  150. return function(size, i, r) {
  151. for (var a = TileUtils.getTileCountForSize(size), s = 0, l = 0; l < a; l++)
  152. TileUtils.getTileLocation(size, l, e),
  153. i && !i(e) || (s++,
  154. r && n(r, e));
  155. return s
  156. }
  157. }();
  158. return function(pano, size, dir, hFov, vFov, result) {
  159. var d = size < TileUtils.TILE_SIZE ? size : TileUtils.TILE_SIZE;
  160. //TileUtils.getTileCountForSize(size);
  161. if (!hFov && !vFov)
  162. return a(size, null, result);
  163. var p = !!vFov;
  164. vFov = vFov || hFov,
  165. vFov = Math.max(0, Math.min(vFov, 360)),
  166. hFov = Math.max(0, Math.min(hFov, 360)),
  167. MathLight.copyVector(dir, e),
  168. TileUtils.getRelativeDirection(pano.quaternion4dkk, e)
  169. if(p){//如果有vFov hFov
  170. i.setFromUnitVectors(e, t);
  171. var f = function(e) {
  172. return TileUtils.isTileWithinFrustum(size, d, e.face, e.tileX, e.tileY, i, hFov, vFov)//在视野中的
  173. };
  174. return a(size, f, result)
  175. }
  176. var g = function(t) {//如果仅有hFov
  177. return TileUtils.isTileWithinFOV(size, d, t.face, t.tileX, t.tileY, e, hFov)
  178. };
  179. return a(size, g, result)
  180. }
  181. }(),
  182. /*
  183. * 是否在屏幕范围内
  184. */
  185. TileUtils.isTileWithinFrustum = function() {
  186. var e = new MathLight.Vector3
  187. , t = 1e-5;
  188. return function(i, n, a, s, l, c, h, u) {
  189. for (var d = Math.tan(.5 * u * MathLight.RADIANS_PER_DEGREE), p = -d, f = Math.tan(.5 * h * MathLight.RADIANS_PER_DEGREE), g = -f, m = TileUtils.mapFaceToCubemapFace(a), v = 0, A = 0, y = 0, C = 0, I = 0, E = 0, b = TileUtils.LocationOnTile.Center; b <= TileUtils.LocationOnTile.LowerLeft; b++){
  190. TileUtils.getTileVector(i, n, m, s, l, b, 0, e),//get e // size, tileSize, cubeFace, tileX, tileY, Center, c, dir
  191. MathLight.applyQuaternionToVector(c, e)
  192. if (e.z >= -t)//似乎是在相机背面
  193. I++;
  194. else {
  195. var w = -1 / e.z
  196. , _ = e.x * w
  197. , T = e.y * w;
  198. T > d ? v++ : T < p && A++, //这四种似乎代表在这个画框之外,如在左、在上、在下、在右
  199. _ > f ? y++ : _ < g && C++,
  200. E++
  201. }
  202. }
  203. return A !== E && v !== E && y !== E && C !== E //如果有一项和E相等代表要么是在相机背面要么是tile的四个顶点都画在画布的同一边,所以肯定不在画布上
  204. }
  205. }(),
  206. /*
  207. * 是否在FOV范围内
  208. */
  209. TileUtils.isTileWithinFOV = function() {
  210. var e = new MathLight.Vector3
  211. , t = new MathLight.Vector3(0,1,0)
  212. , i = new MathLight.Vector3(1,0,0);
  213. return function(panoSize, tileSize, face, tileX, tileY, direction, fov) {//direction是作用了pano.quaternion的camera.direction
  214. var d = TileUtils.mapFaceToCubemapFace(face);
  215. MathLight.cross(direction, t, i) //get i 好像没用到
  216. TileUtils.getTileVector(panoSize, tileSize, d, tileX, tileY, TileUtils.LocationOnTile.Center, 0, e)
  217. if (TileUtils.isWithinFOV(e, direction, fov, null))//先判断tile中心在不在FOV内
  218. return !0;
  219. for (var p = fov / 360, f = Math.floor(1 / p), g = 0, m = 0; m < f; m++) {
  220. for (var v = TileUtils.LocationOnTile.UpperLeft; v <= TileUtils.LocationOnTile.LowerLeft; v++)
  221. if (TileUtils.getTileVector(panoSize, tileSize, d, tileX, tileY, v, g, e),
  222. TileUtils.isWithinFOV(e, direction, fov, null))
  223. return !0;
  224. g += p //可能是考虑到有可能tile比fov覆盖了fov(虽然一般不可能,除非fov特别小),所以将tile分成若干段,取tile中的点再检测下
  225. }
  226. return !1
  227. }
  228. }(),
  229. TileUtils.isWithinFOV = function() {
  230. var e = new MathLight.Vector3
  231. , t = new MathLight.Vector3;
  232. return function(dir, cameraDir, fov, a) {
  233. if (MathLight.copyVector(dir, t),
  234. a) {
  235. MathLight.copyVector(a, e),
  236. MathLight.normalize(e);
  237. var s = MathLight.dot(e, dir);
  238. e.x *= s,
  239. e.y *= s,
  240. e.z *= s,
  241. MathLight.subVector(t, e)
  242. }
  243. var l = fov / 2 * MathLight.RADIANS_PER_DEGREE
  244. , c = Math.cos(l)
  245. , h = MathLight.dot(t, cameraDir);
  246. return h >= c
  247. }
  248. }(),
  249. TileUtils.mapFaceToCubemapFace = function() {
  250. var e = {
  251. 0: GLCubeFaces.GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
  252. 1: GLCubeFaces.GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
  253. 2: GLCubeFaces.GL_TEXTURE_CUBE_MAP_POSITIVE_X,
  254. 3: GLCubeFaces.GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
  255. 4: GLCubeFaces.GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
  256. 5: GLCubeFaces.GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
  257. };
  258. return function(t) {
  259. return e[t]
  260. }
  261. }();
  262. export default TileUtils