Drag...

Started by
13 comments, last by Erzengeldeslichtes 20 years, 6 months ago
I appologize for not using formal coding practices, I haven't even taken a class on c++, nor do I work for a company, so generally I just do what seems right at the time.

I thought it was spherical coordinate system, but I haven't actually worked with that or cylindrical coordinate in any math or physics classes I've been in, so I wasn't entirely sure.

Why I use spherical: It seemed right. An object moves in one direction at a specific speed. The only way I can concieve of doing it in cartesian is to have 3 speeds, one for each axis. This would be the same number of variables and probably faster because I wouldn't have to use 2 sines and 2 cosines every frame, nor 2 sines, 2 cosines, 2 arc tangents, and 2 square roots every time a force is applied (still leaves 2 more sines and cosines)... Hrm, I think I'll look into that conversion... But as I said, when I started programming this engine it seemed more "proper" to represent a single direction and speed than 3 speeds along 3 (albeit fixed) directions.
I have switched everything to *f and a* to a*2f, however now the air density must be less than 0.0002988888888889... I'll see what happens when I've finished converting to total cartesian coords....

Finished conversion... now the air density must be 0.000598995675888588998 or less. Any higher than that creates a #inf now (before it would just overflow). From what I've seen from stepping through debug it's the Force that's going 1.#inf0. From what I can tell, when I get spherical coords the speed goes infinite because the cartesian speeds are extreme--what I haven't isolated is why those cartesian speeds go extreme...

[edited by - Erzengeldeslichtes on October 12, 2003 8:08:56 AM]
----Erzengel des Lichtes光の大天使Archangel of LightEverything has a use. You must know that use, and when to properly use the effects.♀≈♂?
Advertisement
No need to apologize about your code. I only meant to give constructive criticism. But the main thing is to get it working and of course you''re already documenting your use of the structure, so that''s great!

Did you test my correction to your use of atan, *before* converting to Cartesian coords? What happened when you made that correction? I''m afraid you''ve introduce a new problem in your conversion to Cartesian. So, you may need to post part of your new, updated code.

