Glad you like the visualization!
I had stumbled over this in an obscure paper on cartography not too long ago. I was already in the process of producing imagery when the topic came up here. I wanted to gain some in
sight if maybe these tweaked coordinates were interesting for more fractal relatives to the Mandelbulb.
Below is the code of the transformation formulas I used. The idea is to start from a smaller sphere with radius between zero and one, project to the plane, then project back to a larger sphere of radius one. The lower the radius of the first sphere, the closer the poles move towards each other.
/////////////////////////////////////////////////////////////
// stereographic projection from sphere to plane //
// plane is: x = 0 //
// sphere touches in (0,0,0), is in x <= 0 halfspace //
// projection center is sphere point opposite touch point //
// inputs: sphere radius, point on sphere //
// output: projected point on plane //
/////////////////////////////////////////////////////////////
Vec3 sphereToPlane(const double R, const Vec3& P) {
const double scale = (R + R)/P.x;
return Vec3(0.0, scale*P.y, scale*P.z);
}
///////////////////////////////////////////////////////////////////////
// stereographic projection from plane to sphere //
// plane is: x = 0 //
// sphere touches in (0,0,0), is in x <= 0 halfspace, has radius 1.0 //
// projection center is sphere point opposite touch point //
// inputs: point on plane //
// output: projected point on sphere //
///////////////////////////////////////////////////////////////////////
Vec3 planeToSphere(const Vec3& P) {
/*
b := (-2.0, 0.0, 0.0); ray base
d := (2.0, P.y, P.z); ray direction
=>
(x,y,z) := b + t*d;
(x + 1)^2 + y^2 + z^2 - 1 = 0; sphere equation
=>
(x + 1)*(x + 1) + y*y + z*z - 1 = 0;
x := -2.0 + t*2.0;
y := t*P.y;
z := t*P.z;
substitute into sphere equation:
(-1.0 + t*2.0)*(-1.0 + t*2.0) + t*P.y*t*P.y + t*P.z*t*P.z - 1 = 0;
solve((-1.0 + t*2.0)*(-1.0 + t*2.0) + t*P.y*t*P.y + t*P.z*t*P.z - 1 = 0,t);
4
(%o1) [t = -----------------------, t = 0]
2 2
(P . z) + (P . y) + 4
so the relevant solution:
t = 4.0/(P.z*P.z + P.y*P.y + 4.0);
*/
const double t = 4.0/(P.z*P.z + P.y*P.y + 4.0);
return Vec3(t*2.0 - 2.0,
t*P.y,
t*P.z);
}
The "solve" command in the comments above is Maxima code (the free and old-fashioned computer algebra system that I keep plugging every now and then,
http://maxima.sourceforge.net ). The visualisation a few postings above was rendered with the Persistence of Vision Raytracer (a free and old-fashioned 3D computer graphics renderer,
http://www.povray.org ). The grid lines are tori, determined by the fact that three points uniquely define a circle (so I projected three points per grid line, then computed the resulting circumcircle from that triangle).