Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>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.</p> <p>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:</p> <pre><code>// map the given unit sphere position to a unit cube position void cubizePoint(Vector3&amp; 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 &gt;= fx &amp;&amp; fy &gt;= fz) { if (y &gt; 0) { // top face position.y = 1.0; } else { // bottom face position.y = -1.0; } } else if (fx &gt;= fy &amp;&amp; fx &gt;= fz) { if (x &gt; 0) { // right face position.x = 1.0; } else { // left face position.x = -1.0; } } else { if (z &gt; 0) { // front face position.z = 1.0; } else { // back face position.z = -1.0; } } } </code></pre> <p>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:</p> <pre><code>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) </code></pre> <p>You should see that the inner square root is used in both equations so only do that part once. </p> <p>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.</p> <pre><code>void cubizePoint2(Vector3&amp; 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 &gt;= fx &amp;&amp; fy &gt;= 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 &gt; 1.0) position.x = 1.0; if(position.z &gt; 1.0) position.z = 1.0; if(x &lt; 0) position.x = -position.x; if(z &lt; 0) position.z = -position.z; if (y &gt; 0) { // top face position.y = 1.0; } else { // bottom face position.y = -1.0; } } else if (fx &gt;= fy &amp;&amp; fx &gt;= 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 &gt; 1.0) position.y = 1.0; if(position.z &gt; 1.0) position.z = 1.0; if(y &lt; 0) position.y = -position.y; if(z &lt; 0) position.z = -position.z; if (x &gt; 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 &gt; 1.0) position.x = 1.0; if(position.y &gt; 1.0) position.y = 1.0; if(x &lt; 0) position.x = -position.x; if(y &lt; 0) position.y = -position.y; if (z &gt; 0) { // front face position.z = 1.0; } else { // back face position.z = -1.0; } } </code></pre> <p>So, this solution isn't nearly as pretty as the cube to sphere mapping, but it gets the job done!</p> <p>Any suggestions to improve the efficiency or read ability of the code above are appreciated!</p> <p>--- 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.</p> <p>--- 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!</p> <pre><code>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 &gt;= f.x &amp;&amp; f.y &gt;= f.z; bool b = f.x &gt;= f.z; return a ? cubify(sphere.xzy).xzy : b ? cubify(sphere.yzx).zxy : cubify(sphere); } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload