/** * 天空盒子相关计算函数 */ 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] * * 0: mx, 1: my, 2: px, 3: py, 4: pz, 5: mz */ 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; faceId = 0; } else if (y === -1) { // left,my 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; faceId = 2; } else if (y === 1) { // right,py i = (1.0 + x) / 2.0; j = (1.0 - z) / 2.0; faceId = 3; } else if (z === 1) { // top,pz i = (1.0 + x) / 2.0; j = (1.0 + y) / 2.0; faceId = 4; } else if (z === -1) { // bottom,mz 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 }; } export default CatalogSkybox;