const CatalogSkybox = { }; /** * 由立方体盒子上的坐标(单位长度为2)转换为对应盒子面上的图片的坐标 * * @param {number} x 立方盒子的x坐标,[-1,1] * @param {number} y 立方盒子的y坐标,[-1,1] * @param {number} z 立方盒子的z坐标,[-1,1] * @returns {i,j,faceId} i为图片的x坐标(向右),[0,1],j为图片的y坐标(向下),[0,0]为图片的左上角 * faceId为图片的面id,[0,5] */ CatalogSkybox.cubeXyzToImgUV = function(x, y, z) { let faceId, i, j; if (x === -1) { // back,mx //j = (1.0 - y) / 2.0; //i = (1.0 + z) / 2.0; j = (1.0 + y) / 2.0; i = (1.0 + z) / 2.0; faceId = 0; } else if (y === -1) { // left,my //i = (1.0 + x) / 2.0; //j = (1.0 - z) / 2.0; i = (1.0 + x) / 2.0; j = (1.0 + z) / 2.0; faceId = 1; } else if (x === 1) { // front,px //j = (1.0 - y) / 2.0; //i = (1.0 - z) / 2.0; i = (1.0 + y) / 2.0; j = (1.0 - z) / 2.0; faceId = 2; } else if (y === 1) { // right,py //i = (1.0 + x) / 2.0; //j = (1.0 + z) / 2.0; i = (1.0 + x) / 2.0; j = (1.0 - z) / 2.0; faceId = 3; } else if (z === 1) { // top i = (1.0 + x) / 2.0; j = (1.0 - y) / 2.0; faceId = 4; } else if (z === -1) { // bottom i = (1.0 - x) / 2.0; j = (1.0 - y) / 2.0; faceId = 5; } else { throw new Error("x,y,z其中一个必须为1或-1"); } if (i > 1) { i = 1; } if (i < 0) { i = 0; } if (j > 1) { j = 1; } if (j < 0) { j = 0; } return { i, j, faceId }; } const Pi1_4 = Math.PI / 4.0; const Pi3_4 = 3 * Math.PI / 4.0; /** * 天球坐标系坐标(赤经,赤纬)转换为立方体盒子(单位为2)上的坐标 * * @param {number} theta 赤经,弧度,[-PI,PI] * @param {number} phi 赤纬,弧度,[-PI/2,PI/2] */ CatalogSkybox.sphere2CubeXyz = function (theta, phi) { // 计算笛卡尔坐标(单位长度为1的球表面) let x = Math.cos(theta) * Math.cos(phi); let y = Math.sin(theta) * Math.cos(phi); let z = Math.sin(phi); const tanPhi = Math.tan(phi); let cosThe; // 将笛卡尔坐标映射到立方体盒子(单位为2)上 // x = 1,或 z = 1,-1 if (theta >= -Pi1_4 && theta < Pi1_4) { cosThe = Math.cos(theta); if (tanPhi > cosThe) { x = x / Math.abs(z); y = y / Math.abs(z); z = 1; } else if (tanPhi < -cosThe) { x = x / Math.abs(z); y = y / Math.abs(z); z = -1; } else { y = y / Math.abs(x); z = z / Math.abs(x); x = 1; } } // y = 1,或 z = 1,-1 else if (theta >= Pi1_4 && theta < Pi3_4) { cosThe = Math.cos(theta - Math.PI / 2); if (tanPhi > cosThe) { x = x / Math.abs(z); y = y / Math.abs(z); z = 1; } else if (tanPhi < -cosThe) { x = x / Math.abs(z); y = y / Math.abs(z); z = -1; } else { x = x / Math.abs(y); z = z / Math.abs(y); y = 1; } } // x = -1,或 z = 1,-1 else if (theta >= Pi3_4 || theta < -Pi3_4) { cosThe = Math.cos(theta - Math.PI); if (tanPhi > cosThe) { x = x / Math.abs(z); y = y / Math.abs(z); z = 1; } else if (tanPhi < -cosThe) { x = x / Math.abs(z); y = y / Math.abs(z); z = -1; } else { y = y / Math.abs(x); z = z / Math.abs(x); x = -1; } } // y = -1,或 z = 1,-1 else if (theta >= -Pi3_4 && theta < -Pi1_4) { cosThe = Math.cos(theta + Math.PI / 2); if (tanPhi > cosThe) { x = x / Math.abs(z); y = y / Math.abs(z); z = 1; } else if (tanPhi < -cosThe) { x = x / Math.abs(z); y = y / Math.abs(z); z = -1; } else { x = x / Math.abs(y); z = z / Math.abs(y); y = -1; } } return { x, y, z }; } /** * 由立方体盒子某个面的图片坐标转换为对应立方盒子面的坐标 * * @param {number} i 图片的x坐标(向右),[0,1] * @param {number} j 图片的y坐标(向下),[0,0]为图片的左上角 * @param {number} faceId 立方盒子的面id,[0,5] * @returns {x,y,z} 立方盒子的坐标,[-1,1] */ CatalogSkybox.imgUvToCubeXyz = function(i, j, faceId) { /* * 此函数被修改以适应cesium skybox的贴图 */ let a = 2.0 * i ; let b = 2.0 * j; let x, y, z; if (faceId === 0) { // back // (x,y,z) = (-1.0, 1.0 - a, 1.0 - b); x = -1.0; y = 1.0 - b; z = a - 1.0; } else if (faceId === 1) { // left x = a - 1.0; y = -1.0; z = 1.0 - b; } else if (faceId === 2) { // front // (x,y,z) = (1.0, a - 1.0, 1.0 - b); x = 1.0; y = 1.0 - b; z = 1.0 - a; } else if (faceId === 3) { // right // (x,y,z) = (1.0 - a, 1.0, 1.0 - b); x = a - 1.0; y = 1.0; z = b - 1.0; } else if (faceId === 4) { // top // (x,y,z) = (b - 1.0, a - 1.0, 1.0); x = a - 1.0; y = 1.0 - b; z = 1.0; } else if (faceId === 5) { // bottom // (x,y,z) = (1.0 - b, a - 1.0, -1.0); x = 1.0 - a; y = 1.0 - b; z = -1.0; } return { x, y, z }; } /** * 由立方体盒子上的坐标(单位长度为2)转换为赤经赤纬坐标 * * @param {number} x 立方盒子的x坐标,[-1,1] * @param {number} y 立方盒子的y坐标,[-1,1] * @param {number} z 立方盒子的z坐标,[-1,1] * @returns {theta, phi} theta为赤经,弧度,[-PI,PI],phi为赤纬,弧度,[-PI/2,PI/2] */ CatalogSkybox.cubeXyz2Sphere = function (x, y, z) { let theta = Math.atan2(y, x); let r = Math.sqrt(x * x + y * y); let phi = Math.atan2(z, r); return { theta, phi }; } export default CatalogSkybox;