Game Development Community

T3D 1.2 meshRoad fix for PhysX version not having collision

by Dave Wagner · in Torque 3D Professional · 04/02/2012 (7:09 am) · 13 replies

This fix will add PhysX collision to the mesh roads.

The lines of code I added are commented as "Added"
The lines of code I changed are commented as "Changed".
I left some source code lines before and after the changes to find where the lines need to be added to code instead of using line numbers.
Note that _addShapeToPhysX() is a new function.

Added the following lines of code to meshRoad.h

#include "materials/matInstance.h"
#endif
#ifndef _CONVEX_H_
#include "collision/convex.h"
#endif

class PhysicsBody;  // Added
class PhysicsWorld; // Added

//extern U32 gIdxArray[6][2][3];

struct MeshRoadHitSegment
{
   U32 idx;

void _regenerate();
   void _generateSlices();
   void _generateSegments();
   void _generateVerts();

   void _addShapeToPhysX(); // Added

protected:

MeshRoadSliceVector mSlices;
   MeshRoadNodeVector mNodes;
   MeshRoadSegmentVector mSegments;
      
   // Fields.
   F32 mTextureLength;
   F32 mBreakAngle;
   S32 mWidthSubdivisions;

   F32 mStaticFriction;  // Added
   F32 mKineticFriction; // Added
   F32 mRestitution;     // Added
   
   // Collision and Physics.
   Convex* mConvexList;
   Vector<MeshRoadConvex*> mDebugConvex;
   PhysicsBody *mPhysicsRep;
   PhysicsWorld *mWorld;  // Added
};

Added the following lines of code to meshRoad.cpp

#include "materials/shaderData.h"
#include "gfx/sim/gfxStateBlockData.h"
#include "gfx/sim/debugDraw.h"
#include "collision/concretePolyList.h"
#include "T3D/physics/physicsPlugin.h"
#include "T3D/physics/physicsBody.h"
#include "T3D/physics/physicsWorld.h"
#include "T3D/physics/physicsCollision.h" // Added
#include "environment/nodeListManager.h"  // Added

#define MIN_METERS_PER_SEGMENT 1.0f
#define MIN_NODE_DEPTH 0.25f
#define MAX_NODE_DEPTH 50.0f
#define MIN_NODE_WIDTH 0.25f

