px3Player.cpp

Engine/source/T3D/physics/physx3/px3Player.cpp

More...

Detailed Description

  1
  2//-----------------------------------------------------------------------------
  3// Copyright (c) 2012 GarageGames, LLC
  4//
  5// Permission is hereby granted, free of charge, to any person obtaining a copy
  6// of this software and associated documentation files (the "Software"), to
  7// deal in the Software without restriction, including without limitation the
  8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9// sell copies of the Software, and to permit persons to whom the Software is
 10// furnished to do so, subject to the following conditions:
 11//
 12// The above copyright notice and this permission notice shall be included in
 13// all copies or substantial portions of the Software.
 14//
 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 21// IN THE SOFTWARE.
 22//-----------------------------------------------------------------------------
 23
 24#include "platform/platform.h"
 25#include "T3D/physics/physx3/px3Player.h"
 26#include "T3D/physics/physicsPlugin.h"
 27#include "T3D/physics/physx3/px3World.h"
 28#include "T3D/physics/physx3/px3Casts.h"
 29#include "T3D/physics/physx3/px3Utils.h"
 30#include "collision/collision.h"
 31
 32
 33Px3Player::Px3Player()
 34   :  PhysicsPlayer(),
 35      mController( NULL ),
 36      mWorld( NULL ),
 37      mObject( NULL ),
 38      mSkinWidth( 0.05f ),
 39      mOriginOffset( 0.0f ),
 40      mElapsed(0)
 41{
 42   PHYSICSMGR->getPhysicsResetSignal().notify( this, &Px3Player::_onPhysicsReset );
 43}
 44
 45Px3Player::~Px3Player()
 46{
 47   _releaseController();
 48   PHYSICSMGR->getPhysicsResetSignal().remove( this, &Px3Player::_onPhysicsReset );
 49}
 50
 51void Px3Player::_releaseController()
 52{
 53   if ( mController )
 54   {
 55      mController->getActor()->userData = NULL;
 56      mWorld->getStaticChangedSignal().remove( this, &Px3Player::_onStaticChanged );
 57      SafeReleasePhysx(mController);
 58   }
 59}
 60
 61void Px3Player::init( const char *type,
 62                     const Point3F &size,
 63                     F32 runSurfaceCos,
 64                     F32 stepHeight,
 65                     SceneObject *obj, 
 66                     PhysicsWorld *world )
 67{
 68   AssertFatal( obj, "Px3Player::init - Got a null scene object!" );
 69   AssertFatal( world, "Px3Player::init - Got a null world!" );
 70   AssertFatal( dynamic_cast<Px3World*>( world ), "Px3Player::init - The world is the wrong type!" );
 71
 72   // Cleanup any previous controller.
 73   _releaseController();
 74
 75   mObject = obj;
 76   mWorld = (Px3World*)world;
 77   mOriginOffset = size.z * 0.5f;
 78
 79   physx::PxCapsuleControllerDesc desc;
 80   desc.contactOffset = mSkinWidth;
 81   desc.radius = getMax( size.x, size.y ) * 0.5f;
 82   desc.radius -= mSkinWidth;
 83   desc.height = size.z - ( desc.radius * 2.0f );
 84   desc.height -= mSkinWidth * 2.0f;
 85   desc.climbingMode = physx::PxCapsuleClimbingMode::eCONSTRAINED;
 86   desc.position.set( 0, 0, 0 );
 87   desc.upDirection = physx::PxVec3(0,0,1);
 88   desc.reportCallback = this;
 89   desc.slopeLimit = runSurfaceCos;
 90   desc.stepOffset = stepHeight;
 91   desc.behaviorCallback = NULL;
 92   desc.material = gPhysics3SDK->createMaterial(0.1f, 0.1f, 0.2f);
 93
 94   mController = mWorld->createController( desc );
 95
 96   mWorld->getStaticChangedSignal().notify( this, &Px3Player::_onStaticChanged );
 97   physx::PxRigidDynamic *kineActor = mController->getActor();
 98
 99   //player only has one shape
100   physx::PxShape *shape = px3GetFirstShape(kineActor);
101   physx::PxFilterData colData;
102   colData.word0 = PX3_PLAYER;
103   shape->setSimulationFilterData(colData);
104   shape->setQueryFilterData(colData);
105
106   //store geometry for later use in findContact calls
107   shape->getCapsuleGeometry(mGeometry);
108
109   mUserData.setObject( obj );
110   kineActor->userData = &mUserData;
111
112}
113
114void Px3Player::_onStaticChanged()
115{
116   if(mController)
117      mController->invalidateCache();
118}
119
120void Px3Player::_onPhysicsReset( PhysicsResetEvent reset )
121{
122   if(mController)
123      mController->invalidateCache();
124}
125
126Point3F Px3Player::move( const VectorF &disp, CollisionList &outCol )
127{
128   AssertFatal( mController, "Px3Player::move - The controller is null!" );
129
130   // Return the last position if the simulation is stopped.
131   //
132   // See PxPlayer::_onPhysicsReset
133   if ( !mWorld->isEnabled() )
134   {
135      Point3F newPos = px3Cast<Point3F>( mController->getPosition() );
136      newPos.z -= mOriginOffset;
137      return newPos;
138   }
139
140   mCollisionList = &outCol;
141
142   physx::PxVec3 dispNx( disp.x, disp.y, disp.z );
143   if (mIsZero(disp.z))
144      dispNx.z = 0.0f;
145   
146   U32 groups = 0xffffffff;
147   groups &= ~( PX3_TRIGGER ); // No trigger shapes!
148   groups &= ~( PX3_DEBRIS);
149   physx::PxControllerFilters filter;
150   physx::PxFilterData data;
151   data.word0=groups;
152   filter.mFilterData = &data;
153   filter.mFilterFlags = physx::PxQueryFlags(physx::PxQueryFlag::eDYNAMIC | physx::PxQueryFlag::eSTATIC);
154   
155   mController->move( dispNx,0.0001f,0, filter );
156
157   Point3F newPos = px3Cast<Point3F>( mController->getPosition() );
158   newPos.z -= mOriginOffset;
159
160   mCollisionList = NULL;
161
162   return newPos;
163}
164
165void Px3Player::onShapeHit( const physx::PxControllerShapeHit& hit )
166{
167   if (!mCollisionList || mCollisionList->getCount() >= CollisionList::MaxCollisions)
168      return;
169
170   physx::PxRigidActor *actor = hit.actor;
171   PhysicsUserData *userData = PhysicsUserData::cast( actor->userData );
172
173   // Fill out the Collision 
174   // structure for use later.
175   Collision &col = mCollisionList->increment();
176   dMemset( &col, 0, sizeof( col ) );
177
178   col.normal = px3Cast<Point3F>( hit.worldNormal );
179   col.point = px3Cast<Point3F>( hit.worldPos );
180   col.distance = hit.length;      
181   if ( userData )
182      col.object = userData->getObject();
183
184   if (mIsZero(hit.dir.z))
185   {
186      if (col.normal.z > 0.0f)
187      {
188         col.normal.z = 0.0f;
189         col.normal.normalizeSafe();
190      }
191   }
192   else
193   {
194      col.normal.set(0.0f, 0.0f, 1.0f);
195   }
196
197
198}
199
200void Px3Player::onControllerHit( const physx::PxControllersHit& hit )
201{
202   if (!mCollisionList || mCollisionList->getCount() >= CollisionList::MaxCollisions)
203      return;
204
205   physx::PxRigidActor *actor = hit.other->getActor();
206   PhysicsUserData *userData = PhysicsUserData::cast( actor->userData );
207
208   // For controller-to-controller hit we don't have an actual hit point, so all
209   // we can do is set the hit object.
210   Collision &col = mCollisionList->increment();
211   dMemset( &col, 0, sizeof( col ) );
212   if ( userData )
213      col.object = userData->getObject();
214
215}
216
217void Px3Player::findContact(   SceneObject **contactObject, 
218                              VectorF *contactNormal, 
219                              Vector<SceneObject*> *outOverlapObjects ) const
220{
221  // Calculate the sweep motion...
222   F32 halfCapSize = mOriginOffset;
223   F32 halfSmallCapSize = halfCapSize * 0.8f;
224   F32 diff = halfCapSize - halfSmallCapSize;
225
226   F32 distance = diff + mSkinWidth + 0.01f; 
227   physx::PxVec3 dir(0,0,-1);
228 
229   physx::PxScene *scene = mWorld->getScene();
230   physx::PxHitFlags hitFlags(physx::PxHitFlag::eDEFAULT);
231   physx::PxQueryFilterData filterData(physx::PxQueryFlag::eDYNAMIC|physx::PxQueryFlag::eSTATIC);
232   filterData.data.word0 = PX3_DEFAULT;
233   physx::PxSweepHit sweepHit;
234   physx::PxRigidDynamic *actor= mController->getActor();
235   physx::PxU32 shapeIndex;
236
237   bool hit = physx::PxRigidBodyExt::linearSweepSingle(*actor,*scene,dir,distance,hitFlags,sweepHit,shapeIndex,filterData);
238   if ( hit )
239   {
240      PhysicsUserData *data = PhysicsUserData::cast( sweepHit.actor->userData);
241      if ( data )
242      {
243         *contactObject = data->getObject();
244         *contactNormal = px3Cast<Point3F>( sweepHit.normal );
245      }
246   }
247
248  // Check for overlapped objects ( triggers )
249
250   if ( !outOverlapObjects )
251      return;
252
253   filterData.data.word0 = PX3_TRIGGER;
254
255   const physx::PxU32 bufferSize = 10;
256   physx::PxOverlapBufferN<bufferSize> hitBuffer;
257   hit = scene->overlap(mGeometry,actor->getGlobalPose(),hitBuffer,filterData);
258   if(hit)
259   {
260      for ( U32 i = 0; i < hitBuffer.nbTouches; i++ )
261      {
262         PhysicsUserData *data = PhysicsUserData::cast( hitBuffer.touches[i].actor->userData );
263         if ( data )      
264            outOverlapObjects->push_back( data->getObject() );
265      }
266   }
267
268}
269
270void Px3Player::enableCollision()
271{
272   AssertFatal( mController, "Px3Player::enableCollision - The controller is null!" );
273
274   px3GetFirstShape(mController->getActor())->setFlag(physx::PxShapeFlag::eSIMULATION_SHAPE,true);
275}
276
277void Px3Player::disableCollision()
278{
279   AssertFatal( mController, "Px3Player::disableCollision - The controller is null!" );
280
281   px3GetFirstShape(mController->getActor())->setFlag(physx::PxShapeFlag::eSIMULATION_SHAPE,false); 
282}
283
284PhysicsWorld* Px3Player::getWorld()
285{
286   return mWorld;
287}
288
289void Px3Player::setTransform( const MatrixF &transform )
290{
291   AssertFatal( mController, "Px3Player::setTransform - The controller is null!" );
292
293   Point3F newPos = transform.getPosition();
294   newPos.z += mOriginOffset;
295
296   const Point3F &curPos = px3Cast<Point3F>(mController->getPosition());
297   
298   if ( !(newPos - curPos ).isZero() )
299      mController->setPosition( px3Cast<physx::PxExtendedVec3>(newPos) );
300}
301
302MatrixF& Px3Player::getTransform( MatrixF *outMatrix )
303{
304   AssertFatal( mController, "Px3Player::getTransform - The controller is null!" );
305
306   Point3F newPos = px3Cast<Point3F>( mController->getPosition() );
307   newPos.z -= mOriginOffset;
308   outMatrix->setPosition( newPos );
309
310   return *outMatrix;
311}
312
313void Px3Player::setScale( const Point3F &scale )
314{
315   //Ignored
316}
317
318Box3F Px3Player::getWorldBounds()
319{
320   physx::PxBounds3 bounds;
321   physx::PxRigidDynamic *actor = mController->getActor();
322   physx::PxShape *shape = px3GetFirstShape(actor);
323   bounds = physx::PxShapeExt::getWorldBounds(*shape,*actor);
324   return px3Cast<Box3F>( bounds );
325}
326
327bool Px3Player::testSpacials(const Point3F &nPos, const Point3F &nSize) const
328{
329   F32 offset = nSize.z * 0.5f;
330   F32 radius = getMax(nSize.x, nSize.y) * 0.5f - mSkinWidth;
331   F32 height = (nSize.z - (radius * 2.0f)) * 0.5f;
332   height -= mSkinWidth * 2.0f;
333   physx::PxCapsuleGeometry geom(radius, height);
334
335   physx::PxVec3 pos(nPos.x, nPos.y, nPos.z + offset);
336   physx::PxQuat orientation(Float_HalfPi, physx::PxVec3(0.0f, 1.0f, 0.0f));
337
338   physx::PxOverlapBuffer hit;
339   physx::PxQueryFilterData queryFilter(physx::PxQueryFlag::eANY_HIT | physx::PxQueryFlag::eSTATIC | physx::PxQueryFlag::eDYNAMIC);
340   queryFilter.data.word0 = PX3_DEFAULT;
341   bool hasHit = mWorld->getScene()->overlap(geom, physx::PxTransform(pos, orientation), hit, queryFilter);
342
343   return !hasHit;   // Return true if there are no overlapping objects
344}
345
346void Px3Player::setSpacials(const Point3F &nPos, const Point3F &nSize)
347{
348   mOriginOffset = nSize.z * 0.5f;
349   F32 radius = getMax(nSize.x, nSize.y) * 0.5f - mSkinWidth;
350   F32 height = nSize.z - (radius * 2.0f);
351   height -= mSkinWidth * 2.0f;
352
353   mController->resize(height);
354   px3GetFirstShape(mController->getActor())->getCapsuleGeometry(mGeometry);
355}
356