void UBodySetup::AddConvexElemsToRigidActor(PxRigidActor* PDestActor, const FTransform& RelativeTM, const FVector& Scale3D, const FVector& Scale3DAbs, TArray<PxShape*>* NewShapes) const { float ContactOffsetFactor, MaxContactOffset; GetContactOffsetParams(ContactOffsetFactor, MaxContactOffset); PxMaterial* PDefaultMat = GetDefaultPhysMaterial(); for (int32 i = 0; i < AggGeom.ConvexElems.Num(); i++) { const FKConvexElem& ConvexElem = AggGeom.ConvexElems[i]; if (ConvexElem.ConvexMesh) { PxTransform PLocalPose; bool bUseNegX = CalcMeshNegScaleCompensation(Scale3D, PLocalPose); PxConvexMeshGeometry PConvexGeom; PConvexGeom.convexMesh = bUseNegX ? ConvexElem.ConvexMeshNegX : ConvexElem.ConvexMesh; PConvexGeom.scale.scale = U2PVector(Scale3DAbs * ConvexElem.GetTransform().GetScale3D().GetAbs()); FTransform ConvexTransform = ConvexElem.GetTransform(); if (ConvexTransform.GetScale3D().X < 0 || ConvexTransform.GetScale3D().Y < 0 || ConvexTransform.GetScale3D().Z < 0) { UE_LOG(LogPhysics, Warning, TEXT("AddConvexElemsToRigidActor: [%s] ConvexElem[%d] has negative scale. Not currently supported"), *GetPathNameSafe(GetOuter()), i); } if (ConvexTransform.IsValid()) { PxTransform PElementTransform = U2PTransform(ConvexTransform * RelativeTM); PLocalPose.q *= PElementTransform.q; PLocalPose.p = PElementTransform.p; PLocalPose.p.x *= Scale3D.X; PLocalPose.p.y *= Scale3D.Y; PLocalPose.p.z *= Scale3D.Z; if (PConvexGeom.isValid()) { PxVec3 PBoundsExtents = PConvexGeom.convexMesh->getLocalBounds().getExtents(); ensure(PLocalPose.isValid()); PxShape* NewShape = PDestActor->createShape(PConvexGeom, *PDefaultMat, PLocalPose); if (NewShapes) { NewShapes->Add(NewShape); } const float ContactOffset = FMath::Min(MaxContactOffset, ContactOffsetFactor * PBoundsExtents.minElement()); NewShape->setContactOffset(ContactOffset); } else { UE_LOG(LogPhysics, Warning, TEXT("AddConvexElemsToRigidActor: [%s] ConvexElem[%d] invalid"), *GetPathNameSafe(GetOuter()), i); } } else { UE_LOG(LogPhysics, Warning, TEXT("AddConvexElemsToRigidActor: [%s] ConvexElem[%d] has invalid transform"), *GetPathNameSafe(GetOuter()), i); } } else { UE_LOG(LogPhysics, Warning, TEXT("AddConvexElemsToRigidActor: ConvexElem is missing ConvexMesh (%d: %s)"), i, *GetPathName()); } } }
PxController* ControlledActor::init(const ControlledActorDesc& desc, PxControllerManager* manager) { const float radius = desc.mRadius; float height = desc.mHeight; float crouchHeight = desc.mCrouchHeight; PxControllerDesc* cDesc; PxBoxControllerDesc boxDesc; PxCapsuleControllerDesc capsuleDesc; if(desc.mType==PxControllerShapeType::eBOX) { height *= 0.5f; height += radius; crouchHeight *= 0.5f; crouchHeight += radius; boxDesc.halfHeight = height; boxDesc.halfSideExtent = radius; boxDesc.halfForwardExtent = radius; cDesc = &boxDesc; } else { PX_ASSERT(desc.mType==PxControllerShapeType::eCAPSULE); capsuleDesc.height = height; capsuleDesc.radius = radius; capsuleDesc.climbingMode = PxCapsuleClimbingMode::eCONSTRAINED; cDesc = &capsuleDesc; } cDesc->density = desc.mProxyDensity; cDesc->scaleCoeff = desc.mProxyScale; cDesc->material = &mOwner.getDefaultMaterial(); cDesc->position = desc.mPosition; cDesc->slopeLimit = desc.mSlopeLimit; cDesc->contactOffset = desc.mContactOffset; cDesc->stepOffset = desc.mStepOffset; cDesc->invisibleWallHeight = desc.mInvisibleWallHeight; cDesc->maxJumpHeight = desc.mMaxJumpHeight; // cDesc->nonWalkableMode = PxControllerNonWalkableMode::ePREVENT_CLIMBING_AND_FORCE_SLIDING; cDesc->reportCallback = desc.mReportCallback; cDesc->behaviorCallback = desc.mBehaviorCallback; cDesc->volumeGrowth = desc.mVolumeGrowth; mType = desc.mType; mInitialPosition = desc.mPosition; mStandingSize = height; mCrouchingSize = crouchHeight; mControllerRadius = radius; PxController* ctrl = static_cast<PxBoxController*>(manager->createController(*cDesc)); PX_ASSERT(ctrl); // remove controller shape from scene query for standup overlap test PxRigidDynamic* actor = ctrl->getActor(); if(actor) { if(actor->getNbShapes()) { PxShape* ctrlShape; actor->getShapes(&ctrlShape,1); ctrlShape->setFlag(PxShapeFlag::eSCENE_QUERY_SHAPE, false); Renderer* renderer = mOwner.getRenderer(); if(desc.mType==PxControllerShapeType::eBOX) { const PxVec3 standingExtents(radius, height, radius); const PxVec3 crouchingExtents(radius, crouchHeight, radius); mRenderActorStanding = SAMPLE_NEW(RenderBoxActor)(*renderer, standingExtents); mRenderActorCrouching = SAMPLE_NEW(RenderBoxActor)(*renderer, crouchingExtents); } else if(desc.mType==PxControllerShapeType::eCAPSULE) { mRenderActorStanding = SAMPLE_NEW(RenderCapsuleActor)(*renderer, radius, height*0.5f); mRenderActorCrouching = SAMPLE_NEW(RenderCapsuleActor)(*renderer, radius, crouchHeight*0.5f); } } } mController = ctrl; return ctrl; }
void SampleCustomGravityCameraController::update(Camera& camera, PxReal dtime) { const PxExtendedVec3& currentPos = mCCT.getPosition(); const PxVec3 curPos = toVec3(currentPos); // Compute up vector for current CCT position PxVec3 upVector; mBase.mPlanet.getUpVector(upVector, curPos); PX_ASSERT(upVector.isFinite()); // Update CCT if(!mBase.isPaused()) { if(1) { bool recordPos = true; const PxU32 currentSize = mNbRecords; if(currentSize) { const PxVec3 lastPos = mHistory[currentSize-1]; // const float limit = 0.1f; const float limit = 0.5f; if((curPos - lastPos).magnitude()<limit) recordPos = false; } if(recordPos) { if(mNbRecords==POS_HISTORY_LIMIT) { for(PxU32 i=1;i<mNbRecords;i++) mHistory[i-1] = mHistory[i]; mNbRecords--; } mHistory[mNbRecords++] = curPos; } } // Subtract off the 'up' component of the view direction to get our forward motion vector. PxVec3 viewDir = camera.getViewDir(); PxVec3 forward = (viewDir - upVector * upVector.dot(viewDir)).getNormalized(); // PxVec3 forward = mForward; // Compute "right" vector PxVec3 right = forward.cross(upVector); right.normalize(); // PxVec3 right = mRightV; PxVec3 targetKeyDisplacement(0); if(mFwd) targetKeyDisplacement += forward; if(mBwd) targetKeyDisplacement -= forward; if(mRight) targetKeyDisplacement += right; if(mLeft) targetKeyDisplacement -= right; targetKeyDisplacement *= mKeyShiftDown ? mRunningSpeed : mWalkingSpeed; // targetKeyDisplacement += PxVec3(0,-9.81,0); targetKeyDisplacement *= dtime; PxVec3 targetPadDisplacement(0); targetPadDisplacement += forward * mGamepadForwardInc * mRunningSpeed; targetPadDisplacement += right * mGamepadLateralInc * mRunningSpeed; // targetPadDisplacement += PxVec3(0,-9.81,0); targetPadDisplacement *= dtime; const PxF32 heightDelta = gJump.getHeight(dtime); // printf("%f\n", heightDelta); PxVec3 upDisp = upVector; if(heightDelta!=0.0f) upDisp *= heightDelta; else upDisp *= -9.81f * dtime; const PxVec3 disp = targetKeyDisplacement + targetPadDisplacement + upDisp; //upDisp.normalize(); //printf("%f | %f | %f\n", upDisp.x, upDisp.y, upDisp.z); // printf("%f | %f | %f\n", targetKeyDisplacement.x, targetKeyDisplacement.y, targetKeyDisplacement.z); // printf("%f | %f | %f\n\n", targetPadDisplacement.x, targetPadDisplacement.y, targetPadDisplacement.z); mCCT.setUpDirection(upVector); const PxU32 flags = mCCT.move(disp, 0.001f, dtime, PxControllerFilters()); if(flags & PxControllerFlag::eCOLLISION_DOWN) { gJump.stopJump(); // printf("Stop jump\n"); } } // Update camera if(1) { mTargetYaw += mGamepadYawInc * dtime; mTargetPitch += mGamepadPitchInc * dtime; // Clamp pitch // if(mTargetPitch<mPitchMin) mTargetPitch = mPitchMin; // if(mTargetPitch>mPitchMax) mTargetPitch = mPitchMax; } if(1) { PxVec3 up = upVector; PxQuat localPitchQ(mTargetPitch, PxVec3(1.0f, 0.0f, 0.0f)); PX_ASSERT(localPitchQ.isSane()); PxMat33 localPitchM(localPitchQ); const PxVec3 upRef(0.0f, 1.0f, 0.0f); PxQuat localYawQ(mTargetYaw, upRef); PX_ASSERT(localYawQ.isSane()); PxMat33 localYawM(localYawQ); bool res; PxQuat localToWorldQ = rotationArc(upRef, up, res); static PxQuat memory(0,0,0,1); if(!res) { localToWorldQ = memory; } else { memory = localToWorldQ; } PX_ASSERT(localToWorldQ.isSane()); PxMat33 localToWorld(localToWorldQ); static PxVec3 previousUp(0.0f, 1.0f, 0.0f); static PxQuat incLocalToWorldQ(0.0f, 0.0f, 0.0f, 1.0f); PxQuat incQ = rotationArc(previousUp, up, res); PX_ASSERT(incQ.isSane()); // incLocalToWorldQ = incLocalToWorldQ * incQ; incLocalToWorldQ = incQ * incLocalToWorldQ; PX_ASSERT(incLocalToWorldQ.isSane()); incLocalToWorldQ.normalize(); PxMat33 incLocalToWorldM(incLocalToWorldQ); localToWorld = incLocalToWorldM; previousUp = up; mTest = localToWorld; //mTest = localToWorld * localYawM; // PxMat33 rot = localYawM * localToWorld; PxMat33 rot = localToWorld * localYawM * localPitchM; // PxMat33 rot = localToWorld * localYawM; PX_ASSERT(rot.column0.isFinite()); PX_ASSERT(rot.column1.isFinite()); PX_ASSERT(rot.column2.isFinite()); //// PxMat44 view(rot.column0, rot.column1, rot.column2, PxVec3(0)); mForward = -rot.column2; mRightV = rot.column0; camera.setView(PxTransform(view)); PxVec3 viewDir = camera.getViewDir(); PX_ASSERT(viewDir.isFinite()); //// PxRigidActor* characterActor = mCCT.getActor(); PxShape* shape; characterActor->getShapes(&shape,1); PxCapsuleGeometry geom; shape->getCapsuleGeometry(geom); up *= geom.halfHeight+geom.radius; const PxVec3 headPos = curPos + up; const float distanceToTarget = 10.0f; // const float distanceToTarget = 20.0f; // const float distanceToTarget = 5.0f; // const PxVec3 camPos = headPos - viewDir*distanceToTarget; const PxVec3 camPos = headPos - mForward*distanceToTarget;// + up * 20.0f; // view.t = camPos; view.column3 = PxVec4(camPos,0); // camera.setView(view); camera.setView(PxTransform(view)); mTarget = headPos; } if(0) { PxControllerState cctState; mCCT.getState(cctState); printf("\nCCT state:\n"); printf("delta: %.02f | %.02f | %.02f\n", cctState.deltaXP.x, cctState.deltaXP.y, cctState.deltaXP.z); printf("touchedShape: %p\n", cctState.touchedShape); printf("touchedObstacle: %p\n", cctState.touchedObstacle); printf("standOnAnotherCCT: %d\n", cctState.standOnAnotherCCT); printf("standOnObstacle: %d\n", cctState.standOnObstacle); printf("isMovingUp: %d\n", cctState.isMovingUp); printf("collisionFlags: %d\n", cctState.collisionFlags); } }
void SampleParticles::Raygun::update(float dtime) { if(!isEnabled()) return; PX_ASSERT(mSample && mForceSmokeCapsule && mForceWaterCapsule && mRenderActor); // access properties from sample PxScene& scene = mSample->getActiveScene(); PxVec3 position = mSample->getCamera().getPos(); PxTransform cameraPose = mSample->getCamera().getViewMatrix(); PxMat33 cameraBase(cameraPose.q); PxVec3 cameraForward = -cameraBase[2]; PxVec3 cameraUp = -cameraBase[1]; // perform raycast here and update impact point PxRaycastHit hit; mIsImpacting = scene.raycastSingle(cameraPose.p, cameraForward, 500.0f, PxSceneQueryFlags(0xffffffff), hit); float impactParam = mIsImpacting ? (hit.impact - position).magnitude() : FLT_MAX; PxTransform rayPose(position + cameraUp * 0.5f, cameraPose.q*PxQuat(PxHalfPi, PxVec3(0,1,0))); updateRayCapsule(mForceSmokeCapsule, rayPose, 1.0f); updateRayCapsule(mForceWaterCapsule, rayPose, 0.3f); mRenderActor->setTransform(rayPose); // if we had an impact if (impactParam < FLT_MAX) { PxVec3 impactPos = position + cameraForward*impactParam; // update emitter with new impact point and direction if(mSmokeEmitter.emitter) mSmokeEmitter.emitter->setLocalPose(PxTransform(impactPos, directionToQuaternion(-cameraForward))); if(mDebrisEmitter.emitter) mDebrisEmitter.emitter->setLocalPose(PxTransform(impactPos, directionToQuaternion(-cameraForward))); // spawn new RB debris if(mRbDebrisTimer < 0.0f && impactParam < FLT_MAX) { mRbDebrisTimer = RAYGUN_RB_DEBRIS_RATE; PxVec3 randDir(getSampleRandom().rand(-1.0f, 1.0f), getSampleRandom().rand(-1.0f, 1.0f), getSampleRandom().rand(-1.0f, 1.0f)); PxVec3 vel = -7.0f * (cameraForward + RAYGUN_RB_DEBRIS_ANGLE_RANDOMNESS * randDir.getNormalized()); PxVec3 dim(getSampleRandom().rand(0.0f, RAYGUN_RB_DEBRIS_SCALE), getSampleRandom().rand(0.0f, RAYGUN_RB_DEBRIS_SCALE), getSampleRandom().rand(0.0f, RAYGUN_RB_DEBRIS_SCALE)); // give spawn position, initial velocity and dimensions, spawn convex // which will not act in scene queries PxConvexMesh* convexMesh = generateConvex(mSample->getPhysics(), mSample->getCooking(), RAYGUN_RB_DEBRIS_SCALE); mSample->runtimeAssert(convexMesh, "Error generating convex for debris.\n"); PxRigidDynamic* debrisActor = PxCreateDynamic( mSample->getPhysics(), PxTransform(impactPos - cameraForward * 0.5f), PxConvexMeshGeometry(convexMesh), mSample->getDefaultMaterial(), 1.f); mSample->getActiveScene().addActor(*debrisActor); PX_ASSERT(debrisActor->getNbShapes() == 1); PxShape* debrisShape; debrisActor->getShapes(&debrisShape, 1); debrisShape->setFlag(PxShapeFlag::eSCENE_QUERY_SHAPE, false); debrisActor->setLinearVelocity(vel); debrisActor->setActorFlag(PxActorFlag::eVISUALIZATION, true); debrisActor->setAngularDamping(0.5f); // default material is green for debris RenderMaterial* debriMaterial = mSample->getMaterial(MATERIAL_HEIGHTFIELD); if(!debriMaterial) { debriMaterial = mSample->mRenderMaterials[MATERIAL_GREEN]; } mSample->createRenderObjectsFromActor(debrisActor, debriMaterial); mDebrisLifetime[debrisShape] = RAYGUN_RB_DEBRIS_LIFETIME; } } // update debris lifetime, remove if life ends DebrisLifetimeMap::iterator it = mDebrisLifetime.begin(); while(it != mDebrisLifetime.end()) { (*it).second -= dtime; if((*it).second < 0.0f) { PxShape* debrisShape = (*it).first; PX_ASSERT(debrisShape); // remove convex mesh PxConvexMeshGeometry geometry; bool isConvex = debrisShape->getConvexMeshGeometry(geometry); PX_ASSERT(isConvex); PX_UNUSED(isConvex); geometry.convexMesh->release(); // remove render and physics actor PxRigidActor& actorToRemove = debrisShape->getActor(); mSample->removeActor(&actorToRemove); actorToRemove.release(); // remove actor from lifetime map mDebrisLifetime.erase(it); it = mDebrisLifetime.begin(); continue; } ++it; } }
void SampleParticles::loadTerrain(const char* path, PxReal xScale, PxReal yScale, PxReal zScale) { SampleFramework::SampleAsset* asset = getAsset(terrain_hf, SampleFramework::SampleAsset::ASSET_TEXTURE); mManagedAssets.push_back(asset); PX_ASSERT(asset->getType() == SampleFramework::SampleAsset::ASSET_TEXTURE); SampleFramework::SampleTextureAsset* texAsset = static_cast<SampleFramework::SampleTextureAsset*>(asset); SampleRenderer::RendererTexture2D* heightfieldTexture = texAsset->getTexture(); // NOTE: Assuming that heightfield texture has B8G8R8A8 format. if(heightfieldTexture) { PxU16 nbColumns = PxU16(heightfieldTexture->getWidth()); PxU16 nbRows = PxU16(heightfieldTexture->getHeight()); PxHeightFieldDesc heightFieldDesc; heightFieldDesc.nbColumns = nbColumns; heightFieldDesc.nbRows = nbRows; PxU32* samplesData = (PxU32*)SAMPLE_ALLOC(sizeof(PxU32) * nbColumns * nbRows); heightFieldDesc.samples.data = samplesData; heightFieldDesc.samples.stride = sizeof(PxU32); heightFieldDesc.convexEdgeThreshold = 0; PxU8* currentByte = (PxU8*)heightFieldDesc.samples.data; PxU32 texturePitch = 0; PxU8* loaderPtr = static_cast<PxU8*>(heightfieldTexture->lockLevel(0, texturePitch)); PxVec3Alloc* verticesA = SAMPLE_NEW(PxVec3Alloc)[nbRows * nbColumns]; PxVec3* vertices = verticesA; PxReal* UVs = (PxReal*)SAMPLE_ALLOC(sizeof(PxReal) * nbRows * nbColumns * 2); for (PxU32 row = 0; row < nbRows; row++) { for (PxU32 column = 0; column < nbColumns; column++) { PxHeightFieldSample* currentSample = (PxHeightFieldSample*)currentByte; currentSample->height = *loaderPtr; vertices[row * nbColumns + column] = PxVec3(PxReal(row) * xScale, PxReal(currentSample->height * zScale), PxReal(column) * yScale); UVs[2 * (row * nbColumns + column)] = (PxReal(row) / PxReal(nbRows)) * 7.0f; UVs[2 * (row * nbColumns + column) + 1] = (PxReal(column) / PxReal(nbColumns)) * 7.0f; currentSample->materialIndex0 = 0; currentSample->materialIndex1 = 0; currentSample->clearTessFlag(); currentByte += heightFieldDesc.samples.stride; loaderPtr += 4 * sizeof(PxU8); } } PxHeightField* heightField = getPhysics().createHeightField(heightFieldDesc); // free allocated memory for heightfield samples description SAMPLE_FREE(samplesData); // create shape for heightfield PxTransform pose(PxVec3(-((PxReal)nbRows*yScale) / 2.0f, 0.0f, -((PxReal)nbColumns*xScale) / 2.0f), PxQuat::createIdentity()); PxRigidActor* hf = getPhysics().createRigidStatic(pose); runtimeAssert(hf, "PxPhysics::createRigidStatic returned NULL\n"); PxShape* shape = hf->createShape(PxHeightFieldGeometry(heightField, PxMeshGeometryFlags(), zScale, xScale, yScale), getDefaultMaterial()); runtimeAssert(shape, "PxRigidActor::createShape returned NULL\n"); shape->setFlag(PxShapeFlag::ePARTICLE_DRAIN, false); shape->setFlag(PxShapeFlag::eSIMULATION_SHAPE, true); // add actor to the scene getActiveScene().addActor(*hf); mPhysicsActors.push_back(hf); // create indices and UVs PxU32* indices = (PxU32*)SAMPLE_ALLOC(sizeof(PxU32) * (nbColumns - 1) * (nbRows - 1) * 3 * 2); for(int i = 0; i < (nbColumns - 1); ++i) { for(int j = 0; j < (nbRows - 1); ++j) { // first triangle indices[6 * (i * (nbRows - 1) + j) + 0] = (i + 1) * nbRows + j; indices[6 * (i * (nbRows - 1) + j) + 1] = i * nbRows + j; indices[6 * (i * (nbRows - 1) + j) + 2] = i * nbRows + j + 1; // second triangle indices[6 * (i * (nbRows - 1) + j) + 3] = (i + 1) * nbRows + j + 1; indices[6 * (i * (nbRows - 1) + j) + 4] = (i + 1) * nbRows + j; indices[6 * (i * (nbRows - 1) + j) + 5] = i * nbRows + j + 1; } } // add mesh to renderer RAWMesh data; data.mName = "terrain"; data.mTransform = PxTransform::createIdentity(); data.mNbVerts = nbColumns * nbRows; data.mVerts = (PxVec3*)vertices; data.mVertexNormals = NULL; data.mUVs = UVs; data.mMaterialID = MATERIAL_HEIGHTFIELD; data.mNbFaces = (nbColumns - 1) * (nbRows - 1) * 2; data.mIndices = indices; RenderMeshActor* hf_mesh = createRenderMeshFromRawMesh(data); hf_mesh->setPhysicsShape(shape); SAMPLE_FREE(indices); SAMPLE_FREE(UVs); DELETEARRAY(verticesA); } else { char errMsg[256]; physx::string::sprintf_s(errMsg, 256, "Couldn't load %s\n", path); fatalError(errMsg); } }
bool UWorld::ComponentOverlapTest(class UPrimitiveComponent* PrimComp, const FVector& Pos, const FRotator& Rot, const struct FComponentQueryParams& Params) const { if(GetPhysicsScene() == NULL) { return false; } if(PrimComp == NULL) { UE_LOG(LogCollision, Log, TEXT("ComponentOverlapMulti : No PrimComp")); return false; } // if target is skeletalmeshcomponent and do not support singlebody physics, we don't support this yet // talk to @JG, SP, LH if ( !PrimComp->ShouldTrackOverlaps() ) { UE_LOG(LogCollision, Log, TEXT("ComponentOverlapMulti : (%s) Does not support skeletalmesh with Physics Asset and destructibles."), *PrimComp->GetPathName()); return false; } #if WITH_PHYSX ECollisionChannel TraceChannel = PrimComp->GetCollisionObjectType(); PxRigidActor* PRigidActor = PrimComp->BodyInstance.GetPxRigidActor(); if(PRigidActor == NULL) { UE_LOG(LogCollision, Log, TEXT("ComponentOverlapMulti : (%s) No physics data"), *PrimComp->GetPathName()); return false; } // calculate the test global pose of the actor PxTransform PTestGlobalPose = U2PTransform(FTransform(Rot, Pos)); // Get all the shapes from the actor TArray<PxShape*, TInlineAllocator<8>> PShapes; PShapes.AddZeroed(PRigidActor->getNbShapes()); int32 NumShapes = PRigidActor->getShapes(PShapes.GetData(), PShapes.Num()); // Iterate over each shape for(int32 ShapeIdx=0; ShapeIdx<PShapes.Num(); ShapeIdx++) { PxShape* PShape = PShapes[ShapeIdx]; check(PShape); // Calc shape global pose PxTransform PLocalPose = PShape->getLocalPose(); PxTransform PShapeGlobalPose = PTestGlobalPose.transform(PLocalPose); GET_GEOMETRY_FROM_SHAPE(PGeom, PShape); if(PGeom != NULL) { if( GeomOverlapTest(this, *PGeom, PShapeGlobalPose, TraceChannel, Params, FCollisionResponseParams(PrimComp->GetCollisionResponseToChannels()))) { // in this test, it only matters true or false. // if we found first true, we don't care next test anymore. return true; } } } #endif //WITH_PHYSX return false; }
// Creates an physics entity from an entity info structure and a starting transform void PhysicsEngine::createEntity(PhysicsEntity* entity, PhysicsEntityInfo* info, PxTransform transform) { transform.p.y += info->yPosOffset; // Set static/dynamic info for actor depending on its type PxRigidActor* actor; if (info->type == PhysicsType::DYNAMIC) { DynamicInfo* dInfo = info->dynamicInfo; PxRigidDynamic* dynamicActor = physics->createRigidDynamic(transform); dynamicActor->setLinearDamping(dInfo->linearDamping); dynamicActor->setAngularDamping(dInfo->angularDamping); dynamicActor->setMaxAngularVelocity(dInfo->maxAngularVelocity); actor = dynamicActor; } else if (info->type == PhysicsType::STATIC) { PxRigidStatic* staticActor = physics->createRigidStatic(transform); actor = staticActor; } // All shapes in actor for (auto sInfo : info->shapeInfo) { // Create material and geometry for shape and add it to actor PxGeometry* geometry; PxMaterial* material; if (sInfo->geometry == Geometry::SPHERE) { SphereInfo* sphInfo = (SphereInfo*)sInfo; geometry = new PxSphereGeometry(sphInfo->radius); } else if (sInfo->geometry == Geometry::BOX) { BoxInfo* boxInfo = (BoxInfo*)sInfo; geometry = new PxBoxGeometry(boxInfo->halfX, boxInfo->halfY, boxInfo->halfZ); } else if (sInfo->geometry == Geometry::CAPSULE) { CapsuleInfo* capInfo = (CapsuleInfo*)sInfo; geometry = new PxCapsuleGeometry(capInfo->radius, capInfo->halfHeight); } else if (sInfo->geometry == Geometry::CONVEX_MESH) { ConvexMeshInfo* cmInfo = (ConvexMeshInfo*)sInfo; PxConvexMesh* mesh = helper->createConvexMesh(cmInfo->verts.data(), cmInfo->verts.size()); geometry = new PxConvexMeshGeometry(mesh); } // Not working until index drawing is set up else if (sInfo->geometry == Geometry::TRIANGLE_MESH) { TriangleMeshInfo* tmInfo = (TriangleMeshInfo*)sInfo; PxTriangleMesh* mesh = helper->createTriangleMesh(tmInfo->verts.data(), tmInfo->verts.size(), tmInfo->faces.data(), tmInfo->faces.size()/3); geometry = new PxTriangleMeshGeometry(mesh); } material = (sInfo->isDrivable) ? drivingSurfaces[0] : physics->createMaterial(sInfo->dynamicFriction, sInfo->staticFriction, sInfo->restitution); PxShape* shape = actor->createShape(*geometry, *material); // TODO support shape flags shape->setLocalPose(sInfo->transform); material->release(); delete geometry; // Set up querry filter data for shape PxFilterData qryFilterData; qryFilterData.word3 = (sInfo->isDrivable) ? (PxU32)Surface::DRIVABLE : (PxU32)Surface::UNDRIVABLE; shape->setQueryFilterData(qryFilterData); // Set up simulation filter data for shape PxFilterData simFilterData; simFilterData.word0 = (PxU32)sInfo->filterFlag0; simFilterData.word1 = (PxU32)sInfo->filterFlag1; simFilterData.word2 = (PxU32)sInfo->filterFlag2; simFilterData.word3 = (PxU32)sInfo->filterFlag3; shape->setSimulationFilterData(simFilterData); if (info->type == PhysicsType::DYNAMIC) { DynamicInfo* dInfo = info->dynamicInfo; PxRigidBodyExt::updateMassAndInertia(*(PxRigidBody*)actor, dInfo->density, &dInfo->cmOffset); PxRigidBody* body = (PxRigidBody*)actor; } } // Add actor to scene, set actor for entity, and set user data for actor. Creates one to one between entities and phyX scene->addActor(*actor); entity->setActor(actor); actor->userData = entity; }
//================================================================================= // Multiple hits compound sweep // AP: we might be able to improve the return results API but no time for it in 3.3 PxU32 PxRigidBodyExt::linearSweepMultiple( PxRigidBody& body, PxScene& scene, const PxVec3& unitDir, const PxReal distance, PxHitFlags outputFlags, PxSweepHit* hitBuffer, PxU32* hitShapeIndices, PxU32 hitBufferSize, PxSweepHit& block, PxI32& blockingHitShapeIndex, bool& overflow, const PxQueryFilterData& filterData, PxQueryFilterCallback* filterCall, const PxQueryCache* cache, const PxReal inflation) { overflow = false; blockingHitShapeIndex = -1; for (PxU32 i = 0; i < hitBufferSize; i++) hitShapeIndices[i] = 0xFFFFffff; PxI32 sumNbResults = 0; PxU32 nbShapes = body.getNbShapes(); PxF32 shrunkMaxDistance = distance; for(PxU32 i=0; i < nbShapes; i++) { PxShape* shape = NULL; body.getShapes(&shape, 1, i); PX_ASSERT(shape != NULL); PxTransform pose = PxShapeExt::getGlobalPose(*shape, body); PxQueryFilterData fd; fd.flags = filterData.flags; PxU32 or4 = (filterData.data.word0 | filterData.data.word1 | filterData.data.word2 | filterData.data.word3); fd.data = or4 ? filterData.data : shape->getSimulationFilterData(); PxGeometryHolder anyGeom = shape->getGeometry(); PxU32 bufSizeLeft = hitBufferSize-sumNbResults; PxSweepHit extraHit; PxSweepBuffer buffer(bufSizeLeft == 0 ? &extraHit : hitBuffer+sumNbResults, bufSizeLeft == 0 ? 1 : hitBufferSize-sumNbResults); scene.sweep(anyGeom.any(), pose, unitDir, shrunkMaxDistance, buffer, outputFlags, fd, filterCall, cache, inflation); // Check and abort on overflow. Assume overflow if result count is bufSize. PxU32 nbNewResults = buffer.getNbTouches(); overflow |= (nbNewResults >= bufSizeLeft); if (bufSizeLeft == 0) // this is for when we used the extraHit buffer nbNewResults = 0; // set hitShapeIndices for each new non-blocking hit for (PxU32 j = 0; j < nbNewResults; j++) if (sumNbResults + PxU32(j) < hitBufferSize) hitShapeIndices[sumNbResults+j] = i; if (buffer.hasBlock) // there's a blocking hit in the most recent sweepMultiple results { // overwrite the return result blocking hit with the new blocking hit if under if (blockingHitShapeIndex == -1 || buffer.block.distance < block.distance) { blockingHitShapeIndex = (PxI32)i; block = buffer.block; } // Remove all the old touching hits below the new maxDist // sumNbResults is not updated yet at this point // and represents the count accumulated so far excluding the very last query PxI32 nbNewResultsSigned = PxI32(nbNewResults); // need a signed version, see nbNewResultsSigned-- below for (PxI32 j = sumNbResults-1; j >= 0; j--) // iterate over "old" hits (up to shapeIndex-1) if (buffer.block.distance < hitBuffer[j].distance) { // overwrite with last "new" hit PxI32 sourceIndex = PxI32(sumNbResults)+nbNewResultsSigned-1; PX_ASSERT(sourceIndex >= j); hitBuffer[j] = hitBuffer[sourceIndex]; hitShapeIndices[j] = hitShapeIndices[sourceIndex]; nbNewResultsSigned--; // can get negative, that means we are shifting the last results array } sumNbResults += nbNewResultsSigned; } else // if there was no new blocking hit we don't need to do anything special, simply append all results to touch array sumNbResults += nbNewResults; PX_ASSERT(sumNbResults >= 0 && sumNbResults <= PxI32(hitBufferSize)); } return (PxU32)sumNbResults; }
PxRigidActor* SampleSubmarine::loadTerrain(const char* name, const PxReal heightScale, const PxReal rowScale, const PxReal columnScale) { PxRigidActor* heightFieldActor = NULL; BmpLoader loader; if(loader.loadBmp(getSampleMediaFilename(name))) { PxU16 nbColumns = PxU16(loader.mWidth), nbRows = PxU16(loader.mHeight); PxHeightFieldDesc heightFieldDesc; heightFieldDesc.nbColumns = nbColumns; heightFieldDesc.nbRows = nbRows; PxU32* samplesData = (PxU32*)SAMPLE_ALLOC(sizeof(PxU32)*nbColumns * nbRows); heightFieldDesc.samples.data = samplesData; heightFieldDesc.samples.stride = sizeof(PxU32); PxU8* currentByte = (PxU8*)heightFieldDesc.samples.data; PxU8* loader_ptr = loader.mRGB; PxVec3Alloc* vertexesA = SAMPLE_NEW(PxVec3Alloc)[nbRows * nbColumns]; PxF32* uvs = (PxF32*)SAMPLE_ALLOC(sizeof(PxF32) * nbRows * nbColumns * 2); PxVec3* vertexes = vertexesA; for (PxU32 row = 0; row < nbRows; row++) { for (PxU32 column = 0; column < nbColumns; column++) { PxHeightFieldSample* currentSample = (PxHeightFieldSample*)currentByte; currentSample->height = *loader_ptr; vertexes[row * nbColumns + column] = PxVec3(PxReal(row)*rowScale, PxReal(currentSample->height * heightScale), PxReal(column)*columnScale); uvs[(row * nbColumns + column)*2 + 0] = (float)column/7.0f; uvs[(row * nbColumns + column)*2 + 1] = (float)row/7.0f; currentSample->materialIndex0 = 0; currentSample->materialIndex1 = 0; currentSample->clearTessFlag(); currentByte += heightFieldDesc.samples.stride; loader_ptr += 3 * sizeof(PxU8); } } PxHeightField* heightField = getPhysics().createHeightField(heightFieldDesc); if(!heightField) fatalError("createHeightField failed!"); // create shape for heightfield PxTransform pose(PxVec3(-((PxReal)nbRows*rowScale) / 2.0f, 0.0f, -((PxReal)nbColumns*columnScale) / 2.0f), PxQuat::createIdentity()); heightFieldActor = getPhysics().createRigidStatic(pose); if(!heightFieldActor) fatalError("createRigidStatic failed!"); PxShape* shape = heightFieldActor->createShape(PxHeightFieldGeometry(heightField, PxMeshGeometryFlags(), heightScale, rowScale, columnScale), getDefaultMaterial()); if(!shape) fatalError("createShape failed!"); // add actor to the scene getActiveScene().addActor(*heightFieldActor); // create indices PxU32* indices = (PxU32*)SAMPLE_ALLOC(sizeof(PxU32)*((nbColumns - 1) * (nbRows - 1) * 3 * 2)); for(int i = 0; i < (nbColumns - 1); ++i) { for(int j = 0; j < (nbRows - 1); ++j) { // first triangle indices[6 * (i * (nbRows - 1) + j) + 0] = (i + 1) * nbRows + j; indices[6 * (i * (nbRows - 1) + j) + 1] = i * nbRows + j; indices[6 * (i * (nbRows - 1) + j) + 2] = i * nbRows + j + 1; // second triangle indices[6 * (i * (nbRows - 1) + j) + 3] = (i + 1) * nbRows + j + 1; indices[6 * (i * (nbRows - 1) + j) + 4] = (i + 1) * nbRows + j; indices[6 * (i * (nbRows - 1) + j) + 5] = i * nbRows + j + 1; } } // add mesh to renderer RAWMesh data; data.mName = name; data.mTransform = PxTransform::createIdentity(); data.mNbVerts = nbColumns * nbRows; data.mVerts = vertexes; data.mVertexNormals = NULL; data.mUVs = uvs; data.mMaterialID = MATERIAL_TERRAIN_MUD; data.mNbFaces = (nbColumns - 1) * (nbRows - 1) * 2; data.mIndices = indices; RenderMeshActor* hf_mesh = createRenderMeshFromRawMesh(data); if(!hf_mesh) fatalError("createRenderMeshFromRawMesh failed!"); hf_mesh->setPhysicsShape(shape); shape->setFlag(PxShapeFlag::eVISUALIZATION, false); SAMPLE_FREE(indices); SAMPLE_FREE(uvs); DELETEARRAY(vertexesA); SAMPLE_FREE(samplesData); } return heightFieldActor; }
PxCapsuleController* SampleCustomGravity::createCharacter(const PxExtendedVec3& position) #endif { const float height = 2.0f; // const float height = 1e-6f; // PT: TODO: make it work with 0? #ifdef USE_BOX_CONTROLLER PxBoxControllerDesc cDesc; cDesc.halfHeight = height; cDesc.halfSideExtent = mControllerRadius; cDesc.halfForwardExtent = mControllerRadius; #else PxCapsuleControllerDesc cDesc; cDesc.height = height; cDesc.radius = mControllerRadius; #endif cDesc.material = &getDefaultMaterial(); cDesc.position = position; cDesc.slopeLimit = SLOPE_LIMIT; cDesc.contactOffset = CONTACT_OFFSET; cDesc.stepOffset = STEP_OFFSET; cDesc.invisibleWallHeight = INVISIBLE_WALLS_HEIGHT; cDesc.maxJumpHeight = MAX_JUMP_HEIGHT; cDesc.callback = this; mControllerInitialPosition = cDesc.position; #ifdef USE_BOX_CONTROLLER PxBoxController* ctrl = static_cast<PxBoxController*>(mControllerManager->createController(getPhysics(), &getActiveScene(), cDesc)); #else PxCapsuleController* ctrl = static_cast<PxCapsuleController*>(mControllerManager->createController(getPhysics(), &getActiveScene(), cDesc)); #endif // remove controller shape from scene query for standup overlap test PxRigidDynamic* actor = ctrl->getActor(); if(actor) { if(actor->getNbShapes()) { PxShape* ctrlShape; actor->getShapes(&ctrlShape,1); ctrlShape->setFlag(PxShapeFlag::eSCENE_QUERY_SHAPE, false); #ifdef USE_BOX_CONTROLLER const PxVec3 standingExtents(mControllerRadius, height, mControllerRadius); mRenderActor = SAMPLE_NEW(RenderBoxActor)(*getRenderer(), standingExtents); #else mRenderActor = SAMPLE_NEW(RenderCapsuleActor)(*getRenderer(), mControllerRadius, height*0.5f); #endif if(mRenderActor) mRenderActors.push_back(mRenderActor); } else fatalError("character actor has no shape"); } else fatalError("character could not create actor"); // uncomment the next line to render the character //createRenderObjectsFromActor(ctrl->getActor()); return ctrl; }
osg::Node* createNodeForActor( PxRigidActor* actor ) { if ( !actor ) return NULL; std::vector<PxShape*> shapes( actor->getNbShapes() ); osg::ref_ptr<osg::MatrixTransform> transform = new osg::MatrixTransform; transform->setMatrix( toMatrix(PxMat44(actor->getGlobalPose())) ); osg::ref_ptr<osg::Geode> geode = new osg::Geode; transform->addChild( geode.get() ); PxU32 num = actor->getShapes( &(shapes[0]), actor->getNbShapes() ); for ( PxU32 i=0; i<num; ++i ) { PxShape* shape = shapes[i]; osg::Matrix localMatrix = toMatrix( PxMat44(actor->getGlobalPose()) ); osg::Vec3 localPos = toVec3( shape->getLocalPose().p ); osg::Quat localQuat(shape->getLocalPose().q.x, shape->getLocalPose().q.y, shape->getLocalPose().q.z, shape->getLocalPose().q.w); switch ( shape->getGeometryType() ) { case PxGeometryType::eSPHERE: { PxSphereGeometry sphere; shape->getSphereGeometry( sphere ); osg::Sphere* sphereShape = new osg::Sphere(localPos, sphere.radius); geode->addDrawable( new osg::ShapeDrawable(sphereShape) ); } break; case PxGeometryType::ePLANE: // TODO break; case PxGeometryType::eCAPSULE: { PxCapsuleGeometry capsule; shape->getCapsuleGeometry( capsule ); osg::Capsule* capsuleShape = new osg::Capsule( localPos, capsule.radius, capsule.halfHeight * 2.0f); capsuleShape->setRotation( localQuat ); geode->addDrawable( new osg::ShapeDrawable(capsuleShape) ); } break; case PxGeometryType::eBOX: { PxBoxGeometry box; shape->getBoxGeometry( box ); osg::Box* boxShape = new osg::Box(localPos, box.halfExtents[0] * 2.0f, box.halfExtents[1] * 2.0f, box.halfExtents[2] * 2.0f); boxShape->setRotation( localQuat ); geode->addDrawable( new osg::ShapeDrawable(boxShape) ); } break; case PxGeometryType::eCONVEXMESH: { PxConvexMeshGeometry convexMeshGeom; shape->getConvexMeshGeometry( convexMeshGeom ); // TODO: consider convexMeshGeom.scale PxConvexMesh* convexMesh = convexMeshGeom.convexMesh; if ( convexMesh ) { /*for ( unsigned int i=0; i<convexMesh->getNbPolygons(); ++i ) { }*/ // TODO } } break; case PxGeometryType::eTRIANGLEMESH: { PxTriangleMeshGeometry triangleMeshGeom; shape->getTriangleMeshGeometry( triangleMeshGeom ); // TODO: consider triangleMeshGeom.scale PxTriangleMesh* triangleMesh = triangleMeshGeom.triangleMesh; if ( triangleMesh ) { osg::ref_ptr<osg::Vec3Array> va = new osg::Vec3Array( triangleMesh->getNbVertices() ); for ( unsigned int i=0; i<va->size(); ++i ) (*va)[i] = toVec3( *(triangleMesh->getVertices() + i) ) * localMatrix; osg::ref_ptr<osg::DrawElements> de; if ( triangleMesh->getTriangleMeshFlags()&PxTriangleMeshFlag::eHAS_16BIT_TRIANGLE_INDICES ) { osg::DrawElementsUShort* de16 = new osg::DrawElementsUShort(GL_TRIANGLES); de = de16; const PxU16* indices = (const PxU16*)triangleMesh->getTriangles(); for ( unsigned int i=0; i<triangleMesh->getNbTriangles(); ++i ) { de16->push_back( indices[3 * i + 0] ); de16->push_back( indices[3 * i + 1] ); de16->push_back( indices[3 * i + 2] ); } } else { osg::DrawElementsUInt* de32 = new osg::DrawElementsUInt(GL_TRIANGLES); de = de32; const PxU32* indices = (const PxU32*)triangleMesh->getTriangles(); for ( unsigned int i=0; i<triangleMesh->getNbTriangles(); ++i ) { de32->push_back( indices[3 * i + 0] ); de32->push_back( indices[3 * i + 1] ); de32->push_back( indices[3 * i + 2] ); } } geode->addDrawable( createGeometry(va.get(), NULL, NULL, de.get()) ); } } break; case PxGeometryType::eHEIGHTFIELD: { PxHeightFieldGeometry hfGeom; shape->getHeightFieldGeometry( hfGeom ); // TODO: consider hfGeom.*scale PxHeightField* heightField = hfGeom.heightField; if ( heightField ) { // TODO } } break; } } return transform.release(); }
FDbool BuildingSystem::searchForHit(PhysicsSystem& physicsSystem, Ray r, PxGeometry& pixelFrustum, SearchContext& searchContext) { // Cast the ray into the scene. Quit if no intersection at all. PxQueryFilterData qFilterData; qFilterData.flags |= PxQueryFlag::ePREFILTER | PxQueryFlag::ePOSTFILTER; FDbool rayStatus = physicsSystem.scene->raycast( r.position, r.direction, 100, searchContext.hitBuffer, PxHitFlag::ePOSITION | PxHitFlag::eDISTANCE | PxHitFlag::eNORMAL, qFilterData, &CustomPhysicsQueryFilter()); /* Demo-ing to a friend showed that it can be confusing to try to connect * up an existing point that lies on the guide plane, since part of it will * be behind the guide plane, which the ray-cast will see as being closer. * To remedy this, I treat the GuidePlane as a "touching" rather than * "blocking hit" and give some priority to points. */ if (rayStatus && searchContext.hitBuffer.hasBlock) { // In this case, we know we hit something other than the guide plane. searchContext.hitActor = searchContext.hitBuffer.block.actor; searchContext.rayHit = &searchContext.hitBuffer.block; FDreal blockDistance = searchContext.rayHit->distance; searchContext.setHit(&searchContext.hitBuffer.block); // If the guide plane was also hit, see if it is closer. if (searchContext.hitBuffer.nbTouches > 0) { float guidePlaneDistance = searchContext.hitBuffer.getTouch(0). distance; // If the point intersects the plane, prefer it. if (searchContext.hitActor == pointActor) { FDUint i = (FDUint)searchContext.rayHit->shape->userData; Vector3 pointPos = *pointAuthor->getAttribute<Vector3>(i, 0); float pointRadius = 0.2; Vector3 guidePlaneNormal = searchContext.hitBuffer. getTouch(0).normal; Plane p = Plane(searchContext.hitBuffer.getTouch(0).position, guidePlaneNormal); // We know the point (modeled as a sphere) intersects the // plane if the point is within 1 sphere radius. float pointPlaneDistance = p.distance(pointPos); if (abs(pointPlaneDistance) <= pointRadius) { blockDistance = 0; } } if (guidePlaneDistance < blockDistance) { searchContext.hitActor = searchContext.hitBuffer.getTouch(0). actor; searchContext.setHit(&searchContext.hitBuffer.getTouch(0)); } } } else if (rayStatus) { // Only the guide plane was hit. searchContext.hitActor = searchContext.hitBuffer.getTouch(0).actor; searchContext.setHit(&searchContext.hitBuffer.getTouch(0)); } // Try overlap test for other geometry. Quaternion q = fdmath::getRotationBetween(Vector3(0, 0, 1), r.direction); Vector3 obo = q.rotate(Vector3(0, 0, 1)); PxTransform pose(r.position, q); PxQueryFilterData qPixelFilterData; qPixelFilterData.flags |= PxQueryFlag::ePREFILTER; physicsSystem.scene->overlap(pixelFrustum, pose, searchContext.overlapBuffer, qPixelFilterData, &PixelQueryFilter()); for (FDUint i = 0; i < searchContext.overlapBuffer.nbTouches; i++) { PxRigidStatic* thisActor = (PxRigidStatic*)searchContext.overlapBuffer. touches[i].actor; PxShape* thisShape = searchContext.overlapBuffer.touches[i].shape; // Get the closet point on the line to the ray. Transform lineTransform = thisActor->getGlobalPose() * thisShape->getLocalPose(); Vector3 lineAxisPoint = lineTransform.transform(Vector3(1, 0, 0)); Vector3 centerPos = lineTransform.p; Vector3 lineAxis = (lineAxisPoint - centerPos).getNormalized(); Vector3 uAxis = lineAxis.cross(r.direction); uAxis.normalize(); Plane p(centerPos, lineAxisPoint, centerPos + uAxis); Vector3 intersectionPoint; FDbool intersects = r.intersect(p, intersectionPoint); FD_ASSERT(intersects, "Ray did not intersect line's plane."); FDreal y = lineAxis.dot(intersectionPoint) - lineAxis.dot(centerPos); Vector3 closestPoint = centerPos + lineAxis * y; FDreal dist = (closestPoint - r.position).magnitude(); if (dist < searchContext.hitDist) { searchContext.setHit(&searchContext.overlapBuffer.touches[i], closestPoint, -r.direction, dist); searchContext.hitActor = thisActor; } } return searchContext.hitHappened; }
bool UWorld::ComponentSweepMulti(TArray<struct FHitResult>& OutHits, class UPrimitiveComponent* PrimComp, const FVector& Start, const FVector& End, const FRotator& Rot, const struct FComponentQueryParams& Params) const { if(GetPhysicsScene() == NULL) { return false; } if(PrimComp == NULL) { UE_LOG(LogCollision, Log, TEXT("ComponentSweepMulti : No PrimComp")); return false; } // if target is skeletalmeshcomponent and do not support singlebody physics if ( !PrimComp->ShouldTrackOverlaps() ) { UE_LOG(LogCollision, Log, TEXT("ComponentSweepMulti : (%s) Does not support skeletalmesh with Physics Asset and destructibles."), *PrimComp->GetPathName()); return false; } ECollisionChannel TraceChannel = PrimComp->GetCollisionObjectType(); #if WITH_PHYSX // if extent is 0, do line trace if (PrimComp->IsZeroExtent()) { return RaycastMulti(this, OutHits, Start, End, TraceChannel, Params, FCollisionResponseParams(PrimComp->GetCollisionResponseToChannels())); } PxRigidActor* PRigidActor = PrimComp->BodyInstance.GetPxRigidActor(); if(PRigidActor == NULL) { UE_LOG(LogCollision, Log, TEXT("ComponentSweepMulti : (%s) No physics data"), *PrimComp->GetPathName()); return false; } PxScene * const PScene = PRigidActor->getScene(); OutHits.Empty(); // Get all the shapes from the actor TArray<PxShape*, TInlineAllocator<8>> PShapes; { SCOPED_SCENE_READ_LOCK(PScene); PShapes.AddZeroed(PRigidActor->getNbShapes()); PRigidActor->getShapes(PShapes.GetData(), PShapes.Num()); } // calculate the test global pose of the actor PxTransform PGlobalStartPose = U2PTransform(FTransform(Start)); PxTransform PGlobalEndPose = U2PTransform(FTransform(End)); bool bHaveBlockingHit = false; PxQuat PGeomRot = U2PQuat(Rot.Quaternion()); // Iterate over each shape SCENE_LOCK_READ(PScene); for(int32 ShapeIdx=0; ShapeIdx<PShapes.Num(); ShapeIdx++) { PxShape* PShape = PShapes[ShapeIdx]; check(PShape); TArray<struct FHitResult> Hits; // Calc shape global pose PxTransform PLocalShape = PShape->getLocalPose(); PxTransform PShapeGlobalStartPose = PGlobalStartPose.transform(PLocalShape); PxTransform PShapeGlobalEndPose = PGlobalEndPose.transform(PLocalShape); // consider localshape rotation for shape rotation PxQuat PShapeRot = PGeomRot * PLocalShape.q; GET_GEOMETRY_FROM_SHAPE(PGeom, PShape); if(PGeom != NULL) { SCENE_UNLOCK_READ(PScene); if (GeomSweepMulti(this, *PGeom, PShapeRot, Hits, P2UVector(PShapeGlobalStartPose.p), P2UVector(PShapeGlobalEndPose.p), TraceChannel, Params, FCollisionResponseParams(PrimComp->GetCollisionResponseToChannels()))) { bHaveBlockingHit = true; } OutHits.Append(Hits); SCENE_LOCK_READ(PScene); } } SCENE_UNLOCK_READ(PScene); return bHaveBlockingHit; #endif //WITH_PHYSX return false; }
bool UWorld::ComponentSweepSingle(struct FHitResult& OutHit,class UPrimitiveComponent* PrimComp, const FVector& Start, const FVector& End, const FRotator& Rot, const struct FComponentQueryParams& Params) const { OutHit.TraceStart = Start; OutHit.TraceEnd = End; if(GetPhysicsScene() == NULL) { return false; } if(PrimComp == NULL) { UE_LOG(LogCollision, Log, TEXT("ComponentSweepSingle : No PrimComp")); return false; } // if target is skeletalmeshcomponent and do not support singlebody physics if ( !PrimComp->ShouldTrackOverlaps() ) { UE_LOG(LogCollision, Log, TEXT("ComponentSweepSingle : (%s) Does not support skeletalmesh with Physics Asset and destructibles."), *PrimComp->GetPathName()); return false; } ECollisionChannel TraceChannel = PrimComp->GetCollisionObjectType(); #if WITH_PHYSX // if extent is 0, do line trace if (PrimComp->IsZeroExtent()) { return RaycastSingle(this, OutHit, Start, End, TraceChannel, Params, FCollisionResponseParams(PrimComp->GetCollisionResponseToChannels())); } PxRigidActor* PRigidActor = PrimComp->BodyInstance.GetPxRigidActor(); if(PRigidActor == NULL) { UE_LOG(LogCollision, Log, TEXT("ComponentSweepMulti : (%s) No physics data"), *PrimComp->GetPathName()); return false; } // Get all the shapes from the actor TArray<PxShape*, TInlineAllocator<8>> PShapes; PShapes.AddZeroed(PRigidActor->getNbShapes()); int32 NumShapes = PRigidActor->getShapes(PShapes.GetData(), PShapes.Num()); // calculate the test global pose of the actor PxTransform PGlobalStartPose = U2PTransform(FTransform(Start)); PxTransform PGlobalEndPose = U2PTransform(FTransform(End)); bool bHaveBlockingHit = false; PxQuat PGeomRot = U2PQuat(Rot.Quaternion()); // Iterate over each shape for(int32 ShapeIdx=0; ShapeIdx<PShapes.Num(); ShapeIdx++) { PxShape* PShape = PShapes[ShapeIdx]; check(PShape); // Calc shape global pose PxTransform PLocalShape = PShape->getLocalPose(); PxTransform PShapeGlobalStartPose = PGlobalStartPose.transform(PLocalShape); PxTransform PShapeGlobalEndPose = PGlobalEndPose.transform(PLocalShape); // consider localshape rotation for shape rotation PxQuat PShapeRot = PGeomRot * PLocalShape.q; GET_GEOMETRY_FROM_SHAPE(PGeom, PShape); if(PGeom != NULL) { // @todo UE4, this might not be the best behavior. If we're looking for the most closest, this have to change to save the result, and find the closest one or // any other options, right now if anything hits first, it will return if (GeomSweepSingle(this, *PGeom, PShapeRot, OutHit, P2UVector(PShapeGlobalStartPose.p), P2UVector(PShapeGlobalEndPose.p), TraceChannel, Params, FCollisionResponseParams(PrimComp->GetCollisionResponseToChannels()))) { bHaveBlockingHit = true; break; } } } return bHaveBlockingHit; #endif //WITH_PHYSX return false; }
bool UWorld::ComponentSweepMulti(TArray<struct FHitResult>& OutHits, class UPrimitiveComponent* PrimComp, const FVector& Start, const FVector& End, const FQuat& Quat, const struct FComponentQueryParams& Params) const { if (GetPhysicsScene() == NULL) { return false; } if (PrimComp == NULL) { UE_LOG(LogCollision, Log, TEXT("ComponentSweepMulti : No PrimComp")); return false; } ECollisionChannel TraceChannel = PrimComp->GetCollisionObjectType(); // if extent is 0, do line trace if (PrimComp->IsZeroExtent()) { return RaycastMulti(this, OutHits, Start, End, TraceChannel, Params, FCollisionResponseParams(PrimComp->GetCollisionResponseToChannels())); } OutHits.Reset(); #if UE_WITH_PHYSICS const FBodyInstance* BodyInstance = PrimComp->GetBodyInstance(); if (!BodyInstance || !BodyInstance->IsValidBodyInstance()) { UE_LOG(LogCollision, Log, TEXT("ComponentSweepMulti : (%s) No physics data"), *PrimComp->GetReadableName()); return false; } #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) if(PrimComp->IsA(USkeletalMeshComponent::StaticClass())) { UE_LOG(LogCollision, Warning, TEXT("ComponentSweepMulti : SkeletalMeshComponent support only root body (%s) "), *PrimComp->GetReadableName()); } #endif #endif SCOPE_CYCLE_COUNTER(STAT_Collision_GeomSweepMultiple); bool bHaveBlockingHit = false; #if WITH_PHYSX ExecuteOnPxRigidActorReadOnly(BodyInstance, [&] (const PxRigidActor* PRigidActor) { // Get all the shapes from the actor FInlinePxShapeArray PShapes; const int32 NumShapes = FillInlinePxShapeArray(PShapes, *PRigidActor); // calculate the test global pose of the actor const PxQuat PGeomRot = U2PQuat(Quat); const PxTransform PGlobalStartPose = PxTransform(U2PVector(Start), PGeomRot); const PxTransform PGlobalEndPose = PxTransform(U2PVector(End), PGeomRot); // Iterate over each shape for(int32 ShapeIdx=0; ShapeIdx<NumShapes; ShapeIdx++) { PxShape* PShape = PShapes[ShapeIdx]; check(PShape); GET_GEOMETRY_FROM_SHAPE(PGeom, PShape); if (PGeom != NULL) { // Calc shape global pose const PxTransform PLocalShape = PShape->getLocalPose(); const PxTransform PShapeGlobalStartPose = PGlobalStartPose.transform(PLocalShape); const PxTransform PShapeGlobalEndPose = PGlobalEndPose.transform(PLocalShape); // consider localshape rotation for shape rotation const PxQuat PShapeRot = PGeomRot * PLocalShape.q; if (GeomSweepMulti_PhysX(this, *PGeom, PShapeRot, OutHits, P2UVector(PShapeGlobalStartPose.p), P2UVector(PShapeGlobalEndPose.p), TraceChannel, Params, FCollisionResponseParams(PrimComp->GetCollisionResponseToChannels()))) { bHaveBlockingHit = true; } } } }); #endif //WITH_PHYSX //@TODO: BOX2D: Implement UWorld::ComponentSweepMulti #if WITH_BOX2D // if (b2Body* BodyInstance = PrimComp->BodyInstance.BodyInstancePtr) // { // // } #endif return bHaveBlockingHit; }
void SampleSubmarine::createDynamicActors() { // create mines static const PxU32 numMines = 20; static const PxVec3 mineFieldCenter = PxVec3(0, 64, 0); static const PxReal minMineDistance = 3.0f; static const PxI32 mineFieldRadius = 30; for(PxU32 i = 0; i < numMines; i++) { // raycast against floor (height field) to find the height to attach the mine PxRaycastHit rayHit; bool hit = false; do { PxVec3 offset = PxVec3(PxReal(getSampleRandom().rand(-mineFieldRadius, mineFieldRadius)), 0, PxReal(getSampleRandom().rand(-mineFieldRadius, mineFieldRadius))); PxVec3 raycastStart = mineFieldCenter + offset*minMineDistance; hit = getActiveScene().raycastSingle(raycastStart, PxVec3(0,-1,0), 100.0f, PxSceneQueryFlag::eIMPACT, rayHit); } while(!hit || (rayHit.impact.y > 25.0f) || rayHit.shape->getActor().is<PxRigidDynamic>()); createSeamine(rayHit.impact, getSampleRandom().rand(10.0f, 25.0f)); } // create treasure { static const PxVec3 treasureDim = PxVec3(5, 3, 4)*0.5f; PxRaycastHit rayHit; PxVec3 raycastStart = PxVec3(-19, 64, -24); getActiveScene().raycastSingle(raycastStart, PxVec3(0,-1,0), 100.0f, PxSceneQueryFlag::eIMPACT, rayHit); #ifdef RENDERER_PSP2 gTreasureActor = createBox(rayHit.impact+treasureDim, treasureDim, NULL, mTreasureMaterial, 1)->is<PxRigidDynamic>(); #else gTreasureActor = createBox(rayHit.impact+treasureDim, treasureDim, NULL, mManagedMaterials[MATERIAL_BLUE], 1)->is<PxRigidDynamic>(); #endif if(!gTreasureActor) fatalError("createBox failed!"); gTreasureActor->setActorFlag(PxActorFlag::eDISABLE_GRAVITY, true); PxShape* treasureShape; gTreasureActor->getShapes(&treasureShape, 1); treasureShape->setFlag(PxShapeFlag::eSIMULATION_SHAPE, false); treasureShape->setFlag(PxShapeFlag::eTRIGGER_SHAPE, true); } // create submarine createSubmarine(PxVec3(-110, 50, 110), 2.1f); char theCrabName[256]; sprintf(theCrabName, "crab_%s.bin", getPlatformName()); // If we have already had crab copy, just load it, or will create crab and export it char thePathBuffer[1024]; const char* theCrabPath = getSampleOutputDirManager().getFilePath( theCrabName, thePathBuffer, false ); FILE *fp = fopen( theCrabPath, "r" ); if( fp ) { printf("loading the crab from file status: "); gCrab = SAMPLE_NEW(Crab)(*this, theCrabPath, mManagedMaterials[MATERIAL_RED]); if (gCrab && !gCrab->getCrabBody()) { delete gCrab; gCrab = NULL; } printf(gCrab ? "successful\n":"failed\n"); fclose (fp); } if( !gCrab ) { gCrab = SAMPLE_NEW(Crab)(*this, PxVec3(0, 50, 0), mManagedMaterials[MATERIAL_RED]); printf("crab file not found ... exporting crab file\n"); gCrab->save(theCrabPath); } PX_ASSERT( gCrab ); mCrabs.push_back(gCrab); static const PxU32 numCrabs = 3; for(PxU32 i = 0; i < numCrabs; i++) { Crab* crab = SAMPLE_NEW(Crab)(*this, PxVec3(getSampleRandom().rand(-20.0f,20.0f), 50, getSampleRandom().rand(-20.0f,20.0f)), mManagedMaterials[MATERIAL_RED]); mCrabs.push_back(crab); } }
void Cct::findTouchedGeometry( const InternalCBData_FindTouchedGeom* userData, const PxExtendedBounds3& worldBounds, // ### we should also accept other volumes TriArray& worldTriangles, IntArray& triIndicesArray, IntArray& geomStream, const CCTFilter& filter, const CCTParams& params) { PX_ASSERT(userData); const PxInternalCBData_FindTouchedGeom* internalData = static_cast<const PxInternalCBData_FindTouchedGeom*>(userData); PxScene* scene = internalData->scene; Cm::RenderBuffer* renderBuffer = internalData->renderBuffer; PxExtendedVec3 Origin; // Will be TouchedGeom::mOffset getCenter(worldBounds, Origin); // Find touched *boxes* i.e. touched objects' AABBs in the world // We collide against dynamic shapes too, to get back dynamic boxes/etc // TODO: add active groups in interface! PxSceneQueryFilterFlags sqFilterFlags; if(filter.mStaticShapes) sqFilterFlags |= PxSceneQueryFilterFlag::eSTATIC; if(filter.mDynamicShapes) sqFilterFlags |= PxSceneQueryFilterFlag::eDYNAMIC; if(filter.mFilterCallback) { if(filter.mPreFilter) sqFilterFlags |= PxSceneQueryFilterFlag::ePREFILTER; if(filter.mPostFilter) sqFilterFlags |= PxSceneQueryFilterFlag::ePOSTFILTER; } // ### this one is dangerous const PxBounds3 tmpBounds(toVec3(worldBounds.minimum), toVec3(worldBounds.maximum)); // LOSS OF ACCURACY // PT: unfortunate conversion forced by the PxGeometry API PxVec3 center = tmpBounds.getCenter(), extents = tmpBounds.getExtents(); PxShape* hits[100]; PxU32 size = 100; const PxSceneQueryFilterData sceneQueryFilterData = filter.mFilterData ? PxSceneQueryFilterData(*filter.mFilterData, sqFilterFlags) : PxSceneQueryFilterData(sqFilterFlags); PxI32 numberHits = scene->overlapMultiple(PxBoxGeometry(extents), PxTransform(center), hits, size, sceneQueryFilterData, filter.mFilterCallback); for(PxI32 i = 0; i < numberHits; i++) { PxShape* shape = hits[i]; if(shape == NULL) continue; // Filtering // Discard all CCT shapes, i.e. kinematic actors we created ourselves. We don't need to collide with them since they're surrounded // by the real CCT volume - and collisions with those are handled elsewhere. We use the userData field for filtering because that's // really our only valid option (filtering groups are already used by clients and we don't have control over them, clients might // create other kinematic actors that we may want to keep here, etc, etc) if(internalData->cctShapeHashSet->contains(shape)) continue; // Ubi (EA) : Discarding Triggers : if(shape->getFlags() & PxShapeFlag::eTRIGGER_SHAPE) continue; // PT: here you might want to disable kinematic objects. // Output shape to stream const PxTransform globalPose = getShapeGlobalPose(*shape); const PxGeometryType::Enum type = shape->getGeometryType(); // ### VIRTUAL! if(type==PxGeometryType::eSPHERE) outputSphereToStream(shape, globalPose, geomStream, Origin); else if(type==PxGeometryType::eCAPSULE) outputCapsuleToStream(shape, globalPose, geomStream, Origin); else if(type==PxGeometryType::eBOX) outputBoxToStream(shape, globalPose, geomStream, worldTriangles, triIndicesArray, Origin, tmpBounds, params, renderBuffer); else if(type==PxGeometryType::eTRIANGLEMESH) outputMeshToStream(shape, globalPose, geomStream, worldTriangles, triIndicesArray, Origin, tmpBounds, params, renderBuffer); else if(type==PxGeometryType::eHEIGHTFIELD) outputHeightFieldToStream(shape, globalPose, geomStream, worldTriangles, triIndicesArray, Origin, tmpBounds, params, renderBuffer); else if(type==PxGeometryType::eCONVEXMESH) outputConvexToStream(shape, globalPose, geomStream, worldTriangles, triIndicesArray, Origin, tmpBounds); else if(type==PxGeometryType::ePLANE) outputPlaneToStream(shape, globalPose, geomStream, worldTriangles, triIndicesArray, Origin, tmpBounds, params, renderBuffer); } }
void SimulationEventCallback::destroyWallBlock(const PxRigidBody& _krRigidBody, const PxShape& _krShape) { Entity* wallBlock = static_cast<Entity*>(_krRigidBody.userData); if (find(m_destroyedWallBlocks.begin(), m_destroyedWallBlocks.end(), wallBlock) != m_destroyedWallBlocks.end()) { return; } PxBoxGeometry geometry; _krShape.getBoxGeometry(geometry); PxTransform transform = _krRigidBody.getGlobalPose(); Matrix44 transformation = PhysXMatrix::toMatrix44(transform); PxVec3 angularVelocity = _krRigidBody.getAngularVelocity(); PxVec3 linearVelocity = _krRigidBody.getLinearVelocity(); m_destroyedWallBlocks.push_back(wallBlock); GazEngine::removeEntity(*wallBlock); float halfSize = geometry.halfExtents.x / 2.0f; Matrix44 fragment0Transformation = transformation; getTranslation3(fragment0Transformation) += Vector3(-halfSize, halfSize, 0.0f); Entity* pFragment0 = CreateWallBlock(fragment0Transformation, halfSize, *m_pParentNode); PxRigidBody* pFragment0RigidBody = pFragment0->getSingleComponent<PhysXBody>()->getActor()->isRigidBody(); pFragment0RigidBody->setAngularVelocity(angularVelocity); pFragment0RigidBody->setLinearVelocity(linearVelocity); // The body only got a position in the constructor... lets give it a rotation too. PxTransform fragment0Transform = transform; fragment0Transform.p += PxVec3(-halfSize, halfSize, 0.0f); pFragment0RigidBody->setGlobalPose(fragment0Transform); Matrix44 fragment1Transformation = transformation; getTranslation3(fragment1Transformation) += Vector3(halfSize, halfSize, 0.0f); Entity* pFragment1 = CreateWallBlock(fragment1Transformation, halfSize, *m_pParentNode); PxRigidBody* pFragment1RigidBody = pFragment1->getSingleComponent<PhysXBody>()->getActor()->isRigidBody(); pFragment1RigidBody->setAngularVelocity(angularVelocity); pFragment1RigidBody->setLinearVelocity(linearVelocity); // The body only got a position in the constructor... lets give it a rotation too. PxTransform fragment1Transform = transform; fragment1Transform.p += PxVec3(halfSize, halfSize, 0.0f); pFragment1RigidBody->setGlobalPose(fragment1Transform); Matrix44 fragment2Transformation = transformation; getTranslation3(fragment2Transformation) += Vector3(halfSize, -halfSize, 0.0f); Entity* pFragment2 = CreateWallBlock(fragment2Transformation, halfSize, *m_pParentNode); PxRigidBody* pFragment2RigidBody = pFragment2->getSingleComponent<PhysXBody>()->getActor()->isRigidBody(); pFragment2RigidBody->setAngularVelocity(angularVelocity); pFragment2RigidBody->setLinearVelocity(linearVelocity); // The body only got a position in the constructor... lets give it a rotation too. PxTransform fragment2Transform = transform; fragment2Transform.p += PxVec3(halfSize, -halfSize, 0.0f); pFragment2RigidBody->setGlobalPose(fragment2Transform); Matrix44 fragment3Transformation = transformation; getTranslation3(fragment3Transformation) += Vector3(-halfSize, -halfSize, 0.0f); Entity* pFragment3 = CreateWallBlock(fragment3Transformation, halfSize, *m_pParentNode); PxRigidBody* pFragment3RigidBody = pFragment3->getSingleComponent<PhysXBody>()->getActor()->isRigidBody(); pFragment3RigidBody->setAngularVelocity(angularVelocity); pFragment3RigidBody->setLinearVelocity(linearVelocity); // The body only got a position in the constructor... lets give it a rotation too. PxTransform fragment3Transform = transform; fragment3Transform.p += PxVec3(-halfSize, -halfSize, 0.0f); pFragment3RigidBody->setGlobalPose(fragment3Transform); }