diff --git a/Source/Engine/Physics/Actors/RigidBody.cpp b/Source/Engine/Physics/Actors/RigidBody.cpp index a6173d3c6..e2fa531f2 100644 --- a/Source/Engine/Physics/Actors/RigidBody.cpp +++ b/Source/Engine/Physics/Actors/RigidBody.cpp @@ -327,7 +327,7 @@ void RigidBody::OnColliderChanged(Collider* c) void RigidBody::UpdateBounds() { - void* actor = GetPhysicsActor(); + void* actor = _actor; if (actor && PhysicsBackend::GetRigidActorShapesCount(actor) != 0) PhysicsBackend::GetActorBounds(actor, _box); else @@ -406,7 +406,7 @@ void RigidBody::OnActiveTransformChanged() ASSERT(!_isUpdatingTransform); _isUpdatingTransform = true; Transform transform; - PhysicsBackend::GetRigidActorPose(GetPhysicsActor(), transform.Translation, transform.Orientation); + PhysicsBackend::GetRigidActorPose(_actor, transform.Translation, transform.Orientation); transform.Scale = _transform.Scale; if (_parent) { @@ -424,7 +424,8 @@ void RigidBody::BeginPlay(SceneBeginData* data) { // Create rigid body ASSERT(_actor == nullptr); - _actor = PhysicsBackend::CreateRigidDynamicActor(this, _transform.Translation, _transform.Orientation); + void* scene = GetPhysicsScene()->GetPhysicsScene(); + _actor = PhysicsBackend::CreateRigidDynamicActor(this, _transform.Translation, _transform.Orientation, scene); // Apply properties auto actorFlags = PhysicsBackend::ActorFlags::None; @@ -462,7 +463,6 @@ void RigidBody::BeginPlay(SceneBeginData* data) PhysicsBackend::SetRigidDynamicActorCenterOfMassOffset(_actor, _centerOfMassOffset); // Register actor - void* scene = GetPhysicsScene()->GetPhysicsScene(); PhysicsBackend::AddSceneActor(scene, _actor); const bool putToSleep = !_startAwake && GetEnableSimulation() && !GetIsKinematic() && IsActiveInHierarchy(); if (putToSleep) diff --git a/Source/Engine/Physics/Colliders/Collider.cpp b/Source/Engine/Physics/Colliders/Collider.cpp index f0e0b2e9c..061810849 100644 --- a/Source/Engine/Physics/Colliders/Collider.cpp +++ b/Source/Engine/Physics/Colliders/Collider.cpp @@ -258,13 +258,13 @@ void Collider::UpdateGeometry() void Collider::CreateStaticActor() { ASSERT(_staticActor == nullptr); - _staticActor = PhysicsBackend::CreateRigidStaticActor(nullptr, _transform.Translation, _transform.Orientation); + void* scene = GetPhysicsScene()->GetPhysicsScene(); + _staticActor = PhysicsBackend::CreateRigidStaticActor(nullptr, _transform.Translation, _transform.Orientation, scene); // Reset local pos of the shape and link it to the actor PhysicsBackend::SetShapeLocalPose(_shape, _center, Quaternion::Identity); PhysicsBackend::AttachShape(_shape, _staticActor); - void* scene = GetPhysicsScene()->GetPhysicsScene(); PhysicsBackend::AddSceneActor(scene, _staticActor); } diff --git a/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp b/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp index ce67c4405..b4719159b 100644 --- a/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp +++ b/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp @@ -65,6 +65,7 @@ struct ScenePhysX PxCpuDispatcher* CpuDispatcher = nullptr; PxControllerManager* ControllerManager = nullptr; void* ScratchMemory = nullptr; + Vector3 Origin = Vector3::Zero; float LastDeltaTime = 0.0f; FixedStepper Stepper; SimulationEventCallback EventsCallback; @@ -303,7 +304,8 @@ protected: DynamicHitBuffer buffer #define SCENE_QUERY_COLLECT_SINGLE() const auto& hit = buffer.getAnyHit(0); \ - P2C(hit, hitInfo) + P2C(hit, hitInfo); \ + hitInfo.Point += scenePhysX->Origin #define SCENE_QUERY_COLLECT_ALL() results.Clear(); \ results.Resize(buffer.getNbAnyHits(), false); \ @@ -311,6 +313,7 @@ protected: { \ const auto& hit = buffer.getAnyHit(i); \ P2C(hit, results[i]); \ + results[i].Point += scenePhysX->Origin; \ } #define SCENE_QUERY_COLLECT_OVERLAP() results.Clear(); \ @@ -348,6 +351,7 @@ namespace QueryFilterPhysX QueryFilter; CharacterQueryFilterPhysX CharacterQueryFilter; CharacterControllerFilterPhysX CharacterControllerFilter; + Dictionary> SceneOrigins; CriticalSection FlushLocker; Array DeleteObjects; @@ -721,6 +725,9 @@ bool PhysicsBackend::Init() // Create default material DefaultMaterial = PhysX->createMaterial(0.7f, 0.7f, 0.3f); + // Return origin 0,0,0 for invalid/null scenes + SceneOrigins.Add((PxScene*)nullptr, Vector3::Zero); + return false; } @@ -772,6 +779,7 @@ void PhysicsBackend::Shutdown() RELEASE_PHYSX(PVD); #endif RELEASE_PHYSX(Foundation); + SceneOrigins.Clear(); } void PhysicsBackend::ApplySettings(const PhysicsSettings& settings) @@ -825,6 +833,7 @@ void* PhysicsBackend::CreateScene(const PhysicsSettings& settings) // Create scene scenePhysX->Scene = PhysX->createScene(sceneDesc); CHECK_INIT(scenePhysX->Scene, "createScene failed!"); + SceneOrigins[scenePhysX->Scene] = Vector3::Zero; #if WITH_PVD auto pvdClient = scenePhysX->Scene->getScenePvdClient(); if (pvdClient) @@ -852,6 +861,7 @@ void PhysicsBackend::DestroyScene(void* scene) FlushRequests(scene); // Release resources + SceneOrigins.Remove(scenePhysX->Scene); #if WITH_VEHICLE RELEASE_PHYSX(scenePhysX->WheelRaycastBatchQuery); #endif @@ -1182,15 +1192,15 @@ void PhysicsBackend::EndSimulateScene(void* scene) auto& state = wheelData.State; state.IsInAir = perWheel.isInAir; state.TireContactCollider = perWheel.tireContactShape ? static_cast(perWheel.tireContactShape->userData) : nullptr; - state.TireContactPoint = P2C(perWheel.tireContactPoint); + state.TireContactPoint = P2C(perWheel.tireContactPoint) + scenePhysX->Origin; state.TireContactNormal = P2C(perWheel.tireContactNormal); state.TireFriction = perWheel.tireFriction; state.SteerAngle = RadiansToDegrees * perWheel.steerAngle; state.RotationAngle = -RadiansToDegrees * drive->mWheelsDynData.getWheelRotationAngle(j); state.SuspensionOffset = perWheel.suspJounce; #if USE_EDITOR - state.SuspensionTraceStart = P2C(perWheel.suspLineStart); - state.SuspensionTraceEnd = P2C(perWheel.suspLineStart + perWheel.suspLineDir * perWheel.suspLineLength); + state.SuspensionTraceStart = P2C(perWheel.suspLineStart) + scenePhysX->Origin; + state.SuspensionTraceEnd = P2C(perWheel.suspLineStart + perWheel.suspLineDir * perWheel.suspLineLength) + scenePhysX->Origin; #endif if (!wheelData.Collider) @@ -1274,6 +1284,26 @@ void PhysicsBackend::SetSceneBounceThresholdVelocity(void* scene, float value) scenePhysX->Scene->setBounceThresholdVelocity(value); } +void PhysicsBackend::SetSceneOrigin(void* scene, const Vector3& oldOrigin, const Vector3& newOrigin) +{ + auto scenePhysX = (ScenePhysX*)scene; + const PxVec3 shift = C2P(newOrigin - oldOrigin); + scenePhysX->Origin = newOrigin; + scenePhysX->Scene->shiftOrigin(shift); + scenePhysX->ControllerManager->shiftOrigin(shift); + WheelVehiclesCache.Clear(); + for (auto wheelVehicle : scenePhysX->WheelVehicles) + { + if (!wheelVehicle->IsActiveInHierarchy()) + continue; + auto drive = (PxVehicleWheels*)wheelVehicle->_vehicle; + ASSERT(drive); + WheelVehiclesCache.Add(drive); + } + PxVehicleShiftOrigin(shift, WheelVehiclesCache.Count(), WheelVehiclesCache.Get()); + SceneOrigins[scenePhysX->Scene] = newOrigin; +} + void PhysicsBackend::AddSceneActor(void* scene, void* actor) { auto scenePhysX = (ScenePhysX*)scene; @@ -1304,14 +1334,14 @@ bool PhysicsBackend::RayCast(void* scene, const Vector3& origin, const Vector3& { SCENE_QUERY_SETUP(true); PxRaycastBuffer buffer; - return scenePhysX->Scene->raycast(C2P(origin), C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter); + return scenePhysX->Scene->raycast(C2P(origin - scenePhysX->Origin), C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter); } bool PhysicsBackend::RayCast(void* scene, const Vector3& origin, const Vector3& direction, RayCastHit& hitInfo, const float maxDistance, uint32 layerMask, bool hitTriggers) { SCENE_QUERY_SETUP(true); PxRaycastBuffer buffer; - if (!scenePhysX->Scene->raycast(C2P(origin), C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter)) + if (!scenePhysX->Scene->raycast(C2P(origin - scenePhysX->Origin), C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter)) return false; SCENE_QUERY_COLLECT_SINGLE(); return true; @@ -1321,7 +1351,7 @@ bool PhysicsBackend::RayCastAll(void* scene, const Vector3& origin, const Vector { SCENE_QUERY_SETUP(false); DynamicHitBuffer buffer; - if (!scenePhysX->Scene->raycast(C2P(origin), C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter)) + if (!scenePhysX->Scene->raycast(C2P(origin - scenePhysX->Origin), C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter)) return false; SCENE_QUERY_COLLECT_ALL(); return true; @@ -1330,7 +1360,7 @@ bool PhysicsBackend::RayCastAll(void* scene, const Vector3& origin, const Vector bool PhysicsBackend::BoxCast(void* scene, const Vector3& center, const Vector3& halfExtents, const Vector3& direction, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) { SCENE_QUERY_SETUP_SWEEP_1(); - const PxTransform pose(C2P(center), C2P(rotation)); + const PxTransform pose(C2P(center - scenePhysX->Origin), C2P(rotation)); const PxBoxGeometry geometry(C2P(halfExtents)); return scenePhysX->Scene->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter); } @@ -1338,7 +1368,7 @@ bool PhysicsBackend::BoxCast(void* scene, const Vector3& center, const Vector3& bool PhysicsBackend::BoxCast(void* scene, const Vector3& center, const Vector3& halfExtents, const Vector3& direction, RayCastHit& hitInfo, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) { SCENE_QUERY_SETUP_SWEEP_1(); - const PxTransform pose(C2P(center), C2P(rotation)); + const PxTransform pose(C2P(center - scenePhysX->Origin), C2P(rotation)); const PxBoxGeometry geometry(C2P(halfExtents)); if (!scenePhysX->Scene->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter)) return false; @@ -1349,7 +1379,7 @@ bool PhysicsBackend::BoxCast(void* scene, const Vector3& center, const Vector3& bool PhysicsBackend::BoxCastAll(void* scene, const Vector3& center, const Vector3& halfExtents, const Vector3& direction, Array& results, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) { SCENE_QUERY_SETUP_SWEEP(); - const PxTransform pose(C2P(center), C2P(rotation)); + const PxTransform pose(C2P(center - scenePhysX->Origin), C2P(rotation)); const PxBoxGeometry geometry(C2P(halfExtents)); if (!scenePhysX->Scene->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter)) return false; @@ -1360,7 +1390,7 @@ bool PhysicsBackend::BoxCastAll(void* scene, const Vector3& center, const Vector bool PhysicsBackend::SphereCast(void* scene, const Vector3& center, const float radius, const Vector3& direction, const float maxDistance, uint32 layerMask, bool hitTriggers) { SCENE_QUERY_SETUP_SWEEP_1(); - const PxTransform pose(C2P(center)); + const PxTransform pose(C2P(center - scenePhysX->Origin)); const PxSphereGeometry geometry(radius); return scenePhysX->Scene->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter); } @@ -1368,7 +1398,7 @@ bool PhysicsBackend::SphereCast(void* scene, const Vector3& center, const float bool PhysicsBackend::SphereCast(void* scene, const Vector3& center, const float radius, const Vector3& direction, RayCastHit& hitInfo, const float maxDistance, uint32 layerMask, bool hitTriggers) { SCENE_QUERY_SETUP_SWEEP_1(); - const PxTransform pose(C2P(center)); + const PxTransform pose(C2P(center - scenePhysX->Origin)); const PxSphereGeometry geometry(radius); if (!scenePhysX->Scene->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter)) return false; @@ -1379,7 +1409,7 @@ bool PhysicsBackend::SphereCast(void* scene, const Vector3& center, const float bool PhysicsBackend::SphereCastAll(void* scene, const Vector3& center, const float radius, const Vector3& direction, Array& results, const float maxDistance, uint32 layerMask, bool hitTriggers) { SCENE_QUERY_SETUP_SWEEP(); - const PxTransform pose(C2P(center)); + const PxTransform pose(C2P(center - scenePhysX->Origin)); const PxSphereGeometry geometry(radius); if (!scenePhysX->Scene->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter)) return false; @@ -1390,7 +1420,7 @@ bool PhysicsBackend::SphereCastAll(void* scene, const Vector3& center, const flo bool PhysicsBackend::CapsuleCast(void* scene, const Vector3& center, const float radius, const float height, const Vector3& direction, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) { SCENE_QUERY_SETUP_SWEEP_1(); - const PxTransform pose(C2P(center), C2P(rotation)); + const PxTransform pose(C2P(center - scenePhysX->Origin), C2P(rotation)); const PxCapsuleGeometry geometry(radius, height * 0.5f); return scenePhysX->Scene->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter); } @@ -1398,7 +1428,7 @@ bool PhysicsBackend::CapsuleCast(void* scene, const Vector3& center, const float bool PhysicsBackend::CapsuleCast(void* scene, const Vector3& center, const float radius, const float height, const Vector3& direction, RayCastHit& hitInfo, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) { SCENE_QUERY_SETUP_SWEEP_1(); - const PxTransform pose(C2P(center), C2P(rotation)); + const PxTransform pose(C2P(center - scenePhysX->Origin), C2P(rotation)); const PxCapsuleGeometry geometry(radius, height * 0.5f); if (!scenePhysX->Scene->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter)) return false; @@ -1409,7 +1439,7 @@ bool PhysicsBackend::CapsuleCast(void* scene, const Vector3& center, const float bool PhysicsBackend::CapsuleCastAll(void* scene, const Vector3& center, const float radius, const float height, const Vector3& direction, Array& results, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) { SCENE_QUERY_SETUP_SWEEP(); - const PxTransform pose(C2P(center), C2P(rotation)); + const PxTransform pose(C2P(center - scenePhysX->Origin), C2P(rotation)); const PxCapsuleGeometry geometry(radius, height * 0.5f); if (!scenePhysX->Scene->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter)) return false; @@ -1421,7 +1451,7 @@ bool PhysicsBackend::ConvexCast(void* scene, const Vector3& center, const Collis { CHECK_RETURN(convexMesh && convexMesh->GetOptions().Type == CollisionDataType::ConvexMesh, false) SCENE_QUERY_SETUP_SWEEP_1(); - const PxTransform pose(C2P(center), C2P(rotation)); + const PxTransform pose(C2P(center - scenePhysX->Origin), C2P(rotation)); const PxConvexMeshGeometry geometry((PxConvexMesh*)convexMesh->GetConvex(), PxMeshScale(C2P(scale))); return scenePhysX->Scene->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter); } @@ -1430,7 +1460,7 @@ bool PhysicsBackend::ConvexCast(void* scene, const Vector3& center, const Collis { CHECK_RETURN(convexMesh && convexMesh->GetOptions().Type == CollisionDataType::ConvexMesh, false) SCENE_QUERY_SETUP_SWEEP_1(); - const PxTransform pose(C2P(center), C2P(rotation)); + const PxTransform pose(C2P(center - scenePhysX->Origin), C2P(rotation)); const PxConvexMeshGeometry geometry((PxConvexMesh*)convexMesh->GetConvex(), PxMeshScale(C2P(scale))); if (!scenePhysX->Scene->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter)) return false; @@ -1442,7 +1472,7 @@ bool PhysicsBackend::ConvexCastAll(void* scene, const Vector3& center, const Col { CHECK_RETURN(convexMesh && convexMesh->GetOptions().Type == CollisionDataType::ConvexMesh, false) SCENE_QUERY_SETUP_SWEEP(); - const PxTransform pose(C2P(center), C2P(rotation)); + const PxTransform pose(C2P(center - scenePhysX->Origin), C2P(rotation)); const PxConvexMeshGeometry geometry((PxConvexMesh*)convexMesh->GetConvex(), PxMeshScale(C2P(scale))); if (!scenePhysX->Scene->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter)) return false; @@ -1453,7 +1483,7 @@ bool PhysicsBackend::ConvexCastAll(void* scene, const Vector3& center, const Col bool PhysicsBackend::CheckBox(void* scene, const Vector3& center, const Vector3& halfExtents, const Quaternion& rotation, uint32 layerMask, bool hitTriggers) { SCENE_QUERY_SETUP_OVERLAP_1(); - const PxTransform pose(C2P(center), C2P(rotation)); + const PxTransform pose(C2P(center - scenePhysX->Origin), C2P(rotation)); const PxBoxGeometry geometry(C2P(halfExtents)); return scenePhysX->Scene->overlap(geometry, pose, buffer, filterData, &QueryFilter); } @@ -1461,7 +1491,7 @@ bool PhysicsBackend::CheckBox(void* scene, const Vector3& center, const Vector3& bool PhysicsBackend::CheckSphere(void* scene, const Vector3& center, const float radius, uint32 layerMask, bool hitTriggers) { SCENE_QUERY_SETUP_OVERLAP_1(); - const PxTransform pose(C2P(center)); + const PxTransform pose(C2P(center - scenePhysX->Origin)); const PxSphereGeometry geometry(radius); return scenePhysX->Scene->overlap(geometry, pose, buffer, filterData, &QueryFilter); } @@ -1469,7 +1499,7 @@ bool PhysicsBackend::CheckSphere(void* scene, const Vector3& center, const float bool PhysicsBackend::CheckCapsule(void* scene, const Vector3& center, const float radius, const float height, const Quaternion& rotation, uint32 layerMask, bool hitTriggers) { SCENE_QUERY_SETUP_OVERLAP_1(); - const PxTransform pose(C2P(center), C2P(rotation)); + const PxTransform pose(C2P(center - scenePhysX->Origin), C2P(rotation)); const PxCapsuleGeometry geometry(radius, height * 0.5f); return scenePhysX->Scene->overlap(geometry, pose, buffer, filterData, &QueryFilter); } @@ -1478,7 +1508,7 @@ bool PhysicsBackend::CheckConvex(void* scene, const Vector3& center, const Colli { CHECK_RETURN(convexMesh && convexMesh->GetOptions().Type == CollisionDataType::ConvexMesh, false) SCENE_QUERY_SETUP_OVERLAP_1(); - const PxTransform pose(C2P(center), C2P(rotation)); + const PxTransform pose(C2P(center - scenePhysX->Origin), C2P(rotation)); const PxConvexMeshGeometry geometry((PxConvexMesh*)convexMesh->GetConvex(), PxMeshScale(C2P(scale))); return scenePhysX->Scene->overlap(geometry, pose, buffer, filterData, &QueryFilter); } @@ -1486,7 +1516,7 @@ bool PhysicsBackend::CheckConvex(void* scene, const Vector3& center, const Colli bool PhysicsBackend::OverlapBox(void* scene, const Vector3& center, const Vector3& halfExtents, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers) { SCENE_QUERY_SETUP_OVERLAP(); - const PxTransform pose(C2P(center), C2P(rotation)); + const PxTransform pose(C2P(center - scenePhysX->Origin), C2P(rotation)); const PxBoxGeometry geometry(C2P(halfExtents)); if (!scenePhysX->Scene->overlap(geometry, pose, buffer, filterData, &QueryFilter)) return false; @@ -1497,7 +1527,7 @@ bool PhysicsBackend::OverlapBox(void* scene, const Vector3& center, const Vector bool PhysicsBackend::OverlapSphere(void* scene, const Vector3& center, const float radius, Array& results, uint32 layerMask, bool hitTriggers) { SCENE_QUERY_SETUP_OVERLAP(); - const PxTransform pose(C2P(center)); + const PxTransform pose(C2P(center - scenePhysX->Origin)); const PxSphereGeometry geometry(radius); if (!scenePhysX->Scene->overlap(geometry, pose, buffer, filterData, &QueryFilter)) return false; @@ -1508,7 +1538,7 @@ bool PhysicsBackend::OverlapSphere(void* scene, const Vector3& center, const flo bool PhysicsBackend::OverlapCapsule(void* scene, const Vector3& center, const float radius, const float height, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers) { SCENE_QUERY_SETUP_OVERLAP(); - const PxTransform pose(C2P(center), C2P(rotation)); + const PxTransform pose(C2P(center - scenePhysX->Origin), C2P(rotation)); const PxCapsuleGeometry geometry(radius, height * 0.5f); if (!scenePhysX->Scene->overlap(geometry, pose, buffer, filterData, &QueryFilter)) return false; @@ -1520,7 +1550,7 @@ bool PhysicsBackend::OverlapConvex(void* scene, const Vector3& center, const Col { CHECK_RETURN(convexMesh && convexMesh->GetOptions().Type == CollisionDataType::ConvexMesh, false) SCENE_QUERY_SETUP_OVERLAP(); - const PxTransform pose(C2P(center), C2P(rotation)); + const PxTransform pose(C2P(center - scenePhysX->Origin), C2P(rotation)); const PxConvexMeshGeometry geometry((PxConvexMesh*)convexMesh->GetConvex(), PxMeshScale(C2P(scale))); if (!scenePhysX->Scene->overlap(geometry, pose, buffer, filterData, &QueryFilter)) return false; @@ -1531,7 +1561,7 @@ bool PhysicsBackend::OverlapConvex(void* scene, const Vector3& center, const Col bool PhysicsBackend::OverlapBox(void* scene, const Vector3& center, const Vector3& halfExtents, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers) { SCENE_QUERY_SETUP_OVERLAP(); - const PxTransform pose(C2P(center), C2P(rotation)); + const PxTransform pose(C2P(center - scenePhysX->Origin), C2P(rotation)); const PxBoxGeometry geometry(C2P(halfExtents)); if (!scenePhysX->Scene->overlap(geometry, pose, buffer, filterData, &QueryFilter)) return false; @@ -1542,7 +1572,7 @@ bool PhysicsBackend::OverlapBox(void* scene, const Vector3& center, const Vector bool PhysicsBackend::OverlapSphere(void* scene, const Vector3& center, const float radius, Array& results, uint32 layerMask, bool hitTriggers) { SCENE_QUERY_SETUP_OVERLAP(); - const PxTransform pose(C2P(center)); + const PxTransform pose(C2P(center - scenePhysX->Origin)); const PxSphereGeometry geometry(radius); if (!scenePhysX->Scene->overlap(geometry, pose, buffer, filterData, &QueryFilter)) return false; @@ -1553,7 +1583,7 @@ bool PhysicsBackend::OverlapSphere(void* scene, const Vector3& center, const flo bool PhysicsBackend::OverlapCapsule(void* scene, const Vector3& center, const float radius, const float height, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers) { SCENE_QUERY_SETUP_OVERLAP(); - const PxTransform pose(C2P(center), C2P(rotation)); + const PxTransform pose(C2P(center - scenePhysX->Origin), C2P(rotation)); const PxCapsuleGeometry geometry(radius, height * 0.5f); if (!scenePhysX->Scene->overlap(geometry, pose, buffer, filterData, &QueryFilter)) return false; @@ -1565,7 +1595,7 @@ bool PhysicsBackend::OverlapConvex(void* scene, const Vector3& center, const Col { CHECK_RETURN(convexMesh && convexMesh->GetOptions().Type == CollisionDataType::ConvexMesh, false) SCENE_QUERY_SETUP_OVERLAP(); - const PxTransform pose(C2P(center), C2P(rotation)); + const PxTransform pose(C2P(center - scenePhysX->Origin), C2P(rotation)); const PxConvexMeshGeometry geometry((PxConvexMesh*)convexMesh->GetConvex(), PxMeshScale(C2P(scale))); if (!scenePhysX->Scene->overlap(geometry, pose, buffer, filterData, &QueryFilter)) return false; @@ -1604,6 +1634,9 @@ void PhysicsBackend::GetActorBounds(void* actor, BoundingBox& bounds) auto actorPhysX = (PxActor*)actor; const float boundsScale = 1.02f; bounds = P2C(actorPhysX->getWorldBounds(boundsScale)); + const Vector3 sceneOrigin = SceneOrigins[actorPhysX->getScene()]; + bounds.Minimum += sceneOrigin; + bounds.Maximum += sceneOrigin; } int32 PhysicsBackend::GetRigidActorShapesCount(void* actor) @@ -1612,9 +1645,10 @@ int32 PhysicsBackend::GetRigidActorShapesCount(void* actor) return actorPhysX->getNbShapes(); } -void* PhysicsBackend::CreateRigidDynamicActor(IPhysicsActor* actor, const Vector3& position, const Quaternion& orientation) +void* PhysicsBackend::CreateRigidDynamicActor(IPhysicsActor* actor, const Vector3& position, const Quaternion& orientation, void* scene) { - const PxTransform trans(C2P(position), C2P(orientation)); + const Vector3 sceneOrigin = SceneOrigins[scene ? ( (ScenePhysX*)scene)->Scene : nullptr]; + const PxTransform trans(C2P(position - sceneOrigin), C2P(orientation)); PxRigidDynamic* actorPhysX = PhysX->createRigidDynamic(trans); actorPhysX->userData = actor; #if PHYSX_DEBUG_NAMING @@ -1626,9 +1660,10 @@ void* PhysicsBackend::CreateRigidDynamicActor(IPhysicsActor* actor, const Vector return actorPhysX; } -void* PhysicsBackend::CreateRigidStaticActor(IPhysicsActor* actor, const Vector3& position, const Quaternion& orientation) +void* PhysicsBackend::CreateRigidStaticActor(IPhysicsActor* actor, const Vector3& position, const Quaternion& orientation, void* scene) { - const PxTransform trans(C2P(position), C2P(orientation)); + const Vector3 sceneOrigin = SceneOrigins[scene ? ( (ScenePhysX*)scene)->Scene : nullptr]; + const PxTransform trans(C2P(position - sceneOrigin), C2P(orientation)); PxRigidStatic* actorPhysX = PhysX->createRigidStatic(trans); actorPhysX->userData = actor; #if PHYSX_DEBUG_NAMING @@ -1667,13 +1702,15 @@ void PhysicsBackend::GetRigidActorPose(void* actor, Vector3& position, Quaternio { auto actorPhysX = (PxRigidActor*)actor; auto pose = actorPhysX->getGlobalPose(); - position = P2C(pose.p); + const Vector3 sceneOrigin = SceneOrigins[actorPhysX->getScene()]; + position = P2C(pose.p) + sceneOrigin; orientation = P2C(pose.q); } void PhysicsBackend::SetRigidActorPose(void* actor, const Vector3& position, const Quaternion& orientation, bool kinematic, bool wakeUp) { - const PxTransform trans(C2P(position), C2P(orientation)); + const Vector3 sceneOrigin = SceneOrigins[((PxActor*)actor)->getScene()]; + const PxTransform trans(C2P(position - sceneOrigin), C2P(orientation)); if (kinematic) { auto actorPhysX = (PxRigidDynamic*)actor; @@ -1852,7 +1889,8 @@ void PhysicsBackend::AddRigidDynamicActorForce(void* actor, const Vector3& force void PhysicsBackend::AddRigidDynamicActorForceAtPosition(void* actor, const Vector3& force, const Vector3& position, ForceMode mode) { auto actorPhysX = (PxRigidDynamic*)actor; - PxRigidBodyExt::addForceAtPos(*actorPhysX, C2P(force), C2P(position), static_cast(mode)); + const Vector3 sceneOrigin = SceneOrigins[actorPhysX->getScene()]; + PxRigidBodyExt::addForceAtPos(*actorPhysX, C2P(force), C2P(position - sceneOrigin), static_cast(mode)); } void PhysicsBackend::AddRigidDynamicActorTorque(void* actor, const Vector3& torque, ForceMode mode) @@ -1907,7 +1945,8 @@ void PhysicsBackend::GetShapePose(void* shape, Vector3& position, Quaternion& or auto shapePhysX = (PxShape*)shape; PxRigidActor* actorPhysX = shapePhysX->getActor(); PxTransform pose = actorPhysX->getGlobalPose().transform(shapePhysX->getLocalPose()); - position = P2C(pose.p); + const Vector3 sceneOrigin = SceneOrigins[actorPhysX->getScene()]; + position = P2C(pose.p) + sceneOrigin; orientation = P2C(pose.q); } @@ -2015,10 +2054,11 @@ float PhysicsBackend::ComputeShapeSqrDistanceToPoint(void* shape, const Vector3& bool PhysicsBackend::RayCastShape(void* shape, const Vector3& position, const Quaternion& orientation, const Vector3& origin, const Vector3& direction, float& resultHitDistance, float maxDistance) { auto shapePhysX = (PxShape*)shape; - const PxTransform trans(C2P(position), C2P(orientation)); + const Vector3 sceneOrigin = SceneOrigins[shapePhysX->getActor() ? shapePhysX->getActor()->getScene() : nullptr]; + const PxTransform trans(C2P(position - sceneOrigin), C2P(orientation)); const PxHitFlags hitFlags = (PxHitFlags)0; PxRaycastHit hit; - if (PxGeometryQuery::raycast(C2P(origin), C2P(direction), shapePhysX->getGeometry().any(), trans, maxDistance, hitFlags, 1, &hit) != 0) + if (PxGeometryQuery::raycast(C2P(origin - sceneOrigin), C2P(direction), shapePhysX->getGeometry().any(), trans, maxDistance, hitFlags, 1, &hit) != 0) { resultHitDistance = hit.distance; return true; @@ -2029,12 +2069,14 @@ bool PhysicsBackend::RayCastShape(void* shape, const Vector3& position, const Qu bool PhysicsBackend::RayCastShape(void* shape, const Vector3& position, const Quaternion& orientation, const Vector3& origin, const Vector3& direction, RayCastHit& hitInfo, float maxDistance) { auto shapePhysX = (PxShape*)shape; - const PxTransform trans(C2P(position), C2P(orientation)); + const Vector3 sceneOrigin = SceneOrigins[shapePhysX->getActor() ? shapePhysX->getActor()->getScene() : nullptr]; + const PxTransform trans(C2P(position - sceneOrigin), C2P(orientation)); const PxHitFlags hitFlags = PxHitFlag::ePOSITION | PxHitFlag::eNORMAL | PxHitFlag::eFACE_INDEX | PxHitFlag::eUV; PxRaycastHit hit; - if (PxGeometryQuery::raycast(C2P(origin), C2P(direction), shapePhysX->getGeometry().any(), trans, maxDistance, hitFlags, 1, &hit) == 0) + if (PxGeometryQuery::raycast(C2P(origin - sceneOrigin), C2P(direction), shapePhysX->getGeometry().any(), trans, maxDistance, hitFlags, 1, &hit) == 0) return false; P2C(hit, hitInfo); + hitInfo.Point += sceneOrigin; return true; } @@ -2390,10 +2432,11 @@ float PhysicsBackend::GetD6JointSwingZ(void* joint) void* PhysicsBackend::CreateController(void* scene, IPhysicsActor* actor, PhysicsColliderActor* collider, float contactOffset, const Vector3& position, float slopeLimit, int32 nonWalkableMode, JsonAsset* material, float radius, float height, float stepOffset, void*& shape) { auto scenePhysX = (ScenePhysX*)scene; + const Vector3 sceneOrigin = SceneOrigins[scenePhysX->Scene]; PxCapsuleControllerDesc desc; desc.userData = actor; desc.contactOffset = Math::Max(contactOffset, ZeroTolerance); - desc.position = PxExtendedVec3(position.X, position.Y, position.Z); + desc.position = PxExtendedVec3(position.X - sceneOrigin.X, position.Y - sceneOrigin.Y, position.Z - sceneOrigin.Z); desc.slopeLimit = Math::Cos(slopeLimit * DegreesToRadians); desc.nonWalkableMode = static_cast(nonWalkableMode); desc.climbingMode = PxCapsuleClimbingMode::eEASY; @@ -2465,13 +2508,15 @@ void PhysicsBackend::SetControllerUpDirection(void* controller, const Vector3& v Vector3 PhysicsBackend::GetControllerPosition(void* controller) { auto controllerPhysX = (PxCapsuleController*)controller; - return P2C(controllerPhysX->getPosition()); + const Vector3 origin = SceneOrigins[controllerPhysX->getScene()]; + return P2C(controllerPhysX->getPosition()) + origin; } void PhysicsBackend::SetControllerPosition(void* controller, const Vector3& value) { auto controllerPhysX = (PxCapsuleController*)controller; - controllerPhysX->setPosition(PxExtendedVec3(value.X, value.Y, value.Z)); + const Vector3 sceneOrigin = SceneOrigins[controllerPhysX->getScene()]; + controllerPhysX->setPosition(PxExtendedVec3(value.X - sceneOrigin.X, value.Y - sceneOrigin.Y, value.Z - sceneOrigin.Z)); } int32 PhysicsBackend::MoveController(void* controller, void* shape, const Vector3& displacement, float minMoveDistance, float deltaTime) diff --git a/Source/Engine/Physics/Physics.cpp b/Source/Engine/Physics/Physics.cpp index 3bc4f6cd7..2dbd9041c 100644 --- a/Source/Engine/Physics/Physics.cpp +++ b/Source/Engine/Physics/Physics.cpp @@ -384,12 +384,12 @@ void PhysicsScene::SetGravity(const Vector3& value) PhysicsBackend::SetSceneGravity(_scene, value); } -Vector3 PhysicsScene::GetGravity() +Vector3 PhysicsScene::GetGravity() const { return PhysicsBackend::GetSceneGravity(_scene); } -bool PhysicsScene::GetEnableCCD() +bool PhysicsScene::GetEnableCCD() const { return PhysicsBackend::GetSceneEnableCCD(_scene); } @@ -409,6 +409,15 @@ void PhysicsScene::SetBounceThresholdVelocity(float value) PhysicsBackend::SetSceneBounceThresholdVelocity(_scene, value); } +void PhysicsScene::SetOrigin(const Vector3& value) +{ + if (_origin != value) + { + PhysicsBackend::SetSceneOrigin(_scene, _origin, value); + _origin = value; + } +} + bool PhysicsScene::Init(const StringView& name, const PhysicsSettings& settings) { if (_scene) diff --git a/Source/Engine/Physics/PhysicsBackend.h b/Source/Engine/Physics/PhysicsBackend.h index 3086efe1d..50f0a3f71 100644 --- a/Source/Engine/Physics/PhysicsBackend.h +++ b/Source/Engine/Physics/PhysicsBackend.h @@ -94,6 +94,7 @@ public: static void SetSceneEnableCCD(void* scene, bool value); static float GetSceneBounceThresholdVelocity(void* scene); static void SetSceneBounceThresholdVelocity(void* scene, float value); + static void SetSceneOrigin(void* scene, const Vector3& oldOrigin, const Vector3& newOrigin); static void AddSceneActor(void* scene, void* actor); static void RemoveSceneActor(void* scene, void* actor); static void AddSceneActorAction(void* scene, void* actor, ActionType action); @@ -132,8 +133,8 @@ public: static void SetActorFlags(void* actor, ActorFlags value); static void GetActorBounds(void* actor, BoundingBox& bounds); static int32 GetRigidActorShapesCount(void* actor); - static void* CreateRigidDynamicActor(IPhysicsActor* actor, const Vector3& position, const Quaternion& orientation); - static void* CreateRigidStaticActor(IPhysicsActor* actor, const Vector3& position, const Quaternion& orientation); + static void* CreateRigidDynamicActor(IPhysicsActor* actor, const Vector3& position, const Quaternion& orientation, void* scene); + static void* CreateRigidStaticActor(IPhysicsActor* actor, const Vector3& position, const Quaternion& orientation, void* scene); static RigidDynamicFlags GetRigidDynamicActorFlags(void* actor); static void SetRigidDynamicActorFlags(void* actor, RigidDynamicFlags value); static void GetRigidActorPose(void* actor, Vector3& position, Quaternion& orientation); diff --git a/Source/Engine/Physics/PhysicsScene.h b/Source/Engine/Physics/PhysicsScene.h index db17c7ac1..6b5ab41ab 100644 --- a/Source/Engine/Physics/PhysicsScene.h +++ b/Source/Engine/Physics/PhysicsScene.h @@ -28,6 +28,7 @@ private: String _name; bool _autoSimulation = true; bool _isDuringSimulation = false; + Vector3 _origin = Vector3::Zero; void* _scene = nullptr; public: @@ -59,7 +60,7 @@ public: /// /// Gets the current gravity force. /// - API_PROPERTY() Vector3 GetGravity(); + API_PROPERTY() Vector3 GetGravity() const; /// /// Sets the current gravity force. @@ -69,7 +70,7 @@ public: /// /// Gets the CCD feature enable flag. /// - API_PROPERTY() bool GetEnableCCD(); + API_PROPERTY() bool GetEnableCCD() const; /// /// Sets the CCD feature enable flag. @@ -86,6 +87,19 @@ public: /// API_PROPERTY() void SetBounceThresholdVelocity(float value); + /// + /// Gets the current scene origin that defines the center of the simulation (in world). Can be used to run physics simulation relative to the camera. + /// + API_PROPERTY() FORCE_INLINE Vector3 GetOrigin() const + { + return _origin; + } + + /// + /// Sets the current scene origin that defines the center of the simulation (in world). Can be used to run physics simulation relative to the camera. + /// + API_PROPERTY() void SetOrigin(const Vector3& value); + public: /// /// Initializes the scene. diff --git a/Source/Engine/Terrain/TerrainPatch.cpp b/Source/Engine/Terrain/TerrainPatch.cpp index 07140f059..67fa70a34 100644 --- a/Source/Engine/Terrain/TerrainPatch.cpp +++ b/Source/Engine/Terrain/TerrainPatch.cpp @@ -2113,9 +2113,9 @@ void TerrainPatch::CreateCollision() PhysicsBackend::SetShapeLocalPose(_physicsShape, Vector3(0, _yOffset * terrainTransform.Scale.Y, 0), Quaternion::Identity); // Create static actor - _physicsActor = PhysicsBackend::CreateRigidStaticActor(nullptr, terrainTransform.LocalToWorld(_offset), terrainTransform.Orientation); - PhysicsBackend::AttachShape(_physicsShape, _physicsActor); void* scene = _terrain->GetPhysicsScene()->GetPhysicsScene(); + _physicsActor = PhysicsBackend::CreateRigidStaticActor(nullptr, terrainTransform.LocalToWorld(_offset), terrainTransform.Orientation, scene); + PhysicsBackend::AttachShape(_physicsShape, _physicsActor); PhysicsBackend::AddSceneActor(scene, _physicsActor); }