CPhysicUserData* CPhysicsManager::RaycastClosestActor( const Vect3f _vPosRay, const Vect3f& _vDirRay, uint32 _uiImpactMask, SCollisionInfo& _Info, float _uiMaxDistance ) { //NxUserRaycastReport::ALL_SHAPES assert(m_pScene != NULL); NxRay ray; ray.dir = NxVec3 ( _vDirRay.x, _vDirRay.y, _vDirRay.z ); ray.orig = NxVec3 ( _vPosRay.x, _vPosRay.y, _vPosRay.z ); NxRaycastHit hit; NxShape* closestShape = NULL; //closestShape = m_pScene->raycastClosestShape ( ray, NX_ALL_SHAPES, hit, _uiImpactMask, NX_MAX_F32, _uiImpactMask ); //closestShape = m_pScene->raycastClosestShape( ray, NX_ALL_SHAPES, hit, 0xffffffff, NX_MAX_F32, 0xffffffff, NULL, NULL ); NxReal l_Distance = (NxReal) _uiMaxDistance; // --- Jordi : Provisional. Cal deixar aquesta linia i modificar la col·lisió de càmera closestShape = m_pScene->raycastClosestShape( ray, NX_ALL_SHAPES, hit, _uiImpactMask, l_Distance ); if (!closestShape) { //No hemos tocado a ningún objeto físico de la escena. return NULL; } NxActor* actor = &closestShape->getActor(); CPhysicUserData* impactObject =(CPhysicUserData*)actor->userData; //Si está petando aquí quiere decir que se ha registrado un objeto físico sin proporcionarle UserData assert(impactObject); _Info.m_fDistance = hit.distance; _Info.m_Normal = Vect3f(hit.worldNormal.x, hit.worldNormal.y, hit.worldNormal.z ); _Info.m_CollisionPoint = Vect3f(hit.worldImpact.x, hit.worldImpact.y, hit.worldImpact.z ); return impactObject; }
CPhysicUserData* CPhysicsManager::RaycastClosestActor (const Vect3f posRay, const Vect3f& dirRay, uint32 impactMask, SCollisionInfo& info ) { //NxUserRaycastReport::ALL_SHAPES assert(m_pScene != NULL); NxRay ray; ray.dir = NxVec3(dirRay.x, dirRay.y, dirRay.z); ray.orig = NxVec3(posRay.x, posRay.y, posRay.z); NxRaycastHit hit; NxShape* closestShape = NULL; closestShape = m_pScene->raycastClosestShape(ray, NX_ALL_SHAPES, hit, impactMask); if (!closestShape) { //No hemos tocado a ningún objeto físico de la escena. return NULL; } NxActor* actor = &closestShape->getActor(); CPhysicUserData* impactObject =(CPhysicUserData*)actor->userData; //Si está petando aquí quiere decir que se ha registrado un objeto físico sin proporcionarle UserData assert(impactObject); info.m_fDistance = hit.distance; info.m_Normal = Vect3f(hit.worldNormal.x, hit.worldNormal.y, hit.worldNormal.z ); info.m_CollisionPoint = Vect3f(hit.worldImpact.x, hit.worldImpact.y, hit.worldImpact.z ); return impactObject; }
bool plPXPhysical::OverlapWithController(const plPXPhysicalControllerCore* controller) { NxCapsule cap; controller->GetWorldSpaceCapsule(cap); NxShape* shape = fActor->getShapes()[0]; return shape->checkOverlapCapsule(cap); }
//---------------------------------------------------------------------------- // ReleaseAllActors : Alliberem tots els actors de l'escena de PhysX //---------------------------------------------------------------------------- bool CPhysicsManager::ReleaseAllActors ( void ) //EUserDataFlag _eFlags ) { assert ( m_pScene != NULL ); assert ( m_pPhysicsSDK != NULL ); bool isOk = true; NxActor** l_ppActorList = m_pScene->getActors(); NxU32 l_TotalActors = m_pScene->getNbActors(); while ( l_TotalActors -- ) { NxActor* nxActor = *l_ppActorList; if ( nxActor != 0) { NxArray<NxCCDSkeleton*> skeletons; for (NxU32 i = 0; i < nxActor->getNbShapes(); i++) { NxShape* shape = nxActor->getShapes()[i]; if (shape->getCCDSkeleton() != NULL) { skeletons.pushBack(shape->getCCDSkeleton()); } } for (NxU32 i = 0; i < skeletons.size(); i++) { m_pPhysicsSDK->releaseCCDSkeleton(*skeletons[i]); } m_pScene->releaseActor(*nxActor); nxActor = 0; } } return isOk; }
bool CPhysicsManager::ReleasePhysicActor (CPhysicActor* actor) { assert(actor != NULL); assert(m_pScene != NULL); assert(m_pPhysicsSDK != NULL); bool isOk = false; NxActor* nxActor = actor->GetPhXActor(); if( nxActor != 0) { NxArray<NxCCDSkeleton*> skeletons; for (NxU32 i = 0; i < nxActor->getNbShapes(); i++) { NxShape* shape = nxActor->getShapes()[i]; if (shape->getCCDSkeleton() != NULL) { skeletons.pushBack(shape->getCCDSkeleton()); } } for (NxU32 i = 0; i < skeletons.size(); i++) { m_pPhysicsSDK->releaseCCDSkeleton(*skeletons[i]); } m_pScene->releaseActor(*nxActor); nxActor = 0; } return true; }
// Release one of the shapes from our compound. At the moment // we are just releasing the first object in the array. // As long as the index is below the number of shapes (uiNumShapes) // it should work, but be careful about releasing an object inside // other objects (for performance reasons) void ReleaseRandomShape() { // Get the array of pointers to shapes NxShape*const* ppShapeArray = mainBox->getShapes(); // Find out how many shapes there are left NxU32 uiNumShapes = mainBox->getNbShapes(); // Don't remove the last shape (or we'll have a shapeless actor) if (uiNumShapes < 2) return; // Record the pose of the shape we intend to release, for later NxShape* pShapeToRelease = ppShapeArray[0]; NxMat34 mNewBoxPose = pShapeToRelease->getGlobalPose(); // Release the object, and make a note of the new total number of objects mainBox->releaseShape(*pShapeToRelease); --iNumberObjects; // We need to update the mass and intertial tensors. We choose to base it // on the density of the objects, which are all fBoxDensity mainBox->updateMassFromShapes(fBoxDensity, 0.0f); // Create the new box, in the pose we recorded earlier CreateBoxPiece(mNewBoxPose); }
//----------------------------------------------------------------------------- // onTrigger //----------------------------------------------------------------------------- //!! void CPhysicScene::onTrigger (NxShape &triggerShape, NxShape &otherShape, NxTriggerFlag status) { if (!m_pCollisionMng) return; TActorInfo *triggerInfo = (TActorInfo*) triggerShape.getActor().userData; TActorInfo *otherInfo = (TActorInfo*) otherShape.getActor().userData; m_pCollisionMng->onTrigger(*triggerInfo, *otherInfo, status); }
int CPhysicsActor::GetCollisionGroup() { NxShape*const* shapes = m_Actor->getShapes(); NxShape* shape; shape = shapes[0]; return shape->getGroup(); }
plPXPhysical::~plPXPhysical() { SpamMsg(plSimulationMgr::Log("Destroying physical %s", GetKeyName().c_str())); if (fActor) { // Grab any mesh we may have (they need to be released manually) NxConvexMesh* convexMesh = nil; NxTriangleMesh* triMesh = nil; NxShape* shape = fActor->getShapes()[0]; if (NxConvexShape* convexShape = shape->isConvexMesh()) convexMesh = &convexShape->getConvexMesh(); else if (NxTriangleMeshShape* trimeshShape = shape->isTriangleMesh()) triMesh = &trimeshShape->getTriangleMesh(); if (!fActor->isDynamic()) plPXPhysicalControllerCore::RebuildCache(); if (fActor->isDynamic() && fActor->readBodyFlag(NX_BF_KINEMATIC)) { if (fGroup == plSimDefs::kGroupDynamic) fNumberAnimatedPhysicals--; else fNumberAnimatedActivators--; } // Release the actor NxScene* scene = plSimulationMgr::GetInstance()->GetScene(fWorldKey); scene->releaseActor(*fActor); fActor = nil; // Now that the actor is freed, release the mesh if (convexMesh) plSimulationMgr::GetInstance()->GetSDK()->releaseConvexMesh(*convexMesh); if (triMesh) plSimulationMgr::GetInstance()->GetSDK()->releaseTriangleMesh(*triMesh); // Release the scene, so it can be cleaned up if no one else is using it plSimulationMgr::GetInstance()->ReleaseScene(fWorldKey); } if (fWorldHull) delete [] fWorldHull; if (fSaveTriangles) delete [] fSaveTriangles; delete fProxyGen; // remove sdl modifier plSceneObject* sceneObj = plSceneObject::ConvertNoRef(fObjectKey->ObjectIsLoaded()); if (sceneObj && fSDLMod) { sceneObj->RemoveModifier(fSDLMod); } delete fSDLMod; }
pWheelContactData* pWheel2::getContact() { NxWheelShape *wShape = getWheelShape(); if (!wShape) { return new pWheelContactData(); } NxWheelContactData wcd; NxShape* contactShape = wShape->getContact(wcd); pWheelContactData result; result.contactEntity = NULL; if (contactShape) { result.contactForce = wcd.contactForce; result.contactNormal = getFrom(wcd.contactNormal); result.contactPoint= getFrom(wcd.contactPoint); result.contactPosition= wcd.contactPosition; result.lateralDirection= getFrom(wcd.lateralDirection); result.lateralImpulse= wcd.lateralImpulse; result.lateralSlip = wcd.lateralSlip; result.longitudalDirection = getFrom(wcd.longitudalDirection); result.longitudalImpulse = wcd.longitudalImpulse; result.longitudalSlip= wcd.longitudalSlip; pSubMeshInfo *sInfo = static_cast<pSubMeshInfo*>(contactShape->userData); if (sInfo->entID) { CKObject *obj = (CKObject*)GetPMan()->m_Context->GetObject(sInfo->entID); if (obj) { result.contactEntity = (CK3dEntity*)obj; }else { result.contactEntity = NULL; } } result.otherShapeMaterialIndex = contactShape->getMaterial(); NxMaterial* otherMaterial = contactShape->getActor().getScene().getMaterialFromIndex(contactShape->getMaterial()); if (otherMaterial) { pFactory::Instance()->copyTo(result.otherMaterial,otherMaterial); } } return &result; }
void pTriggerReport::onTrigger(NxShape& triggerShape, NxShape& otherShape, NxTriggerFlag status) { NxActor *triggerActor = &triggerShape.getActor(); NxActor *otherActor = &otherShape.getActor(); pRigidBody *triggerBody = NULL; pRigidBody *otherBody = NULL; if (triggerActor) { triggerBody = static_cast<pRigidBody*>(triggerActor->userData); triggerBody->getTriggers().Clear(); } if (otherActor) { otherBody = static_cast<pRigidBody*>(otherActor->userData); otherBody->getTriggers().Clear(); } pTriggerEntry entry; entry.shapeA = &triggerShape; entry.shapeB = &otherShape; entry.triggerEvent = status; if (triggerBody) { triggerBody->getTriggers().PushBack(entry); } /*if(status & NX_TRIGGER_ON_ENTER) { } if(status & NX_TRIGGER_ON_LEAVE) { } if(status & NX_TRIGGER_ON_STAY) { // A body entered the trigger area for the first time }*/ }
//----------------------------------------------------------------------- void PhysXActorExtern::_processParticle( ParticleTechnique* particleTechnique, Particle* particle, Ogre::Real timeElapsed, bool firstParticle) { // Only update after a PhysX simulation step if (mSynchronize) { if (particle->particleType != Particle::PT_VISUAL) return; if (!particle->physicsActor) return; VisualParticle* visualParticle = static_cast<VisualParticle*>(particle); PhysXActor* physXActor = static_cast<PhysXActor*>(particle->physicsActor); NxActor* nxActor = physXActor->nxActor; if (nxActor) { // Synchronize both the particle and the pysicsActor with the nxActor particle->position = PhysXMath::convert(nxActor->getGlobalPosition()); particle->direction = PhysXMath::convert(nxActor->getLinearVelocity()); visualParticle->orientation = PhysXMath::convert(nxActor->getGlobalOrientationQuat()); physXActor->position = particle->position; physXActor->direction = particle->direction; physXActor->orientation = visualParticle->orientation; if (nxActor->getNbShapes()) { NxShape *shape = nxActor->getShapes()[0]; // Max one. switch(shape->getType()) { case NX_SHAPE_BOX: (static_cast<NxBoxShape*>(shape))->setDimensions( PhysXMath::convert(0.5 * Ogre::Vector3( visualParticle->width, visualParticle->height, visualParticle->depth))); break; case NX_SHAPE_SPHERE: (static_cast<NxSphereShape*>(shape))->setRadius(0.5f * visualParticle->width); break; case NX_SHAPE_CAPSULE: { (static_cast<NxCapsuleShape*>(shape))->setRadius(0.5f * visualParticle->width); (static_cast<NxCapsuleShape*>(shape))->setHeight(0.5f * visualParticle->height); } break; } } } } }
virtual void onContactNotify(NxContactPair& pair, NxU32 events) { NxU32 carIndex = 0; if (isCar(pair.actors[0])) carIndex = 0; else if (isCar(pair.actors[1])) carIndex = 1; else return; //ignore the 'both are cars' case for now. // Iterate through contact points NxContactStreamIterator i(pair.stream); //user can call getNumPairs() here while (i.goNextPair()) { //user can also call getShape() and getNumPatches() here NxShape * s = i.getShape(carIndex); while (i.goNextPatch()) { //user can also call getPatchNormal() and getNumPoints() here const NxVec3& contactNormal = i.getPatchNormal(); while (i.goNextPoint()) { //user can also call getPoint() and getSeparation() here const NxVec3& contactPoint = i.getPoint(); NxVec3 contactNormalForce = pair.sumNormalForce; NxVec3 contactFrictionForce = pair.sumFrictionForce; //add forces: //assuming front wheel drive we need to apply a force at the wheels. if (s->is(NX_SHAPE_CAPSULE)) //assuming only the wheels of the car are capsules, otherwise we need more checks. //this branch can't be pulled out of loops because we have to do a full iteration through the stream { CarWheelContact cwc; cwc.car = pair.actors[carIndex]; cwc.wheel = s; cwc.contactPoint = contactPoint; cwc.contactNormalForce = contactNormalForce; cwc.contactFrictionForce = contactFrictionForce; wheelContactPoints.pushBack(cwc); //#error too bad this is illegal (reentry) and also technically busted because the accumulators get zeroed after this returns. //pair.actors[carIndex]->addForceAtPos(NxVec3(100,0,0),contactPoint); } } } } }
void plPXPhysical::ExcludeRegionHack(bool cleared) { NxShape* shape = fActor->getShapes()[0]; shape->setFlag(NX_TRIGGER_ON_ENTER, !cleared); shape->setFlag(NX_TRIGGER_ON_LEAVE, !cleared); fGroup = cleared ? plSimDefs::kGroupExcludeRegion : plSimDefs::kGroupDetector; shape->setGroup(fGroup); /*if switching a static need to inform the controller that it needs to rebuild the collision cache otherwise will still think that the detector is still static or that the static is still a detector*/ plPXPhysicalControllerCore::RebuildCache(); }
//************************************ // Method: PBSetTriggerMask // FullName: PBSetTriggerMask // Access: public // Returns: int // Qualifier: // Parameter: const CKBehaviorContext& behcontext //************************************ int PBSetTriggerMask(const CKBehaviorContext& behcontext) { CKBehavior* beh = behcontext.Behavior; CKContext* ctx = behcontext.Context; PhysicManager *pm = GetPMan(); pFactory *pf = pFactory::Instance(); using namespace vtTools::BehaviorTools; if( beh->IsInputActive(0) ) { beh->ActivateInput(0,FALSE); ////////////////////////////////////////////////////////////////////////// //the object : CK3dEntity *target = (CK3dEntity *) beh->GetTarget(); if( !target ) return CKBR_OWNERERROR; ////////////////////////////////////////////////////////////////////////// // the world : pWorld *world = GetPMan()->getWorldByShapeReference(target); if (!world) { beh->ActivateOutput(0); return 0; } if (world) { NxShape *shape = world->getShapeByEntityID(target->GetID()); if (shape) { int onEnter = GetInputParameterValue<int>(beh,bbI_OnEnter); int onStay = GetInputParameterValue<int>(beh,bbI_OnStay); int onLeave = GetInputParameterValue<int>(beh,bbI_OnLeave); shape->setFlag(NX_TRIGGER_ON_ENTER,onEnter); shape->setFlag(NX_TRIGGER_ON_STAY,onStay); shape->setFlag(NX_TRIGGER_ON_LEAVE,onLeave); } } beh->ActivateOutput(0); } return 0; }
//NX_STATIC_SHAPES,NX_DYNAMIC_SHAPES,NX_ALL_SHAPES GameObject* PhysicsManager::castRayGetClosest(Vector3 startPosition, Vector3 direction, bool omitTriggers,bool omitActors, bool omitStatic, bool omitDynamic, bool omitCharacters) { NxRay worldRay; worldRay.orig = NxTools::convert(startPosition); worldRay.dir = NxTools::convert(direction); NxShapesType flags = NX_ALL_SHAPES; // NxShapeType::; NxRaycastHit hit; NxShape* shape = mScene->raycastClosestShape(worldRay, flags, hit); if(shape) { NxActor& actor = shape->getActor(); if(!omitTriggers) { CPhysicsTrigger* trigger = static_cast<CPhysicsTrigger*>(actor.userData); if(trigger) return trigger->getOwnerObject(); } if(!omitActors) { CPhysicsActor* physicsActor = static_cast<CPhysicsActor*>(actor.userData); if(physicsActor) { //if(!omitDynamic) { // if(physicsActor->isDynamic()) { return physicsActor->getOwnerObject(); // } //} else { //} } } if(!omitCharacters) { CCharacterController* character = static_cast<CCharacterController*>(actor.userData); if(character) return character->getOwnerObject(); } } //if(shape) // return hit.distance; //else // return 0; return NULL; }
void myTrigger::onTrigger(NxShape& triggerShape, NxShape& otherShape, NxTriggerFlag status){ if ( ! triggerShape.getActor().userData && ! otherShape.getActor().userData ) { return; } if (status & NX_TRIGGER_ON_ENTER) { // A body just entered the trigger area NxActor* triggerActor = &triggerShape.getActor(); String name = triggerActor->getName(); int thisTarget = StringConverter::parseInt(name); creditTarget(thisTarget); } }
void CPhysicsManager::ReleaseActorCapsule (CPhysicActor* actor) { assert(actor != NULL); assert(m_pScene != NULL); assert(m_pPhysicsSDK != NULL); NxActor* nxActor = actor->GetPhXActor(); if( nxActor != 0) { NxArray<NxCCDSkeleton*> skeletons; for (NxU32 i = 0; i < nxActor->getNbShapes(); i++) { NxShape* shape = nxActor->getShapes()[i]; if (shape->isCapsule()) shape->setGroup(ECG_LAST_GROUP); } } }
void CPhysicsActor::SetCollisionGroup( COLLISIONGROUP group ) { unsigned int numShapes = m_Actor->getNbShapes(); NxShape*const* shapes = m_Actor->getShapes(); NxShape* shape; if( group < 0 || group >= 32 ) { m_ToolBox->Log( LOGERROR, _T("CPhysicsObject::SetCollisionGroup() Invalid collision group! Group must be between 1-31!\n") ); return; } while( numShapes-- ) { shape = shapes[numShapes]; shape->setGroup( group ); } }
virtual void onTrigger(NxShape& triggerShape, NxShape& otherShape, NxTriggerFlag status) { plKey otherKey = nil; bool doReport = false; // Get our trigger physical. This should definitely have a plPXPhysical plPXPhysical* triggerPhys = (plPXPhysical*)triggerShape.getActor().userData; // Get the triggerer. If it doesn't have a plPXPhyscial, it's an avatar plPXPhysical* otherPhys = (plPXPhysical*)otherShape.getActor().userData; if (otherPhys) { otherKey = otherPhys->GetObjectKey(); doReport = triggerPhys->DoReportOn((plSimDefs::Group)otherPhys->GetGroup()); } else { plPXPhysicalControllerCore* controller = plPXPhysicalControllerCore::GetController(otherShape.getActor()); if (controller) { otherKey = controller->GetOwner(); doReport = triggerPhys->DoReportOn(plSimDefs::kGroupAvatar); } } if (doReport) { if (status & NX_TRIGGER_ON_ENTER) { if (plSimulationMgr::fExtraProfile) DetectorLogRed("-->Send Collision %s enter",triggerPhys->GetObjectKey()->GetName().c_str()); plSimulationMgr::GetInstance()->AddCollisionMsg(triggerPhys->GetObjectKey(), otherKey, true); } else if (status & NX_TRIGGER_ON_LEAVE) { if (plSimulationMgr::fExtraProfile) DetectorLogRed("-->Send Collision %s exit",triggerPhys->GetObjectKey()->GetName().c_str()); plSimulationMgr::GetInstance()->AddCollisionMsg(triggerPhys->GetObjectKey(), otherKey, false); } } }
void CPhysicsActor::SetShapeFlag( int flag, bool enable ) { NxShapeFlag nxShapeFlag = (NxShapeFlag) flag; if( m_Actor == NULL ) { m_ToolBox->Log( LOGERROR, _T("CPhysicsObject::SetShapeFlag() Actor is NULL.\n") ); return; } // Loop through shapes in the actor unsigned int numShapes = m_Actor->getNbShapes(); NxShape*const* shapes = m_Actor->getShapes(); NxShape* shape; while( numShapes-- ) { shape = shapes[numShapes]; shape->setFlag( nxShapeFlag, enable ); } }
NxActor*pWheel2::getTouchedActor()const { NxWheelContactData wcd; NxShape * s = mWheelShape->getContact(wcd); if (s) { if (&s->getActor()) { return &s->getActor(); }else { return NULL; } }else { return NULL; } return NULL; //return s ? &s->getActor() : NULL; }
virtual void onTrigger(NxShape& triggerShape, NxShape& otherShape, NxTriggerFlag status) { // other actor is a trigger too? if (*(int *)(&otherShape.getActor().userData) < 0) return; NxActor& triggerActor = triggerShape.getActor(); NxI32 triggerNumber = -(*(int *)(&triggerActor.userData)); NxI32 triggerIndex = triggerNumber - 1; if(status & NX_TRIGGER_ON_ENTER) { // A body entered the trigger area for the first time gNbTouchedBodies[triggerIndex]++; } if(status & NX_TRIGGER_ON_LEAVE) { // A body left the trigger area gNbTouchedBodies[triggerIndex]--; } NX_ASSERT(gNbTouchedBodies[triggerIndex]>=0); //Shouldn't go negative }
CPhysicUserData* CPhysicsManager::RaycastClosestActorShoot (const Vect3f posRay, const Vect3f& dirRay, uint32 impactMask, SCollisionInfo& info, float _fPower) { //NxUserRaycastReport::ALL_SHAPES assert(m_pScene != NULL); NxRay ray; ray.dir = NxVec3(dirRay.x, dirRay.y, dirRay.z); ray.orig = NxVec3(posRay.x, posRay.y, posRay.z); NxRaycastHit hit; NxShape* closestShape = NULL; closestShape = m_pScene->raycastClosestShape(ray, NX_ALL_SHAPES, hit, impactMask); if (!closestShape) { //No hemos tokado a ningún objeto físico de la escena. return NULL; } NxActor* actor = &closestShape->getActor(); CPhysicUserData* impactObject =(CPhysicUserData*)actor->userData; //Si está petando aquí quiere decir que se ha registrado un objeto físico sin proporcionarle UserData assert(impactObject); info.m_fDistance = hit.distance; info.m_Normal = Vect3f(hit.worldNormal.x, hit.worldNormal.y, hit.worldNormal.z ); info.m_CollisionPoint = Vect3f(hit.worldImpact.x, hit.worldImpact.y, hit.worldImpact.z ); Vect3f l_vDirection(dirRay.x-posRay.x,dirRay.y-posRay.y,dirRay.z-posRay.z); l_vDirection.Normalize(); NxVec3 l_vDirectionVec(dirRay.x,dirRay.y,dirRay.z); NxF32 coeff = actor->getMass() * _fPower; actor->addForceAtLocalPos(l_vDirectionVec*coeff, NxVec3(0,0,0), NX_IMPULSE,true); return impactObject; }
void AddUserDataToShapes(NxActor* actor) { NxU32 i = 0; NxShape*const* shapes = actor->getShapes(); NxU32 nbShapes = actor->getNbShapes(); while (nbShapes--) { NxShape* shape = shapes[nbShapes]; shape->userData = new ShapeUserData; ShapeUserData* sud = (ShapeUserData*)(shape->userData); sud->id = i++; if (shape->getType() == NX_SHAPE_CONVEX) { sud->mesh = new NxConvexMeshDesc; shape->isConvexMesh()->getConvexMesh().saveToDesc(*(NxConvexMeshDesc*)sud->mesh); } if (shape->getType() == NX_SHAPE_MESH) { sud->mesh = new NxTriangleMeshDesc; shape->isTriangleMesh()->getTriangleMesh().saveToDesc(*(NxTriangleMeshDesc*)sud->mesh); } } }
void Pick(int x, int y) { LetGo(); NxRay ray; ViewUnProject(x, y, 0.0f, ray.orig); ViewUnProject(x, y, 1.0f, ray.dir); ray.dir -= ray.orig; ray.dir.normalize(); NxRaycastHit hit; NxShape* closestShape = gScene->raycastClosestShape(ray, NX_ALL_SHAPES, hit); NxVec3 origin = ray.orig; NxVec3 impact = hit.worldImpact; NxReal distRB = NX_MAX_REAL; if (closestShape && closestShape->getActor().isDynamic()) { distRB = (impact.x - origin.x) * (impact.x - origin.x) + (impact.y - origin.y) * (impact.y - origin.y) + (impact.z - origin.z) * (impact.z - origin.z); } NxVec3 hitcloth, hitRecord; NxU32 vertexId; NxReal distCloth, closest= NX_MAX_REAL; NxU32 indexCloth, indexClothVertex; NxCloth **cloths = gScene->getCloths(); for (NxU32 i = 0; i < gScene->getNbCloths(); i++) { if (cloths[i]->raycast(ray, hitcloth, vertexId)) { distCloth = (hitcloth.x - origin.x) * (hitcloth.x - origin.x) + (hitcloth.y - origin.y) * (hitcloth.y - origin.y) + (hitcloth.z - origin.z) * (hitcloth.z - origin.z); if(distCloth < closest) { closest = distCloth; indexCloth = i; indexClothVertex = vertexId; hitRecord = hitcloth; } } } if (distRB > closest) // Pick cloth { gHitCloth = cloths[indexCloth]; gHitClothVertex = indexClothVertex; int hitx, hity; ViewProject(hitRecord, hitx, hity, gMouseDepth); } else if (distRB < closest) // Pick actor { gHitActor = &closestShape->getActor(); gHitActor->wakeUp(); int hitx, hity; gMouseSphere = CreateSphere(hit.worldImpact, 0.1, 1); gMouseSphere->raiseBodyFlag(NX_BF_KINEMATIC); gMouseSphere->raiseActorFlag(NX_AF_DISABLE_COLLISION); ViewProject(hit.worldImpact, hitx, hity, gMouseDepth); NxDistanceJointDesc desc; desc.actor[0] = gMouseSphere; desc.actor[1] = gHitActor; gMouseSphere->getGlobalPose().multiplyByInverseRT(hit.worldImpact, desc.localAnchor[0]); gHitActor->getGlobalPose().multiplyByInverseRT(hit.worldImpact, desc.localAnchor[1]); desc.spring.damper = 1; desc.spring.spring = 200; desc.flags |= NX_DJF_MAX_DISTANCE_ENABLED | NX_DJF_SPRING_ENABLED; NxJoint* joint = gScene->createJoint(desc); gMouseJoint = (NxDistanceJoint*)joint->is(NX_JOINT_DISTANCE); } }
virtual void onTrigger(NxShape& triggerShape, NxShape& otherShape, NxTriggerFlag status) { // Get our trigger physical. This should definitely have a plPXPhysical plPXPhysical* triggerPhys = (plPXPhysical*)triggerShape.getActor().userData; bool doReport = false; // Get the triggerer. This may be an avatar, which doesn't have a // plPXPhysical, so we have to extract the necessary info. plKey otherKey = nil; hsPoint3 otherPos = plPXConvert::Point(otherShape.getGlobalPosition()); if (plSimulationMgr::fExtraProfile) DetectorLogRed("-->%s %s (status=%x) other@(%f,%f,%f)",triggerPhys->GetObjectKey()->GetName().c_str(),status & NX_TRIGGER_ON_ENTER ? "enter" : "exit",status,otherPos.fX,otherPos.fY,otherPos.fZ); plPXPhysical* otherPhys = (plPXPhysical*)otherShape.getActor().userData; if (otherPhys) { otherKey = otherPhys->GetObjectKey(); doReport = triggerPhys->DoReportOn((plSimDefs::Group)otherPhys->GetGroup()); if (!doReport) { if (plSimulationMgr::fExtraProfile) DetectorLogRed("<--Kill collision %s :failed group. US=%x OTHER=(%s)%x",triggerPhys->GetObjectKey()->GetName().c_str(),triggerPhys->GetGroup(),otherPhys->GetObjectKey()->GetName().c_str(),otherPhys->GetGroup()); } } else { bool isController; plPXPhysicalControllerCore* controller = plPXPhysicalControllerCore::GetController(otherShape.getActor(),&isController); if (controller) { if (isController) { #ifdef PHYSX_ONLY_TRIGGER_FROM_KINEMATIC if (plSimulationMgr::fExtraProfile) DetectorLogRed("<--Kill collision %s : ignoring controller events.",triggerPhys->GetObjectKey()->GetName().c_str()); return; #else // else if trigger on both controller and kinematic // only suppress controller collision 'enters' when disabled but let 'exits' continue // ...this is because there are detector regions that are on the edge on ladders that the exit gets missed. if ( ( !controller->IsEnabled() /*&& (status & NX_TRIGGER_ON_ENTER)*/ ) || controller->IsKinematic() ) { if (plSimulationMgr::fExtraProfile) DetectorLogRed("<--Kill collision %s : controller is not enabled.",triggerPhys->GetObjectKey()->GetName().c_str()); return; } #endif // PHYSX_ONLY_TRIGGER_FROM_KINEMATIC } #ifndef PHYSX_ONLY_TRIGGER_FROM_KINEMATIC // if triggering only kinematics, then all should trigger else { // only suppress kinematic collision 'enters' when disabled but let 'exits' continue // ...this is because there are detector regions that are on the edge on ladders that the exit gets missed. if ( !controller->IsKinematic() /*&& (status & NX_TRIGGER_ON_ENTER) */ ) { if (plSimulationMgr::fExtraProfile) DetectorLogRed("<--Kill collision %s : kinematic is not enabled.",triggerPhys->GetObjectKey()->GetName().c_str()); return; } } #endif // PHYSX_ONLY_TRIGGER_FROM_KINEMATIC otherKey = controller->GetOwner(); doReport = triggerPhys->DoReportOn(plSimDefs::kGroupAvatar); if (plSimulationMgr::fExtraProfile ) { if (!doReport) { DetectorLogRed("<--Kill collision %s :failed group. US=%x OTHER=(NotAvatar)",triggerPhys->GetObjectKey()->GetName().c_str(),triggerPhys->GetGroup()); } else { hsPoint3 avpos; controller->GetPositionSim(avpos); DetectorLogRed("-->Avatar at (%f,%f,%f)",avpos.fX,avpos.fY,avpos.fZ); } } } } if (doReport) { #ifdef USE_PHYSX_CONVEXHULL_WORKAROUND if ( triggerPhys->DoDetectorHullWorkaround() ) { if (status & NX_TRIGGER_ON_ENTER && triggerPhys->Should_I_Trigger(status & NX_TRIGGER_ON_ENTER, otherPos) ) { if (plSimulationMgr::fExtraProfile) DetectorLogRed("-->Send Collision (CH) %s %s",triggerPhys->GetObjectKey()->GetName().c_str(),status & NX_TRIGGER_ON_ENTER ? "enter" : "exit"); plSimulationMgr::GetInstance()->AddCollisionMsg(triggerPhys->GetObjectKey(), otherKey, true); } else if (status & NX_TRIGGER_ON_ENTER) { if (plSimulationMgr::fExtraProfile) DetectorLogRed("<--Kill collision %s :failed Should I trigger",triggerPhys->GetObjectKey()->GetName().c_str()); } if (status & NX_TRIGGER_ON_LEAVE && triggerPhys->Should_I_Trigger(status & NX_TRIGGER_ON_ENTER, otherPos) ) { if (plSimulationMgr::fExtraProfile) DetectorLogRed("-->Send Collision (CH) %s %s",triggerPhys->GetObjectKey()->GetName().c_str(),status & NX_TRIGGER_ON_ENTER ? "enter" : "exit"); plSimulationMgr::GetInstance()->AddCollisionMsg(triggerPhys->GetObjectKey(), otherKey, false); } else if (status & NX_TRIGGER_ON_LEAVE) { if (plSimulationMgr::fExtraProfile) DetectorLogRed("<--Kill collision %s :failed Should I trigger",triggerPhys->GetObjectKey()->GetName().c_str()); } if (!(status & NX_TRIGGER_ON_ENTER) && !(status & NX_TRIGGER_ON_LEAVE) ) { if (plSimulationMgr::fExtraProfile) DetectorLogRed("<--Kill collision %s :failed event(CH)",triggerPhys->GetObjectKey()->GetName().c_str()); } } else { #endif // USE_PHYSX_CONVEXHULL_WORKAROUND if (status & NX_TRIGGER_ON_ENTER) { if (plSimulationMgr::fExtraProfile) DetectorLogRed("-->Send Collision %s %s",triggerPhys->GetObjectKey()->GetName().c_str(),status & NX_TRIGGER_ON_ENTER ? "enter" : "exit"); plSimulationMgr::GetInstance()->AddCollisionMsg(triggerPhys->GetObjectKey(), otherKey, true); } if (status & NX_TRIGGER_ON_LEAVE) { if (plSimulationMgr::fExtraProfile) DetectorLogRed("-->Send Collision %s %s",triggerPhys->GetObjectKey()->GetName().c_str(),status & NX_TRIGGER_ON_ENTER ? "enter" : "exit"); plSimulationMgr::GetInstance()->AddCollisionMsg(triggerPhys->GetObjectKey(), otherKey, false); } if (!(status & NX_TRIGGER_ON_ENTER) && !(status & NX_TRIGGER_ON_LEAVE) ) { if (plSimulationMgr::fExtraProfile) DetectorLogRed("<--Kill collision %s :failed event",triggerPhys->GetObjectKey()->GetName().c_str()); } #ifdef USE_PHYSX_CONVEXHULL_WORKAROUND } #endif // USE_PHYSX_CONVEXHULL_WORKAROUND } }
bool plPXPhysical::Init(PhysRecipe& recipe) { bool startAsleep = false; fBoundsType = recipe.bounds; fGroup = recipe.group; fReportsOn = recipe.reportsOn; fObjectKey = recipe.objectKey; fSceneNode = recipe.sceneNode; fWorldKey = recipe.worldKey; NxActorDesc actorDesc; NxSphereShapeDesc sphereDesc; NxConvexShapeDesc convexShapeDesc; NxTriangleMeshShapeDesc trimeshShapeDesc; NxBoxShapeDesc boxDesc; plPXConvert::Matrix(recipe.l2s, actorDesc.globalPose); switch (fBoundsType) { case plSimDefs::kSphereBounds: { hsMatrix44 sphereL2W; sphereL2W.Reset(); sphereL2W.SetTranslate(&recipe.offset); sphereDesc.radius = recipe.radius; plPXConvert::Matrix(sphereL2W, sphereDesc.localPose); sphereDesc.group = fGroup; actorDesc.shapes.pushBack(&sphereDesc); } break; case plSimDefs::kHullBounds: // FIXME PHYSX - Remove when hull detection is fixed // If this is read time (ie, meshStream is nil), turn the convex hull // into a box. That way the data won't have to change when convex hulls // actually work right. if (fGroup == plSimDefs::kGroupDetector && recipe.meshStream == nil) { #ifdef USE_BOXES_FOR_DETECTOR_HULLS MakeBoxFromHull(recipe.convexMesh, boxDesc); plSimulationMgr::GetInstance()->GetSDK()->releaseConvexMesh(*recipe.convexMesh); boxDesc.group = fGroup; actorDesc.shapes.push_back(&boxDesc); #else #ifdef USE_PHYSX_CONVEXHULL_WORKAROUND // make a hull of planes for testing IsInside IMakeHull(recipe.convexMesh,recipe.l2s); #endif // USE_PHYSX_CONVEXHULL_WORKAROUND convexShapeDesc.meshData = recipe.convexMesh; convexShapeDesc.userData = recipe.meshStream; convexShapeDesc.group = fGroup; actorDesc.shapes.pushBack(&convexShapeDesc); #endif // USE_BOXES_FOR_DETECTOR_HULLS } else { convexShapeDesc.meshData = recipe.convexMesh; convexShapeDesc.userData = recipe.meshStream; convexShapeDesc.group = fGroup; actorDesc.shapes.pushBack(&convexShapeDesc); } break; case plSimDefs::kBoxBounds: { boxDesc.dimensions = plPXConvert::Point(recipe.bDimensions); hsMatrix44 boxL2W; boxL2W.Reset(); boxL2W.SetTranslate(&recipe.bOffset); plPXConvert::Matrix(boxL2W, boxDesc.localPose); boxDesc.group = fGroup; actorDesc.shapes.push_back(&boxDesc); } break; case plSimDefs::kExplicitBounds: case plSimDefs::kProxyBounds: if (fGroup == plSimDefs::kGroupDetector) { SimLog("Someone using an Exact on a detector region: %s", GetKeyName().c_str()); } trimeshShapeDesc.meshData = recipe.triMesh; trimeshShapeDesc.userData = recipe.meshStream; trimeshShapeDesc.group = fGroup; actorDesc.shapes.pushBack(&trimeshShapeDesc); break; default: hsAssert(false, "Unknown geometry type during read."); return false; break; } // Now fill out the body, or dynamic part of the physical NxBodyDesc bodyDesc; fMass = recipe.mass; if (recipe.mass != 0) { bodyDesc.mass = recipe.mass; actorDesc.body = &bodyDesc; if (GetProperty(plSimulationInterface::kPinned)) { bodyDesc.flags |= NX_BF_FROZEN; startAsleep = true; // put it to sleep if they are going to be frozen } if (fGroup != plSimDefs::kGroupDynamic || GetProperty(plSimulationInterface::kPhysAnim)) { SetProperty(plSimulationInterface::kPassive, true); // Even though the code for animated physicals and animated activators are the same // keep these code snippets separated for fine tuning. Thanks. if (fGroup == plSimDefs::kGroupDynamic) { // handle the animated physicals.... make kinematic for now. fNumberAnimatedPhysicals++; bodyDesc.flags |= NX_BF_KINEMATIC; startAsleep = true; } else { // handle the animated activators.... fNumberAnimatedActivators++; bodyDesc.flags |= NX_BF_KINEMATIC; startAsleep = true; } } } else { if ( GetProperty(plSimulationInterface::kPhysAnim) ) SimLog("An animated physical that has no mass: %s", GetKeyName().c_str()); } actorDesc.userData = this; actorDesc.name = GetKeyName().c_str(); // Put the dynamics into actor group 1. The actor groups are only used for // deciding who we get contact reports for. if (fGroup == plSimDefs::kGroupDynamic) actorDesc.group = 1; NxScene* scene = plSimulationMgr::GetInstance()->GetScene(fWorldKey); try { fActor = scene->createActor(actorDesc); } catch (...) { hsAssert(false, "Actor creation crashed"); return false; } hsAssert(fActor, "Actor creation failed"); if (!fActor) return false; NxShape* shape = fActor->getShapes()[0]; shape->setMaterial(plSimulationMgr::GetInstance()->GetMaterialIdx(scene, recipe.friction, recipe.restitution)); // Turn on the trigger flags for any detectors. // // Normally, we'd set these flags on the shape before it's created. However, // in the case where the detector is going to be animated, it'll have a rigid // body too, and that will cause problems at creation. According to Ageia, // a detector shape doesn't actually count as a shape, so the SDK will have // problems trying to calculate an intertial tensor. By letting it be // created as a normal dynamic first, then setting the flags, we work around // that problem. if (fGroup == plSimDefs::kGroupDetector) { shape->setFlag(NX_TRIGGER_ON_ENTER, true); shape->setFlag(NX_TRIGGER_ON_LEAVE, true); } if (GetProperty(plSimulationInterface::kStartInactive) || startAsleep) { if (!fActor->isSleeping()) { if (plSimulationMgr::fExtraProfile) SimLog("Deactivating %s in SetPositionAndRotationSim", GetKeyName().c_str()); fActor->putToSleep(); } } if (GetProperty(plSimulationInterface::kDisable)) IEnable(false); if (GetProperty(plSimulationInterface::kSuppressed_DEAD)) IEnable(false); plNodeRefMsg* refMsg = new plNodeRefMsg(fSceneNode, plRefMsg::kOnCreate, -1, plNodeRefMsg::kPhysical); hsgResMgr::ResMgr()->AddViaNotify(GetKey(), refMsg, plRefFlags::kActiveRef); if (fWorldKey) { plGenRefMsg* ref = new plGenRefMsg(GetKey(), plRefMsg::kOnCreate, 0, kPhysRefWorld); hsgResMgr::ResMgr()->AddViaNotify(fWorldKey, ref, plRefFlags::kActiveRef); } // only dynamic physicals without noSync need SDLs if ( fGroup == plSimDefs::kGroupDynamic && !fProps.IsBitSet(plSimulationInterface::kNoSynchronize) ) { // add SDL modifier plSceneObject* sceneObj = plSceneObject::ConvertNoRef(fObjectKey->ObjectIsLoaded()); hsAssert(sceneObj, "nil sceneObject, failed to create and attach SDL modifier"); delete fSDLMod; fSDLMod = new plPhysicalSDLModifier; sceneObj->AddModifier(fSDLMod); } return true; }
// Make a visible object that can be viewed by users for debugging purposes. plDrawableSpans* plPXPhysical::CreateProxy(hsGMaterial* mat, hsTArray<uint32_t>& idx, plDrawableSpans* addTo) { plDrawableSpans* myDraw = addTo; hsMatrix44 l2w, unused; GetTransform(l2w, unused); bool blended = ((mat->GetLayer(0)->GetBlendFlags() & hsGMatState::kBlendMask)); NxShape* shape = fActor->getShapes()[0]; NxTriangleMeshShape* trimeshShape = shape->isTriangleMesh(); if (trimeshShape) { NxTriangleMeshDesc desc; trimeshShape->getTriangleMesh().saveToDesc(desc); hsTArray<hsPoint3> pos; hsTArray<uint16_t> tris; const int kMaxTris = 10000; const int kMaxVerts = 32000; if ((desc.numVertices < kMaxVerts) && (desc.numTriangles < kMaxTris)) { pos.SetCount(desc.numVertices); tris.SetCount(desc.numTriangles * 3); for (int i = 0; i < desc.numVertices; i++ ) pos[i] = GetTrimeshVert(desc, i); for (int i = 0; i < desc.numTriangles; i++) GetTrimeshTri(desc, i, &tris[i*3]); myDraw = plDrawableGenerator::GenerateDrawable(pos.GetCount(), pos.AcquireArray(), nil, // normals - def to avg (smooth) norm nil, // uvws 0, // uvws per vertex nil, // colors - def to white true, // do a quick fake shade nil, // optional color modulation tris.GetCount(), tris.AcquireArray(), mat, l2w, blended, &idx, myDraw); } else { int curTri = 0; int trisToDo = desc.numTriangles; while (trisToDo > 0) { int trisThisRound = trisToDo > kMaxTris ? kMaxTris : trisToDo; trisToDo -= trisThisRound; pos.SetCount(trisThisRound * 3); tris.SetCount(trisThisRound * 3); for (int i = 0; i < trisThisRound; i++) { GetTrimeshTri(desc, curTri, &tris[i*3]); pos[i*3 + 0] = GetTrimeshVert(desc, tris[i*3+0]); pos[i*3 + 1] = GetTrimeshVert(desc, tris[i*3+1]); pos[i*3 + 2] = GetTrimeshVert(desc, tris[i*3+2]); curTri++; } myDraw = plDrawableGenerator::GenerateDrawable(pos.GetCount(), pos.AcquireArray(), nil, // normals - def to avg (smooth) norm nil, // uvws 0, // uvws per vertex nil, // colors - def to white true, // do a quick fake shade nil, // optional color modulation tris.GetCount(), tris.AcquireArray(), mat, l2w, blended, &idx, myDraw); } } } NxConvexShape* convexShape = shape->isConvexMesh(); if (convexShape) { NxConvexMeshDesc desc; convexShape->getConvexMesh().saveToDesc(desc); hsTArray<hsPoint3> pos; hsTArray<uint16_t> tris; pos.SetCount(desc.numVertices); tris.SetCount(desc.numTriangles * 3); for (int i = 0; i < desc.numVertices; i++ ) pos[i] = GetConvexVert(desc, i); for (int i = 0; i < desc.numTriangles; i++) GetConvexTri(desc, i, &tris[i*3]); myDraw = plDrawableGenerator::GenerateDrawable(pos.GetCount(), pos.AcquireArray(), nil, // normals - def to avg (smooth) norm nil, // uvws 0, // uvws per vertex nil, // colors - def to white true, // do a quick fake shade nil, // optional color modulation tris.GetCount(), tris.AcquireArray(), mat, l2w, blended, &idx, myDraw); } NxSphereShape* sphere = shape->isSphere(); if (sphere) { float radius = sphere->getRadius(); hsPoint3 offset = plPXConvert::Point(sphere->getLocalPosition()); myDraw = plDrawableGenerator::GenerateSphericalDrawable(offset, radius, mat, l2w, blended, nil, &idx, myDraw); } NxBoxShape* box = shape->isBox(); if (box) { hsPoint3 dim = plPXConvert::Point(box->getDimensions()); myDraw = plDrawableGenerator::GenerateBoxDrawable(dim.fX*2.f, dim.fY*2.f, dim.fZ*2.f, mat,l2w,blended, nil,&idx,myDraw); } return myDraw; }
bool plPXPhysical::OverlapWithCapsule(NxCapsule& cap) { NxShape* shape = fActor->getShapes()[0]; return shape->checkOverlapCapsule(cap); }