将球体映射到立方体

时间:2022-09-10 18:31:44

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

有一种特殊的方法可以将多维数据集映射到这里描述的球体:http://mathproofs.blogspot.com/2005/07/mapping-cubeto -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?

有数学天才想尝试一下吗?

Here's the equations in c++ code:

下面是c++代码中的公式:

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 are the sphere coords and x,y,z are the cube coords.

sx,sy,sz是球面坐标,x,y,z是立方体的坐标。

4 个解决方案

#1


13  

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.

我想要赞扬gmatt因为他做了很多工作。答案中唯一的不同是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;
        }
    }
}

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和t,并利用这些方程解出它们,这是基于剩下的球向量分量表示为a和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.

你应该看到内平方根在两个方程中都用过,所以只做这一部分一次。

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.

这是最终的函数,包含了方程,检查0和-0.0,以及正确设置立方体分量符号的代码——它应该等于球面分量的符号。

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!

如有任何提高效率或阅读能力的建议,我们将不胜感激!

--- 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.

--- -编辑---我应该提到我已经测试过这个,到目前为止,在我的测试中,代码看起来是正确的,结果至少是精确到小数点后第7位。那是我使用浮点数的时候,现在使用双精度可能更准确。

--- 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!

--- -编辑--- -这是Daniel优化的glsl片段着色器版本,以表明它不必是如此可怕的功能。Daniel用这个来过滤立方体地图上的采样!好主意!

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

#2


7  

After some rearranging you can get the "nice" forms

重新排列之后,你就可以得到“漂亮”的表格了

(1)   1/2 z^2 = (alpha) / ( y^2 - x^2) + 1
(2)   1/2 y^2 = (beta)  / ( z^2 - x^2) + 1
(3)   1/2 x^2 = (gamma) / ( y^2 - z^2) + 1

where alpha = sx^2-sy^2 , beta = sx^2 - sz^2 and gamma = sz^2 - sy^2. Verify this yourself.

在α= sx ^ 2-sy ^ 2,β= sx ^ 2 -深圳^ 2和γ=深圳^ 2 - sy ^ 2。验证这个自己。

Now I neither have the motivation nor the time but from this point on its pretty straightforward to solve:

现在我既没有动力也没有时间但是从这一点上来说它很容易解决:

  1. Substitute (1) into (2). Rearrange (2) until you get a polynomial (root) equation of the form

    把(1)代入(2)重新排列(2)直到得到形式的多项式(根)方程

    (4)    a(x) * y^4  + b(x) * y^2 + c(x) = 0
    

    this can be solved using the quadratic formula for y^2. Note that a(x),b(x),c(x) are some functions of x. The quadratic formula yields 2 roots for (4) which you will have to keep in mind.

    这可以解决使用y ^ 2的二次方程。注意a(x) b(x) c(x)是x的一些函数,二次公式为(4)生成2根,你需要记住这一点。

  2. Using (1),(2),(4) figure out an expression for z^2 in terms of only x^2.

    使用(1),(2),(4)算出一个表达式仅供z ^ 2的x ^ 2。

  3. Using (3) write out a polynomial root equation of the form:

    用(3)写出形式的多项式根方程:

    (5)    a * x^4  + b * x^2 + c = 0
    

    where a,b,c are not functions but constants. Solve this using the quadratic formula. In total you will have 2*2=4 possible solutions for x^2,y^2,z^2 pair meaning you will have 4*2=8 total solutions for possible x,y,z pairs satisfying these equations. Check conditions on each x,y,z pair and (hopefully) eliminate all but one (otherwise an inverse mapping does not exist.)

    a b c不是函数而是常数。用二次公式求解。总共有2 * 2 = 4 x ^ 2可能的解决方案,y ^ 2,z ^ 2双的意思你会4 * 2 = 8总解决方案可能的x,y,z对满足这些方程。检查每个x、y、z对上的条件,并(希望)除1外排除所有条件(否则不存在逆映射)。

Good luck.

祝你好运。

PS. It very well may be that the inverse mapping does not exist, think about the geometry: the sphere has surface area 4*pi*r^2 while the cube has surface area 6*d^2=6*(2r)^2=24r^2 so intuitively you have many more points on the cube that get mapped to the sphere. This means a many to one mapping, and any such mapping is not injective and hence is not bijective (i.e. the mapping has no inverse.) Sorry but I think you are out of luck.

