# Converting back and forth between spherical and cartesian coordinates in glsl

I have checked all the possible resources and I still don't know why my code is not working.

This code should convert uv (texture coordinates) or cartesian into spherical and back. But my code still can't convert the values back properly, even though it is the same as under that link: http://mathworld.wolfram.com/SphericalCoordinates.html

#ifdef GL_ES
precision mediump float;
#endif

#extension GL_OES_standard_derivatives : enable

uniform float time;
uniform vec2 mouse;
uniform vec2 resolution;

const float PI = 3.14159265359;

vec2 toUV(vec3 n)
{
vec2 uv;

uv.x = atan(n.y, n.x);
//uv.x = atan(n.y / n.x);   // Doesn't work either
uv.y = acos(n.z);

return uv;
}

// Uv range: [0, 1]
vec3 toSpherical(vec2 uv)
{
float theta = 2.0 * PI * uv.x;
float phi = PI * uv.y;

vec3 n;
n.x = cos(theta) * sin(phi);
n.y = sin(theta) * sin(phi);
n.z = cos(phi);

// x, y, z range: [-1.0, 1.0]
return n;
}

void main( void ) {
// Range from 0 to 1
vec2 p = gl_FragCoord.xy / resolution.xy;

vec3 color = vec3(0.0);

// The point of a sphere with radius 1.0
vec3 n = toSpherical(p);

// The cartesian coord
vec2 uv = toUV(n);

color = vec3(uv, 0.0);

// uv should be p by now
//color = vec3(p, 0.0);

// Showing the color
gl_FragColor = vec4( color, 1.0 );

}


To view this code, you can just paste everything into this site's editor http://www.glslsandbox.com/e

Any help would be appreciated.

• How did you derived your current implementation exactly? I cannot see it in any of the formulas on the source page. Dec 31, 2016 at 13:23
• @wondra 'toSpherical' is the same as the part explaining "In terms of Cartesian coordinates," and 'toUV' should be the part 'The spherical coordinates (r,theta,phi) are related to the Cartesian coordinates (x,y,z) by'. My problem is that these two do not give a bijection. Dec 31, 2016 at 14:12

I hope this will be useful to anyone struggling with a similar problem.

The phrase one should look for is geographic or map projection.

Though I've found a different way to convert between these systems, I was playing around with the ranges and found a solution somehow. However, I wish someone could explain why this works.

'toPolar' converts a unit sized square to the surface of a unit sized sphere placed in origo. 'toUV' is the inverse function.

Full code here: (after many conversions the range is still kept) http://glslsandbox.com/e#37633.0

Important functions:

const float PI = 3.1415926535897932384626433832795028841971693993751058209749;

vec2 toUV(in vec3 n)
{
vec2 uv;

uv.x = atan(-n.x, n.y);
uv.x = (uv.x + PI / 2.0) / (PI * 2.0) + PI * (28.670 / 360.0);

uv.y = acos(n.z) / PI;

return uv;
}

// Uv range: [0, 1]
vec3 toPolar(in vec2 uv)
{
float theta = 2.0 * PI * uv.x + - PI / 2.0;
float phi = PI * uv.y;

vec3 n;
n.x = cos(theta) * sin(phi);
n.y = sin(theta) * sin(phi);
n.z = cos(phi);

//n = normalize(n);
return n;
}