Sign in to follow this  
Viik

Fast way to get spherical coordinates

Recommended Posts

Viik    252
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:
[code]

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);
}

[/code]

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.

Share this post


Link to post
Share on other sites
Fabbo    102
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.

Share this post


Link to post
Share on other sites
haegarr    7372
[i]Optimizing by using atan2:[/i][i]
[/i]
AFAIK HLSL supports the atan2 function, and hence the entire case distinction can be conceded to a predefined function.

[i]Otherwise, optimizing the if-clauses:[/i]

In every of the 4 if-clauses the same statement
[color="#1C2837"][size="2"][color="#000000"]phi [/color][color="#666600"]=[/color][color="#000000"] atan[/color][color="#666600"]([/color][color="#000000"]n[/color][color="#666600"].[/color][color="#000000"]z[/color][color="#666600"]/[/color][color="#000000"]n[/color][color="#666600"].[/color][color="#000000"]x[/color][color="#666600"]);[/color][/size][/color]
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).

[i]However:[/i]

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).

Share this post


Link to post
Share on other sites
macnihilist    377
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.
[code]
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 );
}
[/code]

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this