Graham Rhodes
Senior Scientist
Applied Research Associates, Inc.
Graham Rhodes Moderator, Math & Physics forum @ gamedev.net
Yes, I did test atan2f, I switched all geometric functions to their f function types. The result was that it worked far better than previously (when it wasn't crashing), but it crashed at a lower atmospheric density: 0.0002988888888889.
Also, I am still using atan2f when I want to find out the spherical coords (ApplyForceInDirection requires spherical coords. Even so, I'm doing less conversions now)

VECTOR BaseObject::GetSphericalMomentum() //Gets direction and speed (speed is z coord, x and y are angles){	float yDirectionAngle=0;	if(xPosMom != 0)	{		yDirectionAngle = RAD_2_DEG(atan2f(xPosMom,zPosMom));	}	float xzSpeed = sqrtf(powf(xPosMom, 2) + powf(zPosMom, 2));	float xDirectionAngle=0;	if(xzSpeed != 0)	{		xDirectionAngle = RAD_2_DEG(atan2f(yPosMom,xzSpeed));	}	float Speed = sqrtf(powf(xzSpeed, 2) + powf(yPosMom, 2));	if(!_finite(Speed) || _isnan(Speed))	{		debug.Print(DEBUG_PRIORITY_HIGH, m_Name + string(" has an non-existant speed!"));	}}void BaseObject::ApplyForceInDirection(VECTOR Direction, float Magnitude) //Aplies a force along given direction. Ignores the z angle.{	if(!_finite(Magnitude) || _isnan(Magnitude))	{		return;	} 	float PerSec = m_ParentApp->GetElapsed();	float yForce = (Magnitude * PerSec)/m_Mass * sinf(DEG_2_RAD(Direction.x));	float xzMagnitude = (Magnitude * PerSec)/m_Mass * cosf(DEG_2_RAD(Direction.x));	float xForce = xzMagnitude * sinf(DEG_2_RAD(Direction.y));	float zForce = xzMagnitude * cosf(DEG_2_RAD(Direction.y));	xPosMom += xForce;	yPosMom += yForce;	zPosMom += zForce;	if(xPosMom > 1000 || yPosMom > 1000 || zPosMom > 1000)	{		debug.Print(DEBUG_PRIORITY_HIGH, m_Name + " is moving too fast!");	}}void ObjectManager::ApplyDrag(){	for(int i=0; i<m_NumberOfObjects; i++)	{		//Going to need to create calculations for profile of object. For now use a box.		VECTOR Dimensions = m_ObjectArray[i]->GetSize();		if(Dimensions == VECTOR(0,0,0))		{			continue; //Cameras, etc.		}		VECTOR Momentum = m_ObjectArray[i]->GetSphericalMomentum();		VECTOR Angular = m_ObjectArray[i]->GetAngularMomentum();		if(Momentum.z == 0 && Angular == VECTOR(0,0,0))		{			continue; //Not moving...		}		//Need to put in "atmosphere" objects. For now just use a constant atmosphere.		float AtmosphericDensity	= 0.00000005f;		float Coefficient = 1.28f;//coefficient of a flat plate.		if(Momentum.z != 0 && !_isnan(Momentum.z) && _finite(Momentum.z))		{			//Area calculation is here(haven't implemented lookup table yet)			float Force = Coefficient * ABS(Area) * AtmosphericDensity * powf(Momentum.z, 2);			if(Force < 0)			{				Force *= -1;			}			if(Force > 1000)			{				debug.Print(DEBUG_PRIORITY_HIGH, "Too high a force.");			}			VECTOR InverseDirection(0,0,0);			InverseDirection.y = Momentum.y-180;			InverseDirection.x = -Momentum.x;			debug.Print(DEBUG_PRIORITY_NORMAL, string("Force: ") + string(Force));			m_ObjectArray[i]->ApplyForceInDirection(InverseDirection, Force);		}		//Angular drag was here...	}}


[edited by - Erzengeldeslichtes on October 13, 2003 4:33:12 PM]
----Erzengel des Lichtes光の大天使Archangel of LightEverything has a use. You must know that use, and when to properly use the effects.♀≈♂?
Okay,

I looked over the code quickly. Without looking too carefully, it appears to be fine now. That would mean the crash is due to numerical stability problems. (This is different from numerical precision problems, so going to doubles from floats won''t help.)

So, here is what I think is happening, though I can''t confirm without running the code.

I believe that when you apply the drag, the object may actually be reversing direction, e.g., your velocity/momentum vector (xPosMom, yPosMom, zPosMom) is pointing in the opposite direction after you apply the object''s drag compared with the vector before applying drag. Even though there are some real weird real-life situations where you can have real objects oscillate out of control due to the wind, this is not something that you want here.

You can test to see if this is the case by doing the following. Within the loop in ApplyDrag, do this:

float xPosMomOld = xPosMom;float yPosMomOld = yPosMom;float zPosMomOld = zPosMom;...ApplyForceInDirection// check dot product of old velocity with new and see// if they are in opposite directionsif ((xPosMomOld * xPosMom) + (yPosMomOld * yPosMom) + (zPosMomOld * zPosMom)) < 0.0f){  // we applied too much drag force for the entire duration of  // the frame! BAD result! Lets just set velocity to zero  // in this case  xPosMom = 0.0f;  yPosMom = 0.0f;  zPosMom = 0.0f;}So, that''s a quick-and-dirty way to deal with the situation.I''ll try to explain what''s happening here. Your frame lasts for a certain fraction of a second, say 0.1 seconds. When you apply your drag as you have, you''ve assumed that the drag force remains constant during that 0.1 seconds, which would make it okay to just multily the force times 0.1 seconds and divide by mass to get the velocity change. But, in fact, during that 0.1 seconds your object is slowing down and as it slows down the drag force changes, gets smaller. So, the drag force applied during the 0.1 seconds of the frame is actually, on average, less   than the drag force you''ve calculated.I''ve given you a quick-and-dirty "fix" that may be acceptable. Now, there is a way to get the thing to work without doing this hack. The other way involves upgrading your technique to use a more advanced numerical integration scheme. (Although you probably don''t realize it, you are using something called "explicit Euler integration" to update xPosMom, yPosMom, and zPosMom instead your ApplyForceInDirection function.) Advanced integration schemes are things such as Verlet integration and Runge-Kutta. But my feeling is that you aren''t quite ready to begin working with these yet. So, the quick-and-dirty fix may do well enough. You can search the forum archive for more info on these techniques.(By the way, the average atmospheric density of air at sea level on Earth is 0.0000012 grams per cubic millimeter. Depending on your units for mass and length....a small value may be actually realistic.)   


Graham Rhodes
Senior Scientist
Applied Research Associates, Inc.
Graham Rhodes Moderator, Math & Physics forum @ gamedev.net
I knew that what I was doing was the Euler method--I was thinking that dt between (most) frames would be short enough that the difference is negligable (plus I don't want to have to integrate the change due to rotation, either from my area function or using a lookup table.). The other methods I may know, but I don't know them by name, I'm looking them up (Physics lectures online--head hurting... I don't mind them in a class room or even my book, but online is a bit difficult to follow). I've taken Single Variable Calculus, and when I continue math it will be in multivariable calculus.

I was thinking several posts ago that the point is (almost) moot because at these large values for atmospheric density it's hard to get the object moving visually (My readouts show it is moving, I just can't actually see the object moving), but I'm thinking that no matter how large the density is, shouldn't the object simply not move rather than go to infinity? Is that simply because at these levels the inaccuracy of using the Euler method isn't as negligable as I'd like?
If so, I'll have to just ignore the changing area and integrate for the changing velocity...

PS: It looks like you missed an tag in your post. Had to do more horizontal scrolling than I do in my code, that's odd...

I implimented a check to make sure that the drag wasn't pushing it backwards. Seems to work okay, except that now it's kindof pushing it to the right because according to math.h, sin(D3DX_PI) isn't 0, it's a 8.74228e-008. Why do we insist on using a number system based on a number that doesn't exist? (or at least, we can't determine what it is exactly) sin(PI) = 0.000000874228 because PI isn't pi, it's a number near it. Oig... Maybe I need to put in a check for special cases such as 180...

With said repairs in place, densities that would have caused a crash are now allowing the object to move--even though it is saying that the drag is too large and setting the force to stop the object. So the hack fixed it! Thanks. Aside from implimenting a lookup table or revising my area calculations, and implimenting my atmosphere objects, the drag function is working properly such that external data of any type will work fine.


[edited by - Erzengeldeslichtes on October 13, 2003 10:25:21 PM]

[edited by - Erzengeldeslichtes on October 14, 2003 1:06:49 AM]
----Erzengel des Lichtes光の大天使Archangel of LightEverything has a use. You must know that use, and when to properly use the effects.♀≈♂?

This topic is closed to new replies.

Advertisement