Jump to content

  • Log In with Google      Sign In   
  • 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.

  • You cannot reply to this topic
4 replies to this topic

#1 Viik   Members   -  Reputation: 206

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.



Sponsor:

#2 Fabbo   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

#3 haegarr   Crossbones+   -  Reputation: 3763

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

#4 macnihilist   Members   -  Reputation: 368

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


#5 Viik   Members   -  Reputation: 206

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