Using spherical coords/velocities in D3D

Started by
2 comments, last by ms291052 20 years, 2 months ago
I recently began (seriously) working with particle systems and it occured to me that for things like smoke the particles should be allow to swirl and expand. My bright idea to handle this was to use spherical coordinates for their positions and velocities, then translate and stuff them into a VB for D3D. Everything''s working just fine, but then as phi (angle in the xz plane) approaches pi, things begin to go funky, and my particles either collapse in to one point, or just start blinking and spazing. Relevant code: To convert from spherical to Cartesian:

D3DXVECTOR3 PolarToCartesian(D3DXVECTOR3 polar)
{
	D3DXVECTOR3 pt;
	pt.x = sinf(polar.z) * cosf(polar.y);
	pt.y = sinf(polar.y) * sinf(polar.z);
	pt.z = cosf(polar.z);
	pt *= polar.x;
	return pt;
}
To convert from Cartesian to spherical:

D3DXVECTOR3 CartesianToPolar(D3DXVECTOR3 p)
{
	if(p.x == 0.0f)
		p.x = 0.001f;
	if(p.z == 0.0f)
		p.z = 0.001f;
	D3DXVECTOR3 r;
	r.x = D3DXVec3Length(&p);
	r.y = atan2f(p.y, p.x);
	r.z = atan2f(sqrtf(p.x*p.x + p.y*p.y), p.z);

	if(fabsf(r.x) < 0.01f)
		r.x = 0.0f;
	if(fabsf(r.y) < 0.01f)
		r.y = 0.0f;
	if(fabsf(r.z) < 0.01f)
		r.z = 0.0f;

	return r;
}
And the VB stuffing code:

void PARTICLEEMITTER::Update(float elapsed)
{
	for(DWORD i=0;i<m_NumParticles;i++)
	{
		m_Particles[i].m_Age += elapsed;

		if(m_Particles[i].m_PolarUpdate == false)
		{
			m_Particles[i].m_Position += m_Particles[i].m_PolarVelocity*elapsed;
		}
		else
		{
			m_Particles[i].m_Position = PolarToCartesian(CartesianToPolar(m_Particles[i].m_Position) + m_Particles[i].m_PolarVelocity*elapsed);
		}
	}
	PARTICLEVERTEX* pVertices;
	HRESULT h = m_pVB->Lock(0, 0, (void**)&pVertices, 0);
	for(DWORD i=0; i < m_NumParticles; i++)
	{
		pVertices[i].diffuse = m_Particles[i].m_Color;
		pVertices[i].pos = m_Particles[i].m_Position;
	}
	m_pVB->Unlock();
}
1) Why exactly would such a thing happen? 2) How could it be corrected? 3) Anything look funny in that code? Thanks for your time, ms
Advertisement
//DEG_2_RAD converts degrees to radians//RAD_2_DEG converts radians to degrees//SIN, COS, TAN takes special cases such as 180, 90, etc. and returns the proper number rather than one "close," then converts to radians and uses normal math functions if not a special case.//I'm sure you can make the proper modifications.D3DXVECTOR3 PolarToCartesian(D3DXVECTOR3 direction, float Magnitude){	if(!_finite(Magnitude) || _isnan(Magnitude))	{		return;	}	float yMagnitude = Magnitude  * SIN(Direction.x);	float xzMagnitude = Magnitude * COS(Direction.x);	float xMagnitude = xzMagnitude * SIN(Direction.y);	float zMagnitude = xzMagnitude * COS(Direction.y);	return D3DXVECTOR3(xMagnitude, yMagnitude, zMagnitude);}D3DXVECTOR3 CartesianToPolar(D3DXVECTOR3 Polar){	float yDirectionAngle=0;	if(Polar.z != 0)	{		yDirectionAngle = RAD_2_DEG(atan2f(Polar.x,Polar.z));	}	float xzDistance = sqrtf(powf(Polar.x, 2) + powf(Polar.z, 2));	float xDirectionAngle=0;	if(xzDistance != 0)	{		xDirectionAngle = RAD_2_DEG(atan2f(Polar.y,xzDistance));	}	float Distance = sqrtf(powf(xzDistance, 2) + powf(Polar.y, 2));	return VECTOR(xDirectionAngle, yDirectionAngle, Distance);}

This is from my old movement code when I used spherical coords, and I know that this worked fine.

You might also want to try instead of "m_Particles[i].m_Position = PolarToCartesian(CartesianToPolar(m_Particles[i].m_Position) + m_Particles[i].m_PolarVelocity*elapsed);"
use
"m_Particles[i].m_Position = m_Particles[i].m_Position + PolarToCartesian(m_Particles[i].m_PolarVelocity*elapsed);"
They should work the same, if not better.

[edited by - Erzengeldeslichtes on February 22, 2004 4:33:42 PM]
----Erzengel des Lichtes光の大天使Archangel of LightEverything has a use. You must know that use, and when to properly use the effects.♀≈♂?
Yes, I thought of that too (just making the velocity into cartesian) but it doesn''t seem to work like that, so I''m forced to leave it doing double converting (which does hurt framerate with all the trig functions).

Another note: When I specify a particle velocity of (0, 0, 1) the particles go clockwise (? shouldn''t it be counter) around the origin until they hit pi, then start spazing. On the other hand, when I specify a velocity of (0, 1, 0), instead of going in an upward arc, they simply don''t move at all (staring down negative Z, which I believe should also be +Z).
Erzengeldeslichtes, I''m actually having a hard time converting your functions. It would appear as though your PolarToCartesian function is taking a 3D (spherical) vector and a magnitude. That spherical vector however, should contain rho (the magnitude) in itself, and thus the extra paramter is redundant. However, the coding indicates that the Z coord of that vector is not used, and magnitude is separate, which seems odd. Also, I notice that your formulas are very different from mine, which is also somewhat inexplicable to me. I''m just having a hard time going from my (rho, theta, phi) = (radius, angle in yz, angle in xy) to your Spherical coords with that radius. Any advice?

This topic is closed to new replies.

Advertisement