将球体映射到多维数据集 [英] Mapping A Sphere To A Cube

查看:48
本文介绍了将球体映射到多维数据集的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这里描述了一种将多维数据集映射到球体的特殊方法: http://mathproofs.blogspot.com/2005/07/mapping-cube-to-sphere.html

There is a special way of mapping a cube to a sphere described here: http://mathproofs.blogspot.com/2005/07/mapping-cube-to-sphere.html

这不是您的基本归一化点就完成了"的方法,而是提供了更均匀分布的映射.

It is not your basic "normalize the point and you're done" approach and gives a much more evenly spaced mapping.

我试图做从球坐标到立方坐标的映射的逆过程,但无法得出工作方程.这是一个相当复杂的方程式系统,具有许多平方根.

I've tried to do the inverse of the mapping going from sphere coords to cube coords and have been unable to come up the working equations. It's a rather complex system of equations with lots of square roots.

任何数学天才都想对此进行破解吗?

Any math geniuses want to take a crack at it?

这是c ++代码中的等式:

Here's the equations in c++ code:

sx = x * sqrtf(1.0f - y * y * 0.5f - z * z * 0.5f + y * y * z * z / 3.0f);

sy = y * sqrtf(1.0f - z * z * 0.5f - x * x * 0.5f + z * z * x * x / 3.0f);

sz = z * sqrtf(1.0f - x * x * 0.5f - y * y * 0.5f + x * x * y * y / 3.0f);

sx,sy,sz是球坐标,而x,y,z是立方体坐标.

sx,sy,sz are the sphere coords and x,y,z are the cube coords.

推荐答案

我想为此感谢gmatt,因为他已经做了很多工作.我们答案的唯一区别是x的方程.

I want to give gmatt credit for this because he's done a lot of the work. The only difference in our answers is the equation for x.

要进行从球体到立方体的逆映射,首先确定球体点投影到的立方体面.这一步很简单-只需找到最大长度的球面矢量分量即可,如下所示:

To do the inverse mapping from sphere to cube first determine the cube face the sphere point projects to. This step is simple - just find the component of the sphere vector with the greatest length like so:

// 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;
        }
    }
}

对于每个面孔-取剩余的表示为s和t的立方矢量分量,并使用这些方程式求解它们,这些方程式基于剩余的表示为a和b的球面矢量分量:

For each face - take the remaining cube vector components denoted as s and t and solve for them using these equations, which are based on the remaining sphere vector components denoted as a and 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)

您应该看到两个方程式都使用了内平方根,因此该部分只需做一次.

You should see that the inner square root is used in both equations so only do that part once.

这是最后一个函数,其中包含方程式,并检查0.0和-0.0,以及用于正确设置立方体分量的符号的代码-它应等于球形分量的符号.

Here's the final function with the equations thrown in and checks for 0.0 and -0.0 and the code to properly set the sign of the cube component - it should be equal to the sign of the sphere component.

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;
        }
    }

因此,此解决方案不像多维数据集到球体的映射一样漂亮,但是可以完成工作!

So, this solution isn't nearly as pretty as the cube to sphere mapping, but it gets the job done!

对提高上述代码的效率或阅读能力的任何建议表示赞赏!

Any suggestions to improve the efficiency or read ability of the code above are appreciated!

-编辑-我应该提到我已经对此进行了测试,到目前为止,在我的测试中,代码看起来正确无误,结果至少精确到小数点后第七位.那是从我使用float时开始的,现在使用double可能更准确.

--- edit --- I should mention that I have tested this and so far in my tests the code appears correct with the results being accurate to at least the 7th decimal place. And that was from when I was using floats, it's probably more accurate now with doubles.

-编辑-这是丹尼尔(Daniel)优化的glsl片段着色器版本,可以证明它不必具有如此大的吓人功能.丹尼尔(Daniel)用它来过滤立方体贴图上的采样!好主意!

--- edit --- Here's an optimized glsl fragment shader version by Daniel to show that it doesn't have to be such a big scary function. Daniel uses this to filter sampling on cube maps! Great idea!

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);
}

这篇关于将球体映射到多维数据集的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