import {GLCubeFaces} from '../../../defines' import MathLight from '../../../utils/MathLight' import * as THREE from "../../../../libs/three.js/build/three.module.js"; var TileUtils = {}; TileUtils.TILE_SIZE = 512, TileUtils.FACES_PER_PANO = 6, TileUtils.LocationOnTile = { Center: 0, UpperLeft: 1, UpperRight: 2, LowerRight: 3, LowerLeft: 4 }, /* * 获取某tile在cube中的方向 direction (向量起点在cube中心,终点在tile图的指定位置)。spherical通过先求uv,再直接得到dir * @param {*} size 面分辨率 * @param {*} cubeFace 所在面 * @param {*} Center 在tile上的目标位置,默认为中心,其他位置就是四个顶点 * @param {*} c 似乎是在tile的缩进百分比,根据所在面的不同,分别向不同方向缩进,但都是向tile的中心 * @param {*} dir 所求方向 */ TileUtils.getTileVector = function() {//获取某tile在cube中的方向 direction (向量起点在cube中心,终点在tile图的中心) return function(size, tileSize, cubeFace, tileX, tileY, Center, c, dir) {//c似乎是缩进百分比 Center = Center || TileUtils.LocationOnTile.Center; //假设该cube边长为2: var u = size / tileSize , d = tileX / u; tileY = -tileY + (u - 1); var p = tileY / u , f = tileSize / size , g = 2 * f //一个tile的宽度 (乘以2是因为cube边长是2) , m = g / 2 , v = 2 * d - 1 + m , A = 2 * p - 1 + m; switch (Center) {//计算在tile中指定位置带来的偏移 case TileUtils.LocationOnTile.UpperLeft: //1 v -= m, A += m, v += c * g; //似乎是向内缩进 break; case TileUtils.LocationOnTile.UpperRight: v += m, A += m, A -= c * g; break; case TileUtils.LocationOnTile.LowerRight: v += m, A -= m, v -= c * g; break; case TileUtils.LocationOnTile.LowerLeft: v -= m, A -= m, A += c * g; break; case TileUtils.LocationOnTile.Center: //0 } switch (cubeFace) { case GLCubeFaces.GL_TEXTURE_CUBE_MAP_POSITIVE_X: MathLight.setVector(dir, -1, A, -v); break; case GLCubeFaces.GL_TEXTURE_CUBE_MAP_NEGATIVE_X: MathLight.setVector(dir, 1, A, v); break; case GLCubeFaces.GL_TEXTURE_CUBE_MAP_POSITIVE_Y: //顶面 MathLight.setVector(dir, -v, 1, -A); break; case GLCubeFaces.GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: MathLight.setVector(dir, -v, -1, A); break; case GLCubeFaces.GL_TEXTURE_CUBE_MAP_POSITIVE_Z: MathLight.setVector(dir, -v, A, 1); break; case GLCubeFaces.GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: MathLight.setVector(dir, v, A, -1) } MathLight.normalize(dir) } }(), /* * 获取该tile在第几个面(简易装载法) */ TileUtils.getFaceForTile = function(size, index) {//获取该tile在第几个面 var tileSize = TileUtils.TILE_SIZE; size < TileUtils.TILE_SIZE && (tileSize = size); var n = Math.floor(size / tileSize) , sum = n * n; //得每个面tile总数 return Math.floor(index / sum) } , TileUtils.getTileLocation = function(size, t, result) { var tileSize = TileUtils.TILE_SIZE; size < TileUtils.TILE_SIZE && (tileSize = size); var r = TileUtils.getFaceForTile(size, t) , a = Math.floor(size / tileSize) , s = a * a , l = t - r * s; result.tileX = l % a; result.tileY = Math.floor(l / a); result.face = r; result.faceTileIndex = l; return result } , /* * 求size分辨率需要多少张tile */ TileUtils.getTileCountForSize = function(e) { if (e <= TileUtils.TILE_SIZE) return TileUtils.FACES_PER_PANO; var t = Math.floor(e / TileUtils.TILE_SIZE) , i = t * t , n = i * TileUtils.FACES_PER_PANO; return n } , TileUtils.getRelativeDirection = function() { var e = new MathLight.Matrix4 , t = new MathLight.Quaternion; return function(i, n) {//i是pano.quaternion, n是camera的direction t.copy(i), t.inverse(), e.makeRotationFromQuaternion(t), e.applyToVector3(n), MathLight.normalize(n) } }(), /* * 根据方向寻找合适的tile加载 */ TileUtils.matchingTilesInDirection = function() { var e = new MathLight.Vector3 , t = new MathLight.Vector3(0,0,-1) , i = new MathLight.Quaternion , n = function(e, t) { e.push({ face: t.face, faceTileIndex: t.faceTileIndex, tileX: t.tileX, tileY: t.tileY }) } , a = function() { var e = { face: -1, faceTileIndex: -1, tileX: -1, tileY: -1 }; return function(size, i, r) { for (var a = TileUtils.getTileCountForSize(size), s = 0, l = 0; l < a; l++) TileUtils.getTileLocation(size, l, e), i && !i(e) || (s++, r && n(r, e)); return s } }(); return function(pano, size, dir, hFov, vFov, result) { var d = size < TileUtils.TILE_SIZE ? size : TileUtils.TILE_SIZE; //TileUtils.getTileCountForSize(size); if (!hFov && !vFov) return a(size, null, result); var p = !!vFov; vFov = vFov || hFov, vFov = Math.max(0, Math.min(vFov, 360)), hFov = Math.max(0, Math.min(hFov, 360)), MathLight.copyVector(dir, e), TileUtils.getRelativeDirection(pano.quaternion4dkk, e) if(p){//如果有vFov hFov i.setFromUnitVectors(e, t); var f = function(e) { return TileUtils.isTileWithinFrustum(size, d, e.face, e.tileX, e.tileY, i, hFov, vFov)//在视野中的 }; return a(size, f, result) } var g = function(t) {//如果仅有hFov return TileUtils.isTileWithinFOV(size, d, t.face, t.tileX, t.tileY, e, hFov) }; return a(size, g, result) } }(), /* * 是否在屏幕范围内 */ TileUtils.isTileWithinFrustum = function() { var e = new MathLight.Vector3 , t = 1e-5; return function(i, n, a, s, l, c, h, u) { 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++){ TileUtils.getTileVector(i, n, m, s, l, b, 0, e),//get e // size, tileSize, cubeFace, tileX, tileY, Center, c, dir MathLight.applyQuaternionToVector(c, e) if (e.z >= -t)//似乎是在相机背面 I++; else { var w = -1 / e.z , _ = e.x * w , T = e.y * w; T > d ? v++ : T < p && A++, //这四种似乎代表在这个画框之外,如在左、在上、在下、在右 _ > f ? y++ : _ < g && C++, E++ } } return A !== E && v !== E && y !== E && C !== E //如果有一项和E相等代表要么是在相机背面要么是tile的四个顶点都画在画布的同一边,所以肯定不在画布上 } }(), /* * 是否在FOV范围内 */ TileUtils.isTileWithinFOV = function() { var e = new MathLight.Vector3 , t = new MathLight.Vector3(0,1,0) , i = new MathLight.Vector3(1,0,0); return function(panoSize, tileSize, face, tileX, tileY, direction, fov) {//direction是作用了pano.quaternion的camera.direction var d = TileUtils.mapFaceToCubemapFace(face); MathLight.cross(direction, t, i) //get i 好像没用到 TileUtils.getTileVector(panoSize, tileSize, d, tileX, tileY, TileUtils.LocationOnTile.Center, 0, e) if (TileUtils.isWithinFOV(e, direction, fov, null))//先判断tile中心在不在FOV内 return !0; for (var p = fov / 360, f = Math.floor(1 / p), g = 0, m = 0; m < f; m++) { for (var v = TileUtils.LocationOnTile.UpperLeft; v <= TileUtils.LocationOnTile.LowerLeft; v++) if (TileUtils.getTileVector(panoSize, tileSize, d, tileX, tileY, v, g, e), TileUtils.isWithinFOV(e, direction, fov, null)) return !0; g += p //可能是考虑到有可能tile比fov覆盖了fov(虽然一般不可能,除非fov特别小),所以将tile分成若干段,取tile中的点再检测下 } return !1 } }(), TileUtils.isWithinFOV = function() { var e = new MathLight.Vector3 , t = new MathLight.Vector3; return function(dir, cameraDir, fov, a) { if (MathLight.copyVector(dir, t), a) { MathLight.copyVector(a, e), MathLight.normalize(e); var s = MathLight.dot(e, dir); e.x *= s, e.y *= s, e.z *= s, MathLight.subVector(t, e) } var l = fov / 2 * MathLight.RADIANS_PER_DEGREE , c = Math.cos(l) , h = MathLight.dot(t, cameraDir); return h >= c } }(), TileUtils.mapFaceToCubemapFace = function() { var e = { 0: GLCubeFaces.GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 1: GLCubeFaces.GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 2: GLCubeFaces.GL_TEXTURE_CUBE_MAP_POSITIVE_X, 3: GLCubeFaces.GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 4: GLCubeFaces.GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 5: GLCubeFaces.GL_TEXTURE_CUBE_MAP_NEGATIVE_Y }; return function(t) { return e[t] } }(); export default TileUtils