PS。它很可能是逆映射不存在,考虑几何:球面面积4 *π* r ^ 2虽然立方体表面积6 * d ^ 2 = 6 *(2 r)^ 2 = 24 r ^ 2所以直觉你有更多的点映射到多维数据集上所球体。这意味着一个多到一个映射,任何这样的映射都不是单射的,因此也不是双射的(也就是说映射没有逆)。对不起,我想你运气不好。

----- edit --------------

- - - - - -编辑- - - - - - - - - - - - - - - -

if you follow the advice from MO, setting z=1 means you are looking at the solid square in the plane z=1.

如果你遵循MO的建议,将z=1设置为z=1意味着你正在观察平面z=1中的实方。

Use your first two equations to solve for x,y, wolfram alpha gives the result:

用你的前两个方程解出x,y, wolfram alpha得到的结果是:

x = (sqrt(6) s^2 sqrt(1/2 (sqrt((2 s^2-2 t^2-3)^2-24 t^2)+2 s^2-2 t^2-3)+3)-sqrt(6) t^2 sqrt(1/2 (sqrt((2 s^2-2 t^2-3)^2-24 t^2)+2 s^2-2 t^2-3)+3)-sqrt(3/2) sqrt((2 s^2-2 t^2-3)^2-24 t^2) sqrt(1/2 (sqrt((2 s^2-2 t^2-3)^2-24 t^2)+2 s^2-2 t^2-3)+3)+3 sqrt(3/2) sqrt(1/2 (sqrt((2 s^2-2 t^2-3)^2-24 t^2)+2 s^2-2 t^2-3)+3))/(6 s)

x = sqrt(6)s ^ 2√(1/2(sqrt((2 s ^ 2 - 2 t ^ 2 - 3)^ 2-24 t ^ 2)+ 2 s ^ 2 - 2 t ^ 2 - 3)+ 3)-√(6)t ^ 2倍根号(1/2(sqrt((2 s ^ 2 - 2 t ^ 2 - 3)^ 2-24 t ^ 2)+ 2 s ^ 2 - 2 t ^ 2 - 3)+ 3)-√(3/2)sqrt((2 s ^ 2 - 2 t ^ 2 - 3)^ 2-24 t ^ 2)调用sqrt(1/2(sqrt((2 s ^ 2 - 2 t ^ 2 - 3)^ 2-24 t ^ 2)+ 2 s ^ 2 - 2 t ^ 2 - 3)+ 3)+ 3倍根号(3/2)sqrt(1/2(sqrt((2 s ^ 2 - 2 t ^ 2 - 3)^ 2-24 t ^ 2)+ 2 s ^ 2 - 2 t ^ 2 - 3)+ 3))/(6 s)

and

y = sqrt(-sqrt((2 s^2-2 t^2-3)^2-24 t^2)-2 s^2+2 t^2+3)/sqrt(2)

y =√-√(2 s ^ 2 - 2 t ^ 2 - 3)^ 2-24 t ^ 2)2 s ^ 2 + 2 t ^ 2 + 3)/√(2)

where above I use s=sx and t=sy, and I will use u=sz. Then you can use the third equation you have for u=sz. That is lets say that you want to map the top part of the sphere to the cube. Then for any 0 <= s,t <= 1 (where s,t are in the sphere's coordinate frame ) then the tuple (s,t,u) maps to (x,y,1) (here x,y are in the cubes coordinate frame.) The only thing left is for you to figure out what u is. You can figure this out by using s,t to solve for x,y then using x,y to solve for u.

上面我用s=sx和t=sy,我用u=sz。然后你可以用u=sz的第三个方程。也就是说,假设你想要将球体的顶部映射到立方体上。然后对于任何0 <= s,t <= 1(其中s,t在球的坐标系中)那么元组(s,t,u)映射到(x,y,1)(这里x,y在立方体坐标系中)剩下的就是求u了。你可以用s t来解x,然后用x y来解u。

Note that this will only map the top part of the cube to only the top plane of the cube z=1. You will have to do this for all 6 sides (x=1, y=1, z=0 ... etc ). I suggest using wolfram alpha to solve the resulting equations you get for each sub-case, because they will be as ugly or uglier as those above.

注意,这只会将立方体的顶部映射到立方体z=1的顶部平面。对于所有6条边(x=1, y=1, z=0…)等等)。我建议使用wolfram alpha来解决你得到的每个子案例的结果方程,因为它们将会和上面的一样丑陋或丑陋。

#3


1  

Here's one way you can think about it: for a given point P in the sphere, take the segment that starts at the origin, passes through P, and ends at the surface of the cube. Let L be the length of this segment. Now all you need to do is multiply P by L; this is equivalent to mapping ||P|| from the interval [0, 1] to the interval [0, L]. This mapping should be one-to-one - every point in the sphere goes to a unique point in the cube (and points on the surface stay on the surface). Note that this is assuming a unit sphere and cube; the idea should hold elsewhere, you'll just have a few scale factors involved.

你可以这样想:对于球面上的一个给定点P,取从原点开始的线段,经过P,最后到达立方体的表面。L是这段的长度。现在你要做的就是把P乘以L;这相当于将||P||从区间[0,1]映射到区间[0,l]。这种映射应该是一对一的——球体中的每一个点都指向立方体中的一个唯一点(并且表面上的点停留在表面)。注意这是假设一个单位球面和立方体;这个想法应该适用于其他地方,你只需要考虑一些规模因素。

I've glossed over the hard part (finding the segment), but this is a standard raycasting problem. There are some links here that explain how to compute this for an arbitrary ray versus axis-aligned bounding box; you can probably simplify things since your ray starts at the origin and goes to the unit cube. If you need help simplify the equations, let me know and I'll take a stab at it.

我已经掩饰了困难的部分(找到片段),但这是一个标准的raycasting问题。这里有一些链接解释了如何计算任意射线与轴对齐的边界框;你可能可以化简,因为你的射线从原点开始到单位立方体。如果你需要帮助简化方程,让我知道,我会尝试一下。

#4


0  

It looks like there is a much cleaner solution if you're not afraid of trig and pi, not sure if it's faster/comparable though.

如果你不害怕trig和pi,看起来会有一个更干净的解决方案,但不确定它是否更快/可比性。

Just take the remaining components after determining the face and do:

在确定了面部后,取剩下的部分:

u = asin ( x ) / half_pi
v = asin ( y ) / half_pi

This is an intuitive leap, but this seems to back it up ( though not exactly the same topic ), so please correct me if I'm wrong.

这是一个直观的飞跃,但这似乎支持了它(虽然不是完全相同的主题),所以如果我错了请纠正我。

I'm too lazy to post an illustration that explains why. :D

我太懒了,不想发表解释原因的插图。:D

#1


13  

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.

我想要赞扬gmatt因为他做了很多工作。答案中唯一的不同是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;
        }
    }
}

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和t,并利用这些方程解出它们,这是基于剩下的球向量分量表示为a和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.

你应该看到内平方根在两个方程中都用过,所以只做这一部分一次。

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.

这是最终的函数,包含了方程,检查0和-0.0,以及正确设置立方体分量符号的代码——它应该等于球面分量的符号。

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!

如有任何提高效率或阅读能力的建议,我们将不胜感激!

--- 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.

--- -编辑---我应该提到我已经测试过这个,到目前为止,在我的测试中,代码看起来是正确的,结果至少是精确到小数点后第7位。那是我使用浮点数的时候,现在使用双精度可能更准确。

--- 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!

--- -编辑--- -这是Daniel优化的glsl片段着色器版本,以表明它不必是如此可怕的功能。Daniel用这个来过滤立方体地图上的采样!好主意!

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

#2


7  

After some rearranging you can get the "nice" forms

重新排列之后,你就可以得到“漂亮”的表格了

(1)   1/2 z^2 = (alpha) / ( y^2 - x^2) + 1
(2)   1/2 y^2 = (beta)  / ( z^2 - x^2) + 1
(3)   1/2 x^2 = (gamma) / ( y^2 - z^2) + 1

where alpha = sx^2-sy^2 , beta = sx^2 - sz^2 and gamma = sz^2 - sy^2. Verify this yourself.

在α= sx ^ 2-sy ^ 2,β= sx ^ 2 -深圳^ 2和γ=深圳^ 2 - sy ^ 2。验证这个自己。

Now I neither have the motivation nor the time but from this point on its pretty straightforward to solve:

