Is this right?

Started by
10 comments, last by Mulligan 21 years, 7 months ago
Assuming i choose correct values for mass, and radius for stars and the center of the galaxy, would this work? (Should it work?) bool CGalaxy::Update() { ULDOUBLE G = 0.00000000006670f; ULDOUBLE dForce; ULDOUBLE dz, dx, dy; ULDOUBLE dRadius; for( int i = 0; i < m_iNumStirs; i++ ) { m_pStars->m_vPos.x += m_pStars->m_vDir.x; m_pStars->m_vPos.z += m_pStars->m_vDir.z; m_pStars->m_vPos.y += m_pStars->m_vDir.y; dx = m_pStars->m_vPos.x - m_vPos.x; dz = m_pStars->m_vPos.z - m_vPos.z; dy = m_pStars->m_vPos.y - m_vPos.y; dRadius = sqrt( dx*dx + dz*dz + dy*dy ); dForce = G * ( m_dMass * m_pStars->m_dMass ) / dRadius; m_pStars->m_vDir.x += dForce * ( dx / dRadius ); m_pStars->m_vDir.z += dForce * ( dz / dRadius ); m_pStars->m_vDir.y += dForce * ( dy / dRadius ); } return true; } </i> <SPAN CLASS=editedby>[edited by - Mulligan &#111n August 31, 2002 4:25:44 PM]</SPAN>
Advertisement
i couldn''t make out your code (missing structs)
and I noticed you are calculating the secant version of delta values.

Well, you could actually use vector fields and the computations would be more accurate and reliable. Vector fields are gradients of multidimensional surfaces that will give you a vector in the direction and magnitude of the field effect at that point.

Really, you only have to do the calculations once, then you could plugin some constants and get the vector effect of every body that effects the object you are trying to determine the new position of. In our case, the 3d surface would be an inverse sphere and the vector field would be the gradient of the sphere.

I forget the exact equation to take the gradient of (I can do the operation). I think it''s a negative inverse sphere equation multiplied by the magnitude of the acceleration constant. The gradient of the surface is the surface equation multiplied by the "del" operator.

If you give me till 10:00 eastern time, I will post the formula for the surface and the equations for the sphere.
I''ll check back then. Thanks for the interest!
Gravitational fields are defined by Newton's Law of Gravitation , which states that the force of attraction exerted on a particle(object) of mass m1 located at (x,y,z) by a particle of mass m2 located at (a,b,c) is given by:

F(x,y,z) = (-G*m1*m2)/[(x-a)^2 + (y-b)^2 + (z-c)^2]  
*u

Where u is a unit vector in the direction of (x,y,z) from (a,b,c) and G is a gravitational constant.
------------------------------------------  

Turns out you don't have to do any partial derivatives at all!!

I can solve these equation to give you a vector, but you have to look up the Gravitational Constant (a very small number).

First, we define the origin of the object that is exerting the force(O1 planet) as (a,b,c). We also define the Object being exerted on as points (x,y,z) (O2 ship).

Next, we build our unit u vector. Simply subtract the Object position (x,y,z) (O2 ship) form the object that is exerting the force(O1 planet). This will give a vector in the direction of O2 ship from O1 planet:

= u

To normalize the vector, divide each component by the magnitude:

Magnitude u = ||u|| = sqrt[(a-x)^2 + (b-y)^2 + (c-z)^2]

Normal u = u /||u|| = <(a-x)/||u||, (b-y)/||u||, (c-z)/||u||>

Now, compute the first part of the equation with the numbers plugged in:
[-G*m1*m2]/[(x-a)^2 + (y-b)^2 + (z-c)^2)]  

Store this result, so we can multiply (scale) it into the unit vector u . Rember that G is a very small number. This should bring the masses multiplied to a relatively managable number. This number is then divided by the distance squared between the objects. Obviously, the farther apart the objects get, the bigger the denominator grows and the smaller the number it kicks out. The final result will always be negative. This negative number is going to scale the unit vector u according to the force exerted and will flip the vector to point towards the first object (O1) (a,b,c).

So make the first object [planet] (a,b,c) the larger object, so the force will be applied to the correct object [ship].

Now, that number that you stored (lets say R) will be multiplied into the unit vector u :

<[(x-a)/||u||]*R, [(y-b)/||u||]*R, [(z-c)/||u||]*R>

This will give us a vector pointing towards the planet exerting the force on the ship. The result will be a vector is terms of Meters/sec because this is a velocity field. So the magnitude of the vector will represent the meters traveled in 1 second.

For purposes of your engine, you will have to step this time down to your frame rate, which renders more than once a second. Since we know that this vector last for 1 second, we can multiply a constant (t) that represnted the time in seconds. At one second, the length will not be affected, as everything is multiplied by one. At anything less, the vector will be scaled back to the appropiate time key:

<[(x-a)/||u||]*R*t, [(y-b)/||u||]*R*t, [(z-c)/||u||]*R*t>


    //These would have to be passed in or initialized by you.float x,y,z;float a,b,c;float G,m1,m2;float timekey;//The vector would be the return valuefloat vector[3];float Result = (-G*m1*m2)/((x-a)^2 + (y-b)^2 + (z-c)^2);//Compute the unit vector facing (x,y,z) from (a,b,c)vector[0] = (a-x)/sqrt((a-x)^2 + (b-y)^2 + (c-z)^2);vector[1] = (b-y)/sqrt((a-x)^2 + (b-y)^2 + (c-z)^2);vector[2] = (c-z)/sqrt((a-x)^2 + (b-y)^2 + (c-z)^2);//Multiply the reult into the vector,//changing it to point towards (a,b,c)vector[0] = vector[0]*Result;vector[1] = vector[1]*Result;vector[2] = vector[2]*Result;//Scale the vector by the time keyvector[0] = vector[0]*timekey;vector[1] = vector[1]*timekey;vector[2] = vector[2]*timekey;    


You would computer all of the bodies affecting this mass and add all of them together. They would all be scaled back by their time keys to find the new appropiate position. This is pretty accurate physics approach, with the exception of resistance isn't calculated.

To test this, find G, the mass of the earth the distance of the earth to the moon. Draw a sphere (the correct size of earth) and place a ship at a position where the moon would be. Accelerate(!) and speed in a straight line past the earth, just to the side (use autopilot). You should either crash into earth or curve around it even though you flew straight.

-James





[edited by - natasdm on September 3, 2002 10:14:20 PM]
Now that I look at it, it is your code exactly! Funny how that works!
quote:Original post by Mulligan
dForce = G * ( m_dMass * m_pStars->m_dMass ) / dRadius; 


should be:
dForce = G * ( m_dMass * m_pStars-&gt;m_dMass ) / dRadius^2; </pre> <br><br><BLOCKQUOTE><SPAN CLASS=smallfont>quote:<hr HEIGHT=1 noshade>Original post by Mulligan </i> <pre><br>m_pStars<i>-&gt;m_vDir.x += dForce * ( dx / dRadius );<br>m_pStars-&gt;m_vDir.z += dForce * ( dz / dRadius );<br>m_pStars-&gt;m_vDir.y += dForce * ( dy / dRadius ); </pre> <br> <hr height=1 noshade></SPAN></BLOCKQUOTE> <br>should be:<br><pre><br>m_pStars-&gt;m_vDir.x = dForce * ( dx / dRadius );<br>m_pStars-&gt;m_vDir.z = dForce * ( dz / dRadius );<br>m_pStars-&gt;m_vDir.y = dForce * ( dy / dRadius ); </pre> <br><br><br>And I think your vector is pointing towards the planet, so G doesn''t have to be a negative value.<br><br>Also, don''t forget to scale back with the t value.<br><br>-James<br>  </i>   
Whoa, thanks for the massive responses! I'm implementing many of the changes that you all suggested.

quote:Original post by Anonymous Poster
dForce = G * ( m_dMass * m_pStars->m_dMass ) / dRadius^2;


Ah ha! That explains a lot. I was having to fudge the mass values of the stars to make it work, but now I can plug in the correct (realistic) values for mass and it works like a charm.

About that last comment with the directional vectors, I think I might be right on this one. Here's why:
When it comes time to call Update() again, the star is already moving in a direction. All all gravitational influences just 'nudge' it from the path it was already traveling. Am I wrong? Probably, but its the only thing that works thus far.

