• Create Account

# Fast way to get spherical coordinates

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

4 replies to this topic

### #1Viik  Members   -  Reputation: 252

Like
0Likes
Like

Posted 16 May 2011 - 10:58 PM

I have a 2d texture that I'm reading using sperical coordinates. So two angles theta and phi corresond to uv of texture. As input I'm using xyz vector, that is converted into theta and phi.

Right now my code in hlsl looks like this:

static const float pi = 3.14159265f;
float2 toSphere(float3 n)
{
float  phi = 0;

if((n.x>=0) && (n.z>=0))
{
phi = atan(n.z/n.x);
}
if((n.x<0) && (n.z>=0))
{
phi = atan(n.z/n.x);
phi += pi;
}
if((n.x<0) && (n.z<0))
{ phi = atan(n.z/n.x);
phi += pi;
}
if((n.x>=0) && (n.z<0))
{
phi = atan(n.z/n.x);
phi += 2 * pi;
}
phi /= 2.f * pi;

float  theta = acos(n.y);
theta /= pi;

return float2(phi, theta);
}

It works correctly and basically just an direct implementation from general math formulas of relation between cartezian and spherical coordinates.
But I don't think that this really an efficient implementation, there are almost no math but four branches and that's not good for shader in the way how it's used (it should break cashing). I hope somebody can direct me towards more effeicient implimentation, I know in past spherical mapping was used a lot. Hope somebody remembers "old tricks" that he could share.

### #2Fabbo  Members   -  Reputation: 102

Like
0Likes
Like

Posted 17 May 2011 - 12:53 AM

I am sure there is a more efficient way to get the angles. I would say, you schould never ever use an if statement on the gpu.

But what is the idea behind storing UV coordinates as a Vector? If you would use 2 floats per vertex it would cost less memory and as you can see, the reconstruction is not simple at all. I don't know how exact your reconstruction is but there is a possibility that float inaccuracy causes problems.
E=mc^2 + 2d6

### #3haegarr  Crossbones+   -  Reputation: 7160

Like
1Likes
Like

Posted 17 May 2011 - 01:02 AM

Optimizing by using atan2:

AFAIK HLSL supports the atan2 function, and hence the entire case distinction can be conceded to a predefined function.

Otherwise, optimizing the if-clauses:

In every of the 4 if-clauses the same statement
phi = atan(n.z/n.x);
occurs using the same arguments in any case. So move that statement in front of the if-clauses. Then notice that the 1st if-clause's body is now empty and hence the clause can be dropped. The body of the 2nd and 3rd if-causes are identical and hence can be combined in a single if-clause (but see the comment below).

However:

Your implementation has some flaws. It suffers from division-by-zero problems. The method used to compute the case where both arguments are less than 0 is AFAIK wrong (you add pi instead of subtracting it).

### #4macnihilist  Members   -  Reputation: 377

Like
1Likes
Like

Posted 17 May 2011 - 02:32 AM

As heagarr said, HLSL supports atan2.
This is what I'm using. Not particularly optimized but it should be faster than yours. If you want 'y' to be 'theta'-axis you have to change the swizzles.
float3 CartesianToSpherical( in float3 xyz )
{
float r = length( xyz );
xyz *= 1.f/r;
float theta = acos( xyz.z );
float phi = atan2( xyz.y, xyz.x );
phi += ( phi < 0 ) ? 2*PI : 0;  // only if you want [0,2pi)

return float3( phi, theta, r );
}

### #5Viik  Members   -  Reputation: 252

Like
0Likes
Like

Posted 17 May 2011 - 06:40 AM

Thanks guys! Exactly what I need.

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

PARTNERS