4
\$\begingroup\$

This seems like a fairly basic and common problem. Is there a builtin way to achieve it or do I have to write the algorithm on my own? If I do, how should it work?

\$\endgroup\$
1
  • \$\begingroup\$ @Anko Your edit pretty much changes the objective of the question^^ But it is probably better for future reference... \$\endgroup\$
    – iolo
    Dec 22, 2014 at 9:10

2 Answers 2

4
\$\begingroup\$

Not that I'm aware of (you're asking if there's some sort of glsl function that would do the conversion, right?)

It's a pretty simple conversion though, just three lines; here it is in pseudocode:

r = sqrt(x*x+y*y+z*z);
theta = atan2(y,x);
phi = atan2(sqrt(x*x+y*y),z);
\$\endgroup\$
8
  • \$\begingroup\$ Yeah, I know, but one has to sort out the case when x is zero if I read the spec of atan() correctly. I just thought, people must be doing this all the time, so a builtin function might be available. \$\endgroup\$
    – iolo
    Nov 15, 2014 at 16:41
  • \$\begingroup\$ x being 0 shouldn't be a problem, you'd only have issues with the above if r = 0 en.wikipedia.org/wiki/Atan2#Definition_and_computation \$\endgroup\$ Nov 15, 2014 at 16:50
  • \$\begingroup\$ According to opengl.org/sdk/docs/man/html/atan.xhtml atan(y,x) is undefined whenever x is zero. \$\endgroup\$
    – iolo
    Nov 15, 2014 at 16:54
  • \$\begingroup\$ Oh crap... it looks like there isn't an atan2 function in glsl after all, my bad. Out of curiosity, what are you using the spherical coordinates for? Do they get plugged into other trig functions after you've converted them? \$\endgroup\$ Nov 15, 2014 at 16:58
  • \$\begingroup\$ Well the glsl atan() with 2 args works just like atan2(). I am building an app that displays certain aspects of the wave function of a hydrogen atom (and I am teaching myself OpenGL). \$\endgroup\$
    – iolo
    Nov 15, 2014 at 17:12
1
\$\begingroup\$

This did not helpe me achieve a full sphere coordinate conversions, I always got all my coordinates for a sphere in only half the sphere whether using atan with one parameter (atan(y/x)) or with two (atan(y, x)).

Here's what worked for me. I based the calculations on the formulas in https://en.wikipedia.org/wiki/Spherical_coordinate_system .

In this example vertex shader, the radius is distorted based upon phi and theta.

const float PI = 3.1415926535897932384626433832795028841971693993751058209749;

float getPhi(in float y, in float x)
{
    if (x == 0.0) {
        if (y == 0.0) {
            return 0.0;
        } else if (y > 0.0) {
            return PI/2.0;
        } else {
            return -1.0 * PI/2.0;
        }
    } else if (x > 0.0) {
        return atan(y/x);
    } else if (x < 0.0) {
        if (y >= 0.0) {
            return atan(y/x) + PI;
        } else {
            return atan(y/x) + PI;
        }
    }
}

vec3 toPolar(in vec3 cart)
{
    float xySquared = (cart.x * cart.x) + (cart.y * cart.y);
    float radius = sqrt(xySquared + (cart.z * cart.z));
    return vec3(radius, atan(sqrt(xySquared), cart.z), getPhi(cart.y, cart.x));
}

vec3 toCartesian(in vec3 sph) {
    return vec3(
        sin(sph.y) * cos(sph.z) * sph.x,
        sin(sph.y) * sin(sph.z) * sph.x,
        cos(sph.y) * sph.x
    );
}


void main()
{
    float disp = 2.0;
    vec3 sphericalPt = toPolar(position);

    vec3 sphericalDisp = vec3(
        sphericalPt.x + sin(position.x * 2.0 + position.y * 5.0 + position.z * 12.0 ) * disp,
        sphericalPt.y,
        sphericalPt.z
    );

    gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(toCartesian(sphericalDisp), 1.0);
}
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .