mirror of
https://gitee.com/blitheli/test-skybox.git
synced 2025-06-16 18:38:18 +00:00
227 lines
5.9 KiB
JavaScript
227 lines
5.9 KiB
JavaScript
![]() |
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
|
|||
|
j = (1.0 - y) / 2.0;
|
|||
|
i = (1.0 + z) / 2.0;
|
|||
|
faceId = 0;
|
|||
|
} else if (y === -1) { // left
|
|||
|
i = (1.0 + x) / 2.0;
|
|||
|
j = (1.0 - z) / 2.0;
|
|||
|
faceId = 1;
|
|||
|
} else if (x === 1) { // front
|
|||
|
j = (1.0 - y) / 2.0;
|
|||
|
i = (1.0 - z) / 2.0;
|
|||
|
faceId = 2;
|
|||
|
} else if (y === 1) { // right
|
|||
|
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;
|