MeshRoad::MeshRoad()
		: mTextureLength( 5.0f ),
		  mBreakAngle( 3.0f ),
		  mPhysicsRep( NULL ),
                  mWorld( NULL ),            // Added
		  mWidthSubdivisions( 0 ),
		  mStaticFriction( 1.2f ),   // Added
		  mKineticFriction( 1.2f ),  // Added
		  mRestitution( 0.597f )     // Added
{


addField( "widthSubdivisions", TypeS32, Offset( mWidthSubdivisions, MeshRoad ), 
         "Subdivide segments widthwise this many times when generating vertices." );

	  addField( "staticFriction", TypeF32, Offset( mStaticFriction, MeshRoad ), 
		"Road friction when the wheel is not slipping (has traction)." );      // Added

	  addField( "kineticFriction", TypeF32, Offset( mKineticFriction, MeshRoad ),
		"Road friction when the wheel is slipping (no traction)." );           // Added

	  addField( "restitution", TypeF32, Offset( mRestitution, MeshRoad ),
		"Road restitution.nCurrently unused." );                              // Added

   endGroup( "MeshRoad" );

void MeshRoad::onRemove()
{
   removeFromScene();            // Added

   SAFE_DELETE( mPhysicsRep );
   mWorld = NULL;               //Added

   mConvexList->nukeList();

   for ( U32 i = 0; i < SurfaceCount; i++ )
   {
      SAFE_DELETE( mMatInst[i] );
   }


   Parent::onRemove();
}

stream->write( mTextureLength );      
      stream->write( mBreakAngle );
      stream->write( mWidthSubdivisions );

	  // Write physics materials
      stream->write( mStaticFriction );   // Added
      stream->write( mKineticFriction );  // Added
      stream->write( mRestitution );      // Added
   }

   if ( stream->writeFlag( mask & NodeMask ) )
   {
      const U32 nodeByteSize = 32; // Based on sending all of a node's parameters

stream->read( &mBreakAngle );
      stream->read( &mWidthSubdivisions );

	  // Read physics materials
      stream->read( &mStaticFriction );       // Added
      stream->read( &mKineticFriction );      // Added
      stream->read( &mRestitution );          // Added
   }

   // NodeMask
   if ( stream->readFlag() )
   {
      if (stream->readFlag())

This is actually a fix to the code that I posted earlier.

{
      const MeshRoadSlice &slice = mSlices[i];

      if ( i == 0 )
      {
         box.minExtents = slice.p0;
         box.maxExtents = slice.p0;  // Changed
         box.extend( slice.p2 );     // Added
         box.extend( slice.pb0 );
         box.extend( slice.pb2 );
      }
      else
      {
         box.extend( slice.p0 );

mSegments.push_back( seg );
   }

   if ( isClientObject() )
      _generateVerts();

   _addShapeToPhysX(); // Added
}

void MeshRoad::_generateVerts()
{           
   const U32 widthDivisions = getMax( 0, mWidthSubdivisions );
   const F32 divisionStep = 1.0f / (F32)( widthDivisions + 1 );

This whole function is new.

// Add shape to PhysX engine
void MeshRoad::_addShapeToPhysX()
{
	if ( PHYSICSMGR )
	{
		SAFE_DELETE( mPhysicsRep );
		mWorld = NULL;

		// If we aren't dynamic we don't need to tick.   
		setProcessTick( false );

		mWorld = PHYSICSMGR->getWorld( isServerObject() ? "server" : "client" );

		if( mWorld )
		{
			mPhysicsRep = PHYSICSMGR->createBody();

			if( mPhysicsRep )
			{
				PhysicsCollision *colShape = PHYSICSMGR->createCollision();

				if( colShape )
				{
					Point3F p[8];

					// Points already in world coordinates so we don't need to translate them 
					for( int i = 0, j = 1; j < mSlices.size(); i++, j++ )
					{
						p[0] = mSlices[i].pb0;
						p[1] = mSlices[i].p0;
						p[2] = mSlices[i].p2;
						p[3] = mSlices[i].pb2;

						p[4] = mSlices[j].pb0;
						p[5] = mSlices[j].p0;
						p[6] = mSlices[j].p2;
						p[7] = mSlices[j].pb2;
		
						colShape->addConvex( &p[0], 8,  MatrixF::Identity );
					}

					mPhysicsRep->init( colShape, 0.0f, 0, this, mWorld );

					mPhysicsRep->setMaterial( mRestitution, mKineticFriction, mStaticFriction );
					mPhysicsRep->setTransform(  MatrixF::Identity );
				}
			}
		}
	}
}

//-------------------------------------------------------------------------
// Console Methods
//-------------------------------------------------------------------------

DefineEngineMethod( MeshRoad, setNodeDepth, void, ( S32 idx, F32 meters ),,

#1
04/02/2012 (4:30 pm)
many thanks for posting this Dave

having to choose between physx and the road tool is nasty one.



#2
04/03/2012 (1:34 am)
@Dave,

I implemented collision on meshRoads a while back, I went the mPhysicsRep route though, allowing the use of PhysX or Bullet

in meshRoad.cpp

MeshRoad::MeshRoad()
: mTextureLength( 5.0f ),
  mBreakAngle( 3.0f ),
  mPhysicsRep( NULL ), //added
  mWidthSubdivisions( 0 )
{.........

void MeshRoad::onRemove()
{
   SAFE_DELETE( mPhysicsRep ); //added
............

void MeshRoad::setTransform( const MatrixF &mat )
{
.........
.........
   Parent::setTransform( mat );

   if ( mPhysicsRep ) //added
      mPhysicsRep->setTransform( mat ); //added

void MeshRoad::_generateSegments()
{
........
........
........

   if ( isClientObject() )
      _generateVerts();

//DS PHYSICSREP ADDED
   if ( PHYSICSMGR )
	{
		ConcretePolyList polylist;
		if (buildPolyList(PLC_Collision, &polylist, getWorldBox(), getWorldSphere()))
		{
			polylist.triangulate();

			PhysicsCollision *colShape = PHYSICSMGR->createCollision();
			colShape->addTriangleMesh( polylist.mVertexList.address(), 
				polylist.mVertexList.size(),
				polylist.mIndexList.address(),
				polylist.mIndexList.size() / 3,
				MatrixF::Identity );

			PhysicsWorld *world = PHYSICSMGR->getWorld( isServerObject() ? "server" : "client" );
			mPhysicsRep = PHYSICSMGR->createBody();
			mPhysicsRep->init( colShape, 0, 0, this, world );
		}
	}
//DS END ADDED
}

and in meshRoad.h at the end

........
........
........
   Vector<MeshRoadConvex*> mDebugConvex;
   PhysicsBody *mPhysicsRep; // added
};

#endif // _MESHROAD_H_

its nice to keep the options open with physics
#3
04/03/2012 (6:37 am)
Nice. I hope someone a Garage games puts this into the next release of T3D.
I haven't heard much mention of Bullet from anyone on the Garage game side since the beta versions of the engine. It's not even mentioned in their engine feature list.
#4
04/04/2012 (7:56 am)
Heh, found this just in time. Thanks Dave!
#5
04/01/2013 (3:48 pm)
Old thread this is yes, but still very useful it is. Without this thread this

this thread

would have been hard to use. This community is simply just awesome and the knowledge in these thread are vast and plentiful for the stubborn treasure hunter :o)

Thanks! :o)
#6
04/02/2013 (7:44 am)
Has this been submitted as a pull request? That would be a good thing....
#7
04/02/2013 (12:34 pm)
Oh ya indeed it would. It works like a charm. It is a shame I have no idea whether this has been pulled or not. But boy it works well. Now a mesh road can be used to control a players movement and made transparent and BOOOM into the invisible world barrier the player runs :o)
#8
04/02/2013 (1:50 pm)
I pulled a request and then we must see.
#9
04/02/2013 (2:03 pm)
Pull request was improperly done. Keep in mind that all pull request branches are to be based upon the development branch and not the master branch. Also, there appeared to be no actual work submitted for the pull request which indicates that the purpose was more of a "feature request" -- this is not how the pull request feature through Github is to be used.
#10
04/02/2013 (2:09 pm)
Looking at the changes here, the ones indicated by deepscratch would be a more preferable solution since they should work for either physics solutions and doesn't favor PhsyX.
#11
04/02/2013 (6:19 pm)
Roger, got that. My first real pull request ever. Sorry :o)
#12
08/17/2014 (2:49 pm)
mPhysicsRep = PHYSICSMGR->createBody();
This will get called multiple times in the lifetime of a single object, right? Is that the intended behavior? How does the lifecycle of a physics body work? Browsing the rest of the code, it does actually seem like createBody() is used every time collision is updated, but I don't see calls to destroy these objects.

EDIT: I'm dumb, there's usually a corresponding call to SAFE_DELETE(mPhysicsRep).

EDIT: pull request
#13
11/17/2014 (9:06 am)
merged, good work! :)