px3Player.cpp
Engine/source/T3D/physics/physx3/px3Player.cpp
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