Tôi muốn cung cấp tín dụng gmatt cho điều này bởi vì anh ấy đã thực hiện rất nhiều công việc. Sự khác biệt duy nhất trong câu trả lời của chúng tôi là phương trình cho x.
Để thực hiện ánh xạ ngược từ hình cầu đến khối lập phương đầu tiên, hãy xác định khối lập phương đối diện với các điểm hình cầu.Bước này rất đơn giản - chỉ cần tìm ra thành phần của vector hình cầu với chiều dài lớn nhất như sau:
// map the given unit sphere position to a unit cube position
void cubizePoint(Vector3& position) {
double x,y,z;
x = position.x;
y = position.y;
z = position.z;
double fx, fy, fz;
fx = fabsf(x);
fy = fabsf(y);
fz = fabsf(z);
if (fy >= fx && fy >= fz) {
if (y > 0) {
// top face
position.y = 1.0;
}
else {
// bottom face
position.y = -1.0;
}
}
else if (fx >= fy && fx >= fz) {
if (x > 0) {
// right face
position.x = 1.0;
}
else {
// left face
position.x = -1.0;
}
}
else {
if (z > 0) {
// front face
position.z = 1.0;
}
else {
// back face
position.z = -1.0;
}
}
}
Đối với mỗi khuôn mặt - mất các thành phần vector khối còn lại ký hiệu là s và t và giải quyết cho họ sử dụng các phương trình, mà là dựa trên các thành phần vector lĩnh vực còn lại ký hiệu là a và b:
s = sqrt(-sqrt((2 a^2-2 b^2-3)^2-24 a^2)+2 a^2-2 b^2+3)/sqrt(2)
t = sqrt(-sqrt((2 a^2-2 b^2-3)^2-24 a^2)-2 a^2+2 b^2+3)/sqrt(2)
Bạn sẽ thấy rằng căn bậc hai bên trong được sử dụng trong cả hai phương trình như vậy chỉ làm phần việc đó một lần.
Đây là hàm cuối cùng với các phương trình được ném vào và kiểm tra 0.0 và -0.0 và mã để đặt đúng dấu của thành phần khối - nó phải bằng dấu của thành phần hình cầu.
void cubizePoint2(Vector3& position)
{
double x,y,z;
x = position.x;
y = position.y;
z = position.z;
double fx, fy, fz;
fx = fabsf(x);
fy = fabsf(y);
fz = fabsf(z);
const double inverseSqrt2 = 0.70710676908493042;
if (fy >= fx && fy >= fz) {
double a2 = x * x * 2.0;
double b2 = z * z * 2.0;
double inner = -a2 + b2 -3;
double innersqrt = -sqrtf((inner * inner) - 12.0 * a2);
if(x == 0.0 || x == -0.0) {
position.x = 0.0;
}
else {
position.x = sqrtf(innersqrt + a2 - b2 + 3.0) * inverseSqrt2;
}
if(z == 0.0 || z == -0.0) {
position.z = 0.0;
}
else {
position.z = sqrtf(innersqrt - a2 + b2 + 3.0) * inverseSqrt2;
}
if(position.x > 1.0) position.x = 1.0;
if(position.z > 1.0) position.z = 1.0;
if(x < 0) position.x = -position.x;
if(z < 0) position.z = -position.z;
if (y > 0) {
// top face
position.y = 1.0;
}
else {
// bottom face
position.y = -1.0;
}
}
else if (fx >= fy && fx >= fz) {
double a2 = y * y * 2.0;
double b2 = z * z * 2.0;
double inner = -a2 + b2 -3;
double innersqrt = -sqrtf((inner * inner) - 12.0 * a2);
if(y == 0.0 || y == -0.0) {
position.y = 0.0;
}
else {
position.y = sqrtf(innersqrt + a2 - b2 + 3.0) * inverseSqrt2;
}
if(z == 0.0 || z == -0.0) {
position.z = 0.0;
}
else {
position.z = sqrtf(innersqrt - a2 + b2 + 3.0) * inverseSqrt2;
}
if(position.y > 1.0) position.y = 1.0;
if(position.z > 1.0) position.z = 1.0;
if(y < 0) position.y = -position.y;
if(z < 0) position.z = -position.z;
if (x > 0) {
// right face
position.x = 1.0;
}
else {
// left face
position.x = -1.0;
}
}
else {
double a2 = x * x * 2.0;
double b2 = y * y * 2.0;
double inner = -a2 + b2 -3;
double innersqrt = -sqrtf((inner * inner) - 12.0 * a2);
if(x == 0.0 || x == -0.0) {
position.x = 0.0;
}
else {
position.x = sqrtf(innersqrt + a2 - b2 + 3.0) * inverseSqrt2;
}
if(y == 0.0 || y == -0.0) {
position.y = 0.0;
}
else {
position.y = sqrtf(innersqrt - a2 + b2 + 3.0) * inverseSqrt2;
}
if(position.x > 1.0) position.x = 1.0;
if(position.y > 1.0) position.y = 1.0;
if(x < 0) position.x = -position.x;
if(y < 0) position.y = -position.y;
if (z > 0) {
// front face
position.z = 1.0;
}
else {
// back face
position.z = -1.0;
}
}
Vì vậy, giải pháp này không gần như lập bản đồ khối lập phương, nhưng nó hoàn thành công việc!
Bất kỳ đề xuất nào để cải thiện hiệu quả hoặc khả năng đọc của mã ở trên đều được đánh giá cao!
--- chỉnh sửa --- Tôi nên đề cập đến rằng tôi đã thử nghiệm điều này và cho đến nay trong các thử nghiệm của tôi mã xuất hiện chính xác với kết quả chính xác đến ít nhất là số thập phân thứ 7. Và đó là từ khi tôi đang sử dụng phao nổi, nó có lẽ chính xác hơn bây giờ với đôi.
--- chỉnh sửa --- Đây là phiên bản trình đổ bóng phân đoạn được tối ưu hóa bởi Daniel để cho thấy rằng nó không phải là một chức năng đáng sợ lớn như vậy. Daniel sử dụng điều này để lọc lấy mẫu trên bản đồ khối lập phương! Ý tưởng tuyệt vời!
const float isqrt2 = 0.70710676908493042;
vec3 cubify(const in vec3 s)
{
float xx2 = s.x * s.x * 2.0;
float yy2 = s.y * s.y * 2.0;
vec2 v = vec2(xx2 – yy2, yy2 – xx2);
float ii = v.y – 3.0;
ii *= ii;
float isqrt = -sqrt(ii – 12.0 * xx2) + 3.0;
v = sqrt(v + isqrt);
v *= isqrt2;
return sign(s) * vec3(v, 1.0);
}
vec3 sphere2cube(const in vec3 sphere)
{
vec3 f = abs(sphere);
bool a = f.y >= f.x && f.y >= f.z;
bool b = f.x >= f.z;
return a ? cubify(sphere.xzy).xzy : b ? cubify(sphere.yzx).zxy : cubify(sphere);
}
Có thể là một câu hỏi cho MathOverflow (http://mathoverflow.net/)? –
@James: Có thể là không. Với cộng đồng, tôi đặt cược họ sẽ tìm thấy điều này cả tầm thường lẫn chủ đề. –
Chỉ trong trường hợp, tôi cũng đăng ở đó. Điều này thực sự quan trọng đối với chương trình hành tinh của tôi: http://petrocket.blogspot.com Tôi cần nó để tạo bản đồ ánh sáng và phát hiện va chạm cơ bản với địa hình. – petrocket