pet*_*ket 22 mapping math geometry
有一种将立方体映射到此处描述的球体的特殊方法:http: //mathproofs.blogspot.com/2005/07/mapping-cube-to-sphere.html
这不是你的基本"标准化点和你已完成"的方法,并提供更均匀间隔的映射.
我试图做出从球体坐标到立方体坐标的映射的逆过程,并且无法得出工作方程式.这是一个相当复杂的方程组,有很多平方根.
任何数学天才都希望对此有所了解?
这是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);
Run Code Online (Sandbox Code Playgroud)
sx,sy,sz是球体坐标,x,y,z是立方体坐标.
pet*_*ket 13
我想为此付出代价,因为他完成了很多工作.我们答案的唯一区别是x的等式.
要执行从球体到立方体的逆映射,首先要确定球体点投影到的立方体面.这一步很简单 - 只需找到具有最大长度的球矢量的组件,如下所示:
// 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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
对于每个面 - 取剩余的立方体矢量分量表示为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)
Run Code Online (Sandbox Code Playgroud)
您应该看到内部平方根用于两个方程式中,因此只执行该部分一次.
这是抛出方程式的最终函数,检查0.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;
}
}
Run Code Online (Sandbox Code Playgroud)
因此,这个解决方案并不像立方体到球体映射那么漂亮,但它完成了工作!
任何提高上述代码的效率或阅读能力的建议都值得赞赏!
---编辑---我应该提到我已经测试了这个,到目前为止在我的测试中代码看起来是正确的,结果至少精确到小数点后7位.那是从我使用花车的时候开始,现在双打可能更准确.
---编辑---这是丹尼尔优化的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);
}
Run Code Online (Sandbox Code Playgroud)
经过一些重新安排后,您可以获得"漂亮"的表格
(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
Run Code Online (Sandbox Code Playgroud)
在哪里alpha = sx^2-sy^2,beta = sx^2 - sz^2和gamma = sz^2 - sy^2.自己验证一下.
现在我既没有动力,也没有时间,但从这一点来看,它非常简单易于解决:
将(1)代入(2).重新排列(2)直到得到表格的多项式(根)方程
(4) a(x) * y^4 + b(x) * y^2 + c(x) = 0
Run Code Online (Sandbox Code Playgroud)
这可以使用二次公式来解决y^2.注意,这a(x),b(x),c(x)是一些功能x.二次公式为(4)产生2个根,你必须牢记这一点.
使用(1),(2),(4)z^2仅表示表达式x^2.
使用(3)写出形式的多项式根方程:
(5) a * x^4 + b * x^2 + c = 0
Run Code Online (Sandbox Code Playgroud)
哪里a,b,c不是函数而是常量.使用二次公式解决这个问题.对于对,总共有2*2 = 4个可能的解决方案x^2,y^2,z^2意味着对于x,y,z满足这些方程的可能对,您将有4*2 = 8个总解.检查每x,y,z对上的条件并(希望)消除除一个之外的所有条件(否则不存在逆映射.)
祝好运.
PS.很可能是逆映射不存在,考虑几何:球体具有表面积,4*pi*r^2而立方体具有表面积,6*d^2=6*(2r)^2=24r^2因此直观地说,您在立方体上有更多的点被映射到球体.这意味着多对一的映射,任何这样的映射都不是单射的,因此不是双射的(即映射没有逆.)抱歉,但我认为你运气不好.
-----编辑--------------
如果您遵循MO的建议,设置z=1意味着您正在查看平面中的实心方块z=1.
使用前两个方程求解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)
和
y = sqrt(-sqrt((2 s^2-2 t^2-3)^2-24 t^2)-2 s^2+2 t^2+3)/sqrt(2)
其中,以上我用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,y然后使用x,y来解决这个问题u.
请注意,这只会立方体的顶部映射到仅立方体的顶面z=1.你将不得不对所有的6个面做到这一点(x=1,y=1,z=0...等).我建议使用wolfram alpha来解决每个子案例得到的公式,因为它们会像上面那样丑陋或丑陋.