现在我既没有动力也没有时间但是从这一点上来说它很容易解决:

  1. Substitute (1) into (2). Rearrange (2) until you get a polynomial (root) equation of the form

    把(1)代入(2)重新排列(2)直到得到形式的多项式(根)方程

    (4)    a(x) * y^4  + b(x) * y^2 + c(x) = 0
    

    this can be solved using the quadratic formula for y^2. Note that a(x),b(x),c(x) are some functions of x. The quadratic formula yields 2 roots for (4) which you will have to keep in mind.

    这可以解决使用y ^ 2的二次方程。注意a(x) b(x) c(x)是x的一些函数,二次公式为(4)生成2根,你需要记住这一点。

  2. Using (1),(2),(4) figure out an expression for z^2 in terms of only x^2.

    使用(1),(2),(4)算出一个表达式仅供z ^ 2的x ^ 2。

  3. Using (3) write out a polynomial root equation of the form:

    用(3)写出形式的多项式根方程:

    (5)    a * x^4  + b * x^2 + c = 0
    

    where a,b,c are not functions but constants. Solve this using the quadratic formula. In total you will have 2*2=4 possible solutions for x^2,y^2,z^2 pair meaning you will have 4*2=8 total solutions for possible x,y,z pairs satisfying these equations. Check conditions on each x,y,z pair and (hopefully) eliminate all but one (otherwise an inverse mapping does not exist.)

    a b c不是函数而是常数。用二次公式求解。总共有2 * 2 = 4 x ^ 2可能的解决方案,y ^ 2,z ^ 2双的意思你会4 * 2 = 8总解决方案可能的x,y,z对满足这些方程。检查每个x、y、z对上的条件,并(希望)除1外排除所有条件(否则不存在逆映射)。

Good luck.

祝你好运。

PS. It very well may be that the inverse mapping does not exist, think about the geometry: the sphere has surface area 4*pi*r^2 while the cube has surface area 6*d^2=6*(2r)^2=24r^2 so intuitively you have many more points on the cube that get mapped to the sphere. This means a many to one mapping, and any such mapping is not injective and hence is not bijective (i.e. the mapping has no inverse.) Sorry but I think you are out of luck.

PS。它很可能是逆映射不存在,考虑几何:球面面积4 *π* r ^ 2虽然立方体表面积6 * d ^ 2 = 6 *(2 r)^ 2 = 24 r ^ 2所以直觉你有更多的点映射到多维数据集上所球体。这意味着一个多到一个映射,任何这样的映射都不是单射的,因此也不是双射的(也就是说映射没有逆)。对不起,我想你运气不好。

----- edit --------------

- - - - - -编辑- - - - - - - - - - - - - - - -

if you follow the advice from MO, setting z=1 means you are looking at the solid square in the plane z=1.

如果你遵循MO的建议,将z=1设置为z=1意味着你正在观察平面z=1中的实方。

Use your first two equations to solve for x,y, wolfram alpha gives the result:

用你的前两个方程解出x,y, wolfram alpha得到的结果是:

x = (sqrt(6) s^2 sqrt(1/2 (sqrt((2 s^2-2 t^2-3)^2-24 t^2)+2 s^2-2 t^2-3)+3)-sqrt(6) t^2 sqrt(1/2 (sqrt((2 s^2-2 t^2-3)^2-24 t^2)+2 s^2-2 t^2-3)+3)-sqrt(3/2) sqrt((2 s^2-2 t^2-3)^2-24 t^2) sqrt(1/2 (sqrt((2 s^2-2 t^2-3)^2-24 t^2)+2 s^2-2 t^2-3)+3)+3 sqrt(3/2) sqrt(1/2 (sqrt((2 s^2-2 t^2-3)^2-24 t^2)+2 s^2-2 t^2-3)+3))/(6 s)

x = sqrt(6)s ^ 2√(1/2(sqrt((2 s ^ 2 - 2 t ^ 2 - 3)^ 2-24 t ^ 2)+ 2 s ^ 2 - 2 t ^ 2 - 3)+ 3)-√(6)t ^ 2倍根号(1/2(sqrt((2 s ^ 2 - 2 t ^ 2 - 3)^ 2-24 t ^ 2)+ 2 s ^ 2 - 2 t ^ 2 - 3)+ 3)-√(3/2)sqrt((2 s ^ 2 - 2 t ^ 2 - 3)^ 2-24 t ^ 2)调用sqrt(1/2(sqrt((2 s ^ 2 - 2 t ^ 2 - 3)^ 2-24 t ^ 2)+ 2 s ^ 2 - 2 t ^ 2 - 3)+ 3)+ 3倍根号(3/2)sqrt(1/2(sqrt((2 s ^ 2 - 2 t ^ 2 - 3)^ 2-24 t ^ 2)+ 2 s ^ 2 - 2 t ^ 2 - 3)+ 3))/(6 s)

