Game Development Community

dev|Pro Game Development Curriculum

PhysX in TGE Version 0.3 (Work-In-Progress)

by Shannon "ScarWars" Scarvaci · 07/03/2006 (11:35 am) · 269 comments

Outline
1. License
2. Get SDK from Ageia
3. Implementation
4. Scripts
5. Know Issues
6. Need your supports!

License:
The license of PhysX is following:
Free:
  * Commercial & non-commercial use on PC
       Must keep registration information currect
       Must agree to the EULA at the time of download (pops up, but is copied below)
       Available for Windows & Linux (soon)
       No PhysX HW support requirement
  * PS3 platform (through Sony pre-purchase)
  * All platforms through some of our middleware partnerships, such as UE3, Gamebryo 2.2,
     and others
k per platform:
  * Xbox 360
  * Fee may be waived at our discretion for multi-platform developers providing PC HW support
  * Fee may be waived at our discretion for some Tools & Middleware providers

Get SDK from Ageiq
You can obtain the SDK from www.ageia.com website, my currently version for this physics is 2.7.0.

If you are using Visual Studio then you need to add "include" and "library" in the project configuration.
(If you using linux or mac, then i don't know where to setup because I dont have linux or mac with me)
Directory for include files:
C:\Program Files\AGEIA PhysX SDK\v2.6.4\SDKs\Physics\include
C:\Program Files\AGEIA PhysX SDK\v2.6.4\SDKs\Foundation\include
C:\Program Files\AGEIA PhysX SDK\v2.6.4\SDKs\PhysXLoader\include
C:\Program Files\AGEIA PhysX SDK\v2.6.4\SDKs\Cooking\include
Directory for library files:
C:\Program Files\AGEIA PhysX SDK\v2.6.4\SDKs\lib\win32
Note: These files' path's are relative to my hard drive, your files may be in different directory depending on how you installed the PhysX SDK.

Please install AGEIA PhysX Runtime in your PC (prefered lastest version)
Also put two dll file (PhysXLoader.dll and NxCooking.dll from AGEIA PhysX SDK\v2.7.0\SDKs\Bin\win32) in the example folder.


Implementation
Copy the 17 files from "PhysX" folder into engine/PhysX and modify some TGE's source code files.

Player
in game/player.h in bold
//----------------------------------------------------------------------------

[b]struct sNxActor;[/b]
class Player: public ShapeBase
{
  typedef ShapeBase Parent;
  [b]sNxActor *mActor;[/b]
protected:
  /// Bit masks for different types of events
  enum MaskBits {

game/player.cc at the top in bold
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
[b]#include "physX/PhysX.h"
#include "physX/PhysXWorld.h"[/b]
#include "game/player.h"

game/player.cc in Player::Player() function
mMountPending = 0;

   [b]mActor = NULL;[/b]
}

game/player.cc in Player::onAdd() function
gCamFXMgr.clear();
        }

	 [b]PhysXWorld *PxWorld = PhysXWorld::getWorld(isServerObject());
	 if (PxWorld) {
		 mActor = PxWorld->AddShapeBase(this);
	 }[/b]

   return true;

game/player.cc in Player::setPosition(...)
else {
      mat.set(EulerF(0, 0, rot.z));
      mat.setColumn(3,pos);
   }
   [b]if (mActor) {
      QuatF q(mat);
      Point3F pos;
      mat.getColumn(3,&pos);
      NxQuat quat;
      quat.setXYZW(q.x,q.y,q.z,q.w);
      mActor->actor->setGlobalOrientationQuat(quat);
      mActor->actor->setGlobalPosition(NxVec3(pos.x,pos.y,pos.z));
   }[/b]
   Parent::setTransform(mat);
   mRot = rot;
}

Terrain
in terrain/terrData.cc
at the top of the file
#include "terrain/terrRender.h"
#include "terrain/blender.h"

[b]#include "physX/PhysXWorld.h"[/b]

extern bool gDGLRender;

terrain/terrData.cc in TerrainBlock::onAdd function near the end
if(!unpackEmptySquares())
                 return(false);

	[b]PhysXWorld *PxWorld = PhysXWorld::getWorld(isServerObject());
	if (PxWorld) {
		PxWorld->SetupTerrainCollision(); // old style
	}[/b]

   return true;
}

Interior
in interior/interior.h
class Interior
{
   ...
   friend class EditInteriorResource;
   [b]friend class PhysXInterior;[/b]

in interior/interiorInstance.h
class InteriorInstance : public SceneObject
{
   ...
   friend class FloorPlan;
   [b]friend class PhysXInterior;
   friend class PhysXWorld;[/b]

in interior/interiorInstance.cc
#include "platform/profiler.h"
[b]#include "physX/PhysXWorld.h"[/b]

...

bool InteriorInstance::onAdd()
{
   ...
   
   addToScene();

   [b]PhysXWorld *PxWorld = PhysXWorld::getWorld(isServerObject());
   if (PxWorld) {
      PxWorld->SetupInterior(*this);
   }[/b]
   return true;
}

TSStatic
in ts/tsShapeInstance.h
class TSShapeInstance
{
   ...
   friend class TSPartInstance;
   [b]friend class PhysXTSStatic;
   friend class PhysXActor;[/b]

in game/tsStatic.h
class TSStatic : public SceneObject
{
   ...
   friend class TSStaticConvex; 
   [b]friend class PhysXTSStatic;[/b]

in game/tsStatic.cc
#include "sim/netConnection.h"
[b]#include "physX/PhysXWorld.h"[/b]

...

bool TSStatic::onAdd()
{
   ...
   
   addToScene();

   [b]PhysXWorld *PxWorld = PhysXWorld::getWorld(isServerObject());
   if (PxWorld) {
      PxWorld->SetupTSStatic(*this);
   }[/b]
   return true;
}

ShapeBase
in game\shapeBase.h
class ShapeBase : public GameBase
{
   typedef GameBase Parent;
   friend class ShapeBaseConvex;
   friend class ShapeBaseImageData;
   [b]friend class PhysXWorld;[/b]

Material in GameBase
in game\gameBase.h
[b]struct PhysXMaterialData;[/b]
struct GameBaseData : public SimDataBlock {
   ...
   void unpackData(BitStream* stream);
   [b]// PhysX
   PhysXMaterialData* mMaterialBlock;[/b]
};
...
class GameBase : public SceneObject
{
   ...
   enum GameBaseMasks {
      InitialUpdateMask =     Parent::NextFreeMask,
      DataBlockMask =         InitialUpdateMask << 1,
      ExtendedInfoMask =      DataBlockMask << 1,
      ControlMask =           ExtendedInfoMask << 1,
      [b]//NextFreeMask =        ControlMask << 1
      // PhysX
      MaterialDataBlockMask = ControlMask << 1,
      NextFreeMask =          MaterialDataBlockMask << 1[/b]
   };
   ...

   [b]// PhysX
   bool setMaterialDataBlock(PhysXMaterialData* dptr);
   bool onNewMaterialDataBlock(PhysXMaterialData* dptr);[/b]

};
...
in game\gameBase.cc
[b]#include "physX/PhysX.h"
#include "physX/PhysXActor.h"[/b]
#include "platform/platform.h"
...
GameBaseData::GameBaseData()
{
   ...
   [b]mMaterialBlock = 0;[/b]
}
...
[b]IMPLEMENT_CONSOLETYPE(PhysXMaterialData)
IMPLEMENT_GETDATATYPE(PhysXMaterialData)
IMPLEMENT_SETDATATYPE(PhysXMaterialData)[/b]

void GameBaseData::initPersistFields()
{
   Parent::initPersistFields();
   ...
   [b]addField("materialBlock", TypePhysXMaterialDataPtr, Offset(mMaterialBlock, GameBaseData));[/b]
}
...
bool GameBase::onNewDataBlock(GameBaseData* dptr)
{
   ...
   [b]onNewMaterialDataBlock(mDataBlock->mMaterialBlock);[/b]

   setMaskBits(DataBlockMask);
   return true;
}
...
bool GameBase::setDataBlock(GameBaseData* dptr)
{
   ...
}

[b]bool GameBase::setMaterialDataBlock(PhysXMaterialData* dptr)
{
   if (isGhost() || isProperlyAdded()) {
      if (mDataBlock->mMaterialBlock != dptr)
         return onNewMaterialDataBlock(dptr);
   }
   else
      mDataBlock->mMaterialBlock = dptr;
   return true;
}

bool GameBase::onNewMaterialDataBlock(PhysXMaterialData* dptr)
{
   mDataBlock->mMaterialBlock = dptr;

   if (!mDataBlock->mMaterialBlock)
      return false;

   setMaskBits(MaterialDataBlockMask);
   return true;
}[/b]
...
U32 GameBase::packUpdate(NetConnection *, U32 mask, BitStream *stream)
{
   ...
   [b]if (stream->writeFlag((mask & MaterialDataBlockMask) && mDataBlock->mMaterialBlock != NULL)) {
      stream->writeRangedU32(mDataBlock->mMaterialBlock->getId(),
                             DataBlockObjectIdFirst,
                             DataBlockObjectIdLast);
   }[/b]

   // cafTODO: ControlMask
   return 0;
}

void GameBase::unpackUpdate(NetConnection *con, BitStream *stream)
{
   ...
   [b]if (stream->readFlag()) {
      PhysXMaterialData* dptrMD = 0;
      SimObjectId id = stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast);

      if (!Sim::findObject(id,dptrMD) || !setMaterialDataBlock(dptrMD))
         con->setLastError("Invalid packet GameBase::unpackUpdate()");
   }[/b]
}

Scripts
Copy three script files (PhysX.cs, physXActorBox.cs and physXActorSphere.cs) in starter.fps/server/scripts and add three lines of code in starter.fps/server/scripts/games.cs

// PhysX
	 exec("./physX.cs");
	 exec("./physXActorBox.cs");
	 exec("./physXActorSphere.cs");
	 exec("./physXJoints.cs");

add one line of code in common/client/mission.cs
function clientCmdMissionStart(%seq)
{
   // The client recieves a mission start right before
   // being dropped into the game.
	[b]startPhysX();[/b]
}

and in every mission file need to add PhysXWorld as show in bold:
new SimGroup(MissionGroup) {

	 [b]new PhysXWorld() {
		errorReport = false; // set to true if you want error report from PhysX
	 };[/b]
	
	 new ScriptObject(MissionInfo) {
	 ...

If you want to testing around by droping the object in the free-look camera, then use default.bind.cs script
function addCrate(%val)
{
	if (%val)
		commandToServer('pxcrate');
}
function addBox(%val)
{
	if (%val)
		commandToServer('pxbox');
}
function addRock(%val)
{
	if (%val)
		commandToServer('pxsphere');
}

moveMap.bind( keyboard, "alt r", addCrate);
moveMap.bind( keyboard, "alt t", addBox);
moveMap.bind( keyboard, "alt y", addRock);

Know Issues
Terrain is the problem here because PhysX can accept 256x256 collision mesh in their engine which is mean squareSize equal to one! So the TGE's default squareSize is 8 and you see object will miss the collision in some area of the terrain. Possible solution is to create chunks, for example if you use squareSize of 8 then use 64 chunks of 256x256 collision mesh.

Loading the mesh of 256x256 collision will very slow but there possible solution is to write the mesh to file create by PhysX engine and read the file from PhysX will be lots faster, similar to lighting system which is used in TGE.

I've tried number of way to use Terrain collision in PhysX such as split in four section, NxHeightfield which make it very slow but I haven't tried this in PPU yet. So I have to stick with 256x256 collision mesh for a while.

Player/ShapeBase collision with PhysX's object is not complete.

Networking:
Loading objects from the begin in the remote client sometime not showing but if object appear during the gameplay will work ok. That something i need to be working on. (There may be some problem because of improved speed, but didn't test it yet)

Improved PhysX Speed
Big thank to decryptoid for helping us in PhysX, esp. for speed improvement.

Need your supports!
Now you can play with PhysX in your TGE game! If you find any improvement for this Physics in coding or script or anything please post here and I'll happy to update in here.
Also please use TDNfor any info to advise for our community

In the future:
- Run in PPU.
- Player collision.
- ShapeBase, (TSStatic and Interior - Completed) collision.
- Use advance physics such as joints, clothes and fluid. Done two type of joints

Enjoy your Physics!

Check out the video.
First Video
Second Video
Joints Video (4MB, prefer download before watch)

This is my first resource, please be kind to me :)

Due to file limit please download from here Updated 13th Apirl 2006

Here TGEA PhysX Resource here
#101
08/08/2006 (5:36 pm)
Got Vs 2.3.3 working :)

But VS 2.4.1 will not work for me :/
#102
08/08/2006 (5:41 pm)
I have Ageia PhysX 2.4.4 working fine.
#103
08/08/2006 (11:23 pm)
Matt:

I get these errors with vs 2.4.4, Do you know how solve this ??

Compiling...
PhysXWorld.cpp
\SDK\GameEngines\Torque_engines\TGE_SDK_1.4_ENGINETEST\engine\physX\PhysXWorld.cpp(137) : error C2039: 'broadPhase' : is not a member of 'NxSceneDesc'
h:\SDK\MiddleWare\Ageia PhysX SDK\v2.4.4\SDKs\Physics\include\NxSceneDesc.h(175) : see declaration of 'NxSceneDesc'
\SDK\GameEngines\Torque_engines\TGE_SDK_1.4_ENGINETEST\engine\physX\PhysXWorld.cpp(137) : error C2065: 'NX_BROADPHASE_COHERENT' : undeclared identifier
\SDK\GameEngines\Torque_engines\TGE_SDK_1.4_ENGINETEST\engine\physX\PhysXWorld.cpp(138) : error C2039: 'collisionDetection' : is not a member of 'NxSceneDesc'
h:\SDK\MiddleWare\Ageia PhysX SDK\v2.4.4\SDKs\Physics\include\NxSceneDesc.h(175) : see declaration of 'NxSceneDesc'
#104
08/08/2006 (11:32 pm)
Ah, I got that as well. I just commented out the lines that gave the error. I figured this was ok (and the game functioned fine) because if this vars were no longer included in the SDK - it can't hurt not to use them.

Note - you may not get terrain collision. I do - but I'm not sure why.
#105
09/01/2006 (2:48 pm)
hows it going on improving the Ageia resource...
meaning: adding more features to use in TGE and so on
#106
09/04/2006 (1:00 am)
Hi,
i've tested the code on my Laptop and everything is working fine. But on my Desktop not. I've found out that this method is the reason for it.

NxActor* PhysXWorld::AddActor(NxActorDesc actorDesc)
{
	if (!gScene) return NULL;
	NxActor* actor = gScene->createActor(actorDesc);
	if (!actor) return NULL;
	actor->userData = this;
	return actor;
}

Sometimes the gScene is write protected. I've found a working solution for it

NxActor* PhysXWorld::AddActor(NxActorDesc actorDesc)
{
	if (!gScene) return NULL;
                // wait until gScene is writable
	while(!gScene->isWritable()){}
	NxActor* actor = gScene->createActor(actorDesc);
	if (!actor) return NULL;
	actor->userData = this;
	return actor;
}

Then its working on my Desktop, too. May be it depended on my DualCore system. Don't know.

I'm working to implementing working joints to the code. I've created the code for this:

// create first object
  %obj1 = new PhysXActor() {
	  position = %pos1;
      rotation = "0 0 0 0";
      dataBlock = pxCrate1;
	  materialBlock = pxMaterialBox;
	};


  // create second object
  %obj2 = new PhysXActor() {
	  position = %pos2;
      rotation = "0 0 0 0";
      dataBlock = pxCrate1;
	  materialBlock = pxMaterialBox;
	};

  // join it together
  new PhysXJoint() {
      position = %pos3;
      pxActor1 = %obj1;
      pxActor2 = %obj2;
      dataBlock = pxJoint1;
    };

It is working but it has a thinking problem :-D

The first Box is created and simulated immediately.
The second Box is created and simulated immediately.
Then the joint will be created but in the moment you add the join the boxes had simulated before and the joint between both is not on the correct place.

The beste way is to create and join the boxes in one class. By this i will create a *.max file with two boxes and one Joint Node. In my class i want to read the collision boxes from the boxes and create them and place the joint on the location where the joint node is. Hopefully it works ? :-D

If it works i will post it here.

Cu
#107
09/04/2006 (9:01 am)
Isn't adding that while loop to check if it is write protected slow - and it uses up CPU cycles? Or is the time needed to wait so minimal it doesn't really make a difference?
#108
09/20/2006 (1:20 am)
I have a question...i use a 1.3 engine...And i have a problem to install a physX.....It's possible installa a PhysX to engine 1.3? thanks
#109
09/20/2006 (6:31 am)
Describing your problem would help :P
#110
09/20/2006 (7:17 am)
I have a torque 1.3 and i download a ageia sdk 2.3.3...
I include all directory and i download the file zip in this resource and include the file .h and .cpp in my engine...
Put this in example: PhysXLoader.dll and NxCooking.dll
And clean and compile my engine...
I have this error:

torqueDemo.exe - 17 error(s), 0 warning(s)

C:\TORQUE\AGEIA PHYSX\SDK V2.3.3\SDKS\PHYSICS\INCLUDE\NxIntersectionRayPlane.h(34) : error C2562: 'NxSegmentPlaneIntersect' : 'void' function returning a value
C:\TORQUE\AGEIA PHYSX\SDK V2.3.3\SDKS\PHYSICS\INCLUDE\NxIntersectionRayPlane.h(31) : see declaration of 'NxSegmentPlaneIntersect'
../engine\physX/PhysXWorld.h(22) : fatal error C1083: Cannot open include file: 'core/iTickable.h': No such file or directory

terrData.cc
../engine\physX/PhysXWorld.h(22) : fatal error C1083: Cannot open include file: 'core/iTickable.h': No such file or directory

PhysXActor.cpp
C:\TORQUE\AGEIA PHYSX\SDK V2.3.3\SDKS\PHYSICS\INCLUDE\NxIntersectionRayPlane.h(34) : error C2562: 'NxSegmentPlaneIntersect' : 'void' function returning a value
C:\TORQUE\AGEIA PHYSX\SDK V2.3.3\SDKS\PHYSICS\INCLUDE\NxIntersectionRayPlane.h(31) : see declaration of 'NxSegmentPlaneIntersect'
../engine\physX/PhysXActor.h(39) : error C2065: 'pxMaterialData' : undeclared identifier
../engine\physX/PhysXActor.h(42) : error C2501: 'DECLARE_CONSOLETYPE' : missing storage-class or type specifiers
../engine\physX/PhysXActor.h(42) : error C2143: syntax error : missing ';' before ''
../engine\physX/PhysXWorld.h(22) : fatal error C1083: Cannot open include file: 'core/iTickable.h': No such file or directory

PhysXJoint.cpp
C:\TORQUE\AGEIA PHYSX\SDK V2.3.3\SDKS\PHYSICS\INCLUDE\NxIntersectionRayPlane.h(34) : error C2562: 'NxSegmentPlaneIntersect' : 'void' function returning a value
C:\TORQUE\AGEIA PHYSX\SDK V2.3.3\SDKS\PHYSICS\INCLUDE\NxIntersectionRayPlane.h(31) : see declaration of 'NxSegmentPlaneIntersect'
../engine\physX/PhysXWorld.h(22) : fatal error C1083: Cannot open include file: 'core/iTickable.h': No such file or directory

PhysXStream.cpp
C:\TORQUE\AGEIA PHYSX\SDK V2.3.3\SDKS\PHYSICS\INCLUDE\NxIntersectionRayPlane.h(34) : error C2562: 'NxSegmentPlaneIntersect' : 'void' function returning a value
C:\TORQUE\AGEIA PHYSX\SDK V2.3.3\SDKS\PHYSICS\INCLUDE\NxIntersectionRayPlane.h(31) : see declaration of 'NxSegmentPlaneIntersect'

PhysXTerrain.cpp
C:\TORQUE\AGEIA PHYSX\SDK V2.3.3\SDKS\PHYSICS\INCLUDE\NxIntersectionRayPlane.h(34) : error C2562: 'NxSegmentPlaneIntersect' : 'void' function returning a value
C:\TORQUE\AGEIA PHYSX\SDK V2.3.3\SDKS\PHYSICS\INCLUDE\NxIntersectionRayPlane.h(31) : see declaration of 'NxSegmentPlaneIntersect'
../engine\physX/PhysXWorld.h(22) : fatal error C1083: Cannot open include file: 'core/iTickable.h': No such file or directory

PhysXTerrData.cpp
C:\TORQUE\AGEIA PHYSX\SDK V2.3.3\SDKS\PHYSICS\INCLUDE\NxIntersectionRayPlane.h(34) : error C2562: 'NxSegmentPlaneIntersect' : 'void' function returning a value
C:\TORQUE\AGEIA PHYSX\SDK V2.3.3\SDKS\PHYSICS\INCLUDE\NxIntersectionRayPlane.h(31) : see declaration of 'NxSegmentPlaneIntersect'
../engine\physX/PhysXWorld.h(22) : fatal error C1083: Cannot open include file: 'core/iTickable.h': No such file or directory
PhysXWorld.cpp

C:\TORQUE\AGEIA PHYSX\SDK V2.3.3\SDKS\PHYSICS\INCLUDE\NxIntersectionRayPlane.h(34) : error C2562: 'NxSegmentPlaneIntersect' : 'void' function returning a value
C:\TORQUE\AGEIA PHYSX\SDK V2.3.3\SDKS\PHYSICS\INCLUDE\NxIntersectionRayPlane.h(31) : see declaration of 'NxSegmentPlaneIntersect'
../engine\physX/PhysXWorld.h(22) : fatal error C1083: Cannot open include file: 'core/iTickable.h': No such file or directory
Error executing cl.exe.

Help me please....THANKS
#111
09/20/2006 (7:32 am)
I resolve a first problem....But now remaing this...
End i don't say how resolve....
ufff
#112
09/23/2006 (3:10 am)
But .... never say help me?
This is my problem:
C:\Torque\SDK Giochi\Fast Shooter\engine\physX\PhysXActor.cpp(195) : error C2065: 'TypePhysXMaterialDataPtr' : undeclared identifier
THANKS
#113
09/26/2006 (10:26 am)
@ Cimo - thats part of the SDK, not this resource
#114
09/26/2006 (10:40 am)
? what? i dont understood....
#115
09/26/2006 (10:44 am)
Well, it all compiles fine on my pc, so it must be a problem with the SDK version you're using or your implementation of this resource
#116
09/26/2006 (10:49 am)
? i use a 1.3 torque game engine....
You? but i use this modify:

I try resolve this problem with Shannon "PhysX resource"

I put this in gameBase.cc
Con::registerType("GameBaseDataPtr", TypeGameBaseDataPtr, 
sizeof(GameBaseData*),
                     REF_GETDATATYPE(GameBaseData),
                     REF_SETDATATYPE(GameBaseData));



I put this in physXActor.cpp

IMPLEMENT_GETDATATYPE(PhysXMaterialData);
IMPLEMENT_SETDATATYPE(PhysXMaterialData);
//IMPLEMENT_CONSOLETYPE(PhysXMaterialData);

void PhysXActor::initPersistFields()
{   
   Parent::initPersistFields();
 
   Con::registerType("PhysXMaterialDataPtr", TypePhysXMaterialDataPtr, 
sizeof(PhysXMaterialData*),
                     REF_GETDATATYPE(PhysXMaterialData),
                     REF_SETDATATYPE(PhysXMaterialData));
     addField("MaterialBlock", TypePhysXMaterialDataPtr , 
Offset(mMaterialBlock, PhysXActor));
}

But i have this problem

C:\Torque\SDK Giochi\Fast Shooter\engine\physX\PhysXActor.cpp(196) : error C2065: TypePhysXMaterialDataPtr' : undeclared identifier

Very very impossible!!
Help please....
#117
09/26/2006 (10:50 am)
To get this to compile on the 2.4.4 SDK, just comment out:
sceneDesc.broadPhase					= NX_BROADPHASE_COHERENT;
		sceneDesc.collisionDetection	= true;//false;

BTW: this does mean the objects wont move :(
#118
09/26/2006 (10:51 am)
@Cimo - Why did you put that there?
Im using 1.4.2
#119
09/26/2006 (11:26 am)
Sorry....I'm confusing....
You use a Torque game engine 1.4?

Why i use 1.3 and i have a SDK physX 2.3.3
#120
09/26/2006 (11:29 am)
I use 1.4,
Why did you add the code above to gameBase.cc?