test-skybox/CatalogSkybox.js
2024-08-13 18:56:27 +08:00

227 lines
5.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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;