and

y = sqrt(-sqrt((2 s^2-2 t^2-3)^2-24 t^2)-2 s^2+2 t^2+3)/sqrt(2)

y =√-√(2 s ^ 2 - 2 t ^ 2 - 3)^ 2-24 t ^ 2)2 s ^ 2 + 2 t ^ 2 + 3)/√(2)

where above I use s=sx and t=sy, and I will use u=sz. Then you can use the third equation you have for u=sz. That is lets say that you want to map the top part of the sphere to the cube. Then for any 0 <= s,t <= 1 (where s,t are in the sphere's coordinate frame ) then the tuple (s,t,u) maps to (x,y,1) (here x,y are in the cubes coordinate frame.) The only thing left is for you to figure out what u is. You can figure this out by using s,t to solve for x,y then using x,y to solve for u.

上面我用s=sx和t=sy,我用u=sz。然后你可以用u=sz的第三个方程。也就是说,假设你想要将球体的顶部映射到立方体上。然后对于任何0 <= s,t <= 1(其中s,t在球的坐标系中)那么元组(s,t,u)映射到(x,y,1)(这里x,y在立方体坐标系中)剩下的就是求u了。你可以用s t来解x,然后用x y来解u。

Note that this will only map the top part of the cube to only the top plane of the cube z=1. You will have to do this for all 6 sides (x=1, y=1, z=0 ... etc ). I suggest using wolfram alpha to solve the resulting equations you get for each sub-case, because they will be as ugly or uglier as those above.

注意,这只会将立方体的顶部映射到立方体z=1的顶部平面。对于所有6条边(x=1, y=1, z=0…)等等)。我建议使用wolfram alpha来解决你得到的每个子案例的结果方程,因为它们将会和上面的一样丑陋或丑陋。

#3


1  

Here's one way you can think about it: for a given point P in the sphere, take the segment that starts at the origin, passes through P, and ends at the surface of the cube. Let L be the length of this segment. Now all you need to do is multiply P by L; this is equivalent to mapping ||P|| from the interval [0, 1] to the interval [0, L]. This mapping should be one-to-one - every point in the sphere goes to a unique point in the cube (and points on the surface stay on the surface). Note that this is assuming a unit sphere and cube; the idea should hold elsewhere, you'll just have a few scale factors involved.

你可以这样想:对于球面上的一个给定点P,取从原点开始的线段,经过P,最后到达立方体的表面。L是这段的长度。现在你要做的就是把P乘以L;这相当于将||P||从区间[0,1]映射到区间[0,l]。这种映射应该是一对一的——球体中的每一个点都指向立方体中的一个唯一点(并且表面上的点停留在表面)。注意这是假设一个单位球面和立方体;这个想法应该适用于其他地方,你只需要考虑一些规模因素。

I've glossed over the hard part (finding the segment), but this is a standard raycasting problem. There are some links here that explain how to compute this for an arbitrary ray versus axis-aligned bounding box; you can probably simplify things since your ray starts at the origin and goes to the unit cube. If you need help simplify the equations, let me know and I'll take a stab at it.

我已经掩饰了困难的部分(找到片段),但这是一个标准的raycasting问题。这里有一些链接解释了如何计算任意射线与轴对齐的边界框;你可能可以化简,因为你的射线从原点开始到单位立方体。如果你需要帮助简化方程,让我知道,我会尝试一下。

#4


0  

It looks like there is a much cleaner solution if you're not afraid of trig and pi, not sure if it's faster/comparable though.

如果你不害怕trig和pi,看起来会有一个更干净的解决方案,但不确定它是否更快/可比性。

Just take the remaining components after determining the face and do:

在确定了面部后,取剩下的部分:

u = asin ( x ) / half_pi
v = asin ( y ) / half_pi

This is an intuitive leap, but this seems to back it up ( though not exactly the same topic ), so please correct me if I'm wrong.

这是一个直观的飞跃,但这似乎支持了它(虽然不是完全相同的主题),所以如果我错了请纠正我。

I'm too lazy to post an illustration that explains why. :D

我太懒了,不想发表解释原因的插图。:D