Anywho, I changed a bunch of stuff to make it more realistic, but horribly slow...
Here is the code

  bool CGalaxy::Update(){	ULDOUBLE G = 0.0000000000667f;	ULDOUBLE dForce;	ULDOUBLE dz, dx, dy;	ULDOUBLE dRadius;	for( int i = 1; i < m_iNumStars; i++ )	{		// Mass of -1 just means the star was sucked into the center		// and shouldnt be computed anymore		if( m_pStars[i]->m_dMass == -1 )			continue;		// Update position		m_pStars[i]->m_vPos.x += m_pStars[i]->m_vDir.x;		m_pStars[i]->m_vPos.z += m_pStars[i]->m_vDir.z;		m_pStars[i]->m_vPos.y += m_pStars[i]->m_vDir.y;		for( int j = 1; j < m_iNumStars; j++ )		{			// Make sure were not looking at the same star twice			if( m_pStars[i] == m_pStars[j] )				continue;			dx = m_pStars[i]->m_vPos.x - m_pStars[j]->m_vPos.x;			dz = m_pStars[i]->m_vPos.z - m_pStars[j]->m_vPos.z;			dy = m_pStars[i]->m_vPos.y - m_pStars[j]->m_vPos.y;			dRadius = sqrt( dx*dx + dz*dz + dy*dy );			// The star has collided with the center of the galaxy			// (called Event Horizon?)			if( dRadius <= m_pStars[0]->m_dRadius )			{				m_pStars[0]->m_dMass += m_pStars[i]->m_dMass;				m_pStars[i]->m_dMass = -1;				m_pStars[i]->m_vPos.x = 0;				m_pStars[i]->m_vPos.y = 0;				m_pStars[i]->m_vPos.z = 0;				continue;			}			dForce = G * ( m_pStars[j]->m_dMass * m_pStars[i]->m_dMass ) / ( dRadius * dRadius );			m_pStars[i]->m_vDir.x += dForce * ( dx / dRadius );			m_pStars[i]->m_vDir.z += dForce * ( dz / dRadius );			m_pStars[i]->m_vDir.y += dForce * ( dy / dRadius );		}	}    return true;}  



I must explain the significance of m_pStars[ 0 ]. Is a star object like the rest, but Is 5,000 lightyears in diameter and super dense. It sits in the middle of the galaxy, and never moves. This is why the loops start at 1 instead of 0.

It renders a galaxy of 10,000 stars at a healthy 1 frame per 93 seconds, but looks beautiful when I combine the screenshots from each frame together.

This brings me to my next question. Are there any simple speed optimizations that can made to make the inner loop run faster? ANY small performance increase would help dramatically.

Once again, you brainiacs have helped me beyone compare.

Oh yea, what tags do I use to put my code into the white code box?


[edited by - Mulligan on September 4, 2002 6:48:36 PM]

[edited by - Mulligan on September 5, 2002 3:35:39 PM]

I hate to burst your bubble, but I''m the only one who has replied so far. I really appreciate the cheers though! Turns out when you do take Cal 3, this stuff will become almost second nature.

And about you being right on the second part, you are (sort of). See, I was thinking you would calculate all of influence on an object and add all of the vectors together to get a final direction/magnitude. You could then shrink that vector to your time scale. The way I thought you were calculating it was calculating the velocity and adding it to the old velocity. This would increase the velocity exponentially, and incorrectly. If you zero out that vector before you compute the effects of all the bodies, then you should be very accurate. After computing all of the effects, scale the final vector and add it to your position(s).

As far as speed optimizations go, which graphics API are you using? I know some tricks on boosting performance, such as batching primitives, limiting vertex buffer writes and vertex shaders.

-James
I''m using OpenGL, but that code is fast as lightning. The origional update function rendered 10,000 stars at 60fps. I render single points.
I did this some time ago, in Turbo Pascal,
in 2D.

Im going to add my 2 cents to the discussion.
The way I did it was:
a-->b = fab
a-->c = fac
a-->d = fad

first, i calculated how stongly a particle wold get attracted
to all the other particles in the simulation (force ab =fab)
Then i would sum all those Fxx together, plus the inertial
value of the particle.

Now I knew where the next position of the particle would be.

This is all fine and works, but if you have 4 particles, you''re
cheking (n-1)*(n), or 3*4 = 12 calculations.

Then something ocurred to me.

After the attraction vector of a--->b gets calculated, and
all the stuff for particle a is calculated, i move on to
particle b, right? It ocurred to me that b--->a == a--->b !!

So, this is one vector you dont need to calculate, in fact all
the vectors you need to calculate, in a 4 particle simulation are:

a-->b
a-->c
a-->d
b-->c
b-->d
c-->d

This totals 6 calculations. Half of the initial value.
Mind you I didn''t invent the wheel. This is an old optimization technique. Hope you got the point, enjoy gravitics!








[Hugo Ferreira][Positronic Dreams][Stick Soldiers]
"Redundant book title: "Windows For Dummies".
"Camouflage condoms: So they won''t see you coming".

This topic is closed to new replies.

Advertisement