[Edit Profile]  [Edit Your Preferences]  [Search]
[Private Messages[FAQ]  [Logout]
Genesis3D Forum Index -> Programming -> Physics Sample Code
Author Physics Sample Code
Jeff
Genesis God

Joined: Dec 06, 1998
Posts: 946
From: Oxnard, CA, USA
Posted: 2001-08-30 18:36   
Here is some sample code on how to implement a very simple physics system. It only has one physics object, and no forces are applied. The only thing that will move the object is gravity.

I wrote this code fast, and cut a lot of it out from another program. This is not a full program, it's only intended to give you an idea of how to implement physics using G3D. Also, there are probably typos and error.

If you need any further explanation, post you questions, and I'll try to answer them.


Code:

gePhysicsSystem *PS;
gePhysicsObject *PO;
geXForm3d Xform;
geExtBox ExtBox;
geActor *Actor;
BOOL Running = TRUE;
DWORD Timer1 = timeGetTime();
DWORD Timer2 = Timer1;
geVec3d OldVec,NewVec;
GE_Collision Col;

// Load an actor
LoadActor(Actor,"Dema.act");

geXForm3d_SetIdentity(&Xform);
geActor_GetDynamicExtBox(Actor,&ExtBox);

// Create physics system
PS = gePhysicsSystem_Create();

// Create physics object
PO = gePhysicsObject_Create(&Xform.Translation,1.0f,GE_TRUE,GE_TRUE,0.00005f,0.00005f,&ExtBox.Min,&ExtBox.Max,1.0f);

// Add physics object to physics system
gePhysicsSystem_AddObject(PS,PO);

// Set physics object XForm
gePhysicsObject_SetXForm(PO, &Xform, 0);

// physics and rendering loop
while(Running)
{

// This is used to limit the number of times the physics are updated
// The time used will entierly depend on your program
// Basiclly this make the physics independent of rendering
if ((timeGetTime()-Timer1) > 2)
{
// reset the timer
Timer1 = timeGetTime();

// Save the xform's position before updating
OldVec = Xform.Translation;

// Update the physics system, the largest number is 0.03f and
// it only makes a differance if physics joints are added to the physics system.
// This function will call gePhysicsObject_ComputeForces() and
// gePhysicsObject_Integrate() for every physics object in the physics system.

gePhysicsSystem_Iterate(PS,0.03f);

// Get the updated XForm
gePhysicsObject_GetXFormInEditorSpace(PO, &Xform, 0);

// save the xform's position after updating
NewVec = Xform.Translation;

// test if there was a collision
if (geWorld_Collision(World,&ExtBox.Min,&ExtBox.Max,&OldVec,&NewVec,GE_CONTENTS_SOLID_CLIP,GE_COLLIDE_ALL,0xffffffff,NULL,NULL,&Col))
{
// Collision found do something

Xform.Translation = Col.Impact;
gePhysicsObject_SetXForm(PO, &Xform, 0);
}

// Set actors xform
geActor_ClearPose(Actor, &Xform);

}

// Limit rendering to 30 FPS
// This is needed because physics are slow and when
// trying to render every frame the physics slows to a crawl
if ((timeGetTime()-Timer2)>34)
{
Timer2=timeGetTime();

if (!geEngine_BeginFrame(Engine, Camera, GE_TRUE))
Running = 0;
if (!geEngine_RenderWorld(Engine, World, Camera, 0.0f))
Running = 0;
if (!geEngine_EndFrame(Engine))
Running = 0;
}

}



  View Profile of Jeff      Edit/Delete This Post   Reply with quote
jwvanderbeck
Administrator

Joined: Dec 18, 2000
Posts: 2213
From: Palm Bay, FL, USA
Posted: 2001-08-30 20:16   
Thanks a million for this Jeff. I'm printing it out right now

One thing though, is I could really learn from seeing hot to handle the collision between two actors as it relates to the physics system. I'm really unclear on that, since the physics system doesn't do the collision. So I am unclear what information I need to gather from the collion, and how/what to pass on to the physics system.
_________________
- John Vanderbeck
- Producer, Dark Relic
"Better leave the lights on"
- Novus Delta
"Change is coming..."


  View Profile of jwvanderbeck   Email jwvanderbeck      Edit/Delete This Post   Reply with quote
jwvanderbeck
Administrator

Joined: Dec 18, 2000
Posts: 2213
From: Palm Bay, FL, USA
Posted: 2001-08-30 20:24   
A question. If you are ding your physics, seperately from the main loop, wouldn't that cause problems with it bien gupdated more often then everythign else? I.E. An object falling further than it should because the gravity was applied twice for only one pass of the main loop?

Or maybe I misunderstood your comments here. If so, I apoligize for my idiocy
_________________
- John Vanderbeck
- Producer, Dark Relic
"Better leave the lights on"
- Novus Delta
"Change is coming..."


  View Profile of jwvanderbeck   Email jwvanderbeck      Edit/Delete This Post   Reply with quote
Jeff
Genesis God

Joined: Dec 06, 1998
Posts: 946
From: Oxnard, CA, USA
Posted: 2001-08-30 23:19   
Quote:

One thing though, is I could really learn from seeing hot to handle the collision between two actors as it relates to the physics system. I'm really unclear on that, since the physics system doesn't do the collision. So I am unclear what information I need to gather from the collion, and how/what to pass on to the physics system.



I really haven't done collisions with two actors yet, so I basically would be guessing how to do it.


Quote:

A question. If you are ding your physics, seperately from the main loop, wouldn't that cause problems with it bien gupdated more often then everythign else? I.E. An object falling further than it should because the gravity was applied twice for only one pass of the main loop?



Your question made me go look through the source code again and I made a mistake in the comment about gePhysicsSystem_Iterate() function, 0.03f is the highest number that can be used and it is used as the delta time for the gePhysicsObject_Integrate() function. So basically what that means is every time you call gePhysicsSystem_Iterate() with a value of 0.03f it is updating the physics system 30 milliseconds. So you need to call that function about 34 times a second to get it to update in real time.

So the code should look like this for real time:

Code:

.
.
.
if ((timeGetTime()-Timer1) > 30)
{
Timer1 = timeGetTime();
OldVec = Xform.Translation;
gePhysicsSystem_Iterate(PS,0.03f);
.
.
.



or it can look like this:

Code:

.
.
.
while(Running)
{

OldVec = Xform.Translation;

gePhysicsSystem_Iterate(PS,(float)(timeGetTime()-Timer1)/1000);

Timer1 = timeGetTime();

gePhysicsObject_GetXFormInEditorSpace(PO, &Xform, 0);
.
.
.




The first method updates the physics system only every 30 milliseconds. The second method updates the physics system every time through the loop but using the delta time. Both methods work and both have advantages and disadvantage.

The first method doesn't take up as much CPU power. But it has a fixed rate of movement. You could decrease the time from 30 millisecond to a lower number but you also need to lower the 0.03f in the gePhysicsSystem_Iterate() function.

The second method takes more of the CPU because it get called more often but you probably get smoother physics.

Hopefully I answered your question and you understand what I said.


  View Profile of Jeff      Edit/Delete This Post   Reply with quote
jwvanderbeck
Administrator

Joined: Dec 18, 2000
Posts: 2213
From: Palm Bay, FL, USA
Posted: 2001-08-30 23:29   
Actually, I don't see how the second method is goign to take more power. If you limit your rendering loop to 30FPS, and your PhysicsIterate is based on your rendering loop, then it too should only be calced 30FPS.


_________________
- John Vanderbeck
- Producer, Dark Relic
"Better leave the lights on"
- Novus Delta
"Change is coming..."


  View Profile of jwvanderbeck   Email jwvanderbeck      Edit/Delete This Post   Reply with quote
jwvanderbeck
Administrator

Joined: Dec 18, 2000
Posts: 2213
From: Palm Bay, FL, USA
Posted: 2001-08-30 23:33   
And in actuality, basing it on delta time coudl SAVE cpu time..What if a render loop takes a bit longer? Then instead of still doing it every 30ms, you might actually do a few less calcs that cyle, just with a longer iteration.
_________________
- John Vanderbeck
- Producer, Dark Relic
"Better leave the lights on"
- Novus Delta
"Change is coming..."


  View Profile of jwvanderbeck   Email jwvanderbeck      Edit/Delete This Post   Reply with quote
Jeff
Genesis God

Joined: Dec 06, 1998
Posts: 946
From: Oxnard, CA, USA
Posted: 2001-08-30 23:57   
Quote:

Actually, I don't see how the second method is goign to take more power. If you limit your rendering loop to 30FPS, and your PhysicsIterate is based on your rendering loop, then it too should only be calced 30FPS.



The physics are not tied to the rendering, I just removed the first time check not the second one. It is still rendering at 30 FPS but the physics could be getting updated 100 times a second. And this will take up more of the CPU time opposed to just updating the physics every 30 milliseconds which would be about 34 times a second.

For what your doing the second method is probably better because you can keep track of the time with in your physics class and when ever the update method is called you can calculate the delta time. But for this example the first method is probably better because it's not updating the physics a 100 times a second leaving room for other thing like AI or a particle system. It all depends on how you use the physics.


  View Profile of Jeff      Edit/Delete This Post   Reply with quote
Jeff
Genesis God

Joined: Dec 06, 1998
Posts: 946
From: Oxnard, CA, USA
Posted: 2001-08-31 00:37   
Quote:

And in actuality, basing it on delta time coudl SAVE cpu time..What if a render loop takes a bit longer? Then instead of still doing it every 30ms, you might actually do a few less calcs that cyle, just with a longer iteration.



For this example it is not the case because all it's doing is physics and rendering but in a real program you are exacly right. It all depends on your program. The level I used for this example only has a few polys.


  View Profile of Jeff      Edit/Delete This Post   Reply with quote
securitron
Genesis God

Joined: Sep 21, 1999
Posts: 478
From: CANADA
Posted: 2001-08-31 00:57   
there may be a problem with the timer1 and the > sign. if rendering takes awhile then the test at timer 1 could be way off imo


  View Profile of securitron   Email securitron   Goto the website of securitron      Edit/Delete This Post   Reply with quote
Jeff
Genesis God

Joined: Dec 06, 1998
Posts: 946
From: Oxnard, CA, USA
Posted: 2001-08-31 02:25   
Quote:

On 2001-08-31 00:57, securitron wrote:
there may be a problem with the timer1 and the > sign. if rendering takes awhile then the test at timer 1 could be way off imo




If you are talking about:

if ((timeGetTime()-Timer1) > 2)

in the original code, I updated it in one of my previous posts to:

if ((timeGetTime()-Timer1) > 30)


But you are correct, if the rendering does take longer than 30 milliseconds your physics will not be in real time and you probably won't be getting 30 FPS.

The only way to correct this is to ether reduce the rendering time by removing polys or using a lower frame rate. Or to call gePhysicsSystem_Iterate() twice to make up for the extra time. But this will cause the step between actor updates to be large and might cause jerky movement for the actor.


  View Profile of Jeff      Edit/Delete This Post   Reply with quote
ZaG
Godling

Joined: Mar 29, 2000
Posts: 312
From: Ohio
Posted: 2001-08-31 06:15   
Well, now I'm lost. I had essentially the exact same thing set up to do gravity for my actors but it didn't work. The only difference between this and what I did was I didn't use a gePhysicsSystem. I just create a gePhysicsObject for my actor and then I called gePhysicsObject_ComputeForces and gePhysicsObject_Integrate myself instead of using the gePhysicsSystem_Iterate to do it. But mine doesn't work. The actor floats above the ground never going down. Weird.

ZaG


  View Profile of ZaG   Email ZaG   Goto the website of ZaG      Edit/Delete This Post   Reply with quote
Jeff
Genesis God

Joined: Dec 06, 1998
Posts: 946
From: Oxnard, CA, USA
Posted: 2001-08-31 12:57   
Quote:

Well, now I'm lost. I had essentially the exact same thing set up to do gravity for my actors but it didn't work. The only difference between this and what I did was I didn't use a gePhysicsSystem. I just create a gePhysicsObject for my actor and then I called gePhysicsObject_ComputeForces and gePhysicsObject_Integrate myself instead of using the gePhysicsSystem_Iterate to do it. But mine doesn't work. The actor floats above the ground never going down. Weird.



I just tried to remove the physics system and just use a physics object and it didn't work. So I looked at the G3D source code and found that the ConfigIndex used for the physics object is manipulated by the physics system. I didn't really understand what it was doing but I do know that the ConfigIndex can only be 0 or 1 and that the physics system alternates between them every time gePhysicsSystem_Iterate() is called. I tried to emulate what it was doing with no success. I would suggest just sticking to using a physics system and adding an object to it. If you really want to have your objects separated you can use a different physics system for every object.


  View Profile of Jeff      Edit/Delete This Post   Reply with quote
ZaG
Godling

Joined: Mar 29, 2000
Posts: 312
From: Ohio
Posted: 2001-08-31 13:41   
Yeah, I switched to using a PhysicsSystem this morning. After trying to manipulate the config indexes myself I decided to try using a instead. Still doesn't work but I'm tracing through it and at least the xform is changing now which it wasn't before so I'm a step further.

  View Profile of ZaG   Email ZaG   Goto the website of ZaG      Edit/Delete This Post   Reply with quote
Jeff
Genesis God

Joined: Dec 06, 1998
Posts: 946
From: Oxnard, CA, USA
Posted: 2001-08-31 15:12   
Here is some updated code. I changed a few of the things that have been discussed in this thread.

I added a high performance counter, timeGetTime() was not getting the job done. All the code for it was taken from GTest. I also removed the timer that limited the physics and it now just uses the high performance counter to calculate the delta time. Another addition is the gePhysicsSystem_GetSourceConfigIndex() function. It will get the current config from the physics system and the returned number should be used as the config index for the physics objects. This number just seems to alternate between 0 and 1.

Here is the code:

Code:


// Needed for high performance counter
static void SubLarge(LARGE_INTEGER *start, LARGE_INTEGER *end, LARGE_INTEGER *delta)
{
_asm {
mov ebx,dword ptr [start]
mov esi,dword ptr [end]

mov eax,dword ptr [esi+0]
sub eax,dword ptr [ebx+0]

mov edx,dword ptr [esi+4]
sbb edx,dword ptr [ebx+4]

mov ebx,dword ptr [delta]
mov dword ptr [ebx+0],eax
mov dword ptr [ebx+4],edx
}
}



// sample physics system
void Physics()
{


LARGE_INTEGER CurTick,DeltaTick,OldTick,Freq;
float ElapsedTime;
gePhysicsSystem *PS;
gePhysicsObject *PO;
geXForm3d Xform;
geExtBox ExtBox;
geActor *Actor;
int ConfigIndex = 0;
BOOL Running = TRUE;
DWORD Timer = timeGetTime();
geVec3d OldVec,NewVec;
GE_Collision Col;

// Load an actor
LoadActor(Actor,"Dema.act");

geXForm3d_SetIdentity(&Xform);
geActor_GetDynamicExtBox(Actor,&ExtBox);

// Create physics system
PS = gePhysicsSystem_Create();

// Create physics object
PO = gePhysicsObject_Create(&Xform.Translation,1.0f,GE_TRUE,GE_TRUE,0.00005f,0.00005f,&ExtBox.Min,&ExtBox.Max,1.0f);

// Add physics object to physics system
gePhysicsSystem_AddObject(PS,PO);

// Set physics object XForm
gePhysicsObject_SetXForm(PO, &Xform, 0);

// Needed for high performance counter
QueryPerformanceFrequency(&Freq);
QueryPerformanceCounter(&OldTick);

// physics and rendering loop
while(Running)
{


// Save the xform's position before updating
OldVec = Xform.Translation;

//High performace counter
QueryPerformanceCounter(&CurTick);
SubLarge(&OldTick, &CurTick, &DeltaTick);
OldTick = CurTick;
if (DeltaTick.LowPart > 0)
ElapsedTime = 1.0f / (((float)Freq.LowPart / (float)DeltaTick.LowPart));
else
ElapsedTime = 0.001f;

// Update the physics system, the largest number is 0.03f and
// This function will call gePhysicsObject_ComputeForces() and
// gePhysicsObject_Integrate() for every physics object in the physics system.
gePhysicsSystem_Iterate(PS,ElapsedTime);

// Get The current config index for the physics system
ConfigIndex = gePhysicsSystem_GetSourceConfigIndex(PS);

// Get the updated XForm
gePhysicsObject_GetXFormInEditorSpace(PO, &Xform, ConfigIndex);

// save the xform's position after updating
NewVec = Xform.Translation;

// test if there was a collision
if (geWorld_Collision(World,&ExtBox.Min,&ExtBox.Max,&OldVec,&NewVec,GE_CONTENTS_SOLID_CLIP,GE_COLLIDE_ALL,0xffffffff,NULL,NULL,&Col))
{
// Collision found do something

Xform.Translation = Col.Impact;
gePhysicsObject_SetXForm(PO, &Xform, ConfigIndex);
}


// Set actors xform
geActor_ClearPose(Actor, &Xform);


// Limit rendering to 30 FPS
// This is needed because physics are slow and when
// trying to render every frame the physics slows to a crawl
if ((timeGetTime()-Timer)>=34)
{
Timer=timeGetTime();

if (!geEngine_BeginFrame(Engine, Camera, GE_TRUE))
Running = 0;
if (!geEngine_RenderWorld(Engine, World, Camera, 0.0f))
Running = 0;
if (!geEngine_EndFrame(Engine))
Running = 0;
}
}

}





This code works but it doesn't seem to be in real time. My level is the same scale as GTest, maybe that scale is just large. Can someone tell me what scale GTest uses and how it relates to real world mesurements? My actor could be falling 10 feet every textile and I just don't know it.


[ This Message was edited by: Jeff on 2001-08-31 15:30 ]


  View Profile of Jeff      Edit/Delete This Post   Reply with quote
securitron
Genesis God

Joined: Sep 21, 1999
Posts: 478
From: CANADA
Posted: 2001-08-31 20:07   
i like the addition of queryperformance, when i got up to around 100 actors animating thats when i saw a noticable difference using the more accurate counter.


jeff lol now i'm going to whinge about exactly the same thing *again*, i'm still not sold on the way that you are controlling the FPS with that check on the timer ( its the > sign that bugs me ).


Here's how i'm doing that check:


...
QueryPerformanceCounter(QPCount);

while QPCount < LastQPCount+FPS
do begin
QueryPerformanceCounter(QPCount);
Application.ProcessMessages
end;

QueryPerformanceCounter(LastQPCount);
...


So physics stuff would go where/with Application.ProcessMessages is, and I would further slice up whats left of the time pie imo.



  View Profile of securitron   Email securitron   Goto the website of securitron      Edit/Delete This Post   Reply with quote
Jeff
Genesis God

Joined: Dec 06, 1998
Posts: 946
From: Oxnard, CA, USA
Posted: 2001-08-31 20:49   
Quote:

jeff lol now i'm going to whinge about exactly the same thing *again*, i'm still not sold on the way that you are controlling the FPS with that check on the timer ( its the > sign that bugs me ).



I guess I don't understand what you mean by "its the > sign that bugs me". Here is what it's doing.

The timeGetTime() function returns the elapsed system time in milliseconds. When the Timer variable is initialized it is set to equal timeGetTime().

So lets evaluate this statement:

if ((timeGetTime()-Timer) >= 33)
{
Timer = timeGetTime();
//render
}


The (timeGetTime() - Timer) part is equal to the delta time. This is the time that has elapsed since Timer was set to timeGetTime(). Now if it is greater than or equal to 33 millisecond than it sets the Timer variable to the current time and renders. If it's less than 33 then it just continues without resetting the Timer variable or rendering.

The 33 is computed by taking 1000 milliseconds and dividing it by 30 FPS which give 33.333333333 milliseconds. Since were working with DWORD values I rounded to 33.

So basically what it is saying is if 33 milliseconds or greater have passed since last rendering then render. if not don't render. It should never render more that 30 FPS but it can render less if the rendering and physics take longer than 33 milliseconds.


[ This Message was edited by: Jeff on 2001-08-31 20:52 ]


  View Profile of Jeff      Edit/Delete This Post   Reply with quote
securitron
Genesis God

Joined: Sep 21, 1999
Posts: 478
From: CANADA
Posted: 2001-08-31 22:34   
right, i know that your calculations come out correctly, what i meant i guess, was that it shouldn't imo be in the physics procedure, not sure if that was intentional or just for testing...

  View Profile of securitron   Email securitron   Goto the website of securitron      Edit/Delete This Post   Reply with quote
Jeff
Genesis God

Joined: Dec 06, 1998
Posts: 946
From: Oxnard, CA, USA
Posted: 2001-08-31 23:31   
Quote:

right, i know that your calculations come out correctly, what i meant i guess, was that it shouldn't imo be in the physics procedure, not sure if that was intentional or just for testing...



Ok now I get what your saying, and your correct. The rendering and physics should not be mixed like this in a real program. This is meant to just be a sample of how to do physics. I didn't want people having to flip back and forth through a bunch of functions or classes trying to figure out what was going on, so I placed everything in one loop. In a real program you should have the physics in it's own function or class and the rendering in another.

Also, I might have confused the issue when I named the function Physics maybe I should have called it SampleCode.


  View Profile of Jeff      Edit/Delete This Post   Reply with quote
securitron
Genesis God

Joined: Sep 21, 1999
Posts: 478
From: CANADA
Posted: 2001-08-31 23:49   
i have a constant in my ge_physicsobject.pas ( your PhysicsObject.c supposedly) that was 'automatically' generated out by neils delphi generator:

const
PHYSOB_GRAVITY: gefloat = (-3.9)

and appears that it is never called.
in the c file jason says 'integrate a gephysicsObjects equations of motion by time step deltatime' so, per frame imo

i did manage to put in a 'pause game' tonight. lol.


  View Profile of securitron   Email securitron   Goto the website of securitron      Edit/Delete This Post   Reply with quote
Jeff
Genesis God

Joined: Dec 06, 1998
Posts: 946
From: Oxnard, CA, USA
Posted: 2001-09-01 01:22   
Quote:

have a constant in my ge_physicsobject.pas ( your PhysicsObject.c supposedly) that was 'automatically' generated out by neils delphi generator:

const
PHYSOB_GRAVITY: gefloat = (-3.9)

and appears that it is never called.





#define PHYSICSOBJECT_GRAVITY (-3.9)

The above line appears in the PhysicsObject.h header file and is used in the gePhysicsObject_ComputeForces() function which is located in the PhysicsObject.c file.

Maybe the program that generated the code used (-3.9) instead of using PHYSOB_GRAVITY.


  View Profile of Jeff      Edit/Delete This Post   Reply with quote
securitron
Genesis God

Joined: Sep 21, 1999
Posts: 478
From: CANADA
Posted: 2001-09-01 11:44   
i just forgot to check the h file doh
so that 3.9 would have to be adjusted for different scaling then.


  View Profile of securitron   Email securitron   Goto the website of securitron      Edit/Delete This Post   Reply with quote
  
Lock this Topic Move this Topic Delete this Topic
Official Genesis3D Website

Powered by phpBB Version 1.4.0
Copyright © 2000 - 2001 The phpBB Group

Board Posting Rules
  1. Post your message once in the most appropriate topic. Do not post the same or similar messages in multiple topics. This is referred to as spamming the board and your duplicate messages will get deleted. Also any traditional spam such as the "Get Rich Quick", pyramid schemes, etc. will be deleted.
  2. Job ads go in the Unrelated forum only. Job ads found in any other topics will get deleted.
  3. Absolutely no warez or porn allowed.
  4. No trolls. Go back to the usenet where you belong.
  5. Bypassing the word filters will result in a banning. See this post for more information.
  6. All posts must be in English. See this post for more information.
phpBB Created this page in 0.604438 seconds.