diff --git a/Source/Engine/ContentImporters/CreateCollisionData.cpp b/Source/Engine/ContentImporters/CreateCollisionData.cpp index f2d90ea10..8409915ee 100644 --- a/Source/Engine/ContentImporters/CreateCollisionData.cpp +++ b/Source/Engine/ContentImporters/CreateCollisionData.cpp @@ -5,6 +5,7 @@ #if COMPILE_WITH_ASSETS_IMPORTER #include "AssetsImportingManager.h" +#include "Engine/Physics/CollisionData.h" CreateAssetResult CreateCollisionData::Create(CreateAssetContext& context) { diff --git a/Source/Engine/Engine/Engine.cpp b/Source/Engine/Engine/Engine.cpp index 4e411243d..f8a3a11a6 100644 --- a/Source/Engine/Engine/Engine.cpp +++ b/Source/Engine/Engine/Engine.cpp @@ -197,7 +197,7 @@ int32 Engine::Main(const Char* cmdLine) } // Collect physics simulation results (does nothing if Simulate hasn't been called in the previous loop step) - Physics::CollectResultsAll(); + Physics::CollectResults(); } // Call on exit event @@ -242,7 +242,7 @@ void Engine::OnFixedUpdate() { PROFILE_CPU_NAMED("Fixed Update"); - Physics::FlushRequestsAll(); + Physics::FlushRequests(); // Call event FixedUpdate(); @@ -253,7 +253,7 @@ void Engine::OnFixedUpdate() if (!Time::GetGamePaused()) { const float dt = Time::Physics.DeltaTime.GetTotalSeconds(); - Physics::SimulateAll(dt); + Physics::Simulate(dt); // After this point we should not modify physic objects state (rendering operations is mostly readonly) // That's because auto-simulation mode is performing rendering during physics simulation @@ -429,7 +429,7 @@ void Engine::OnExit() EngineImpl::IsReady = false; // Collect physics simulation results because we cannot exit with physics running - Physics::CollectResultsAll(); + Physics::CollectResults(); // Before Application::BeforeExit(); diff --git a/Source/Engine/Level/Actor.cpp b/Source/Engine/Level/Actor.cpp index f2a0a3a62..ac10d3ed6 100644 --- a/Source/Engine/Level/Actor.cpp +++ b/Source/Engine/Level/Actor.cpp @@ -1814,9 +1814,9 @@ void Actor::FromJson(const StringAnsiView& json) void Actor::SetPhysicsScene(PhysicsScene* scene) { - ASSERT(scene); + CHECK(scene); - auto previous = GetPhysicsScene(); + const auto previous = GetPhysicsScene(); _physicsScene = scene; if (previous != _physicsScene) @@ -1829,10 +1829,7 @@ void Actor::SetPhysicsScene(PhysicsScene* scene) } } -PhysicsScene* Actor::GetPhysicsScene() +PhysicsScene* Actor::GetPhysicsScene() const { - if (_physicsScene == nullptr) - _physicsScene = Physics::DefaultScene; - - return _physicsScene; + return _physicsScene ? _physicsScene : Physics::DefaultScene; } diff --git a/Source/Engine/Level/Actor.h b/Source/Engine/Level/Actor.h index a54155e5f..ef310204c 100644 --- a/Source/Engine/Level/Actor.h +++ b/Source/Engine/Level/Actor.h @@ -970,10 +970,10 @@ public: /// /// Get the physics world the controller is part of. /// - API_PROPERTY(Attributes="HideInEditor") PhysicsScene* GetPhysicsScene(); + API_PROPERTY(Attributes="HideInEditor") PhysicsScene* GetPhysicsScene() const; protected: - virtual void OnPhysicsSceneChanged(PhysicsScene* previous) {}; + virtual void OnPhysicsSceneChanged(PhysicsScene* previous) {} private: diff --git a/Source/Engine/Physics/Actors/IPhysicsActor.h b/Source/Engine/Physics/Actors/IPhysicsActor.h index 28f7fddf4..9ce642d1f 100644 --- a/Source/Engine/Physics/Actors/IPhysicsActor.h +++ b/Source/Engine/Physics/Actors/IPhysicsActor.h @@ -2,36 +2,27 @@ #pragma once -namespace physx -{ - class PxRigidActor; - class PxTransform; -} - /// /// A base interface for all physical actors types/owners that can responds on transformation changed event. /// class FLAXENGINE_API IPhysicsActor { public: - /// /// Finalizes an instance of the class. /// virtual ~IPhysicsActor() = default; /// - /// Gets the rigid actor (PhysX object) may be null. + /// Gets the native physics backend object. /// - /// PhysX rigid actor or null if not using - virtual physx::PxRigidActor* GetRigidActor() = 0; + virtual void* GetPhysicsActor() const = 0; /// - /// Called when actor's active transformation gets changed after the physics simulation step. + /// Called when actor's active transformation gets changed after the physics simulation step during. /// /// /// This event is called internally by the Physics service and should not be used by the others. /// - /// The current transformation. - virtual void OnActiveTransformChanged(const physx::PxTransform& transform) = 0; + virtual void OnActiveTransformChanged() = 0; }; diff --git a/Source/Engine/Physics/Actors/PhysicsActor.cpp b/Source/Engine/Physics/Actors/PhysicsActor.cpp index 8e92ea902..b0adcf09d 100644 --- a/Source/Engine/Physics/Actors/PhysicsActor.cpp +++ b/Source/Engine/Physics/Actors/PhysicsActor.cpp @@ -1,10 +1,7 @@ // Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. #include "PhysicsActor.h" -#include "Engine/Physics/Utilities.h" -#include "Engine/Physics/Physics.h" -#include -#include +#include "../PhysicsBackend.h" PhysicsActor::PhysicsActor(const SpawnParams& params) : Actor(params) @@ -13,28 +10,23 @@ PhysicsActor::PhysicsActor(const SpawnParams& params) { } -void PhysicsActor::OnActiveTransformChanged(const PxTransform& transform) +void PhysicsActor::OnActiveTransformChanged() { // Change actor transform (but with locking) ASSERT(!_isUpdatingTransform); _isUpdatingTransform = true; - //SetTransform(Transform(P2C(transform.p), P2C(transform.q), GetScale())); + Transform transform; + PhysicsBackend::GetRigidActorPose(GetPhysicsActor(), transform.Translation, transform.Orientation); + transform.Scale = _transform.Scale; + if (_parent) { - Transform v; - v.Translation = P2C(transform.p); - v.Orientation = P2C(transform.q); - v.Scale = _transform.Scale; - - if (_parent) - { - _parent->GetTransform().WorldToLocal(v, _localTransform); - } - else - { - _localTransform = v; - } - OnTransformChanged(); + _parent->GetTransform().WorldToLocal(transform, _localTransform); } + else + { + _localTransform = transform; + } + OnTransformChanged(); _isUpdatingTransform = false; } @@ -48,31 +40,11 @@ void PhysicsActor::OnTransformChanged() void PhysicsActor::UpdateBounds() { - const auto actor = GetPhysXActor(); - const float boundsScale = 1.02f; - if (actor && actor->getScene() != nullptr) - { - if (actor->is()) - { - const auto rigidActor = (PxRigidActor*)actor; - if (rigidActor->getNbShapes() != 0) - { - _box = P2C(actor->getWorldBounds(boundsScale)); - } - else - { - _box = BoundingBox(_transform.Translation); - } - } - else - { - _box = P2C(actor->getWorldBounds(boundsScale)); - } - } + void* actor = GetPhysicsActor(); + if (actor) + PhysicsBackend::GetActorBounds(actor, _box); else - { _box = BoundingBox(_transform.Translation); - } BoundingSphere::FromBox(_box, _sphere); } diff --git a/Source/Engine/Physics/Actors/PhysicsActor.h b/Source/Engine/Physics/Actors/PhysicsActor.h index 05e015074..07d7291e3 100644 --- a/Source/Engine/Physics/Actors/PhysicsActor.h +++ b/Source/Engine/Physics/Actors/PhysicsActor.h @@ -6,8 +6,6 @@ #include "Engine/Physics/Types.h" #include "IPhysicsActor.h" -class PhysicsScene; - /// /// A base class for all physical actors. /// @@ -22,12 +20,6 @@ protected: public: - /// - /// Gets the native PhysX actor object. - /// - /// The PhysX actor. - virtual PxActor* GetPhysXActor() = 0; - /// /// Updates the bounding box. /// @@ -39,7 +31,7 @@ public: bool IntersectsItself(const Ray& ray, float& distance, Vector3& normal) override; // [IPhysicsActor] - void OnActiveTransformChanged(const PxTransform& transform) override; + void OnActiveTransformChanged() override; protected: diff --git a/Source/Engine/Physics/Actors/RigidBody.cpp b/Source/Engine/Physics/Actors/RigidBody.cpp index a3047889d..fc64113cc 100644 --- a/Source/Engine/Physics/Actors/RigidBody.cpp +++ b/Source/Engine/Physics/Actors/RigidBody.cpp @@ -1,19 +1,11 @@ // Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. #include "RigidBody.h" -#include "PxMaterial.h" - #include "Engine/Core/Log.h" -#include "Engine/Physics/Utilities.h" #include "Engine/Physics/Colliders/Collider.h" -#include "Engine/Physics/Physics.h" -#include "Engine/Physics/PhysicalMaterial.h" +#include "Engine/Physics/PhysicsBackend.h" #include "Engine/Physics/PhysicsScene.h" #include "Engine/Serialization/Serialization.h" -#include -#include -#include -#include RigidBody::RigidBody(const SpawnParams& params) : PhysicsActor(params) @@ -39,52 +31,38 @@ void RigidBody::SetIsKinematic(const bool value) { if (value == GetIsKinematic()) return; - _isKinematic = value; - if (_actor) - _actor->setRigidBodyFlag(PxRigidBodyFlag::eKINEMATIC, value); + PhysicsBackend::SetRigidDynamicActorFlag(_actor, PhysicsBackend::RigidDynamicFlags::Kinematic, value); } void RigidBody::SetLinearDamping(float value) { if (Math::NearEqual(value, _linearDamping)) return; - _linearDamping = value; - if (_actor) - { - _actor->setLinearDamping(value); - } + PhysicsBackend::SetRigidDynamicActorLinearDamping(_actor, _linearDamping); } void RigidBody::SetAngularDamping(float value) { if (Math::NearEqual(value, _angularDamping)) return; - _angularDamping = value; - if (_actor) - { - _actor->setAngularDamping(value); - } + PhysicsBackend::SetRigidDynamicActorAngularDamping(_actor, _angularDamping); } void RigidBody::SetEnableSimulation(bool value) { if (value == GetEnableSimulation()) return; - _enableSimulation = value; - if (_actor) { const bool isActive = _enableSimulation && IsActiveInHierarchy(); - _actor->setActorFlag(PxActorFlag::eDISABLE_SIMULATION, !isActive); - - // Auto wake up + PhysicsBackend::SetActorFlag(_actor, PhysicsBackend::ActorFlags::NoSimulation, !isActive); if (isActive && GetStartAwake()) WakeUp(); } @@ -94,24 +72,19 @@ void RigidBody::SetUseCCD(bool value) { if (value == GetUseCCD()) return; - _useCCD = value; - if (_actor) - _actor->setRigidBodyFlag(PxRigidBodyFlag::eENABLE_CCD, value); + PhysicsBackend::SetRigidDynamicActorFlag(_actor, PhysicsBackend::RigidDynamicFlags::CCD, value); } void RigidBody::SetEnableGravity(bool value) { if (value == GetEnableGravity()) return; - _enableGravity = value; - if (_actor) { - _actor->setActorFlag(PxActorFlag::eDISABLE_GRAVITY, !value); - + PhysicsBackend::SetActorFlag(_actor, PhysicsBackend::ActorFlags::NoGravity, !value); if (value) WakeUp(); } @@ -131,11 +104,9 @@ void RigidBody::SetMaxAngularVelocity(float value) { if (Math::NearEqual(value, _maxAngularVelocity)) return; - _maxAngularVelocity = value; - if (_actor) - _actor->setMaxAngularVelocity(value); + PhysicsBackend::SetRigidDynamicActorMaxAngularVelocity(_actor, _maxAngularVelocity); } bool RigidBody::GetOverrideMass() const @@ -147,9 +118,7 @@ void RigidBody::SetOverrideMass(bool value) { if (value == GetOverrideMass()) return; - _overrideMass = value; - UpdateMass(); } @@ -162,12 +131,8 @@ void RigidBody::SetMass(float value) { if (Math::NearEqual(value, _mass)) return; - _mass = value; - - // Auto enable override _overrideMass = true; - UpdateMass(); } @@ -180,7 +145,6 @@ void RigidBody::SetMassScale(float value) { if (Math::NearEqual(value, _massScale)) return; - _massScale = value; UpdateMass(); } @@ -189,163 +153,102 @@ void RigidBody::SetCenterOfMassOffset(const Vector3& value) { if (Vector3::NearEqual(value, _centerOfMassOffset)) return; - _centerOfMassOffset = value; - if (_actor) - { - PxTransform pose = _actor->getCMassLocalPose(); - pose.p += C2P(_centerOfMassOffset); - _actor->setCMassLocalPose(pose); - } + PhysicsBackend::SetRigidDynamicActorCenterOfMassOffset(_actor, _centerOfMassOffset); } void RigidBody::SetConstraints(const RigidbodyConstraints value) { if (value == _constraints) return; - _constraints = value; - if (_actor) - { - _actor->setRigidDynamicLockFlags(static_cast(value)); - } + PhysicsBackend::SetRigidDynamicActorConstraints(_actor, value); } Vector3 RigidBody::GetLinearVelocity() const { - return _actor ? P2C(_actor->getLinearVelocity()) : Vector3::Zero; + return _actor ? PhysicsBackend::GetRigidDynamicActorLinearVelocity(_actor) : Vector3::Zero; } void RigidBody::SetLinearVelocity(const Vector3& value) const { if (_actor) - _actor->setLinearVelocity(C2P(value), GetStartAwake()); + PhysicsBackend::SetRigidDynamicActorLinearVelocity(_actor, value, GetStartAwake()); } Vector3 RigidBody::GetAngularVelocity() const { - return _actor ? P2C(_actor->getAngularVelocity()) : Vector3::Zero; + return _actor ? PhysicsBackend::GetRigidDynamicActorAngularVelocity(_actor) : Vector3::Zero; } void RigidBody::SetAngularVelocity(const Vector3& value) const { if (_actor) - _actor->setAngularVelocity(C2P(value), GetStartAwake()); + PhysicsBackend::SetRigidDynamicActorAngularVelocity(_actor, value, GetStartAwake()); } float RigidBody::GetMaxDepenetrationVelocity() const { - return _actor ? _actor->getMaxDepenetrationVelocity() : 0; + return _actor ? PhysicsBackend::GetRigidDynamicActorMaxDepenetrationVelocity(_actor) : 0; } void RigidBody::SetMaxDepenetrationVelocity(const float value) const { if (_actor) - _actor->setMaxDepenetrationVelocity(value); + PhysicsBackend::SetRigidDynamicActorMaxDepenetrationVelocity(_actor, value); } float RigidBody::GetSleepThreshold() const { - return _actor ? _actor->getSleepThreshold() : 0; + return _actor ? PhysicsBackend::GetRigidDynamicActorSleepThreshold(_actor) : 0; } void RigidBody::SetSleepThreshold(const float value) const { if (_actor) - _actor->setSleepThreshold(value); + PhysicsBackend::SetRigidDynamicActorSleepThreshold(_actor, value); } Vector3 RigidBody::GetCenterOfMass() const { - return _actor ? P2C(_actor->getCMassLocalPose().p) : Vector3::Zero; + return _actor ? PhysicsBackend::GetRigidDynamicActorCenterOfMass(_actor) : Vector3::Zero; } bool RigidBody::IsSleeping() const { - return _actor ? _actor->isSleeping() : false; + return _actor ? PhysicsBackend::GetRigidDynamicActorIsSleeping(_actor) : false; } void RigidBody::Sleep() const { - if (_actor && GetEnableSimulation() && !GetIsKinematic() && IsActiveInHierarchy() && _actor->getScene()) - { - _actor->putToSleep(); - } + if (_actor && GetEnableSimulation() && !GetIsKinematic() && IsActiveInHierarchy()) + PhysicsBackend::GetRigidActorSleep(_actor); } void RigidBody::WakeUp() const { - if (_actor && GetEnableSimulation() && !GetIsKinematic() && IsActiveInHierarchy() && _actor->getScene()) - { - _actor->wakeUp(); - } + if (_actor && GetEnableSimulation() && !GetIsKinematic() && IsActiveInHierarchy()) + PhysicsBackend::GetRigidDynamicActorWakeUp(_actor); } void RigidBody::UpdateMass() { - if (_actor == nullptr) - return; - - if (_overrideMass) - { - // Use fixed mass - PxRigidBodyExt::setMassAndUpdateInertia(*_actor, Math::Max(_mass * _massScale, 0.001f)); - } - else - { - // Calculate per-shape densities (convert kg/m^3 into engine units) - const float minDensity = 0.08375f; // Hydrogen density - const float defaultDensity = 1000.0f; // Water density - Array> densities; - for (uint32 i = 0; i < _actor->getNbShapes(); i++) - { - PxShape* shape; - _actor->getShapes(&shape, 1, i); - if (shape->getFlags() & PxShapeFlag::eSIMULATION_SHAPE) - { - float density = defaultDensity; - PxMaterial* material; - if (shape->getMaterials(&material, 1, 0) == 1) - { - if (const auto mat = (PhysicalMaterial*)material->userData) - { - density = Math::Max(mat->Density, minDensity); - } - } - densities.Add(KgPerM3ToKgPerCm3(density)); - } - } - if (densities.IsEmpty()) - densities.Add(KgPerM3ToKgPerCm3(defaultDensity)); - - // Auto calculated mass - PxRigidBodyExt::updateMassAndInertia(*_actor, densities.Get(), densities.Count()); - _mass = _actor->getMass(); - const float massScale = Math::Max(_massScale, 0.001f); - if (!Math::IsOne(massScale)) - { - _mass *= massScale; - _actor->setMass(_mass); - } - } + if (_actor) + PhysicsBackend::UpdateRigidDynamicActorMass(_actor, _mass, _massScale, _overrideMass == 0); } void RigidBody::AddForce(const Vector3& force, ForceMode mode) const { if (_actor && GetEnableSimulation()) - { - _actor->addForce(C2P(force), static_cast(mode)); - } + PhysicsBackend::AddRigidDynamicActorForce(_actor, force, mode); } void RigidBody::AddForceAtPosition(const Vector3& force, const Vector3& position, ForceMode mode) const { if (_actor && GetEnableSimulation()) - { - PxRigidBodyExt::addForceAtPos(*_actor, C2P(force), C2P(position), static_cast(mode)); - } + PhysicsBackend::AddRigidDynamicActorForceAtPosition(_actor, force, position, mode); } void RigidBody::AddRelativeForce(const Vector3& force, ForceMode mode) const @@ -356,9 +259,7 @@ void RigidBody::AddRelativeForce(const Vector3& force, ForceMode mode) const void RigidBody::AddTorque(const Vector3& torque, ForceMode mode) const { if (_actor && GetEnableSimulation()) - { - _actor->addTorque(C2P(torque), static_cast(mode)); - } + PhysicsBackend::AddRigidDynamicActorTorque(_actor, torque, mode); } void RigidBody::AddRelativeTorque(const Vector3& torque, ForceMode mode) const @@ -369,9 +270,7 @@ void RigidBody::AddRelativeTorque(const Vector3& torque, ForceMode mode) const void RigidBody::SetSolverIterationCounts(int32 minPositionIters, int32 minVelocityIters) const { if (_actor) - { - _actor->setSolverIterationCounts(Math::Clamp(minPositionIters, 1, 255), Math::Clamp(minVelocityIters, 1, 255)); - } + PhysicsBackend::SetRigidDynamicActorSolverIterationCounts(_actor, minPositionIters, minVelocityIters); } void RigidBody::ClosestPoint(const Vector3& position, Vector3& result) const @@ -424,67 +323,6 @@ void RigidBody::OnColliderChanged(Collider* c) // WakeUp(); } -void RigidBody::CreateActor() -{ - ASSERT(_actor == nullptr); - - // Create rigid body - const PxTransform trans(C2P(_transform.Translation), C2P(_transform.Orientation)); - _actor = CPhysX->createRigidDynamic(trans); - _actor->userData = this; - - // Setup flags -#if WITH_PVD - PxActorFlags actorFlags = PxActorFlag::eVISUALIZATION; -#else - PxActorFlags actorFlags = static_cast(0); -#endif - const bool isActive = _enableSimulation && IsActiveInHierarchy(); - if (!isActive) - actorFlags |= PxActorFlag::eDISABLE_SIMULATION; - if (!_enableGravity) - actorFlags |= PxActorFlag::eDISABLE_GRAVITY; - _actor->setActorFlags(actorFlags); - if (_useCCD) - _actor->setRigidBodyFlag(PxRigidBodyFlag::eENABLE_CCD, true); - if (_isKinematic) - _actor->setRigidBodyFlag(PxRigidBodyFlag::eKINEMATIC, true); - - // Apply properties - _actor->setLinearDamping(_linearDamping); - _actor->setAngularDamping(_angularDamping); - _actor->setMaxAngularVelocity(_maxAngularVelocity); - _actor->setRigidDynamicLockFlags(static_cast(_constraints)); - - // Find colliders to attach - for (int32 i = 0; i < Children.Count(); i++) - { - auto collider = dynamic_cast(Children[i]); - if (collider && collider->CanAttach(this)) - { - collider->Attach(this); - } - } - - // Setup mass (calculate or use overriden value) - UpdateMass(); - - // Apply the Center Of Mass offset - if (!_centerOfMassOffset.IsZero()) - { - PxTransform pose = _actor->getCMassLocalPose(); - pose.p += C2P(_centerOfMassOffset); - _actor->setCMassLocalPose(pose); - } - - // Register actor - const bool putToSleep = !_startAwake && GetEnableSimulation() && !GetIsKinematic() && IsActiveInHierarchy(); - GetPhysicsScene()->AddActor(_actor, putToSleep); - - // Update cached data - UpdateBounds(); -} - void RigidBody::UpdateScale() { const Vector3 scale = GetScale(); @@ -546,19 +384,61 @@ void RigidBody::Deserialize(DeserializeStream& stream, ISerializeModifier* modif DESERIALIZE_BIT_MEMBER(UpdateMassWhenScaleChanges, _updateMassWhenScaleChanges); } -PxActor* RigidBody::GetPhysXActor() +void* RigidBody::GetPhysicsActor() const { - return (PxActor*)_actor; -} - -PxRigidActor* RigidBody::GetRigidActor() -{ - return (PxRigidActor*)_actor; + return _actor; } void RigidBody::BeginPlay(SceneBeginData* data) { - CreateActor(); + // Create rigid body + ASSERT(_actor == nullptr); + _actor = PhysicsBackend::CreateRigidDynamicActor(this, _transform.Translation, _transform.Orientation); + + // Apply properties + auto actorFlags = PhysicsBackend::ActorFlags::None; + if (!_enableSimulation || !IsActiveInHierarchy()) + actorFlags |= PhysicsBackend::ActorFlags::NoSimulation; + if (!_enableGravity) + actorFlags |= PhysicsBackend::ActorFlags::NoGravity; + PhysicsBackend::SetActorFlags(_actor, actorFlags); + auto rigidBodyFlags = PhysicsBackend::RigidDynamicFlags::None; + if (_isKinematic) + rigidBodyFlags |= PhysicsBackend::RigidDynamicFlags::Kinematic; + if (_useCCD) + rigidBodyFlags |= PhysicsBackend::RigidDynamicFlags::CCD; + PhysicsBackend::SetRigidDynamicActorFlags(_actor, rigidBodyFlags); + PhysicsBackend::SetRigidDynamicActorLinearDamping(_actor, _linearDamping); + PhysicsBackend::SetRigidDynamicActorAngularDamping(_actor, _angularDamping); + PhysicsBackend::SetRigidDynamicActorMaxAngularVelocity(_actor, _maxAngularVelocity); + PhysicsBackend::SetRigidDynamicActorConstraints(_actor, _constraints); + + // Find colliders to attach + for (int32 i = 0; i < Children.Count(); i++) + { + auto collider = dynamic_cast(Children[i]); + if (collider && collider->CanAttach(this)) + { + collider->Attach(this); + } + } + + // Setup mass (calculate or use overriden value) + UpdateMass(); + + // Apply the Center Of Mass offset + if (!_centerOfMassOffset.IsZero()) + PhysicsBackend::SetRigidDynamicActorCenterOfMassOffset(_actor, _centerOfMassOffset); + + // Register actor + void* scene = GetPhysicsScene()->GetPhysicsScene(); + PhysicsBackend::AddSceneActor(scene, _actor); + const bool putToSleep = !_startAwake && GetEnableSimulation() && !GetIsKinematic() && IsActiveInHierarchy(); + if (putToSleep) + PhysicsBackend::AddSceneActorAction(scene, _actor, PhysicsBackend::ActionType::Sleep); + + // Update cached data + UpdateBounds(); // Base PhysicsActor::BeginPlay(data); @@ -566,24 +446,15 @@ void RigidBody::BeginPlay(SceneBeginData* data) void RigidBody::EndPlay() { - // Detach all the shapes - PxShape* shapes[8]; - while (_actor && _actor->getNbShapes() > 0) - { - const uint32 count = _actor->getShapes(shapes, 8, 0); - for (uint32 i = 0; i < count; i++) - { - _actor->detachShape(*shapes[i], false); - } - } - // Base PhysicsActor::EndPlay(); if (_actor) { // Remove actor - GetPhysicsScene()->RemoveActor(_actor); + void* scene = GetPhysicsScene()->GetPhysicsScene(); + PhysicsBackend::RemoveSceneActor(scene, _actor); + PhysicsBackend::DestroyActor(_actor); _actor = nullptr; } } @@ -596,7 +467,7 @@ void RigidBody::OnActiveInTreeChanged() if (_actor) { const bool isActive = _enableSimulation && IsActiveInHierarchy(); - _actor->setActorFlag(PxActorFlag::eDISABLE_SIMULATION, !isActive); + PhysicsBackend::SetActorFlag(_actor, PhysicsBackend::ActorFlags::NoSimulation, !isActive); // Auto wake up if (isActive && GetStartAwake()) @@ -615,11 +486,8 @@ void RigidBody::OnTransformChanged() // Base (skip PhysicsActor call to optimize) Actor::OnTransformChanged(); - const PxTransform trans(C2P(_transform.Translation), C2P(_transform.Orientation)); - if (GetIsKinematic() && GetEnableSimulation()) - _actor->setKinematicTarget(trans); - else - _actor->setGlobalPose(trans, true); + const bool kinematic = GetIsKinematic() && GetEnableSimulation(); + PhysicsBackend::SetRigidActorPose(_actor, _transform.Translation, _transform.Orientation, kinematic, true); UpdateScale(); UpdateBounds(); @@ -633,12 +501,10 @@ void RigidBody::OnTransformChanged() void RigidBody::OnPhysicsSceneChanged(PhysicsScene* previous) { - ASSERT(previous); - - PhysicsActor::OnPhysicsSceneChanged(previous); - - previous->UnlinkActor(_actor); - + PhysicsBackend::RemoveSceneActor(previous->GetPhysicsScene(), _actor); + void* scene = GetPhysicsScene()->GetPhysicsScene(); + PhysicsBackend::AddSceneActor(scene, _actor); const bool putToSleep = !_startAwake && GetEnableSimulation() && !GetIsKinematic() && IsActiveInHierarchy(); - GetPhysicsScene()->AddActor(_actor, putToSleep); + if (putToSleep) + PhysicsBackend::AddSceneActorAction(scene, _actor, PhysicsBackend::ActionType::Sleep); } diff --git a/Source/Engine/Physics/Actors/RigidBody.h b/Source/Engine/Physics/Actors/RigidBody.h index 8726161da..04f253dba 100644 --- a/Source/Engine/Physics/Actors/RigidBody.h +++ b/Source/Engine/Physics/Actors/RigidBody.h @@ -6,6 +6,7 @@ #include "Engine/Physics/Collisions.h" class PhysicsColliderActor; +class Collider; /// /// Physics simulation driven object. @@ -16,7 +17,7 @@ API_CLASS() class FLAXENGINE_API RigidBody : public PhysicsActor DECLARE_SCENE_OBJECT(RigidBody); protected: - PxRigidDynamic* _actor; + void* _actor; Vector3 _cachedScale; float _mass; @@ -386,15 +387,6 @@ public: /// API_FUNCTION() void UpdateMass(); - /// - /// Gets the native PhysX rigid actor object. - /// - /// The PhysX dynamic rigid actor. - FORCE_INLINE PxRigidDynamic* GetPhysXRigidActor() const - { - return _actor; - } - /// /// Applies a force (or impulse) defined in the world space to the rigidbody at its center of mass. /// @@ -547,11 +539,6 @@ public: protected: - /// - /// Creates the physics actor. - /// - void CreateActor(); - /// /// Updates the rigidbody scale dependent properties like mass (may be modified when actor transformation changes). /// @@ -562,8 +549,7 @@ public: // [PhysicsActor] void Serialize(SerializeStream& stream, const void* otherObj) override; void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) override; - PxActor* GetPhysXActor() override; - PxRigidActor* GetRigidActor() override; + void* GetPhysicsActor() const override; protected: diff --git a/Source/Engine/Physics/Actors/WheeledVehicle.cpp b/Source/Engine/Physics/Actors/WheeledVehicle.cpp index 5becca07e..886b6d6d4 100644 --- a/Source/Engine/Physics/Actors/WheeledVehicle.cpp +++ b/Source/Engine/Physics/Actors/WheeledVehicle.cpp @@ -1,47 +1,15 @@ // Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. #include "WheeledVehicle.h" -#include "Engine/Core/Log.h" #include "Engine/Physics/Physics.h" -#include "Engine/Physics/Utilities.h" #include "Engine/Level/Scene/Scene.h" +#include "Engine/Physics/PhysicsBackend.h" #include "Engine/Physics/PhysicsScene.h" #include "Engine/Serialization/Serialization.h" #if USE_EDITOR #include "Engine/Level/Scene/SceneRendering.h" #include "Engine/Debug/DebugDraw.h" #endif -#if WITH_VEHICLE -#include -#include -#include -#include -#include -#include -#endif - -#if WITH_VEHICLE -extern void InitVehicleSDK(); -#endif - -namespace -{ - void FreeDrive(WheeledVehicle::DriveTypes driveType, PxVehicleWheels* drive) - { - switch (driveType) - { - case WheeledVehicle::DriveTypes::Drive4W: - ((PxVehicleDrive4W*)drive)->free(); - break; - case WheeledVehicle::DriveTypes::DriveNW: - ((PxVehicleDriveNW*)drive)->free(); - break; - case WheeledVehicle::DriveTypes::NoDrive: - ((PxVehicleNoDrive*)drive)->free(); - break; - } - } -} WheeledVehicle::WheeledVehicle(const SpawnParams& params) : RigidBody(params) @@ -101,12 +69,8 @@ WheeledVehicle::GearboxSettings WheeledVehicle::GetGearbox() const void WheeledVehicle::SetGearbox(const GearboxSettings& value) { #if WITH_VEHICLE - auto& drive = (PxVehicleDrive*&)_drive; - if (drive) - { - drive->mDriveDynData.setUseAutoGears(value.AutoGear); - drive->mDriveDynData.setAutoBoxSwitchTime(Math::Max(value.SwitchTime, 0.0f)); - } + if (_vehicle) + PhysicsBackend::SetVehicleGearbox(_vehicle, &value); #endif _gearbox = value; } @@ -142,8 +106,7 @@ void WheeledVehicle::ClearInput() float WheeledVehicle::GetForwardSpeed() const { #if WITH_VEHICLE - auto& drive = (const PxVehicleWheels*&)_drive; - return drive ? drive->computeForwardSpeed() : 0.0f; + return _vehicle ? PhysicsBackend::GetVehicleForwardSpeed(_vehicle) : 0.0f; #else return 0.0f; #endif @@ -152,8 +115,7 @@ float WheeledVehicle::GetForwardSpeed() const float WheeledVehicle::GetSidewaysSpeed() const { #if WITH_VEHICLE - auto& drive = (const PxVehicleWheels*&)_drive; - return drive ? drive->computeSidewaysSpeed() : 0.0f; + return _vehicle ? PhysicsBackend::GetVehicleSidewaysSpeed(_vehicle) : 0.0f; #else return 0.0f; #endif @@ -162,8 +124,7 @@ float WheeledVehicle::GetSidewaysSpeed() const float WheeledVehicle::GetEngineRotationSpeed() const { #if WITH_VEHICLE - auto& drive = (const PxVehicleDrive*&)_drive; - return drive && _driveType != DriveTypes::NoDrive ? RadPerSToRpm(drive->mDriveDynData.getEngineRotationSpeed()) : 0.0f; + return _vehicle && _driveType != DriveTypes::NoDrive ? PhysicsBackend::GetVehicleEngineRotationSpeed(_vehicle) : 0.0f; #else return 0.0f; #endif @@ -172,8 +133,7 @@ float WheeledVehicle::GetEngineRotationSpeed() const int32 WheeledVehicle::GetCurrentGear() const { #if WITH_VEHICLE - auto& drive = (const PxVehicleDrive*&)_drive; - return drive && _driveType != DriveTypes::NoDrive ? (int32)drive->mDriveDynData.getCurrentGear() - 1 : 0; + return _vehicle && _driveType != DriveTypes::NoDrive ? PhysicsBackend::GetVehicleCurrentGear(_vehicle) : 0; #else return 0; #endif @@ -182,19 +142,15 @@ int32 WheeledVehicle::GetCurrentGear() const void WheeledVehicle::SetCurrentGear(int32 value) { #if WITH_VEHICLE - auto& drive = (PxVehicleDrive*&)_drive; - if (drive && _driveType != DriveTypes::NoDrive) - { - drive->mDriveDynData.forceGearChange((PxU32)(value + 1)); - } + if (_vehicle && _driveType != DriveTypes::NoDrive) + PhysicsBackend::SetVehicleCurrentGear(_vehicle, value); #endif } int32 WheeledVehicle::GetTargetGear() const { #if WITH_VEHICLE - auto& drive = (const PxVehicleDrive*&)_drive; - return drive && _driveType != DriveTypes::NoDrive ? (int32)drive->mDriveDynData.getTargetGear() - 1 : 0; + return _vehicle && _driveType != DriveTypes::NoDrive ? PhysicsBackend::GetVehicleTargetGear(_vehicle) : 0; #else return 0; #endif @@ -203,11 +159,8 @@ int32 WheeledVehicle::GetTargetGear() const void WheeledVehicle::SetTargetGear(int32 value) { #if WITH_VEHICLE - auto& drive = (PxVehicleDrive*&)_drive; - if (drive && _driveType != DriveTypes::NoDrive) - { - drive->mDriveDynData.startGearChange((PxU32)(value + 1)); - } + if (_vehicle && _driveType != DriveTypes::NoDrive) + PhysicsBackend::SetVehicleTargetGear(_vehicle, value); #endif } @@ -232,281 +185,25 @@ void WheeledVehicle::Setup() #if WITH_VEHICLE if (!_actor || !IsDuringPlay()) return; - auto& drive = (PxVehicleWheels*&)_drive; // Release previous - if (drive) + if (_vehicle) { - GetPhysicsScene()->RemoveWheeledVehicle(this); - FreeDrive(_driveTypeCurrent, drive); - drive = nullptr; + PhysicsBackend::RemoveVehicle(GetPhysicsScene()->GetPhysicsScene(), this); + PhysicsBackend::DestroyVehicle(_vehicle, (int32)_driveTypeCurrent); + _vehicle = nullptr; } - // Get wheels - Array> wheels; + // Create a new one _wheelsData.Clear(); - for (auto& wheel : _wheels) - { - if (!wheel.Collider) - { - LOG(Warning, "Missing wheel collider in vehicle {0}", ToString()); - continue; - } - if (wheel.Collider->GetParent() != this) - { - LOG(Warning, "Invalid wheel collider {1} in vehicle {0} attached to {2} (wheels needs to be added as children to vehicle)", ToString(), wheel.Collider->ToString(), wheel.Collider->GetParent() ? wheel.Collider->GetParent()->ToString() : String::Empty); - continue; - } - if (wheel.Collider->GetIsTrigger()) - { - LOG(Warning, "Invalid wheel collider {1} in vehicle {0} cannot be a trigger", ToString(), wheel.Collider->ToString()); - continue; - } - if (wheel.Collider->IsDuringPlay()) - { - wheels.Add(&wheel); - } - } - if (wheels.IsEmpty()) - { - // No wheel, no car - // No woman, no cry + _vehicle = PhysicsBackend::CreateVehicle(this); + if (!_vehicle) return; - } - _wheelsData.Resize(wheels.Count()); - - InitVehicleSDK(); - - // Get linked shapes for the wheels mapping - Array> shapes; - shapes.Resize(_actor->getNbShapes()); - _actor->getShapes(shapes.Get(), shapes.Count(), 0); - const PxTransform centerOfMassOffset = _actor->getCMassLocalPose(); - - // Initialize wheels simulation data - PxVec3 offsets[PX_MAX_NB_WHEELS]; - for (int32 i = 0; i < wheels.Count(); i++) - { - Wheel& wheel = *wheels[i]; - offsets[i] = C2P(wheel.Collider->GetLocalPosition()); - } - PxF32 sprungMasses[PX_MAX_NB_WHEELS]; - const float mass = _actor->getMass(); - PxVehicleComputeSprungMasses(wheels.Count(), offsets, centerOfMassOffset.p, mass, 1, sprungMasses); - PxVehicleWheelsSimData* wheelsSimData = PxVehicleWheelsSimData::allocate(wheels.Count()); - for (int32 i = 0; i < wheels.Count(); i++) - { - Wheel& wheel = *wheels[i]; - - auto& data = _wheelsData[i]; - data.Collider = wheel.Collider; - data.LocalOrientation = wheel.Collider->GetLocalOrientation(); - - PxVehicleSuspensionData suspensionData; - const float suspensionFrequency = 7.0f; - suspensionData.mMaxCompression = wheel.SuspensionMaxRaise; - suspensionData.mMaxDroop = wheel.SuspensionMaxDrop; - suspensionData.mSprungMass = sprungMasses[i]; - suspensionData.mSpringStrength = Math::Square(suspensionFrequency) * suspensionData.mSprungMass; - suspensionData.mSpringDamperRate = wheel.SuspensionDampingRate * 2.0f * Math::Sqrt(suspensionData.mSpringStrength * suspensionData.mSprungMass); - - PxVehicleTireData tire; - tire.mType = 0; - tire.mLatStiffX = wheel.TireLateralMax; - tire.mLatStiffY = wheel.TireLateralStiffness; - tire.mLongitudinalStiffnessPerUnitGravity = wheel.TireLongitudinalStiffness; - - PxVehicleWheelData wheelData; - wheelData.mMass = wheel.Mass; - wheelData.mRadius = wheel.Radius; - wheelData.mWidth = wheel.Width; - wheelData.mMOI = 0.5f * wheelData.mMass * Math::Square(wheelData.mRadius); - wheelData.mDampingRate = M2ToCm2(wheel.DampingRate); - wheelData.mMaxSteer = wheel.MaxSteerAngle * DegreesToRadians; - wheelData.mMaxBrakeTorque = M2ToCm2(wheel.MaxBrakeTorque); - wheelData.mMaxHandBrakeTorque = M2ToCm2(wheel.MaxHandBrakeTorque); - - PxVec3 centreOffset = centerOfMassOffset.transformInv(offsets[i]); - PxVec3 forceAppPointOffset(centreOffset.x, wheel.SuspensionForceOffset, centreOffset.z); - - wheelsSimData->setTireData(i, tire); - wheelsSimData->setWheelData(i, wheelData); - wheelsSimData->setSuspensionData(i, suspensionData); - wheelsSimData->setSuspTravelDirection(i, centerOfMassOffset.rotate(PxVec3(0.0f, -1.0f, 0.0f))); - wheelsSimData->setWheelCentreOffset(i, centreOffset); - wheelsSimData->setSuspForceAppPointOffset(i, forceAppPointOffset); - wheelsSimData->setTireForceAppPointOffset(i, forceAppPointOffset); - wheelsSimData->setSubStepCount(4.0f * 100.0f, 3, 1); - wheelsSimData->setMinLongSlipDenominator(4.0f * 100.0f); - - PxShape* wheelShape = wheel.Collider->GetPxShape(); - if (wheel.Collider->IsActiveInHierarchy()) - { - wheelsSimData->setWheelShapeMapping(i, shapes.Find(wheelShape)); - - // Setup Vehicle ID inside word3 for suspension raycasts to ignore self - PxFilterData filter = wheelShape->getQueryFilterData(); - filter.word3 = _id.D + 1; - wheelShape->setQueryFilterData(filter); - wheelShape->setSimulationFilterData(filter); - wheelsSimData->setSceneQueryFilterData(i, filter); - - // Remove wheels from the simulation (suspension force hold the vehicle) - wheelShape->setFlag(PxShapeFlag::eSIMULATION_SHAPE, false); - } - else - { - wheelsSimData->setWheelShapeMapping(i, -1); - wheelsSimData->disableWheel(i); - } - } - for (auto child : Children) - { - auto collider = Cast(child); - if (collider && collider->GetAttachedRigidBody() == this) - { - bool isWheel = false; - for (auto& w : wheels) - { - if (w->Collider == collider) - { - isWheel = true; - break; - } - } - if (!isWheel) - { - // Setup Vehicle ID inside word3 for suspension raycasts to ignore self - PxShape* shape = collider->GetPxShape(); - PxFilterData filter = shape->getQueryFilterData(); - filter.word3 = _id.D + 1; - shape->setQueryFilterData(filter); - shape->setSimulationFilterData(filter); - } - } - } - - // Initialize vehicle drive _driveTypeCurrent = _driveType; - switch (_driveType) - { - case DriveTypes::Drive4W: - { - PxVehicleDriveSimData4W driveSimData; - - // Differential - PxVehicleDifferential4WData diff; - diff.mType = (PxVehicleDifferential4WData::Enum)_differential.Type; - diff.mFrontRearSplit = _differential.FrontRearSplit; - diff.mFrontLeftRightSplit = _differential.FrontLeftRightSplit; - diff.mRearLeftRightSplit = _differential.RearLeftRightSplit; - diff.mCentreBias = _differential.CentreBias; - diff.mFrontBias = _differential.FrontBias; - diff.mRearBias = _differential.RearBias; - driveSimData.setDiffData(diff); - - // Engine - PxVehicleEngineData engine; - engine.mMOI = M2ToCm2(_engine.MOI); - engine.mPeakTorque = M2ToCm2(_engine.MaxTorque); - engine.mMaxOmega = RpmToRadPerS(_engine.MaxRotationSpeed); - engine.mDampingRateFullThrottle = M2ToCm2(0.15f); - engine.mDampingRateZeroThrottleClutchEngaged = M2ToCm2(2.0f); - engine.mDampingRateZeroThrottleClutchDisengaged = M2ToCm2(0.35f); - driveSimData.setEngineData(engine); - - // Gears - PxVehicleGearsData gears; - gears.mSwitchTime = Math::Max(_gearbox.SwitchTime, 0.0f); - driveSimData.setGearsData(gears); - - // Auto Box - PxVehicleAutoBoxData autoBox; - driveSimData.setAutoBoxData(autoBox); - - // Clutch - PxVehicleClutchData clutch; - clutch.mStrength = M2ToCm2(_gearbox.ClutchStrength); - driveSimData.setClutchData(clutch); - - // Ackermann steer accuracy - PxVehicleAckermannGeometryData ackermann; - ackermann.mAxleSeparation = Math::Abs(wheelsSimData->getWheelCentreOffset(PxVehicleDrive4WWheelOrder::eFRONT_LEFT).x - wheelsSimData->getWheelCentreOffset(PxVehicleDrive4WWheelOrder::eREAR_LEFT).x); - ackermann.mFrontWidth = Math::Abs(wheelsSimData->getWheelCentreOffset(PxVehicleDrive4WWheelOrder::eFRONT_RIGHT).z - wheelsSimData->getWheelCentreOffset(PxVehicleDrive4WWheelOrder::eFRONT_LEFT).z); - ackermann.mRearWidth = Math::Abs(wheelsSimData->getWheelCentreOffset(PxVehicleDrive4WWheelOrder::eREAR_RIGHT).z - wheelsSimData->getWheelCentreOffset(PxVehicleDrive4WWheelOrder::eREAR_LEFT).z); - driveSimData.setAckermannGeometryData(ackermann); - - // Create vehicle drive - auto drive4W = PxVehicleDrive4W::allocate(wheels.Count()); - drive4W->setup(CPhysX, _actor, *wheelsSimData, driveSimData, Math::Max(wheels.Count() - 4, 0)); - drive4W->setToRestState(); - drive4W->mDriveDynData.forceGearChange(PxVehicleGearsData::eFIRST); - drive4W->mDriveDynData.setUseAutoGears(_gearbox.AutoGear); - drive = drive4W; - break; - } - case DriveTypes::DriveNW: - { - PxVehicleDriveSimDataNW driveSimData; - - // Differential - PxVehicleDifferentialNWData diff; - for (int32 i = 0; i < wheels.Count(); i++) - diff.setDrivenWheel(i, true); - driveSimData.setDiffData(diff); - - // Engine - PxVehicleEngineData engine; - engine.mMOI = M2ToCm2(_engine.MOI); - engine.mPeakTorque = M2ToCm2(_engine.MaxTorque); - engine.mMaxOmega = RpmToRadPerS(_engine.MaxRotationSpeed); - engine.mDampingRateFullThrottle = M2ToCm2(0.15f); - engine.mDampingRateZeroThrottleClutchEngaged = M2ToCm2(2.0f); - engine.mDampingRateZeroThrottleClutchDisengaged = M2ToCm2(0.35f); - driveSimData.setEngineData(engine); - - // Gears - PxVehicleGearsData gears; - gears.mSwitchTime = Math::Max(_gearbox.SwitchTime, 0.0f); - driveSimData.setGearsData(gears); - - // Auto Box - PxVehicleAutoBoxData autoBox; - driveSimData.setAutoBoxData(autoBox); - - // Clutch - PxVehicleClutchData clutch; - clutch.mStrength = M2ToCm2(_gearbox.ClutchStrength); - driveSimData.setClutchData(clutch); - - // Create vehicle drive - auto driveNW = PxVehicleDriveNW::allocate(wheels.Count()); - driveNW->setup(CPhysX, _actor, *wheelsSimData, driveSimData, wheels.Count()); - driveNW->setToRestState(); - driveNW->mDriveDynData.forceGearChange(PxVehicleGearsData::eFIRST); - driveNW->mDriveDynData.setUseAutoGears(_gearbox.AutoGear); - drive = driveNW; - break; - } - case DriveTypes::NoDrive: - { - // Create vehicle drive - auto driveNo = PxVehicleNoDrive::allocate(wheels.Count()); - driveNo->setup(CPhysX, _actor, *wheelsSimData); - driveNo->setToRestState(); - drive = driveNo; - break; - } - default: - CRASH; - } - - GetPhysicsScene()->AddWheeledVehicle(this); - wheelsSimData->free(); - _actor->setSolverIterationCounts(12, 4); - + PhysicsBackend::AddVehicle(GetPhysicsScene()->GetPhysicsScene(), this); + PhysicsBackend::SetRigidDynamicActorSolverIterationCounts(_actor, 12, 4); #else - LOG(Fatal, "PhysX Vehicle SDK is not supported."); + LOG(Fatal, "Vehicles are not supported."); #endif } @@ -560,9 +257,12 @@ void WheeledVehicle::OnDebugDrawSelected() { const Vector3 currentPos = wheel.Collider->GetPosition(); const Vector3 basePos = currentPos - Vector3(0, data.State.SuspensionOffset, 0); + Transform actorPose = Transform::Identity, shapePose = Transform::Identity; + PhysicsBackend::GetRigidActorPose(_actor, actorPose.Translation, actorPose.Orientation); + PhysicsBackend::GetShapeLocalPose(wheel.Collider->GetPhysicsShape(), shapePose.Translation, shapePose.Orientation); DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(basePos, wheel.Radius * 0.07f), Color::Blue * 0.3f, 0, false); DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(currentPos, wheel.Radius * 0.08f), Color::Blue * 0.8f, 0, false); - DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(P2C(_actor->getGlobalPose().transform(wheel.Collider->GetPxShape()->getLocalPose()).p), wheel.Radius * 0.11f), Color::OrangeRed * 0.8f, 0, false); + DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(actorPose.LocalToWorld(shapePose.Translation), wheel.Radius * 0.11f), Color::OrangeRed * 0.8f, 0, false); DEBUG_DRAW_LINE(basePos, currentPos, Color::Blue, 0, false); DEBUG_DRAW_WIRE_CYLINDER(currentPos, wheel.Collider->GetOrientation(), wheel.Radius, wheel.Width, Color::Red * 0.4f, 0, false); if (!data.State.SuspensionTraceStart.IsZero()) @@ -625,8 +325,10 @@ void WheeledVehicle::OnPhysicsSceneChanged(PhysicsScene* previous) { RigidBody::OnPhysicsSceneChanged(previous); - previous->RemoveWheeledVehicle(this); - GetPhysicsScene()->AddWheeledVehicle(this); +#if WITH_VEHICLE + PhysicsBackend::RemoveVehicle(previous->GetPhysicsScene(), this); + PhysicsBackend::AddVehicle(GetPhysicsScene()->GetPhysicsScene(), this); +#endif } void WheeledVehicle::BeginPlay(SceneBeginData* data) @@ -649,13 +351,12 @@ void WheeledVehicle::EndPlay() #endif #if WITH_VEHICLE - auto& drive = (PxVehicleWheels*&)_drive; - if (drive) + if (_vehicle) { // Parkway Drive - GetPhysicsScene()->RemoveWheeledVehicle(this); - FreeDrive(_driveTypeCurrent, drive); - drive = nullptr; + PhysicsBackend::RemoveVehicle(GetPhysicsScene()->GetPhysicsScene(), this); + PhysicsBackend::DestroyVehicle(_vehicle, (int32)_driveTypeCurrent); + _vehicle = nullptr; } #endif diff --git a/Source/Engine/Physics/Actors/WheeledVehicle.h b/Source/Engine/Physics/Actors/WheeledVehicle.h index cd3ef88f4..78e1ea9bb 100644 --- a/Source/Engine/Physics/Actors/WheeledVehicle.h +++ b/Source/Engine/Physics/Actors/WheeledVehicle.h @@ -6,17 +6,14 @@ #include "Engine/Physics/Colliders/Collider.h" #include "Engine/Scripting/ScriptingObjectReference.h" -class PhysicsScene; - /// /// Representation of the car vehicle that uses wheels. Built on top of the RigidBody with collider representing its chassis shape and wheels. /// /// API_CLASS() class FLAXENGINE_API WheeledVehicle : public RigidBody { - friend PhysicsScene; + friend class PhysicsBackend; DECLARE_SCENE_OBJECT(WheeledVehicle); -public: /// /// Vehicle driving mode types. @@ -319,7 +316,7 @@ private: WheelState State; }; - void* _drive = nullptr; + void* _vehicle = nullptr; DriveTypes _driveType = DriveTypes::Drive4W, _driveTypeCurrent; Array> _wheelsData; float _throttle = 0.0f, _steering = 0.0f, _brake = 0.0f, _handBrake = 0.0f; diff --git a/Source/Engine/Physics/Colliders/BoxCollider.cpp b/Source/Engine/Physics/Colliders/BoxCollider.cpp index 3473b5961..e3d1cd2be 100644 --- a/Source/Engine/Physics/Colliders/BoxCollider.cpp +++ b/Source/Engine/Physics/Colliders/BoxCollider.cpp @@ -2,8 +2,7 @@ #include "BoxCollider.h" #include "Engine/Serialization/Serialization.h" -#include "Engine/Physics/Utilities.h" -#include +#include "Engine/Physics/PhysicsBackend.h" BoxCollider::BoxCollider(const SpawnParams& params) : Collider(params) @@ -134,11 +133,11 @@ void BoxCollider::UpdateBounds() BoundingSphere::FromBox(_box, _sphere); } -void BoxCollider::GetGeometry(PxGeometryHolder& geometry) +void BoxCollider::GetGeometry(CollisionShape& collision) { Vector3 size = _size * _cachedScale; size.Absolute(); const float minSize = 0.001f; - const PxBoxGeometry box(Math::Max(size.X * 0.5f, minSize), Math::Max(size.Y * 0.5f, minSize), Math::Max(size.Z * 0.5f, minSize)); - geometry.storeAny(box); + size = Vector3::Max(size * 0.5f, Vector3(minSize)); + collision.SetBox(size.Raw); } diff --git a/Source/Engine/Physics/Colliders/BoxCollider.h b/Source/Engine/Physics/Colliders/BoxCollider.h index 89850b101..26b190ee2 100644 --- a/Source/Engine/Physics/Colliders/BoxCollider.h +++ b/Source/Engine/Physics/Colliders/BoxCollider.h @@ -62,7 +62,7 @@ protected: // [Collider] void UpdateBounds() override; - void GetGeometry(PxGeometryHolder& geometry) override; + void GetGeometry(CollisionShape& collision) override; #if USE_EDITOR void DrawPhysicsDebug(RenderView& view) override; #endif diff --git a/Source/Engine/Physics/Colliders/CapsuleCollider.cpp b/Source/Engine/Physics/Colliders/CapsuleCollider.cpp index 916c2b34b..065164f08 100644 --- a/Source/Engine/Physics/Colliders/CapsuleCollider.cpp +++ b/Source/Engine/Physics/Colliders/CapsuleCollider.cpp @@ -2,8 +2,6 @@ #include "CapsuleCollider.h" #include "Engine/Serialization/Serialization.h" -#include "Engine/Physics/Utilities.h" -#include CapsuleCollider::CapsuleCollider(const SpawnParams& params) : Collider(params) @@ -106,12 +104,11 @@ void CapsuleCollider::UpdateBounds() BoundingSphere::FromBox(_box, _sphere); } -void CapsuleCollider::GetGeometry(PxGeometryHolder& geometry) +void CapsuleCollider::GetGeometry(CollisionShape& collision) { const float scaling = _cachedScale.GetAbsolute().MaxValue(); const float minSize = 0.001f; const float radius = Math::Max(Math::Abs(_radius) * scaling, minSize); const float height = Math::Max(Math::Abs(_height) * scaling, minSize); - const PxCapsuleGeometry capsule(radius, height * 0.5f); - geometry.storeAny(capsule); + collision.SetCapsule(radius, height * 0.5f); } diff --git a/Source/Engine/Physics/Colliders/CapsuleCollider.h b/Source/Engine/Physics/Colliders/CapsuleCollider.h index 9e133dd7a..d55910f77 100644 --- a/Source/Engine/Physics/Colliders/CapsuleCollider.h +++ b/Source/Engine/Physics/Colliders/CapsuleCollider.h @@ -77,7 +77,7 @@ protected: // [Collider] void UpdateBounds() override; - void GetGeometry(PxGeometryHolder& geometry) override; + void GetGeometry(CollisionShape& collision) override; #if USE_EDITOR void DrawPhysicsDebug(RenderView& view) override; #endif diff --git a/Source/Engine/Physics/Colliders/CharacterController.cpp b/Source/Engine/Physics/Colliders/CharacterController.cpp index 52324c98b..cc8e3e852 100644 --- a/Source/Engine/Physics/Colliders/CharacterController.cpp +++ b/Source/Engine/Physics/Colliders/CharacterController.cpp @@ -1,18 +1,12 @@ // Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. #include "CharacterController.h" -#include "Engine/Physics/Utilities.h" #include "Engine/Physics/Colliders/Collider.h" #include "Engine/Physics/Physics.h" +#include "Engine/Physics/PhysicsBackend.h" +#include "Engine/Physics/PhysicsScene.h" #include "Engine/Serialization/Serialization.h" #include "Engine/Engine/Time.h" -#include "Engine/Physics/PhysicalMaterial.h" -#include "Engine/Physics/PhysicsScene.h" -#include -#include -#include -#include -#include CharacterController::CharacterController(const SpawnParams& params) : Collider(params) @@ -27,7 +21,6 @@ CharacterController::CharacterController(const SpawnParams& params) , _nonWalkableMode(NonWalkableModes::PreventClimbing) , _lastFlags(CollisionFlags::None) { - static_assert(sizeof(_filterData) == sizeof(PxFilterData), "Invalid filter data size."); } float CharacterController::GetRadius() const @@ -72,11 +65,9 @@ void CharacterController::SetSlopeLimit(float value) value = Math::Clamp(value, 0.0f, 89.0f); if (Math::NearEqual(value, _slopeLimit)) return; - _slopeLimit = value; - if (_controller) - _controller->setSlopeLimit(Math::Cos(value * DegreesToRadians)); + PhysicsBackend::SetControllerSlopeLimit(_controller, value); } CharacterController::NonWalkableModes CharacterController::GetNonWalkableMode() const @@ -86,10 +77,11 @@ CharacterController::NonWalkableModes CharacterController::GetNonWalkableMode() void CharacterController::SetNonWalkableMode(NonWalkableModes value) { + if (_nonWalkableMode == value) + return; _nonWalkableMode = value; - if (_controller) - _controller->setNonWalkableMode(static_cast(value)); + PhysicsBackend::SetControllerNonWalkableMode(_controller, (int32)value); } float CharacterController::GetStepOffset() const @@ -111,15 +103,15 @@ void CharacterController::SetStepOffset(float value) const float minSize = 0.001f; const float height = Math::Max(Math::Abs(_height) * scaling, minSize); const float radius = Math::Max(Math::Abs(_radius) * scaling - contactOffset, minSize); - _controller->setStepOffset(Math::Min(value, height + radius * 2.0f - minSize)); + PhysicsBackend::SetControllerStepOffset(_controller, Math::Min(value, height + radius * 2.0f - minSize)); } } void CharacterController::SetUpDirection(const Vector3& up) { - if (_controller) - _controller->setUpDirection(C2P(up)); _upDirection = up; + if (_controller) + PhysicsBackend::SetControllerUpDirection(_controller, up); } float CharacterController::GetMinMoveDistance() const @@ -129,7 +121,7 @@ float CharacterController::GetMinMoveDistance() const Vector3 CharacterController::GetUpDirection() const { - return _controller ? P2C(_controller->getUpDirection()) : _upDirection; + return _controller ? PhysicsBackend::GetControllerUpDirection(_controller) : _upDirection; } void CharacterController::SetMinMoveDistance(float value) @@ -139,7 +131,7 @@ void CharacterController::SetMinMoveDistance(float value) Vector3 CharacterController::GetVelocity() const { - return _controller ? P2C(_controller->getActor()->getLinearVelocity()) : Vector3::Zero; + return _controller ? PhysicsBackend::GetRigidDynamicActorLinearVelocity(PhysicsBackend::GetControllerRigidDynamicActor(_controller)) : Vector3::Zero; } bool CharacterController::IsGrounded() const @@ -165,30 +157,16 @@ CharacterController::CollisionFlags CharacterController::SimpleMove(const Vector CharacterController::CollisionFlags CharacterController::Move(const Vector3& displacement) { CollisionFlags result = CollisionFlags::None; - if (_controller) { const float deltaTime = Time::GetCurrentSafe()->DeltaTime.GetTotalSeconds(); - PxControllerFilters filters; - filters.mFilterData = (PxFilterData*)&_filterData; - filters.mFilterCallback = GetPhysicsScene()->GetCharacterQueryFilterCallback(); - filters.mFilterFlags = PxQueryFlag::eDYNAMIC | PxQueryFlag::eSTATIC | PxQueryFlag::ePREFILTER; - filters.mCCTFilterCallback = GetPhysicsScene()->GetCharacterControllerFilterCallback(); - - result = (CollisionFlags)(byte)_controller->move(C2P(displacement), _minMoveDistance, deltaTime, filters); + result = (CollisionFlags)PhysicsBackend::MoveController(_controller, _shape, displacement, _minMoveDistance, deltaTime); _lastFlags = result; - - SetPosition(P2C(_controller->getPosition())); + SetPosition(PhysicsBackend::GetControllerPosition(_controller)); } - return result; } -PxRigidDynamic* CharacterController::GetPhysXRigidActor() const -{ - return _controller ? _controller->getActor() : nullptr; -} - #if USE_EDITOR #include "Engine/Debug/DebugDraw.h" @@ -222,41 +200,16 @@ void CharacterController::OnDebugDrawSelected() void CharacterController::CreateController() { + // Create controller ASSERT(_controller == nullptr && _shape == nullptr); - - PxCapsuleControllerDesc desc; - desc.userData = this; - desc.contactOffset = Math::Max(_contactOffset, ZeroTolerance); - desc.position = PxExtendedVec3(_transform.Translation.X, _transform.Translation.Y, _transform.Translation.Z); - desc.slopeLimit = Math::Cos(_slopeLimit * DegreesToRadians); - desc.nonWalkableMode = static_cast(_nonWalkableMode); - desc.climbingMode = PxCapsuleClimbingMode::eEASY; - if (Material && !Material->WaitForLoaded()) - desc.material = ((PhysicalMaterial*)Material->Instance)->GetPhysXMaterial(); - else - desc.material = Physics::GetDefaultMaterial(); _cachedScale = GetScale(); const float scaling = _cachedScale.GetAbsolute().MaxValue(); - const float minSize = 0.001f; - desc.height = Math::Max(Math::Abs(_height) * scaling, minSize); - desc.radius = Math::Max(Math::Abs(_radius) * scaling - desc.contactOffset, minSize); - desc.stepOffset = Math::Min(_stepOffset, desc.height + desc.radius * 2.0f - minSize); + _controller = PhysicsBackend::CreateController(GetPhysicsScene()->GetPhysicsScene(), this, this, _contactOffset, _transform.Translation, _slopeLimit, (int32)_nonWalkableMode, Material.Get(), Math::Abs(_radius) * scaling, Math::Abs(_height) * scaling, _stepOffset, _shape); - // Create controller - _controller = (PxCapsuleController*)GetPhysicsScene()->GetControllerManager()->createController(desc); - ASSERT(_controller); - _controller->setUpDirection(C2P(_upDirection)); - const auto actor = _controller->getActor(); - ASSERT(actor && actor->getNbShapes() == 1); - actor->getShapes(&_shape, 1); - actor->userData = this; - _shape->userData = this; - - // Apply additional shape properties - _shape->setLocalPose(PxTransform(C2P(_center))); + // Setup + PhysicsBackend::SetControllerUpDirection(_shape, _upDirection); + PhysicsBackend::SetShapeLocalPose(_shape, _center, Quaternion::Identity); UpdateLayerBits(); - - // Update cached data UpdateBounds(); } @@ -264,12 +217,10 @@ void CharacterController::DeleteController() { if (_controller) { - _shape->userData = nullptr; - _controller->getActor()->userData = nullptr; - _controller->release(); + PhysicsBackend::DestroyController(_controller); _controller = nullptr; + _shape = nullptr; } - _shape = nullptr; } void CharacterController::UpdateSize() const @@ -280,9 +231,7 @@ void CharacterController::UpdateSize() const const float minSize = 0.001f; const float radius = Math::Max(Math::Abs(_radius) * scaling - Math::Max(_contactOffset, ZeroTolerance), minSize); const float height = Math::Max(Math::Abs(_height) * scaling, minSize); - - _controller->setRadius(radius); - _controller->resize(height); + PhysicsBackend::SetControllerSize(_controller, radius, height); } } @@ -293,10 +242,9 @@ void CharacterController::CreateShape() void CharacterController::UpdateBounds() { - const auto actor = GetPhysXRigidActor(); - const float boundsScale = 1.03f; + void* actor = PhysicsBackend::GetShapeActor(_shape); if (actor) - _box = P2C(actor->getWorldBounds(boundsScale)); + PhysicsBackend::GetActorBounds(actor, _box); else _box = BoundingBox(_transform.Translation); BoundingSphere::FromBox(_box, _sphere); @@ -322,22 +270,24 @@ RigidBody* CharacterController::GetAttachedRigidBody() const return nullptr; } -void CharacterController::OnActiveTransformChanged(const PxTransform& transform) +void CharacterController::OnActiveTransformChanged() { // Change actor transform (but with locking) ASSERT(!_isUpdatingTransform); _isUpdatingTransform = true; - Transform t = _transform; - t.Translation = P2C(transform.p); - SetTransform(t); + Transform transform; + PhysicsBackend::GetRigidActorPose(PhysicsBackend::GetShapeActor(_shape), transform.Translation, transform.Orientation); + transform.Orientation = _transform.Orientation; + transform.Scale = _transform.Scale; + SetTransform(transform); _isUpdatingTransform = false; UpdateBounds(); } -PxRigidActor* CharacterController::GetRigidActor() +void* CharacterController::GetPhysicsActor() const { - return _shape ? _shape->getActor() : nullptr; + return _shape ? PhysicsBackend::GetShapeActor(_shape) : nullptr; } void CharacterController::UpdateGeometry() @@ -351,20 +301,11 @@ void CharacterController::UpdateGeometry() UpdateSize(); } -void CharacterController::GetGeometry(PxGeometryHolder& geometry) +void CharacterController::GetGeometry(CollisionShape& collision) { // Unused } -void CharacterController::UpdateLayerBits() -{ - // Base - Collider::UpdateLayerBits(); - - // Cache filter data - *(PxFilterData*)&_filterData = _shape->getSimulationFilterData(); -} - void CharacterController::BeginPlay(SceneBeginData* data) { if (IsActiveInHierarchy()) @@ -418,9 +359,7 @@ void CharacterController::OnTransformChanged() // Update physics if (!_isUpdatingTransform && _controller) { - const PxExtendedVec3 pos(_transform.Translation.X, _transform.Translation.Y, _transform.Translation.Z); - _controller->setPosition(pos); - + PhysicsBackend::SetControllerPosition(_controller, _transform.Translation); const Vector3 scale = GetScale(); if (!Vector3::NearEqual(_cachedScale, scale)) UpdateGeometry(); diff --git a/Source/Engine/Physics/Colliders/CharacterController.h b/Source/Engine/Physics/Colliders/CharacterController.h index 8a0a79223..129a432e6 100644 --- a/Source/Engine/Physics/Colliders/CharacterController.h +++ b/Source/Engine/Physics/Colliders/CharacterController.h @@ -58,7 +58,7 @@ public: private: - PxCapsuleController* _controller; + void* _controller; float _stepOffset; float _slopeLimit; float _radius; @@ -68,7 +68,6 @@ private: Vector3 _upDirection; NonWalkableModes _nonWalkableMode; CollisionFlags _lastFlags; - uint32 _filterData[4]; public: /// @@ -181,11 +180,6 @@ public: /// The collision flags. It can be used to trigger various character animations. API_FUNCTION() CollisionFlags Move(const Vector3& displacement); - /// - /// Gets the native PhysX rigid actor object. - /// - PxRigidDynamic* GetPhysXRigidActor() const; - protected: /// @@ -218,15 +212,14 @@ public: RigidBody* GetAttachedRigidBody() const override; // [IPhysicsActor] - void OnActiveTransformChanged(const PxTransform& transform) override; - PxRigidActor* GetRigidActor() override; + void OnActiveTransformChanged() override; + void* GetPhysicsActor() const override; protected: // [PhysicsActor] void UpdateGeometry() override; - void GetGeometry(PxGeometryHolder& geometry) override; - void UpdateLayerBits() override; + void GetGeometry(CollisionShape& collision) override; void BeginPlay(SceneBeginData* data) override; void EndPlay() override; #if USE_EDITOR diff --git a/Source/Engine/Physics/Colliders/Collider.cpp b/Source/Engine/Physics/Colliders/Collider.cpp index 73440c5b3..6d971dc52 100644 --- a/Source/Engine/Physics/Colliders/Collider.cpp +++ b/Source/Engine/Physics/Colliders/Collider.cpp @@ -6,18 +6,11 @@ #include "Engine/Level/Scene/SceneRendering.h" #endif #include "Engine/Serialization/Serialization.h" -#include "Engine/Physics/Utilities.h" #include "Engine/Physics/PhysicsSettings.h" #include "Engine/Physics/Physics.h" -#include "Engine/Physics/PhysicalMaterial.h" +#include "Engine/Physics/PhysicsBackend.h" #include "Engine/Physics/PhysicsScene.h" #include "Engine/Physics/Actors/RigidBody.h" -#include -#include -#include -#include -#include -#include Collider::Collider(const SpawnParams& params) : PhysicsColliderActor(params) @@ -31,7 +24,7 @@ Collider::Collider(const SpawnParams& params) Material.Changed.Bind(this); } -PxShape* Collider::GetPxShape() const +void* Collider::GetPhysicsShape() const { return _shape; } @@ -40,33 +33,24 @@ void Collider::SetIsTrigger(bool value) { if (value == _isTrigger || !CanBeTrigger()) return; - _isTrigger = value; - if (_shape) - { - const bool isTrigger = _isTrigger && CanBeTrigger(); - const PxShapeFlags shapeFlags = GetShapeFlags(isTrigger, IsActiveInHierarchy()); - _shape->setFlags(shapeFlags); - } + PhysicsBackend::SetShapeState(_shape, IsActiveInHierarchy(), _isTrigger && CanBeTrigger()); } void Collider::SetCenter(const Vector3& value) { if (Vector3::NearEqual(value, _center)) return; - _center = value; - if (_staticActor) { - _shape->setLocalPose(PxTransform(C2P(_center))); + PhysicsBackend::SetShapeLocalPose(_shape, _center, Quaternion::Identity); } else if (const RigidBody* rigidBody = GetAttachedRigidBody()) { - _shape->setLocalPose(PxTransform(C2P((_localTransform.Translation + _localTransform.Orientation * _center) * rigidBody->GetScale()), C2P(_localTransform.Orientation))); + PhysicsBackend::SetShapeLocalPose(_shape, (_localTransform.Translation + _localTransform.Orientation * _center) * rigidBody->GetScale(), _localTransform.Orientation); } - UpdateBounds(); } @@ -75,13 +59,9 @@ void Collider::SetContactOffset(float value) value = Math::Clamp(value, 0.0f, 100.0f); if (Math::NearEqual(value, _contactOffset)) return; - _contactOffset = value; - if (_shape) - { - _shape->setContactOffset(Math::Max(_shape->getRestOffset() + ZeroTolerance, _contactOffset)); - } + PhysicsBackend::SetShapeContactOffset(_shape, _contactOffset); } bool Collider::RayCast(const Vector3& origin, const Vector3& direction, float& resultHitDistance, float maxDistance) const @@ -89,73 +69,36 @@ bool Collider::RayCast(const Vector3& origin, const Vector3& direction, float& r resultHitDistance = MAX_float; if (_shape == nullptr) return false; - - // Prepare data - const PxTransform trans(C2P(_transform.Translation), C2P(_transform.Orientation)); - const PxHitFlags hitFlags = PxHitFlag::ePOSITION | PxHitFlag::eNORMAL | PxHitFlag::eFACE_INDEX | PxHitFlag::eUV; - - // Perform raycast test - PxRaycastHit hit; - if (PxGeometryQuery::raycast(C2P(origin), C2P(direction), _shape->getGeometry().any(), trans, maxDistance, hitFlags, 1, &hit) != 0) - { - resultHitDistance = hit.distance; - return true; - } - - return false; + return PhysicsBackend::RayCastShape(_shape, _transform.Translation, _transform.Orientation, origin, direction, resultHitDistance, maxDistance); } bool Collider::RayCast(const Vector3& origin, const Vector3& direction, RayCastHit& hitInfo, float maxDistance) const { if (_shape == nullptr) return false; - - // Prepare data - const PxTransform trans(C2P(_transform.Translation), C2P(_transform.Orientation)); - const PxHitFlags hitFlags = PxHitFlag::ePOSITION | PxHitFlag::eNORMAL | PxHitFlag::eUV; - PxRaycastHit hit; - - // Perform raycast test - if (PxGeometryQuery::raycast(C2P(origin), C2P(direction), _shape->getGeometry().any(), trans, maxDistance, hitFlags, 1, &hit) == 0) - return false; - - // Gather results - hitInfo.Gather(hit); - return true; + return PhysicsBackend::RayCastShape(_shape, _transform.Translation, _transform.Orientation, origin, direction, hitInfo, maxDistance); } -void Collider::ClosestPoint(const Vector3& position, Vector3& result) const +void Collider::ClosestPoint(const Vector3& point, Vector3& result) const { if (_shape == nullptr) { result = Vector3::Maximum; return; } - - // Prepare data - const PxTransform trans(C2P(_transform.Translation), C2P(_transform.Orientation)); - PxVec3 closestPoint; - - // Compute distance between a point and a geometry object - const float distanceSqr = PxGeometryQuery::pointDistance(C2P(position), _shape->getGeometry().any(), trans, &closestPoint); + Vector3 closestPoint; + const float distanceSqr = PhysicsBackend::ComputeShapeSqrDistanceToPoint(_shape, _transform.Translation, _transform.Orientation, point, &closestPoint); if (distanceSqr > 0.0f) - { - // Use calculated point - result = P2C(closestPoint); - } + result = closestPoint; else - { - // Fallback to the input location - result = position; - } + result = point; } bool Collider::ContainsPoint(const Vector3& point) const { if (_shape) { - const PxTransform trans(C2P(_transform.Translation), C2P(_transform.Orientation)); - const float distanceSqr = PxGeometryQuery::pointDistance(C2P(point), _shape->getGeometry().any(), trans); + const float distanceSqr = PhysicsBackend::ComputeShapeSqrDistanceToPoint(_shape, _transform.Translation, _transform.Orientation, point); return distanceSqr <= 0.0f; } return false; @@ -165,17 +108,12 @@ bool Collider::ComputePenetration(const Collider* colliderA, const Collider* col { direction = Vector3::Zero; distance = 0.0f; - CHECK_RETURN(colliderA && colliderB, false); - const PxShape* shapeA = colliderA->GetPxShape(); - const PxShape* shapeB = colliderB->GetPxShape(); + void* shapeA = colliderA->GetPhysicsShape(); + void* shapeB = colliderB->GetPhysicsShape(); if (!shapeA || !shapeB) return false; - - const PxTransform poseA(C2P(colliderA->GetPosition()), C2P(colliderA->GetOrientation())); - const PxTransform poseB(C2P(colliderB->GetPosition()), C2P(colliderB->GetOrientation())); - - return PxGeometryQuery::computePenetration(C2P(direction), distance, shapeA->getGeometry().any(), poseA, shapeB->getGeometry().any(), poseB); + return PhysicsBackend::ComputeShapesPenetration(shapeA, shapeB, colliderA->GetPosition(), colliderA->GetOrientation(), colliderB->GetPosition(), colliderB->GetOrientation(), direction, distance); } bool Collider::CanAttach(RigidBody* rigidBody) const @@ -192,9 +130,7 @@ RigidBody* Collider::GetAttachedRigidBody() const { if (_shape && _staticActor == nullptr) { - auto actor = _shape->getActor(); - if (actor && actor->is()) - return static_cast(actor->userData); + return dynamic_cast(GetParent()); } return nullptr; } @@ -232,10 +168,10 @@ void Collider::Attach(RigidBody* rigidBody) CreateShape(); // Attach - rigidBody->GetPhysXRigidActor()->attachShape(*_shape); + PhysicsBackend::AttachShape(_shape, rigidBody->GetPhysicsActor()); _cachedLocalPosePos = (_localTransform.Translation + _localTransform.Orientation * _center) * rigidBody->GetScale(); _cachedLocalPoseRot = _localTransform.Orientation; - _shape->setLocalPose(PxTransform(C2P(_cachedLocalPosePos), C2P(_cachedLocalPoseRot))); + PhysicsBackend::SetShapeLocalPose(_shape, _cachedLocalPosePos, _cachedLocalPoseRot); if (rigidBody->IsDuringPlay()) { rigidBody->UpdateBounds(); @@ -245,40 +181,29 @@ void Collider::Attach(RigidBody* rigidBody) void Collider::UpdateLayerBits() { - ASSERT(_shape); - - PxFilterData filterData; - // Own layer ID - filterData.word0 = GetLayerMask(); + const uint32 mask0 = GetLayerMask(); // Own layer mask - filterData.word1 = Physics::LayerMasks[GetLayer()]; + const uint32 mask1 = Physics::LayerMasks[GetLayer()]; - _shape->setSimulationFilterData(filterData); - _shape->setQueryFilterData(filterData); + ASSERT(_shape); + PhysicsBackend::SetShapeFilterMask(_shape, mask0, mask1); } void Collider::CreateShape() { + ASSERT(_shape == nullptr); + // Setup shape geometry _cachedScale = GetScale(); - PxGeometryHolder geometry; - GetGeometry(geometry); + CollisionShape shape; + GetGeometry(shape); // Create shape const bool isTrigger = _isTrigger && CanBeTrigger(); - const PxShapeFlags shapeFlags = GetShapeFlags(isTrigger, IsActiveInHierarchy()); - PxMaterial* material = Physics::GetDefaultMaterial(); - if (Material && !Material->WaitForLoaded() && Material->Instance) - { - material = ((PhysicalMaterial*)Material->Instance)->GetPhysXMaterial(); - } - ASSERT(_shape == nullptr); - _shape = CPhysX->createShape(geometry.any(), *material, true, shapeFlags); - ASSERT(_shape); - _shape->userData = this; - _shape->setContactOffset(Math::Max(_shape->getRestOffset() + ZeroTolerance, _contactOffset)); + _shape = PhysicsBackend::CreateShape(this, shape, Material.Get(), IsActiveInHierarchy(), isTrigger); + PhysicsBackend::SetShapeContactOffset(_shape, _contactOffset); UpdateLayerBits(); } @@ -289,20 +214,20 @@ void Collider::UpdateGeometry() // Setup shape geometry _cachedScale = GetScale(); - PxGeometryHolder geometry; - GetGeometry(geometry); + CollisionShape shape; + GetGeometry(shape); // Recreate shape if geometry has different type - if (_shape->getGeometryType() != geometry.getType()) + if (PhysicsBackend::GetShapeType(_shape) != shape.Type) { // Detach from the actor - auto actor = _shape->getActor(); + void* actor = PhysicsBackend::GetShapeActor(_shape); if (actor) - actor->detachShape(*_shape); + PhysicsBackend::DetachShape(_shape, actor); // Release shape - GetPhysicsScene()->RemoveCollider(this); - _shape->release(); + PhysicsBackend::RemoveCollider(this); + PhysicsBackend::DestroyShape(_shape); _shape = nullptr; // Recreate shape @@ -314,7 +239,7 @@ void Collider::UpdateGeometry() const auto rigidBody = dynamic_cast(GetParent()); if (_staticActor != nullptr || (rigidBody && CanAttach(rigidBody))) { - actor->attachShape(*_shape); + PhysicsBackend::AttachShape(_shape, actor); } else { @@ -327,33 +252,28 @@ void Collider::UpdateGeometry() } // Update shape - _shape->setGeometry(geometry.any()); + PhysicsBackend::SetShapeGeometry(_shape, shape); } void Collider::CreateStaticActor() { ASSERT(_staticActor == nullptr); - - const PxTransform trans(C2P(_transform.Translation), C2P(_transform.Orientation)); - _staticActor = CPhysX->createRigidStatic(trans); - ASSERT(_staticActor); - _staticActor->userData = this; -#if WITH_PVD - _staticActor->setActorFlag(PxActorFlag::eVISUALIZATION, true); -#endif + _staticActor = PhysicsBackend::CreateRigidStaticActor(nullptr, _transform.Translation, _transform.Orientation); // Reset local pos of the shape and link it to the actor - _shape->setLocalPose(PxTransform(C2P(_center))); - _staticActor->attachShape(*_shape); + PhysicsBackend::SetShapeLocalPose(_shape, _center, Quaternion::Identity); + PhysicsBackend::AttachShape(_shape, _staticActor); - GetPhysicsScene()->AddActor(_staticActor); + void* scene = GetPhysicsScene()->GetPhysicsScene(); + PhysicsBackend::AddSceneActor(scene, _staticActor); } void Collider::RemoveStaticActor() { ASSERT(_staticActor != nullptr); - - GetPhysicsScene()->RemoveActor(_staticActor); + void* scene = GetPhysicsScene()->GetPhysicsScene(); + PhysicsBackend::RemoveSceneActor(scene, _staticActor); + PhysicsBackend::DestroyActor(_staticActor); _staticActor = nullptr; } @@ -369,14 +289,7 @@ void Collider::OnMaterialChanged() { // Update the shape material if (_shape) - { - PxMaterial* material = Physics::GetDefaultMaterial(); - if (Material && !Material->WaitForLoaded() && Material->Instance) - { - material = ((PhysicalMaterial*)Material->Instance)->GetPhysXMaterial(); - } - _shape->setMaterials(&material, 1); - } + PhysicsBackend::SetShapeMaterial(_shape, Material.Get()); } void Collider::Serialize(SerializeStream& stream, const void* otherObj) @@ -436,19 +349,22 @@ void Collider::EndPlay() if (_shape) { // Detach from the actor - auto actor = _shape->getActor(); + void* actor = PhysicsBackend::GetShapeActor(_shape); + RigidBody* rigidBody = GetAttachedRigidBody(); if (actor) - actor->detachShape(*_shape); - if (actor && actor->is()) - static_cast(actor->userData)->OnColliderChanged(this); + PhysicsBackend::DetachShape(_shape, actor); + if (rigidBody) + { + rigidBody->OnColliderChanged(this); + } else if (_staticActor) { RemoveStaticActor(); } // Release shape - GetPhysicsScene()->RemoveCollider(this); - _shape->release(); + PhysicsBackend::RemoveCollider(this); + PhysicsBackend::DestroyShape(_shape); _shape = nullptr; } } @@ -460,9 +376,7 @@ void Collider::OnActiveInTreeChanged() if (_shape) { - const bool isTrigger = _isTrigger && CanBeTrigger(); - const PxShapeFlags shapeFlags = GetShapeFlags(isTrigger, IsActiveInHierarchy()); - _shape->setFlags(shapeFlags); + PhysicsBackend::SetShapeState(_shape, IsActiveInHierarchy(), _isTrigger && CanBeTrigger()); auto rigidBody = GetAttachedRigidBody(); if (rigidBody) @@ -481,17 +395,20 @@ void Collider::OnParentChanged() if (_shape) { // Detach from the actor - auto actor = _shape->getActor(); + void* actor = PhysicsBackend::GetShapeActor(_shape); + RigidBody* rigidBody = GetAttachedRigidBody(); if (actor) - actor->detachShape(*_shape); - if (actor && actor->is()) - static_cast(actor->userData)->OnColliderChanged(this); + PhysicsBackend::DetachShape(_shape, actor); + if (rigidBody) + { + rigidBody->OnColliderChanged(this); + } // Check if the new parent is a rigidbody - const auto rigidBody = dynamic_cast(GetParent()); + rigidBody = dynamic_cast(GetParent()); if (rigidBody && CanAttach(rigidBody)) { - // Attach to the rigidbody (will remove static actor if it's n use) + // Attach to the rigidbody Attach(rigidBody); } else @@ -499,6 +416,8 @@ void Collider::OnParentChanged() // Use static actor (if not created yet) if (_staticActor == nullptr) CreateStaticActor(); + else + PhysicsBackend::AttachShape(_shape, _staticActor); } } } @@ -510,7 +429,7 @@ void Collider::OnTransformChanged() if (_staticActor) { - _staticActor->setGlobalPose(PxTransform(C2P(_transform.Translation), C2P(_transform.Orientation))); + PhysicsBackend::SetRigidActorPose(_staticActor, _transform.Translation, _transform.Orientation); } else if (const RigidBody* rigidBody = GetAttachedRigidBody()) { @@ -519,7 +438,7 @@ void Collider::OnTransformChanged() { _cachedLocalPosePos = localPosePos; _cachedLocalPoseRot = _localTransform.Orientation; - _shape->setLocalPose(PxTransform(C2P(localPosePos), C2P(_cachedLocalPoseRot))); + PhysicsBackend::SetShapeLocalPose(_shape, localPosePos, _cachedLocalPoseRot); } } @@ -544,7 +463,8 @@ void Collider::OnPhysicsSceneChanged(PhysicsScene* previous) if (_staticActor != nullptr) { - previous->UnlinkActor(_staticActor); - GetPhysicsScene()->AddActor(_staticActor); + PhysicsBackend::RemoveSceneActor(previous->GetPhysicsScene(), _staticActor); + void* scene = GetPhysicsScene()->GetPhysicsScene(); + PhysicsBackend::AddSceneActor(scene, _staticActor); } } diff --git a/Source/Engine/Physics/Colliders/Collider.h b/Source/Engine/Physics/Colliders/Collider.h index 479b7c288..07a06c3bc 100644 --- a/Source/Engine/Physics/Colliders/Collider.h +++ b/Source/Engine/Physics/Colliders/Collider.h @@ -22,8 +22,8 @@ protected: Vector3 _center; bool _isTrigger; - PxShape* _shape; - PxRigidStatic* _staticActor; + void* _shape; + void* _staticActor; Vector3 _cachedScale; float _contactOffset; Vector3 _cachedLocalPosePos; @@ -32,9 +32,9 @@ protected: public: /// - /// Gets the collider shape PhysX object. + /// Gets the native physics backend object. /// - PxShape* GetPxShape() const; + void* GetPhysicsShape() const; /// /// Gets the 'IsTrigger' flag. @@ -121,9 +121,9 @@ public: /// /// Gets a point on the collider that is closest to a given location. Can be used to find a hit location or position to apply explosion force or any other special effects. /// - /// The position to find the closest point to it. + /// The position to find the closest point to it. /// The result point on the collider that is closest to the specified location. - API_FUNCTION() void ClosestPoint(const Vector3& position, API_PARAM(Out) Vector3& result) const; + API_FUNCTION() void ClosestPoint(const Vector3& point, API_PARAM(Out) Vector3& result) const; /// /// Checks if a point is inside the collider. @@ -171,7 +171,7 @@ protected: /// /// Updates the shape actor collisions/queries layer mask bits. /// - virtual void UpdateLayerBits(); + void UpdateLayerBits(); /// /// Updates the bounding box of the shape. @@ -181,8 +181,8 @@ protected: /// /// Gets the collider shape geometry. /// - /// The output geometry. - virtual void GetGeometry(PxGeometryHolder& geometry) = 0; + /// The output collision shape. + virtual void GetGeometry(CollisionShape& collision) = 0; /// /// Creates the collider shape. diff --git a/Source/Engine/Physics/Colliders/MeshCollider.cpp b/Source/Engine/Physics/Colliders/MeshCollider.cpp index 5b720860c..32e47429a 100644 --- a/Source/Engine/Physics/Colliders/MeshCollider.cpp +++ b/Source/Engine/Physics/Colliders/MeshCollider.cpp @@ -4,7 +4,6 @@ #include "Engine/Core/Math/Matrix.h" #include "Engine/Core/Math/Ray.h" #include "Engine/Serialization/Serialization.h" -#include "Engine/Physics/Utilities.h" #include "Engine/Physics/Physics.h" #include "Engine/Physics/PhysicsScene.h" #if USE_EDITOR || !BUILD_RELEASE @@ -147,7 +146,7 @@ void MeshCollider::UpdateBounds() BoundingSphere::FromBox(_box, _sphere); } -void MeshCollider::GetGeometry(PxGeometryHolder& geometry) +void MeshCollider::GetGeometry(CollisionShape& collision) { // Prepare scale Vector3 scale = _cachedScale; @@ -160,25 +159,9 @@ void MeshCollider::GetGeometry(PxGeometryHolder& geometry) if (CollisionData && CollisionData->IsLoaded()) type = CollisionData->GetOptions().Type; if (type == CollisionDataType::ConvexMesh) - { - // Convex mesh - PxConvexMeshGeometry convexMesh; - convexMesh.scale.scale = C2P(scale); - convexMesh.convexMesh = CollisionData->GetConvex(); - geometry.storeAny(convexMesh); - } + collision.SetConvexMesh(CollisionData->GetConvex(), scale.Raw); else if (type == CollisionDataType::TriangleMesh) - { - // Triangle mesh - PxTriangleMeshGeometry triangleMesh; - triangleMesh.scale.scale = C2P(scale); - triangleMesh.triangleMesh = CollisionData->GetTriangle(); - geometry.storeAny(triangleMesh); - } + collision.SetTriangleMesh(CollisionData->GetTriangle(), scale.Raw); else - { - // Dummy geometry - const PxSphereGeometry sphere(minSize); - geometry.storeAny(sphere); - } + collision.SetSphere(minSize); } diff --git a/Source/Engine/Physics/Colliders/MeshCollider.h b/Source/Engine/Physics/Colliders/MeshCollider.h index efcf60cee..9db547477 100644 --- a/Source/Engine/Physics/Colliders/MeshCollider.h +++ b/Source/Engine/Physics/Colliders/MeshCollider.h @@ -45,5 +45,5 @@ protected: void DrawPhysicsDebug(RenderView& view) override; #endif void UpdateBounds() override; - void GetGeometry(PxGeometryHolder& geometry) override; + void GetGeometry(CollisionShape& collision) override; }; diff --git a/Source/Engine/Physics/Colliders/SphereCollider.cpp b/Source/Engine/Physics/Colliders/SphereCollider.cpp index 1ff955c3d..6d1a009aa 100644 --- a/Source/Engine/Physics/Colliders/SphereCollider.cpp +++ b/Source/Engine/Physics/Colliders/SphereCollider.cpp @@ -2,8 +2,6 @@ #include "SphereCollider.h" #include "Engine/Serialization/Serialization.h" -#include "Engine/Physics/Utilities.h" -#include SphereCollider::SphereCollider(const SpawnParams& params) : Collider(params) @@ -78,11 +76,10 @@ void SphereCollider::UpdateBounds() _sphere.GetBoundingBox(_box); } -void SphereCollider::GetGeometry(PxGeometryHolder& geometry) +void SphereCollider::GetGeometry(CollisionShape& collision) { const float scaling = _cachedScale.GetAbsolute().MaxValue(); const float radius = Math::Abs(_radius) * scaling; const float minSize = 0.001f; - const PxSphereGeometry sphere(Math::Max(radius, minSize)); - geometry.storeAny(sphere); + collision.SetSphere(Math::Max(radius, minSize)); } diff --git a/Source/Engine/Physics/Colliders/SphereCollider.h b/Source/Engine/Physics/Colliders/SphereCollider.h index ed2d4cd09..172e6438c 100644 --- a/Source/Engine/Physics/Colliders/SphereCollider.h +++ b/Source/Engine/Physics/Colliders/SphereCollider.h @@ -54,5 +54,5 @@ protected: void DrawPhysicsDebug(RenderView& view) override; #endif void UpdateBounds() override; - void GetGeometry(PxGeometryHolder& geometry) override; + void GetGeometry(CollisionShape& collision) override; }; diff --git a/Source/Engine/Physics/Colliders/SplineCollider.cpp b/Source/Engine/Physics/Colliders/SplineCollider.cpp index 62516a954..117ec757e 100644 --- a/Source/Engine/Physics/Colliders/SplineCollider.cpp +++ b/Source/Engine/Physics/Colliders/SplineCollider.cpp @@ -6,16 +6,13 @@ #include "Engine/Core/Math/Ray.h" #include "Engine/Level/Actors/Spline.h" #include "Engine/Serialization/Serialization.h" -#include "Engine/Physics/Utilities.h" #include "Engine/Physics/Physics.h" +#include "Engine/Physics/PhysicsBackend.h" #include "Engine/Physics/PhysicsScene.h" #include "Engine/Profiler/ProfilerCPU.h" #if COMPILE_WITH_PHYSICS_COOKING #include "Engine/Physics/CollisionCooking.h" -#include -#include #endif -#include SplineCollider::SplineCollider(const SpawnParams& params) : Collider(params) @@ -173,7 +170,7 @@ void SplineCollider::EndPlay() // Cleanup if (_triangleMesh) { - GetPhysicsScene()->RemoveObject(_triangleMesh); + PhysicsBackend::DestroyObject(_triangleMesh); _triangleMesh = nullptr; } } @@ -183,18 +180,17 @@ void SplineCollider::UpdateBounds() // Unused as bounds are updated during collision building } -void SplineCollider::GetGeometry(PxGeometryHolder& geometry) +void SplineCollider::GetGeometry(CollisionShape& collision) { // Reset bounds _box = BoundingBox(_transform.Translation); BoundingSphere::FromBox(_box, _sphere); + const float minSize = 0.001f; + collision.SetSphere(minSize); // Skip if sth is missing if (!_spline || !IsActiveInHierarchy() || _spline->GetSplinePointsCount() < 2 || !CollisionData || !CollisionData->IsLoaded()) - { - geometry.storeAny(PxSphereGeometry(0.001f)); return; - } PROFILE_CPU(); // Extract collision geometry @@ -203,10 +199,7 @@ void SplineCollider::GetGeometry(PxGeometryHolder& geometry) Array collisionIndices; CollisionData->ExtractGeometry(collisionVertices, collisionIndices); if (collisionIndices.IsEmpty()) - { - geometry.storeAny(PxSphereGeometry(0.001f)); return; - } // Apply local mesh transformation if (!_preTransform.IsIdentity()) @@ -288,7 +281,6 @@ void SplineCollider::GetGeometry(PxGeometryHolder& geometry) // Prepare scale Vector3 scale = _cachedScale; scale.Absolute(); - const float minSize = 0.001f; scale = Vector3::Max(scale, minSize); // TODO: add support for cooking collision for static splines in editor and reusing it in game @@ -307,16 +299,15 @@ void SplineCollider::GetGeometry(PxGeometryHolder& geometry) // Create triangle mesh if (_triangleMesh) { - GetPhysicsScene()->RemoveObject(_triangleMesh); + PhysicsBackend::DestroyObject(_triangleMesh); _triangleMesh = nullptr; } - PxDefaultMemoryInputData input(collisionData.Get(), collisionData.Length()); // TODO: try using getVerticesForModification for dynamic triangle mesh vertices updating when changing curve in the editor - _triangleMesh = Physics::GetPhysics()->createTriangleMesh(input); + BoundingBox localBounds; + _triangleMesh = PhysicsBackend::CreateTriangleMesh(collisionData.Get(), collisionData.Length(), localBounds); if (!_triangleMesh) { LOG(Error, "Failed to create triangle mesh from collision data of {0}.", ToString()); - geometry.storeAny(PxSphereGeometry(0.001f)); return; } @@ -325,17 +316,13 @@ void SplineCollider::GetGeometry(PxGeometryHolder& geometry) _vertexBuffer[i] = colliderTransform.LocalToWorld(_vertexBuffer[i]); // Update bounds - _box = P2C(_triangleMesh->getLocalBounds()); Matrix splineWorld; colliderTransform.GetWorld(splineWorld); - BoundingBox::Transform(_box, splineWorld, _box); + BoundingBox::Transform(localBounds, splineWorld, _box); BoundingSphere::FromBox(_box, _sphere); // Setup geometry - PxTriangleMeshGeometry triangleMesh; - triangleMesh.scale.scale = C2P(scale); - triangleMesh.triangleMesh = _triangleMesh; - geometry.storeAny(triangleMesh); + collision.SetTriangleMesh(_triangleMesh, scale.Raw); // TODO: find a way of releasing _vertexBuffer and _indexBuffer for static colliders (note: ExtractGeometry usage for navmesh generation at runtime) @@ -344,5 +331,4 @@ void SplineCollider::GetGeometry(PxGeometryHolder& geometry) #endif LOG(Error, "Cannot build collision data for {0} due to runtime collision cooking diabled.", ToString()); - geometry.storeAny(PxSphereGeometry(0.001f)); } diff --git a/Source/Engine/Physics/Colliders/SplineCollider.h b/Source/Engine/Physics/Colliders/SplineCollider.h index c1cdab7b7..910bdd9fc 100644 --- a/Source/Engine/Physics/Colliders/SplineCollider.h +++ b/Source/Engine/Physics/Colliders/SplineCollider.h @@ -18,7 +18,7 @@ API_CLASS() class FLAXENGINE_API SplineCollider : public Collider DECLARE_SCENE_OBJECT(SplineCollider); private: Spline* _spline = nullptr; - PxTriangleMesh* _triangleMesh = nullptr; + void* _triangleMesh = nullptr; Array _vertexBuffer; Array _indexBuffer; Transform _preTransform = Transform::Identity; @@ -76,5 +76,5 @@ protected: void DrawPhysicsDebug(RenderView& view) override; #endif void UpdateBounds() override; - void GetGeometry(PxGeometryHolder& geometry) override; + void GetGeometry(CollisionShape& collision) override; }; diff --git a/Source/Engine/Physics/CollisionCooking.cpp b/Source/Engine/Physics/CollisionCooking.cpp index 18d11b718..d6915f24c 100644 --- a/Source/Engine/Physics/CollisionCooking.cpp +++ b/Source/Engine/Physics/CollisionCooking.cpp @@ -8,96 +8,6 @@ #include "Engine/Graphics/Models/MeshBase.h" #include "Engine/Threading/Threading.h" #include "Engine/Core/Log.h" -#include "Physics.h" -#include -#include - -#define CONVEX_VERTEX_MIN 8 -#define CONVEX_VERTEX_MAX 255 -#define ENSURE_CAN_COOK \ - auto cooking = Physics::GetCooking(); \ - if (cooking == nullptr) \ - { \ - LOG(Warning, "Physics collisions cooking is disabled at runtime. Enable Physics Settings option SupportCookingAtRuntime to use collision generation at runtime."); \ - return true; \ - } - -bool CollisionCooking::CookConvexMesh(CookingInput& input, BytesContainer& output) -{ - ENSURE_CAN_COOK; - if (input.VertexCount == 0) - LOG(Warning, "Empty mesh data for collision cooking."); - - // Init options - PxConvexMeshDesc desc; - desc.points.count = input.VertexCount; - desc.points.stride = sizeof(Vector3); - desc.points.data = input.VertexData; - desc.flags = PxConvexFlag::eCOMPUTE_CONVEX; - if (input.ConvexVertexLimit == 0) - desc.vertexLimit = CONVEX_VERTEX_MAX; - else - desc.vertexLimit = (PxU16)Math::Clamp(input.ConvexVertexLimit, CONVEX_VERTEX_MIN, CONVEX_VERTEX_MAX); - if (input.ConvexFlags & ConvexMeshGenerationFlags::SkipValidation) - desc.flags |= PxConvexFlag::Enum::eDISABLE_MESH_VALIDATION; - if (input.ConvexFlags & ConvexMeshGenerationFlags::UsePlaneShifting) - desc.flags |= PxConvexFlag::Enum::ePLANE_SHIFTING; - if (input.ConvexFlags & ConvexMeshGenerationFlags::UseFastInteriaComputation) - desc.flags |= PxConvexFlag::Enum::eFAST_INERTIA_COMPUTATION; - if (input.ConvexFlags & ConvexMeshGenerationFlags::ShiftVertices) - desc.flags |= PxConvexFlag::Enum::eSHIFT_VERTICES; - PxCookingParams cookingParams = cooking->getParams(); - cookingParams.suppressTriangleMeshRemapTable = input.ConvexFlags & ConvexMeshGenerationFlags::SuppressFaceRemapTable; - cooking->setParams(cookingParams); - - // Perform cooking - PxDefaultMemoryOutputStream outputStream; - PxConvexMeshCookingResult::Enum result; - if (!cooking->cookConvexMesh(desc, outputStream, &result)) - { - LOG(Warning, "Convex Mesh cooking failed. Error code: {0}, Input vertices count: {1}", result, input.VertexCount); - return true; - } - - // Copy result - output.Copy(outputStream.getData(), outputStream.getSize()); - - return false; -} - -bool CollisionCooking::CookTriangleMesh(CookingInput& input, BytesContainer& output) -{ - ENSURE_CAN_COOK; - if (input.VertexCount == 0 || input.IndexCount == 0) - LOG(Warning, "Empty mesh data for collision cooking."); - - // Init options - PxTriangleMeshDesc desc; - desc.points.count = input.VertexCount; - desc.points.stride = sizeof(Vector3); - desc.points.data = input.VertexData; - desc.triangles.count = input.IndexCount / 3; - desc.triangles.stride = 3 * (input.Is16bitIndexData ? sizeof(uint16) : sizeof(uint32)); - desc.triangles.data = input.IndexData; - desc.flags = input.Is16bitIndexData ? PxMeshFlag::e16_BIT_INDICES : (PxMeshFlag::Enum)0; - PxCookingParams cookingParams = cooking->getParams(); - cookingParams.suppressTriangleMeshRemapTable = input.ConvexFlags & ConvexMeshGenerationFlags::SuppressFaceRemapTable; - cooking->setParams(cookingParams); - - // Perform cooking - PxDefaultMemoryOutputStream outputStream; - PxTriangleMeshCookingResult::Enum result; - if (!cooking->cookTriangleMesh(desc, outputStream, &result)) - { - LOG(Warning, "Triangle Mesh cooking failed. Error code: {0}, Input vertices count: {1}, indices count: {2}", result, input.VertexCount, input.IndexCount); - return true; - } - - // Copy result - output.Copy(outputStream.getData(), outputStream.getSize()); - - return false; -} bool CollisionCooking::CookCollision(const Argument& arg, CollisionData::SerializedOptions& outputOptions, BytesContainer& outputData) { @@ -371,17 +281,4 @@ bool CollisionCooking::CookCollision(const Argument& arg, CollisionData::Seriali return false; } -bool CollisionCooking::CookHeightField(const physx::PxHeightFieldDesc& desc, physx::PxOutputStream& stream) -{ - ENSURE_CAN_COOK; - - if (!Physics::GetCooking()->cookHeightField(desc, stream)) - { - LOG(Warning, "Height Field collision cooking failed."); - return true; - } - - return false; -} - #endif diff --git a/Source/Engine/Physics/CollisionCooking.h b/Source/Engine/Physics/CollisionCooking.h index 992038224..afd3098a9 100644 --- a/Source/Engine/Physics/CollisionCooking.h +++ b/Source/Engine/Physics/CollisionCooking.h @@ -8,12 +8,10 @@ #include "Engine/Physics/CollisionData.h" #include "Engine/Graphics/Models/ModelData.h" #include "Engine/Content/Assets/ModelBase.h" +#include "Engine/Physics/PhysicsBackend.h" -namespace physx -{ - class PxHeightFieldDesc; - class PxOutputStream; -} +#define CONVEX_VERTEX_MIN 8 +#define CONVEX_VERTEX_MAX 255 /// /// Physical collision data cooking tools. Allows to bake heightfield, convex and triangle mesh colliders data. @@ -21,7 +19,6 @@ namespace physx class CollisionCooking { public: - struct CookingInput { int32 VertexCount = 0; @@ -65,6 +62,16 @@ public: /// True if failed, otherwise false. static bool CookTriangleMesh(CookingInput& input, BytesContainer& output); + /// + /// Cooks a heightfield. The results are written to the stream. To create a heightfield object there is an option to precompute some of calculations done while loading the heightfield data. + /// + /// The heightfield columns count. + /// The heightfield rows count. + /// The heightfield data. + /// The user stream to output the cooked data. + /// True if failed, otherwise false. + static bool CookHeightField(int32 cols, int32 rows, const PhysicsBackend::HeightFieldSample* data, WriteStream& stream); + /// /// Cooks the collision from the model and prepares the data for the format. /// @@ -73,14 +80,6 @@ public: /// The output data container. /// True if failed, otherwise false. static bool CookCollision(const Argument& arg, CollisionData::SerializedOptions& outputOptions, BytesContainer& outputData); - - /// - /// Cooks a heightfield. The results are written to the stream. To create a heightfield object there is an option to precompute some of calculations done while loading the heightfield data. - /// - /// The heightfield descriptor to read the HF from. - /// The user stream to output the cooked data. - /// True if failed, otherwise false. - static bool CookHeightField(const physx::PxHeightFieldDesc& desc, physx::PxOutputStream& stream); }; #endif diff --git a/Source/Engine/Physics/CollisionData.cpp b/Source/Engine/Physics/CollisionData.cpp index 95e5a67ca..deb343384 100644 --- a/Source/Engine/Physics/CollisionData.cpp +++ b/Source/Engine/Physics/CollisionData.cpp @@ -1,19 +1,14 @@ // Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. +#include "CollisionData.h" #include "Engine/Core/Log.h" #include "Engine/Content/Content.h" #include "Engine/Content/Assets/Model.h" #include "Engine/Content/Factories/BinaryAssetFactory.h" -#include "Engine/Physics/Physics.h" #include "Engine/Physics/PhysicsScene.h" -#include "Engine/Physics/Utilities.h" -#include "Engine/Physics/CollisionData.h" +#include "Engine/Physics/PhysicsBackend.h" #include "Engine/Physics/CollisionCooking.h" #include "Engine/Threading/Threading.h" -#include -#include -#include -#include REGISTER_BINARY_ASSET(CollisionData, "FlaxEngine.CollisionData", true); @@ -141,9 +136,11 @@ bool CollisionData::GetModelTriangle(uint32 faceIndex, MeshBase*& mesh, uint32& if (!IsLoaded()) return false; ScopeLock lock(Locker); - if (_triangleMesh && faceIndex < _triangleMesh->getNbTriangles()) + if (_triangleMesh) { - if (const PxU32* remap = _triangleMesh->getTrianglesRemap()) + uint32 trianglesCount; + const uint32* remap = PhysicsBackend::GetTriangleMeshRemap(_triangleMesh, trianglesCount); + if (remap && faceIndex < trianglesCount) { // Get source triangle index from the triangle mesh meshTriangleIndex = remap[faceIndex]; @@ -187,98 +184,10 @@ void CollisionData::ExtractGeometry(Array& vertexBuffer, Array& indexBuffer.Clear(); ScopeLock lock(Locker); - - uint32 numVertices = 0; - uint32 numIndices = 0; - - // Convex Mesh if (_convexMesh) - { - numVertices = _convexMesh->getNbVertices(); - - const uint32 numPolygons = _convexMesh->getNbPolygons(); - for (uint32 i = 0; i < numPolygons; i++) - { - PxHullPolygon face; - const bool status = _convexMesh->getPolygonData(i, face); - ASSERT(status); - - numIndices += (face.mNbVerts - 2) * 3; - } - } - // Triangle Mesh + PhysicsBackend::GetConvexMeshTriangles(_convexMesh, vertexBuffer, indexBuffer); else if (_triangleMesh) - { - numVertices = _triangleMesh->getNbVertices(); - numIndices = _triangleMesh->getNbTriangles() * 3; - } - // No collision data - else - { - return; - } - - // Prepare vertex and index buffers - vertexBuffer.Resize(numVertices); - indexBuffer.Resize(numIndices); - auto outVertices = vertexBuffer.Get(); - auto outIndices = indexBuffer.Get(); - - if (_convexMesh) - { - const PxVec3* convexVertices = _convexMesh->getVertices(); - const byte* convexIndices = _convexMesh->getIndexBuffer(); - - for (uint32 i = 0; i < numVertices; i++) - *outVertices++ = P2C(convexVertices[i]); - - uint32 numPolygons = _convexMesh->getNbPolygons(); - for (uint32 i = 0; i < numPolygons; i++) - { - PxHullPolygon face; - bool status = _convexMesh->getPolygonData(i, face); - ASSERT(status); - - const PxU8* faceIndices = convexIndices + face.mIndexBase; - for (uint32 j = 2; j < face.mNbVerts; j++) - { - *outIndices++ = faceIndices[0]; - *outIndices++ = faceIndices[j]; - *outIndices++ = faceIndices[j - 1]; - } - } - } - else - { - const PxVec3* vertices = _triangleMesh->getVertices(); - for (uint32 i = 0; i < numVertices; i++) - *outVertices++ = P2C(vertices[i]); - - if (_triangleMesh->getTriangleMeshFlags() & PxTriangleMeshFlag::e16_BIT_INDICES) - { - const uint16* indices = (const uint16*)_triangleMesh->getTriangles(); - - uint32 numTriangles = numIndices / 3; - for (uint32 i = 0; i < numTriangles; i++) - { - outIndices[i * 3 + 0] = (uint32)indices[i * 3 + 0]; - outIndices[i * 3 + 1] = (uint32)indices[i * 3 + 1]; - outIndices[i * 3 + 2] = (uint32)indices[i * 3 + 2]; - } - } - else - { - const uint32* indices = (const uint32*)_triangleMesh->getTriangles(); - - uint32 numTriangles = numIndices / 3; - for (uint32 i = 0; i < numTriangles; i++) - { - outIndices[i * 3 + 0] = indices[i * 3 + 0]; - outIndices[i * 3 + 1] = indices[i * 3 + 1]; - outIndices[i * 3 + 2] = indices[i * 3 + 2]; - } - } - } + PhysicsBackend::GetTriangleMeshTriangles(_triangleMesh, vertexBuffer, indexBuffer); } #if USE_EDITOR @@ -360,16 +269,13 @@ CollisionData::LoadResult CollisionData::load(const SerializedOptions* options, return LoadResult::InvalidData; // Create PhysX object - PxDefaultMemoryInputData input(dataPtr, dataSize); if (_options.Type == CollisionDataType::ConvexMesh) { - _convexMesh = Physics::GetPhysics()->createConvexMesh(input); - _options.Box = P2C(_convexMesh->getLocalBounds()); + _convexMesh = PhysicsBackend::CreateConvexMesh(dataPtr, dataSize, _options.Box); } else if (_options.Type == CollisionDataType::TriangleMesh) { - _triangleMesh = Physics::GetPhysics()->createTriangleMesh(input); - _options.Box = P2C(_triangleMesh->getLocalBounds()); + _triangleMesh = PhysicsBackend::CreateTriangleMesh(dataPtr, dataSize, _options.Box); } else { @@ -385,16 +291,12 @@ void CollisionData::unload(bool isReloading) { if (_convexMesh) { - for (auto scene : Physics::Scenes) - scene->RemoveObject(_convexMesh); - + PhysicsBackend::DestroyObject(_convexMesh); _convexMesh = nullptr; } if (_triangleMesh) { - for (auto scene : Physics::Scenes) - scene->RemoveObject(_triangleMesh); - + PhysicsBackend::DestroyObject(_triangleMesh); _triangleMesh = nullptr; } _options = CollisionDataOptions(); diff --git a/Source/Engine/Physics/CollisionData.h b/Source/Engine/Physics/CollisionData.h index e95f73c77..8804ebf6b 100644 --- a/Source/Engine/Physics/CollisionData.h +++ b/Source/Engine/Physics/CollisionData.h @@ -10,12 +10,6 @@ class ModelBase; class ModelData; class MeshBase; -namespace physx -{ - class PxConvexMesh; - class PxTriangleMesh; -} - /// /// A storage data type. /// @@ -165,8 +159,8 @@ public: private: CollisionDataOptions _options; - physx::PxConvexMesh* _convexMesh; - physx::PxTriangleMesh* _triangleMesh; + void* _convexMesh; + void* _triangleMesh; public: @@ -181,7 +175,7 @@ public: /// /// Gets the convex mesh object (valid only if asset is loaded and has cooked convex data). /// - FORCE_INLINE physx::PxConvexMesh* GetConvex() const + FORCE_INLINE void* GetConvex() const { return _convexMesh; } @@ -189,7 +183,7 @@ public: /// /// Gets the triangle mesh object (valid only if asset is loaded and has cooked triangle data). /// - FORCE_INLINE physx::PxTriangleMesh* GetTriangle() const + FORCE_INLINE void* GetTriangle() const { return _triangleMesh; } diff --git a/Source/Engine/Physics/Collisions.h b/Source/Engine/Physics/Collisions.h index 658e9a211..205ec3b43 100644 --- a/Source/Engine/Physics/Collisions.h +++ b/Source/Engine/Physics/Collisions.h @@ -2,13 +2,9 @@ #pragma once -#include "Engine/Core/Delegate.h" #include "Engine/Core/Math/Vector3.h" class PhysicsColliderActor; -class Joint; -class Rigidbody; -class Collider; /// /// Contains a contact point data for the collision location. diff --git a/Source/Engine/Physics/Joints/D6Joint.cpp b/Source/Engine/Physics/Joints/D6Joint.cpp index 079c9a1cc..7b890c5a0 100644 --- a/Source/Engine/Physics/Joints/D6Joint.cpp +++ b/Source/Engine/Physics/Joints/D6Joint.cpp @@ -3,9 +3,7 @@ #include "D6Joint.h" #include "Engine/Serialization/JsonTools.h" #include "Engine/Serialization/Serialization.h" -#include "Engine/Physics/Utilities.h" -#include "Engine/Physics/Physics.h" -#include +#include "Engine/Physics/PhysicsBackend.h" D6Joint::D6Joint(const SpawnParams& params) : Joint(params) @@ -19,185 +17,118 @@ void D6Joint::SetMotion(const D6JointAxis axis, const D6JointMotion value) { if (value == GetMotion(axis)) return; - _motion[static_cast(axis)] = value; - if (_joint) - { - auto joint = static_cast(_joint); - joint->setMotion(static_cast(axis), static_cast(value)); - } + PhysicsBackend::SetD6JointMotion(_joint, axis, value); } void D6Joint::SetDrive(const D6JointDriveType index, const D6JointDrive& value) { if (value == GetDrive(index)) return; - _drive[static_cast(index)] = value; - if (_joint) - { - auto joint = static_cast(_joint); - PxD6JointDrive drive; - if (value.Acceleration) - drive.flags = PxD6JointDriveFlag::eACCELERATION; - drive.stiffness = value.Stiffness; - drive.damping = value.Damping; - drive.forceLimit = value.ForceLimit; - ASSERT_LOW_LAYER(drive.isValid()); - joint->setDrive(static_cast(index), drive); - } + PhysicsBackend::SetD6JointDrive(_joint, index, value); } void D6Joint::SetLimitLinear(const LimitLinear& value) { if (value == _limitLinear) return; - _limitLinear = value; - if (_joint) - { - auto joint = static_cast(_joint); - PxJointLinearLimit limit(*Physics::GetTolerancesScale(), Math::Max(value.Extent, ZeroTolerance), value.ContactDist); - limit.stiffness = value.Spring.Stiffness; - limit.damping = value.Spring.Damping; - limit.restitution = value.Restitution; - ASSERT_LOW_LAYER(limit.isValid()); - joint->setLinearLimit(limit); - } + PhysicsBackend::SetD6JointLimitLinear(_joint, value); } void D6Joint::SetLimitTwist(const LimitAngularRange& value) { if (value == _limitTwist) return; - _limitTwist = value; - if (_joint) - { - auto joint = static_cast(_joint); - PxJointAngularLimitPair limit(value.Lower * DegreesToRadians, Math::Max(value.Upper, value.Lower) * DegreesToRadians, value.ContactDist); - limit.stiffness = value.Spring.Stiffness; - limit.damping = value.Spring.Damping; - limit.restitution = value.Restitution; - ASSERT_LOW_LAYER(limit.isValid()); - joint->setTwistLimit(limit); - } + PhysicsBackend::SetD6JointLimitTwist(_joint, value); } void D6Joint::SetLimitSwing(const LimitConeRange& value) { if (value == _limitSwing) return; - _limitSwing = value; - if (_joint) - { - auto joint = static_cast(_joint); - PxJointLimitCone limit(Math::Clamp(value.YLimitAngle * DegreesToRadians, ZeroTolerance, PI - ZeroTolerance), Math::Clamp(value.ZLimitAngle * DegreesToRadians, ZeroTolerance, PI - ZeroTolerance), value.ContactDist); - limit.stiffness = value.Spring.Stiffness; - limit.damping = value.Spring.Damping; - limit.restitution = value.Restitution; - ASSERT_LOW_LAYER(limit.isValid()); - joint->setSwingLimit(limit); - } + PhysicsBackend::SetD6JointLimitSwing(_joint, value); } Vector3 D6Joint::GetDrivePosition() const { - return _joint ? P2C(static_cast(_joint)->getDrivePosition().p) : Vector3::Zero; + return _joint ? PhysicsBackend::GetD6JointDrivePosition(_joint) : Vector3::Zero; } void D6Joint::SetDrivePosition(const Vector3& value) { if (_joint) - { - auto joint = static_cast(_joint); - PxTransform t = joint->getDrivePosition(); - t.p = C2P(value); - joint->setDrivePosition(t); - } + PhysicsBackend::SetD6JointDrivePosition(_joint, value); } Quaternion D6Joint::GetDriveRotation() const { - return _joint ? P2C(static_cast(_joint)->getDrivePosition().q) : Quaternion::Identity; + return _joint ? PhysicsBackend::GetD6JointDriveRotation(_joint) : Quaternion::Identity; } void D6Joint::SetDriveRotation(const Quaternion& value) { if (_joint) - { - auto joint = static_cast(_joint); - PxTransform t = joint->getDrivePosition(); - t.q = C2P(value); - joint->setDrivePosition(t); - } + PhysicsBackend::SetD6JointDriveRotation(_joint, value); } Vector3 D6Joint::GetDriveLinearVelocity() const { + Vector3 linear = Vector3::Zero, angular; if (_joint) - { - PxVec3 linear, angular; - static_cast(_joint)->getDriveVelocity(linear, angular); - return P2C(linear); - } - return Vector3::Zero; + PhysicsBackend::GetD6JointDriveVelocity(_joint, linear, angular); + return linear; } void D6Joint::SetDriveLinearVelocity(const Vector3& value) { if (_joint) { - PxVec3 linear, angular; - auto joint = static_cast(_joint); - joint->getDriveVelocity(linear, angular); - linear = C2P(value); - joint->setDriveVelocity(linear, angular); + Vector3 linear, angular; + PhysicsBackend::GetD6JointDriveVelocity(_joint, linear, angular); + PhysicsBackend::SetD6JointDriveVelocity(_joint, value, angular); } } Vector3 D6Joint::GetDriveAngularVelocity() const { + Vector3 linear, angular = Vector3::Zero; if (_joint) - { - PxVec3 linear, angular; - static_cast(_joint)->getDriveVelocity(linear, angular); - return P2C(angular); - } - return Vector3::Zero; + PhysicsBackend::GetD6JointDriveVelocity(_joint, linear, angular); + return angular; } void D6Joint::SetDriveAngularVelocity(const Vector3& value) { if (_joint) { - PxVec3 linear, angular; - auto joint = static_cast(_joint); - joint->getDriveVelocity(linear, angular); - angular = C2P(value); - joint->setDriveVelocity(linear, angular); + Vector3 linear, angular; + PhysicsBackend::GetD6JointDriveVelocity(_joint, linear, angular); + PhysicsBackend::SetD6JointDriveVelocity(_joint, linear, value); } } float D6Joint::GetCurrentTwist() const { - return _joint ? static_cast(_joint)->getTwistAngle() : 0.0f; + return _joint ? PhysicsBackend::GetD6JointTwist(_joint) : 0.0f; } -float D6Joint::GetCurrentSwingYAngle() const +float D6Joint::GetCurrentSwingY() const { - return _joint ? static_cast(_joint)->getSwingYAngle() : 0.0f; + return _joint ? PhysicsBackend::GetD6JointSwingY(_joint) : 0.0f; } -float D6Joint::GetCurrentSwingZAngle() const +float D6Joint::GetCurrentSwingZ() const { - return _joint ? static_cast(_joint)->getSwingZAngle() : 0.0f; + return _joint ? PhysicsBackend::GetD6JointSwingZ(_joint) : 0.0f; } #if USE_EDITOR @@ -412,59 +343,15 @@ void D6Joint::Deserialize(DeserializeStream& stream, ISerializeModifier* modifie JsonTools::GetFloat(_limitSwing.Spring.Damping, stream, "LimitSwing.Damping"); } -PxJoint* D6Joint::CreateJoint(JointData& data) +void* D6Joint::CreateJoint(const PhysicsJointDesc& desc) { - const PxTransform trans0(C2P(data.Pos0), C2P(data.Rot0)); - const PxTransform trans1(C2P(data.Pos1), C2P(data.Rot1)); - auto joint = PxD6JointCreate(*data.Physics, data.Actor0, trans0, data.Actor1, trans1); - + void* joint = PhysicsBackend::CreateD6Joint(desc); for (int32 i = 0; i < static_cast(D6JointAxis::MAX); i++) - { - joint->setMotion(static_cast(i), static_cast(_motion[i])); - } - + PhysicsBackend::SetD6JointMotion(joint, (D6JointAxis)i, _motion[i]); for (int32 i = 0; i < static_cast(D6JointAxis::MAX); i++) - { - const auto& value = _drive[i]; - PxD6JointDrive drive; - if (value.Acceleration) - drive.flags = PxD6JointDriveFlag::eACCELERATION; - drive.stiffness = value.Stiffness; - drive.damping = value.Damping; - drive.forceLimit = value.ForceLimit; - ASSERT_LOW_LAYER(drive.isValid()); - joint->setDrive(static_cast(i), drive); - } - - { - const auto& value = _limitLinear; - PxJointLinearLimit limit(*Physics::GetTolerancesScale(), Math::Max(value.Extent, ZeroTolerance), value.ContactDist); - limit.stiffness = value.Spring.Stiffness; - limit.damping = value.Spring.Damping; - limit.restitution = value.Restitution; - ASSERT_LOW_LAYER(limit.isValid()); - joint->setDistanceLimit(limit); - } - - { - const auto& value = _limitTwist; - PxJointAngularLimitPair limit(value.Lower * DegreesToRadians, Math::Max(value.Upper, value.Lower) * DegreesToRadians, value.ContactDist); - limit.stiffness = value.Spring.Stiffness; - limit.damping = value.Spring.Damping; - limit.restitution = value.Restitution; - ASSERT_LOW_LAYER(limit.isValid()); - joint->setTwistLimit(limit); - } - - { - const auto& value = _limitSwing; - PxJointLimitCone limit(Math::Clamp(value.YLimitAngle * DegreesToRadians, ZeroTolerance, PI - ZeroTolerance), Math::Clamp(value.ZLimitAngle * DegreesToRadians, ZeroTolerance, PI - ZeroTolerance), value.ContactDist); - limit.stiffness = value.Spring.Stiffness; - limit.damping = value.Spring.Damping; - limit.restitution = value.Restitution; - ASSERT_LOW_LAYER(limit.isValid()); - joint->setSwingLimit(limit); - } - + PhysicsBackend::SetD6JointDrive(joint, (D6JointDriveType)i, _drive[i]); + PhysicsBackend::SetD6JointLimitLinear(joint, _limitLinear); + PhysicsBackend::SetD6JointLimitTwist(joint, _limitTwist); + PhysicsBackend::SetD6JointLimitSwing(joint, _limitSwing); return joint; } diff --git a/Source/Engine/Physics/Joints/D6Joint.h b/Source/Engine/Physics/Joints/D6Joint.h index f17571bbb..c57742cea 100644 --- a/Source/Engine/Physics/Joints/D6Joint.h +++ b/Source/Engine/Physics/Joints/D6Joint.h @@ -303,19 +303,19 @@ public: public: /// - /// Gets the twist angle of the joint. + /// Gets the twist angle of the joint (in the range (-2*Pi, 2*Pi]). /// API_PROPERTY() float GetCurrentTwist() const; /// /// Gets the current swing angle of the joint from the Y axis. /// - API_PROPERTY() float GetCurrentSwingYAngle() const; + API_PROPERTY() float GetCurrentSwingY() const; /// /// Gets the current swing angle of the joint from the Z axis. /// - API_PROPERTY() float GetCurrentSwingZAngle() const; + API_PROPERTY() float GetCurrentSwingZ() const; public: @@ -329,5 +329,5 @@ public: protected: // [Joint] - PxJoint* CreateJoint(JointData& data) override; + void* CreateJoint(const PhysicsJointDesc& desc) override; }; diff --git a/Source/Engine/Physics/Joints/DistanceJoint.cpp b/Source/Engine/Physics/Joints/DistanceJoint.cpp index 5df279801..f38fc2498 100644 --- a/Source/Engine/Physics/Joints/DistanceJoint.cpp +++ b/Source/Engine/Physics/Joints/DistanceJoint.cpp @@ -1,9 +1,8 @@ // Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. #include "DistanceJoint.h" +#include "Engine/Physics/PhysicsBackend.h" #include "Engine/Serialization/Serialization.h" -#include "Engine/Physics/Utilities.h" -#include DistanceJoint::DistanceJoint(const SpawnParams& params) : Joint(params) @@ -18,13 +17,9 @@ void DistanceJoint::SetFlags(DistanceJointFlag value) { if (_flags == value) return; - _flags = value; - if (_joint) - { - static_cast(_joint)->setDistanceJointFlags(static_cast(value)); - } + PhysicsBackend::SetDistanceJointFlags(_joint, value); } void DistanceJoint::SetMinDistance(float value) @@ -32,13 +27,9 @@ void DistanceJoint::SetMinDistance(float value) value = Math::Clamp(value, 0.0f, _maxDistance); if (Math::NearEqual(value, _minDistance)) return; - _minDistance = value; - if (_joint) - { - static_cast(_joint)->setMinDistance(value); - } + PhysicsBackend::SetDistanceJointMinDistance(_joint, value); } void DistanceJoint::SetMaxDistance(float value) @@ -46,13 +37,9 @@ void DistanceJoint::SetMaxDistance(float value) value = Math::Max(_minDistance, value); if (Math::NearEqual(value, _maxDistance)) return; - _maxDistance = value; - if (_joint) - { - static_cast(_joint)->setMaxDistance(value); - } + PhysicsBackend::SetDistanceJointMaxDistance(_joint, value); } void DistanceJoint::SetTolerance(float value) @@ -60,32 +47,23 @@ void DistanceJoint::SetTolerance(float value) value = Math::Max(0.1f, value); if (Math::NearEqual(value, _tolerance)) return; - _tolerance = value; - if (_joint) - { - static_cast(_joint)->setTolerance(value); - } + PhysicsBackend::SetDistanceJointTolerance(_joint, value); } void DistanceJoint::SetSpringParameters(const SpringParameters& value) { if (value == _spring) return; - _spring = value; - if (_joint) - { - static_cast(_joint)->setStiffness(value.Stiffness); - static_cast(_joint)->setDamping(value.Damping); - } + PhysicsBackend::SetDistanceJointSpring(_joint, value); } float DistanceJoint::GetCurrentDistance() const { - return _joint ? static_cast(_joint)->getDistance() : 0.0f; + return _joint ? PhysicsBackend::GetDistanceJointDistance(_joint) : 0.0f; } #if USE_EDITOR @@ -149,18 +127,13 @@ void DistanceJoint::Deserialize(DeserializeStream& stream, ISerializeModifier* m DESERIALIZE_MEMBER(Damping, _spring.Damping); } -PxJoint* DistanceJoint::CreateJoint(JointData& data) +void* DistanceJoint::CreateJoint(const PhysicsJointDesc& desc) { - const PxTransform trans0(C2P(data.Pos0), C2P(data.Rot0)); - const PxTransform trans1(C2P(data.Pos1), C2P(data.Rot1)); - auto joint = PxDistanceJointCreate(*data.Physics, data.Actor0, trans0, data.Actor1, trans1); - - joint->setMinDistance(_minDistance); - joint->setMaxDistance(_maxDistance); - joint->setTolerance(_tolerance); - joint->setDistanceJointFlags(static_cast(_flags)); - joint->setStiffness(_spring.Stiffness); - joint->setDamping(_spring.Damping); - + void* joint = PhysicsBackend::CreateDistanceJoint(desc); + PhysicsBackend::SetDistanceJointFlags(joint, _flags); + PhysicsBackend::SetDistanceJointMinDistance(joint, _minDistance); + PhysicsBackend::SetDistanceJointMaxDistance(joint, _maxDistance); + PhysicsBackend::SetDistanceJointTolerance(joint, _tolerance); + PhysicsBackend::SetDistanceJointSpring(joint, _spring); return joint; } diff --git a/Source/Engine/Physics/Joints/DistanceJoint.h b/Source/Engine/Physics/Joints/DistanceJoint.h index 05dad5d0c..fc1c615f3 100644 --- a/Source/Engine/Physics/Joints/DistanceJoint.h +++ b/Source/Engine/Physics/Joints/DistanceJoint.h @@ -157,5 +157,5 @@ public: protected: // [Joint] - PxJoint* CreateJoint(JointData& data) override; + void* CreateJoint(const PhysicsJointDesc& desc) override; }; diff --git a/Source/Engine/Physics/Joints/FixedJoint.cpp b/Source/Engine/Physics/Joints/FixedJoint.cpp index 7c01e3e3c..8f1c2a888 100644 --- a/Source/Engine/Physics/Joints/FixedJoint.cpp +++ b/Source/Engine/Physics/Joints/FixedJoint.cpp @@ -1,8 +1,7 @@ // Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. #include "FixedJoint.h" -#include "Engine/Physics/Utilities.h" -#include +#include "Engine/Physics/PhysicsBackend.h" FixedJoint::FixedJoint(const SpawnParams& params) : Joint(params) @@ -23,9 +22,7 @@ void FixedJoint::OnDebugDrawSelected() #endif -PxJoint* FixedJoint::CreateJoint(JointData& data) +void* FixedJoint::CreateJoint(const PhysicsJointDesc& desc) { - const PxTransform trans0(C2P(data.Pos0), C2P(data.Rot0)); - const PxTransform trans1(C2P(data.Pos1), C2P(data.Rot1)); - return PxFixedJointCreate(*data.Physics, data.Actor0, trans0, data.Actor1, trans1); + return PhysicsBackend::CreateFixedJoint(desc); } diff --git a/Source/Engine/Physics/Joints/FixedJoint.h b/Source/Engine/Physics/Joints/FixedJoint.h index d2ee0f583..c62789c4e 100644 --- a/Source/Engine/Physics/Joints/FixedJoint.h +++ b/Source/Engine/Physics/Joints/FixedJoint.h @@ -21,5 +21,5 @@ public: protected: // [Joint] - PxJoint* CreateJoint(JointData& data) override; + void* CreateJoint(const PhysicsJointDesc& desc) override; }; diff --git a/Source/Engine/Physics/Joints/HingeJoint.cpp b/Source/Engine/Physics/Joints/HingeJoint.cpp index a651dab63..4d078880d 100644 --- a/Source/Engine/Physics/Joints/HingeJoint.cpp +++ b/Source/Engine/Physics/Joints/HingeJoint.cpp @@ -2,8 +2,7 @@ #include "HingeJoint.h" #include "Engine/Serialization/Serialization.h" -#include "Engine/Physics/Utilities.h" -#include +#include "Engine/Physics/PhysicsBackend.h" HingeJoint::HingeJoint(const SpawnParams& params) : Joint(params) @@ -17,61 +16,37 @@ void HingeJoint::SetFlags(const HingeJointFlag value) { if (_flags == value) return; - _flags = value; - if (_joint) - { - auto joint = static_cast(_joint); - joint->setRevoluteJointFlag(PxRevoluteJointFlag::eLIMIT_ENABLED, (_flags & HingeJointFlag::Limit) != 0); - joint->setRevoluteJointFlag(PxRevoluteJointFlag::eDRIVE_ENABLED, (_flags & HingeJointFlag::Drive) != 0); - } + PhysicsBackend::SetHingeJointFlags(_joint, value, _drive.FreeSpin); } void HingeJoint::SetLimit(const LimitAngularRange& value) { if (_limit == value) return; - _limit = value; - if (_joint) - { - auto joint = static_cast(_joint); - PxJointAngularLimitPair limit(value.Lower * DegreesToRadians, Math::Max(value.Upper, value.Lower) * DegreesToRadians, value.ContactDist); - limit.stiffness = value.Spring.Stiffness; - limit.damping = value.Spring.Damping; - limit.restitution = value.Restitution; - ASSERT_LOW_LAYER(limit.isValid()); - joint->setLimit(limit); - } + PhysicsBackend::SetHingeJointLimit(_joint, value); } void HingeJoint::SetDrive(const HingeJointDrive& value) { if (_drive == value) return; - _drive = value; - if (_joint) - { - auto joint = static_cast(_joint); - joint->setDriveVelocity(Math::Max(value.Velocity, 0.0f)); - joint->setDriveForceLimit(Math::Max(value.ForceLimit, 0.0f)); - joint->setDriveGearRatio(Math::Max(value.GearRatio, 0.0f)); - joint->setRevoluteJointFlag(PxRevoluteJointFlag::eDRIVE_FREESPIN, value.FreeSpin); - } + PhysicsBackend::SetHingeJointDrive(_joint, value); } float HingeJoint::GetCurrentAngle() const { - return _joint ? static_cast(_joint)->getAngle() : 0.0f; + return _joint ? PhysicsBackend::GetHingeJointAngle(_joint) : 0.0f; } float HingeJoint::GetCurrentVelocity() const { - return _joint ? static_cast(_joint)->getVelocity() : 0.0f; + return _joint ? PhysicsBackend::GetHingeJointVelocity(_joint) : 0.0f; } #if USE_EDITOR @@ -146,29 +121,11 @@ void HingeJoint::Deserialize(DeserializeStream& stream, ISerializeModifier* modi DESERIALIZE_MEMBER(FreeSpin, _drive.FreeSpin); } -PxJoint* HingeJoint::CreateJoint(JointData& data) +void* HingeJoint::CreateJoint(const PhysicsJointDesc& desc) { - const PxTransform trans0(C2P(data.Pos0), C2P(data.Rot0)); - const PxTransform trans1(C2P(data.Pos1), C2P(data.Rot1)); - auto joint = PxRevoluteJointCreate(*data.Physics, data.Actor0, trans0, data.Actor1, trans1); - - int32 flags = 0; - if (_flags & HingeJointFlag::Limit) - flags |= PxRevoluteJointFlag::eLIMIT_ENABLED; - if (_flags & HingeJointFlag::Drive) - flags |= PxRevoluteJointFlag::eDRIVE_ENABLED; - if (_drive.FreeSpin) - flags |= PxRevoluteJointFlag::eDRIVE_FREESPIN; - joint->setRevoluteJointFlags(static_cast(flags)); - joint->setDriveVelocity(_drive.Velocity); - joint->setDriveForceLimit(_drive.ForceLimit); - joint->setDriveGearRatio(_drive.GearRatio); - PxJointAngularLimitPair limit(_limit.Lower * DegreesToRadians, Math::Max(_limit.Upper, _limit.Lower) * DegreesToRadians, _limit.ContactDist); - limit.stiffness = _limit.Spring.Stiffness; - limit.damping = _limit.Spring.Damping; - limit.restitution = _limit.Restitution; - ASSERT_LOW_LAYER(limit.isValid()); - joint->setLimit(limit); - + void* joint = PhysicsBackend::CreateHingeJoint(desc); + PhysicsBackend::SetHingeJointFlags(joint, _flags, _drive.FreeSpin); + PhysicsBackend::SetHingeJointLimit(joint, _limit); + PhysicsBackend::SetHingeJointDrive(joint, _drive); return joint; } diff --git a/Source/Engine/Physics/Joints/HingeJoint.h b/Source/Engine/Physics/Joints/HingeJoint.h index cea8a30ff..7b0957101 100644 --- a/Source/Engine/Physics/Joints/HingeJoint.h +++ b/Source/Engine/Physics/Joints/HingeJoint.h @@ -165,5 +165,5 @@ public: protected: // [Joint] - PxJoint* CreateJoint(JointData& data) override; + void* CreateJoint(const PhysicsJointDesc& desc) override; }; diff --git a/Source/Engine/Physics/Joints/Joint.cpp b/Source/Engine/Physics/Joints/Joint.cpp index 84a8ad249..3e65f3e60 100644 --- a/Source/Engine/Physics/Joints/Joint.cpp +++ b/Source/Engine/Physics/Joints/Joint.cpp @@ -3,14 +3,13 @@ #include "Joint.h" #include "Engine/Serialization/Serialization.h" #include "Engine/Core/Log.h" -#include "Engine/Physics/Utilities.h" #include "Engine/Physics/Physics.h" +#include "Engine/Physics/PhysicsBackend.h" +#include "Engine/Physics/PhysicsScene.h" #include "Engine/Physics/Actors/IPhysicsActor.h" #if USE_EDITOR #include "Engine/Level/Scene/SceneRendering.h" #endif -#include "Engine/Scripting/Script.h" -#include Joint::Joint(const SpawnParams& params) : Actor(params) @@ -27,36 +26,27 @@ void Joint::SetBreakForce(float value) { if (Math::NearEqual(value, _breakForce)) return; - _breakForce = value; if (_joint) - { - _joint->setBreakForce(_breakForce, _breakTorque); - } + PhysicsBackend::SetJointBreakForce(_joint, _breakForce, _breakTorque); } void Joint::SetBreakTorque(float value) { if (Math::NearEqual(value, _breakTorque)) return; - _breakTorque = value; if (_joint) - { - _joint->setBreakForce(_breakForce, _breakTorque); - } + PhysicsBackend::SetJointBreakForce(_joint, _breakForce, _breakTorque); } void Joint::SetEnableCollision(bool value) { if (value == GetEnableCollision()) return; - _enableCollision = value; if (_joint) - { - _joint->setConstraintFlag(PxConstraintFlag::eCOLLISION_ENABLED, value); - } + PhysicsBackend::SetJointFlags(_joint, _enableCollision ? PhysicsBackend::JointFlags::Collision : PhysicsBackend::JointFlags::None); } bool Joint::GetEnableAutoAnchor() const @@ -73,24 +63,23 @@ void Joint::SetTargetAnchor(const Vector3& value) { if (Vector3::NearEqual(value, _targetAnchor)) return; - _targetAnchor = value; if (_joint && !_enableAutoAnchor) - { - _joint->setLocalPose(PxJointActorIndex::eACTOR1, PxTransform(C2P(_targetAnchor), C2P(_targetAnchorRotation))); - } + PhysicsBackend::SetJointActorPose(_joint, _targetAnchor, _targetAnchorRotation, 1); } void Joint::SetTargetAnchorRotation(const Quaternion& value) { if (Quaternion::NearEqual(value, _targetAnchorRotation)) return; - _targetAnchorRotation = value; if (_joint && !_enableAutoAnchor) - { - _joint->setLocalPose(PxJointActorIndex::eACTOR1, PxTransform(C2P(_targetAnchor), C2P(_targetAnchorRotation))); - } + PhysicsBackend::SetJointActorPose(_joint, _targetAnchor, _targetAnchorRotation, 1); +} + +void* Joint::GetPhysicsImpl() const +{ + return _joint; } void Joint::SetJointLocation(const Vector3& location) @@ -128,14 +117,9 @@ void Joint::SetJointOrientation(const Quaternion& orientation) void Joint::GetCurrentForce(Vector3& linear, Vector3& angular) const { - if (_joint && _joint->getConstraint()) - { - _joint->getConstraint()->getForce(*(PxVec3*)&linear, *(PxVec3*)&angular); - } - else - { - linear = angular = Vector3::Zero; - } + linear = angular = Vector3::Zero; + if (_joint) + PhysicsBackend::GetJointForce(_joint, linear, angular); } void Joint::Create() @@ -151,26 +135,25 @@ void Joint::Create() } // Create joint object - JointData data; - data.Physics = Physics::GetPhysics(); - data.Actor0 = parent->GetRigidActor(); - data.Actor1 = target ? target->GetRigidActor() : nullptr; - data.Pos0 = _localTransform.Translation; - data.Rot0 = _localTransform.Orientation; - data.Pos1 = _targetAnchor; - data.Rot1 = _targetAnchorRotation; + PhysicsJointDesc desc; + desc.Joint = this; + desc.Actor0 = parent->GetPhysicsActor(); + desc.Actor1 = target ? target->GetPhysicsActor() : nullptr; + desc.Pos0 = _localTransform.Translation; + desc.Rot0 = _localTransform.Orientation; + desc.Pos1 = _targetAnchor; + desc.Rot1 = _targetAnchorRotation; if (_enableAutoAnchor && target) { // Place target anchor at the joint location - data.Pos1 = Target->GetTransform().WorldToLocal(GetPosition()); - data.Rot1 = WorldToLocal(Target->GetOrientation(), GetOrientation()); + desc.Pos1 = Target->GetTransform().WorldToLocal(GetPosition()); + desc.Rot1 = WorldToLocal(Target->GetOrientation(), GetOrientation()); } - _joint = CreateJoint(data); - _joint->userData = this; + _joint = CreateJoint(desc); // Setup joint properties - _joint->setBreakForce(_breakForce, _breakTorque); - _joint->setConstraintFlag(PxConstraintFlag::eCOLLISION_ENABLED, _enableCollision); + PhysicsBackend::SetJointBreakForce(_joint, _breakForce, _breakTorque); + PhysicsBackend::SetJointFlags(_joint, _enableCollision ? PhysicsBackend::JointFlags::Collision : PhysicsBackend::JointFlags::None); } void Joint::OnJointBreak() @@ -180,10 +163,8 @@ void Joint::OnJointBreak() void Joint::Delete() { - // Remove the joint - Physics::RemoveJoint(this); - _joint->userData = nullptr; - _joint->release(); + PhysicsBackend::RemoveJoint(this); + PhysicsBackend::DestroyJoint(_joint); _joint = nullptr; } @@ -192,8 +173,7 @@ void Joint::SetActors() auto parent = dynamic_cast(GetParent()); auto target = dynamic_cast(Target.Get()); ASSERT(parent != nullptr); - - _joint->setActors(parent ? parent->GetRigidActor() : nullptr, target ? target->GetRigidActor() : nullptr); + PhysicsBackend::SetJointActors(_joint, parent->GetPhysicsActor(), target ? target->GetPhysicsActor() : nullptr); } void Joint::OnTargetChanged() @@ -347,7 +327,7 @@ void Joint::OnActiveInTreeChanged() else Delete(); } - // Joint object may not be created if actor is disabled on play mode begin (late init feature) + // Joint object may not be created if actor is disabled on play mode begin (late init feature) else if (IsDuringPlay()) { Create(); @@ -393,9 +373,6 @@ void Joint::OnTransformChanged() _box = BoundingBox(_transform.Translation); _sphere = BoundingSphere(_transform.Translation, 0.0f); - if (_joint) - { - _joint->setLocalPose(PxJointActorIndex::eACTOR0, PxTransform(C2P(_localTransform.Translation), C2P(_localTransform.Orientation))); - } + PhysicsBackend::SetJointActorPose(_joint, _localTransform.Translation, _localTransform.Orientation, 0); } diff --git a/Source/Engine/Physics/Joints/Joint.h b/Source/Engine/Physics/Joints/Joint.h index a9f1a02ab..f8e341eb5 100644 --- a/Source/Engine/Physics/Joints/Joint.h +++ b/Source/Engine/Physics/Joints/Joint.h @@ -21,7 +21,7 @@ API_CLASS(Abstract) class FLAXENGINE_API Joint : public Actor DECLARE_SCENE_OBJECT_ABSTRACT(Joint); protected: - PxJoint* _joint; + void* _joint; float _breakForce; float _breakTorque; Vector3 _targetAnchor; @@ -133,12 +133,9 @@ public: public: /// - /// Gets the native PhysX joint object. + /// Gets the native physics backend object. /// - FORCE_INLINE PxJoint* GetPhysXJoint() const - { - return _joint; - } + void* GetPhysicsImpl() const; /// /// Sets the location of the joint by automatically computing local position and target anchor to place a joint at the given location (world-space). @@ -178,20 +175,9 @@ public: protected: - struct JointData - { - PxPhysics* Physics; - PxRigidActor* Actor0; - PxRigidActor* Actor1; - Quaternion Rot0; - Quaternion Rot1; - Vector3 Pos0; - Vector3 Pos1; - }; - Vector3 GetTargetPosition() const; Quaternion GetTargetOrientation() const; - virtual PxJoint* CreateJoint(JointData& data) = 0; + virtual void* CreateJoint(const struct PhysicsJointDesc& desc) = 0; #if USE_EDITOR virtual void DrawPhysicsDebug(RenderView& view); #endif diff --git a/Source/Engine/Physics/Joints/SliderJoint.cpp b/Source/Engine/Physics/Joints/SliderJoint.cpp index f6bda1b1f..62f1b646b 100644 --- a/Source/Engine/Physics/Joints/SliderJoint.cpp +++ b/Source/Engine/Physics/Joints/SliderJoint.cpp @@ -2,9 +2,7 @@ #include "SliderJoint.h" #include "Engine/Serialization/Serialization.h" -#include "Engine/Physics/Utilities.h" -#include "Engine/Physics/Physics.h" -#include +#include "Engine/Physics/PhysicsBackend.h" SliderJoint::SliderJoint(const SpawnParams& params) : Joint(params) @@ -18,43 +16,28 @@ void SliderJoint::SetFlags(const SliderJointFlag value) { if (_flags == value) return; - _flags = value; - if (_joint) - { - auto joint = static_cast(_joint); - joint->setPrismaticJointFlag(PxPrismaticJointFlag::eLIMIT_ENABLED, (_flags & SliderJointFlag::Limit) != 0); - } + PhysicsBackend::SetSliderJointFlags(_joint, value); } void SliderJoint::SetLimit(const LimitLinearRange& value) { if (_limit == value) return; - _limit = value; - if (_joint) - { - auto joint = static_cast(_joint); - PxJointLinearLimitPair limit(*Physics::GetTolerancesScale(), value.Lower, value.Upper, value.ContactDist); - limit.stiffness = value.Spring.Stiffness; - limit.damping = value.Spring.Damping; - limit.restitution = value.Restitution; - ASSERT_LOW_LAYER(limit.isValid()); - joint->setLimit(limit); - } + PhysicsBackend::SetSliderJointLimit(_joint, value); } float SliderJoint::GetCurrentPosition() const { - return _joint ? static_cast(_joint)->getPosition() : 0.0f; + return _joint ? PhysicsBackend::GetSliderJointPosition(_joint) : 0.0f; } float SliderJoint::GetCurrentVelocity() const { - return _joint ? static_cast(_joint)->getVelocity() : 0.0f; + return _joint ? PhysicsBackend::GetSliderJointVelocity(_joint) : 0.0f; } #if USE_EDITOR @@ -111,21 +94,10 @@ void SliderJoint::Deserialize(DeserializeStream& stream, ISerializeModifier* mod DESERIALIZE_MEMBER(UpperLimit, _limit.Upper); } -PxJoint* SliderJoint::CreateJoint(JointData& data) +void* SliderJoint::CreateJoint(const PhysicsJointDesc& desc) { - const PxTransform trans0(C2P(data.Pos0), C2P(data.Rot0)); - const PxTransform trans1(C2P(data.Pos1), C2P(data.Rot1)); - auto joint = PxPrismaticJointCreate(*data.Physics, data.Actor0, trans0, data.Actor1, trans1); - - int32 flags = 0; - if (_flags & SliderJointFlag::Limit) - flags |= PxPrismaticJointFlag::eLIMIT_ENABLED; - joint->setPrismaticJointFlags(static_cast(flags)); - PxJointLinearLimitPair limit(*Physics::GetTolerancesScale(), _limit.Lower, _limit.Upper, _limit.ContactDist); - limit.stiffness = _limit.Spring.Stiffness; - limit.damping = _limit.Spring.Damping; - limit.restitution = _limit.Restitution; - joint->setLimit(limit); - + void* joint = PhysicsBackend::CreateSliderJoint(desc); + PhysicsBackend::SetSliderJointFlags(joint, _flags); + PhysicsBackend::SetSliderJointLimit(joint, _limit); return joint; } diff --git a/Source/Engine/Physics/Joints/SliderJoint.h b/Source/Engine/Physics/Joints/SliderJoint.h index b9a11c0a0..12dbed970 100644 --- a/Source/Engine/Physics/Joints/SliderJoint.h +++ b/Source/Engine/Physics/Joints/SliderJoint.h @@ -95,5 +95,5 @@ public: protected: // [Joint] - PxJoint* CreateJoint(JointData& data) override; + void* CreateJoint(const PhysicsJointDesc& desc) override; }; diff --git a/Source/Engine/Physics/Joints/SphericalJoint.cpp b/Source/Engine/Physics/Joints/SphericalJoint.cpp index bb83ee7cb..0833086cf 100644 --- a/Source/Engine/Physics/Joints/SphericalJoint.cpp +++ b/Source/Engine/Physics/Joints/SphericalJoint.cpp @@ -2,8 +2,7 @@ #include "SphericalJoint.h" #include "Engine/Serialization/Serialization.h" -#include "Engine/Physics/Utilities.h" -#include +#include "Engine/Physics/PhysicsBackend.h" SphericalJoint::SphericalJoint(const SpawnParams& params) : Joint(params) @@ -15,33 +14,18 @@ void SphericalJoint::SetFlags(const SphericalJointFlag value) { if (_flags == value) return; - _flags = value; - if (_joint) - { - auto joint = static_cast(_joint); - joint->setSphericalJointFlag(PxSphericalJointFlag::eLIMIT_ENABLED, (_flags & SphericalJointFlag::Limit) != 0); - } + PhysicsBackend::SetSphericalJointFlags(_joint, value); } void SphericalJoint::SetLimit(const LimitConeRange& value) { if (_limit == value) return; - _limit = value; - if (_joint) - { - auto joint = static_cast(_joint); - PxJointLimitCone limit(Math::Clamp(value.YLimitAngle * DegreesToRadians, ZeroTolerance, PI - ZeroTolerance), Math::Clamp(value.ZLimitAngle * DegreesToRadians, ZeroTolerance, PI - ZeroTolerance), value.ContactDist); - limit.stiffness = value.Spring.Stiffness; - limit.damping = value.Spring.Damping; - limit.restitution = value.Restitution; - ASSERT_LOW_LAYER(limit.isValid()); - joint->setLimitCone(limit); - } + PhysicsBackend::SetSphericalJointLimit(_joint, value); } #if USE_EDITOR @@ -101,21 +85,10 @@ void SphericalJoint::Deserialize(DeserializeStream& stream, ISerializeModifier* DESERIALIZE_MEMBER(ZLimitAngle, _limit.ZLimitAngle); } -PxJoint* SphericalJoint::CreateJoint(JointData& data) +void* SphericalJoint::CreateJoint(const PhysicsJointDesc& desc) { - const PxTransform trans0(C2P(data.Pos0), C2P(data.Rot0)); - const PxTransform trans1(C2P(data.Pos1), C2P(data.Rot1)); - auto joint = PxSphericalJointCreate(*data.Physics, data.Actor0, trans0, data.Actor1, trans1); - - int32 flags = 0; - if (_flags & SphericalJointFlag::Limit) - flags |= PxSphericalJointFlag::eLIMIT_ENABLED; - joint->setSphericalJointFlags(static_cast(flags)); - PxJointLimitCone limit(Math::Clamp(_limit.YLimitAngle * DegreesToRadians, ZeroTolerance, PI - ZeroTolerance), Math::Clamp(_limit.ZLimitAngle * DegreesToRadians, ZeroTolerance, PI - ZeroTolerance), _limit.ContactDist); - limit.stiffness = _limit.Spring.Stiffness; - limit.damping = _limit.Spring.Damping; - limit.restitution = _limit.Restitution; - joint->setLimitCone(limit); - + void* joint = PhysicsBackend::CreateSphericalJoint(desc); + PhysicsBackend::SetSphericalJointFlags(joint, _flags); + PhysicsBackend::SetSphericalJointLimit(joint, _limit); return joint; } diff --git a/Source/Engine/Physics/Joints/SphericalJoint.h b/Source/Engine/Physics/Joints/SphericalJoint.h index 67d7e8e07..6fc370dee 100644 --- a/Source/Engine/Physics/Joints/SphericalJoint.h +++ b/Source/Engine/Physics/Joints/SphericalJoint.h @@ -85,5 +85,5 @@ public: protected: // [Joint] - PxJoint* CreateJoint(JointData& data) override; + void* CreateJoint(const PhysicsJointDesc& desc) override; }; diff --git a/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp b/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp new file mode 100644 index 000000000..940f4e260 --- /dev/null +++ b/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp @@ -0,0 +1,3061 @@ +// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved. + +#if COMPILE_WITH_PHYSX + +#include "PhysicsBackendPhysX.h" +#include "PhysicsStepperPhysX.h" +#include "SimulationEventCallbackPhysX.h" +#include "Engine/Core/Log.h" +#include "Engine/Core/Utilities.h" +#include "Engine/Physics/CollisionData.h" +#include "Engine/Physics/PhysicalMaterial.h" +#include "Engine/Physics/PhysicsScene.h" +#include "Engine/Physics/CollisionCooking.h" +#include "Engine/Physics/Actors/IPhysicsActor.h" +#include "Engine/Physics/Joints/Limits.h" +#include "Engine/Physics/Joints/DistanceJoint.h" +#include "Engine/Physics/Joints/HingeJoint.h" +#include "Engine/Physics/Joints/SliderJoint.h" +#include "Engine/Physics/Joints/SphericalJoint.h" +#include "Engine/Physics/Joints/D6Joint.h" +#include "Engine/Physics/Colliders/Collider.h" +#include "Engine/Platform/CPUInfo.h" +#include "Engine/Platform/CriticalSection.h" +#include "Engine/Profiler/ProfilerCPU.h" +#include "Engine/Serialization/WriteStream.h" +#include +#include +#include +#include +#if WITH_VEHICLE +#include "Engine/Physics/Actors/WheeledVehicle.h" +#include +#include +#include +#include +#include +#include +#include +#endif +#if WITH_PVD +#include +#endif + +// Temporary memory size used by the PhysX during the simulation. Must be multiply of 4kB and 16bit aligned. +#define PHYSX_SCRATCH_BLOCK_SIZE (1024 * 128) + +// Enables vehicles simulation debugging +#define PHYSX_VEHICLE_DEBUG_TELEMETRY 0 + +// Enables using debug naming for PhysX objects (eg. for debugging) +#define PHYSX_DEBUG_NAMING 0 + +// Temporary result buffer size +#define PHYSX_HIT_BUFFER_SIZE 128 + +struct ActionDataPhysX +{ + PhysicsBackend::ActionType Type; + PxActor* Actor; +}; + +struct ScenePhysX +{ + PxScene* Scene = nullptr; + PxCpuDispatcher* CpuDispatcher = nullptr; + PxControllerManager* ControllerManager = nullptr; + void* ScratchMemory = nullptr; + float LastDeltaTime = 0.0f; + FixedStepper Stepper; + SimulationEventCallback EventsCallback; + Array AddActors; + Array RemoveActors; + Array RemoveColliders; + Array RemoveJoints; + Array Actions; +#if WITH_VEHICLE + Array WheelVehicles; + PxBatchQuery* WheelRaycastBatchQuery = nullptr; +#endif +}; + +class AllocatorPhysX : public PxAllocatorCallback +{ + void* allocate(size_t size, const char* typeName, const char* filename, int line) override + { + return Allocator::Allocate(size, 16); + } + + void deallocate(void* ptr) override + { + Allocator::Free(ptr); + } +}; + +class ErrorPhysX : public PxErrorCallback +{ + void reportError(PxErrorCode::Enum code, const char* message, const char* file, int line) override + { + LOG(Error, "PhysX Error! Code: {0}.\n{1}\nSource: {2} : {3}.", static_cast(code), String(message), String(file), line); + } +}; + +class QueryFilterPhysX : public PxQueryFilterCallback +{ + PxQueryHitType::Enum preFilter(const PxFilterData& filterData, const PxShape* shape, const PxRigidActor* actor, PxHitFlags& queryFlags) override + { + // Early out to avoid crashing + if (!shape) + return PxQueryHitType::eNONE; + + // Check mask + const PxFilterData shapeFilter = shape->getQueryFilterData(); + if ((filterData.word0 & shapeFilter.word0) == 0) + { + return PxQueryHitType::eNONE; + } + + // Check if skip triggers + const bool hitTriggers = filterData.word2 != 0; + if (!hitTriggers && shape->getFlags() & PxShapeFlag::eTRIGGER_SHAPE) + return PxQueryHitType::eNONE; + + const bool blockSingle = filterData.word1 != 0; + return blockSingle ? PxQueryHitType::eBLOCK : PxQueryHitType::eTOUCH; + } + + PxQueryHitType::Enum postFilter(const PxFilterData& filterData, const PxQueryHit& hit) override + { + // Not used + return PxQueryHitType::eNONE; + } +}; + +class CharacterQueryFilterPhysX : public PxQueryFilterCallback +{ + PxQueryHitType::Enum preFilter(const PxFilterData& filterData, const PxShape* shape, const PxRigidActor* actor, PxHitFlags& queryFlags) override + { + // Early out to avoid crashing + if (!shape) + return PxQueryHitType::eNONE; + + // Let triggers through + if (PxFilterObjectIsTrigger(shape->getFlags())) + return PxQueryHitType::eNONE; + + // Trigger the contact callback for pairs (A,B) where the filtermask of A contains the ID of B and vice versa + const PxFilterData shapeFilter = shape->getQueryFilterData(); + if (filterData.word0 & shapeFilter.word1) + return PxQueryHitType::eBLOCK; + + return PxQueryHitType::eNONE; + } + + PxQueryHitType::Enum postFilter(const PxFilterData& filterData, const PxQueryHit& hit) override + { + // Not used + return PxQueryHitType::eNONE; + } +}; + +class CharacterControllerFilterPhysX : public PxControllerFilterCallback +{ + static PxShape* getShape(const PxController& controller) + { + PxRigidDynamic* actor = controller.getActor(); + + // Early out if no actor or no shapes + if (!actor || actor->getNbShapes() < 1) + return nullptr; + + // Get first shape only + PxShape* shape = nullptr; + actor->getShapes(&shape, 1); + + return shape; + } + + bool filter(const PxController& a, const PxController& b) override + { + // Early out to avoid crashing + PxShape* shapeA = getShape(a); + if (!shapeA) + return false; + + PxShape* shapeB = getShape(b); + if (!shapeB) + return false; + + // Let triggers through + if (PxFilterObjectIsTrigger(shapeB->getFlags())) + return false; + + // Trigger the contact callback for pairs (A,B) where the filtermask of A contains the ID of B and vice versa + const PxFilterData shapeFilterA = shapeA->getQueryFilterData(); + const PxFilterData shapeFilterB = shapeB->getQueryFilterData(); + if (shapeFilterA.word0 & shapeFilterB.word1) + return true; + + return false; + } +}; + +class WriteStreamPhysX : public PxOutputStream +{ +public: + WriteStream* Stream; + + uint32_t write(const void* src, uint32_t count) override + { + Stream->WriteBytes(src, (int32)count); + return count; + } +}; + +template +class DynamicHitBuffer : public PxHitCallback +{ +private: + uint32 _count; + HitType _buffer[PHYSX_HIT_BUFFER_SIZE]; + +public: + DynamicHitBuffer() + : PxHitCallback(_buffer, PHYSX_HIT_BUFFER_SIZE) + , _count(0) + { + } + +public: + // Computes the number of any hits in this result, blocking or touching. + PX_INLINE PxU32 getNbAnyHits() const + { + return getNbTouches(); + } + + // Convenience iterator used to access any hits in this result, blocking or touching. + PX_INLINE const HitType& getAnyHit(const PxU32 index) const + { + PX_ASSERT(index < getNbTouches() + PxU32(this->hasBlock)); + return index < getNbTouches() ? getTouches()[index] : this->block; + } + + PX_INLINE PxU32 getNbTouches() const + { + return _count; + } + + PX_INLINE const HitType* getTouches() const + { + return _buffer; + } + + PX_INLINE const HitType& getTouch(const PxU32 index) const + { + PX_ASSERT(index < getNbTouches()); + return _buffer[index]; + } + + PX_INLINE PxU32 getMaxNbTouches() const + { + return PHYSX_HIT_BUFFER_SIZE; + } + +protected: + PxAgain processTouches(const HitType* buffer, PxU32 nbHits) override + { + nbHits = Math::Min(nbHits, PHYSX_HIT_BUFFER_SIZE - _count); + for (PxU32 i = 0; i < nbHits; i++) + { + _buffer[_count + i] = buffer[i]; + } + _count += nbHits; + return true; + } + + void finalizeQuery() override + { + if (this->hasBlock) + { + // Blocking hits go to hits + processTouches(&this->block, 1); + } + } +}; + +#define SCENE_QUERY_SETUP(blockSingle) auto scenePhysX = (ScenePhysX*)scene; if (scene == nullptr) return false; \ + const PxHitFlags hitFlags = PxHitFlag::ePOSITION | PxHitFlag::eNORMAL | PxHitFlag::eUV; \ + PxQueryFilterData filterData; \ + filterData.flags |= PxQueryFlag::ePREFILTER; \ + filterData.data.word0 = layerMask; \ + filterData.data.word1 = blockSingle ? 1 : 0; \ + filterData.data.word2 = hitTriggers ? 1 : 0 + +#define SCENE_QUERY_SETUP_SWEEP_1() SCENE_QUERY_SETUP(true); \ + PxSweepBufferN<1> buffer + +#define SCENE_QUERY_SETUP_SWEEP() SCENE_QUERY_SETUP(false); \ + DynamicHitBuffer buffer + +#define SCENE_QUERY_SETUP_OVERLAP_1() SCENE_QUERY_SETUP(false); \ + PxOverlapBufferN<1> buffer + +#define SCENE_QUERY_SETUP_OVERLAP() SCENE_QUERY_SETUP(false); \ + DynamicHitBuffer buffer + +#define SCENE_QUERY_COLLECT_SINGLE() const auto& hit = buffer.getAnyHit(0); \ + P2C(hit, hitInfo) + +#define SCENE_QUERY_COLLECT_ALL() results.Clear(); \ + results.Resize(buffer.getNbAnyHits(), false); \ + for (int32 i = 0; i < results.Count(); i++) \ + { \ + const auto& hit = buffer.getAnyHit(i); \ + P2C(hit, results[i]); \ + } + +#define SCENE_QUERY_COLLECT_OVERLAP() results.Clear(); \ + results.Resize(buffer.getNbTouches(), false); \ + for (int32 i = 0; i < results.Count(); i++) \ + { \ + auto& hitInfo = results[i]; \ + const auto& hit = buffer.getTouch(i); \ + hitInfo = hit.shape ? static_cast(hit.shape->userData) : nullptr; \ + } + +#define SCENE_QUERY_COLLECT_OVERLAP_COLLIDER() results.Clear(); \ + results.Resize(buffer.getNbTouches(), false); \ + for (int32 i = 0; i < results.Count(); i++) \ + { \ + auto& hitInfo = results[i]; \ + const auto& hit = buffer.getTouch(i); \ + hitInfo = hit.shape ? static_cast(hit.shape->userData) : nullptr; \ + } + +namespace +{ + PxFoundation* Foundation = nullptr; + PxPhysics* PhysX = nullptr; +#if WITH_PVD + PxPvd* PVD = nullptr; +#endif +#if COMPILE_WITH_PHYSICS_COOKING + PxCooking* Cooking = nullptr; +#endif + PxMaterial* DefaultMaterial = nullptr; + AllocatorPhysX AllocatorCallback; + ErrorPhysX ErrorCallback; + PxTolerancesScale ToleranceScale; + QueryFilterPhysX QueryFilter; + CharacterQueryFilterPhysX CharacterQueryFilter; + CharacterControllerFilterPhysX CharacterControllerFilter; + + CriticalSection FlushLocker; + Array DeleteObjects; + + bool _queriesHitTriggers = true; + PhysicsCombineMode _frictionCombineMode = PhysicsCombineMode::Average; + PhysicsCombineMode _restitutionCombineMode = PhysicsCombineMode::Average; + +#if WITH_VEHICLE + bool VehicleSDKInitialized = false; + Array WheelVehiclesCache; + Array WheelQueryResults; + Array WheelHitResults; + Array WheelVehiclesResultsPerWheel; + Array WheelVehiclesResultsPerVehicle; + PxVehicleDrivableSurfaceToTireFrictionPairs* WheelTireFrictions = nullptr; +#endif +} + +PxShapeFlags GetShapeFlags(bool isTrigger, bool isEnabled) +{ +#if WITH_PVD + PxShapeFlags flags = PxShapeFlag::eVISUALIZATION; +#else + PxShapeFlags flags = static_cast(0); +#endif + + if (isEnabled) + { + if (isTrigger) + { + flags |= PxShapeFlag::eTRIGGER_SHAPE; + if (_queriesHitTriggers) + flags |= PxShapeFlag::eSCENE_QUERY_SHAPE; + } + else + { + flags = PxShapeFlag::eSIMULATION_SHAPE | PxShapeFlag::eSCENE_QUERY_SHAPE; + } + } + + return flags; +} + +void GetShapeGeometry(const CollisionShape& shape, PxGeometryHolder& geometry) +{ + switch (shape.Type) + { + case CollisionShape::Types::Sphere: + geometry.storeAny(PxSphereGeometry(shape.Sphere.Radius)); + break; + case CollisionShape::Types::Box: + geometry.storeAny(PxBoxGeometry(shape.Box.HalfExtents[0], shape.Box.HalfExtents[1], shape.Box.HalfExtents[2])); + break; + case CollisionShape::Types::Capsule: + geometry.storeAny(PxCapsuleGeometry(shape.Capsule.Radius, shape.Capsule.HalfHeight)); + break; + case CollisionShape::Types::ConvexMesh: + geometry.storeAny(PxConvexMeshGeometry((PxConvexMesh*)shape.ConvexMesh.ConvexMesh, PxMeshScale(PxVec3(shape.ConvexMesh.Scale[0], shape.ConvexMesh.Scale[1], shape.ConvexMesh.Scale[2])))); + break; + case CollisionShape::Types::TriangleMesh: + geometry.storeAny(PxTriangleMeshGeometry((PxTriangleMesh*)shape.TriangleMesh.TriangleMesh, PxMeshScale(PxVec3(shape.TriangleMesh.Scale[0], shape.TriangleMesh.Scale[1], shape.TriangleMesh.Scale[2])))); + break; + case CollisionShape::Types::HeightField: + geometry.storeAny(PxHeightFieldGeometry((PxHeightField*)shape.HeightField.HeightField, PxMeshGeometryFlags(0), Math::Max(shape.HeightField.HeightScale, PX_MIN_HEIGHTFIELD_Y_SCALE), Math::Max(shape.HeightField.RowScale, PX_MIN_HEIGHTFIELD_XZ_SCALE), Math::Max(shape.HeightField.ColumnScale, PX_MIN_HEIGHTFIELD_XZ_SCALE))); + break; + } +} + +PxFilterFlags FilterShader( + PxFilterObjectAttributes attributes0, PxFilterData filterData0, + PxFilterObjectAttributes attributes1, PxFilterData filterData1, + PxPairFlags& pairFlags, const void* constantBlock, PxU32 constantBlockSize) +{ + // Let triggers through + if (PxFilterObjectIsTrigger(attributes0) || PxFilterObjectIsTrigger(attributes1)) + { + pairFlags |= PxPairFlag::eNOTIFY_TOUCH_FOUND; + pairFlags |= PxPairFlag::eNOTIFY_TOUCH_LOST; + pairFlags |= PxPairFlag::eDETECT_DISCRETE_CONTACT; + return PxFilterFlag::eDEFAULT; + } + + // Send events for the kinematic actors but don't solve the contact + if (PxFilterObjectIsKinematic(attributes0) && PxFilterObjectIsKinematic(attributes1)) + { + pairFlags |= PxPairFlag::eNOTIFY_TOUCH_FOUND; + pairFlags |= PxPairFlag::eNOTIFY_TOUCH_PERSISTS; + pairFlags |= PxPairFlag::eNOTIFY_TOUCH_LOST; + pairFlags |= PxPairFlag::eDETECT_DISCRETE_CONTACT; + return PxFilterFlag::eSUPPRESS; + } + + // Trigger the contact callback for pairs (A,B) where the filtermask of A contains the ID of B and vice versa + if ((filterData0.word0 & filterData1.word1) && (filterData1.word0 & filterData0.word1)) + { + pairFlags |= PxPairFlag::eSOLVE_CONTACT; + pairFlags |= PxPairFlag::eDETECT_DISCRETE_CONTACT; + pairFlags |= PxPairFlag::eNOTIFY_TOUCH_FOUND; + pairFlags |= PxPairFlag::eNOTIFY_TOUCH_PERSISTS; + pairFlags |= PxPairFlag::ePOST_SOLVER_VELOCITY; + pairFlags |= PxPairFlag::eNOTIFY_CONTACT_POINTS; + return PxFilterFlag::eDEFAULT; + } + + // Ignore pair (no collisions nor events) + return PxFilterFlag::eKILL; +} + +#if WITH_VEHICLE + +void InitVehicleSDK() +{ + if (!VehicleSDKInitialized) + { + VehicleSDKInitialized = true; + PxInitVehicleSDK(*PhysX); + PxVehicleSetBasisVectors(PxVec3(0, 1, 0), PxVec3(1, 0, 0)); + PxVehicleSetUpdateMode(PxVehicleUpdateMode::eVELOCITY_CHANGE); + } +} + +PxQueryHitType::Enum WheelRaycastPreFilter(PxFilterData filterData0, PxFilterData filterData1, const void* constantBlock, PxU32 constantBlockSize, PxHitFlags& queryFlags) +{ + // Hardcoded id for vehicle shapes masking + if (filterData0.word3 == filterData1.word3) + { + return PxQueryHitType::eNONE; + } + + // Collide for pairs (A,B) where the filtermask of A contains the ID of B and vice versa + if ((filterData0.word0 & filterData1.word1) && (filterData1.word0 & filterData0.word1)) + { + return PxQueryHitType::eBLOCK; + } + + return PxQueryHitType::eNONE; +} + +#endif + +void* PhysicalMaterial::GetPhysicsMaterial() +{ + if (_material == nullptr && PhysX) + { + auto material = PhysX->createMaterial(Friction, Friction, Restitution); + material->userData = this; + _material = material; + + const PhysicsCombineMode useFrictionCombineMode = OverrideFrictionCombineMode ? FrictionCombineMode : _frictionCombineMode; + material->setFrictionCombineMode(static_cast(useFrictionCombineMode)); + + const PhysicsCombineMode useRestitutionCombineMode = OverrideRestitutionCombineMode ? RestitutionCombineMode : _restitutionCombineMode; + material->setRestitutionCombineMode(static_cast(useRestitutionCombineMode)); + } + return _material; +} + +void PhysicalMaterial::UpdatePhysicsMaterial() +{ + auto material = (PxMaterial*)_material; + if (material != nullptr) + { + material->setStaticFriction(Friction); + material->setDynamicFriction(Friction); + + const PhysicsCombineMode useFrictionCombineMode = OverrideFrictionCombineMode ? FrictionCombineMode : _frictionCombineMode; + material->setFrictionCombineMode(static_cast(useFrictionCombineMode)); + + material->setRestitution(Restitution); + const PhysicsCombineMode useRestitutionCombineMode = OverrideRestitutionCombineMode ? RestitutionCombineMode : _restitutionCombineMode; + material->setRestitutionCombineMode(static_cast(useRestitutionCombineMode)); + } +} + +#if COMPILE_WITH_PHYSICS_COOKING + +#define ENSURE_CAN_COOK \ + auto cooking = Cooking; \ + if (cooking == nullptr) \ + { \ + LOG(Warning, "Physics collisions cooking is disabled at runtime. Enable Physics Settings option SupportCookingAtRuntime to use collision generation at runtime."); \ + return true; \ + } + +bool CollisionCooking::CookConvexMesh(CookingInput& input, BytesContainer& output) +{ + ENSURE_CAN_COOK; + if (input.VertexCount == 0) + LOG(Warning, "Empty mesh data for collision cooking."); + + // Init options + PxConvexMeshDesc desc; + desc.points.count = input.VertexCount; + desc.points.stride = sizeof(Vector3); + desc.points.data = input.VertexData; + desc.flags = PxConvexFlag::eCOMPUTE_CONVEX; + if (input.ConvexVertexLimit == 0) + desc.vertexLimit = CONVEX_VERTEX_MAX; + else + desc.vertexLimit = (PxU16)Math::Clamp(input.ConvexVertexLimit, CONVEX_VERTEX_MIN, CONVEX_VERTEX_MAX); + if (input.ConvexFlags & ConvexMeshGenerationFlags::SkipValidation) + desc.flags |= PxConvexFlag::Enum::eDISABLE_MESH_VALIDATION; + if (input.ConvexFlags & ConvexMeshGenerationFlags::UsePlaneShifting) + desc.flags |= PxConvexFlag::Enum::ePLANE_SHIFTING; + if (input.ConvexFlags & ConvexMeshGenerationFlags::UseFastInteriaComputation) + desc.flags |= PxConvexFlag::Enum::eFAST_INERTIA_COMPUTATION; + if (input.ConvexFlags & ConvexMeshGenerationFlags::ShiftVertices) + desc.flags |= PxConvexFlag::Enum::eSHIFT_VERTICES; + PxCookingParams cookingParams = cooking->getParams(); + cookingParams.suppressTriangleMeshRemapTable = input.ConvexFlags & ConvexMeshGenerationFlags::SuppressFaceRemapTable; + cooking->setParams(cookingParams); + + // Perform cooking + PxDefaultMemoryOutputStream outputStream; + PxConvexMeshCookingResult::Enum result; + if (!cooking->cookConvexMesh(desc, outputStream, &result)) + { + LOG(Warning, "Convex Mesh cooking failed. Error code: {0}, Input vertices count: {1}", result, input.VertexCount); + return true; + } + + // Copy result + output.Copy(outputStream.getData(), outputStream.getSize()); + + return false; +} + +bool CollisionCooking::CookTriangleMesh(CookingInput& input, BytesContainer& output) +{ + ENSURE_CAN_COOK; + if (input.VertexCount == 0 || input.IndexCount == 0) + LOG(Warning, "Empty mesh data for collision cooking."); + + // Init options + PxTriangleMeshDesc desc; + desc.points.count = input.VertexCount; + desc.points.stride = sizeof(Vector3); + desc.points.data = input.VertexData; + desc.triangles.count = input.IndexCount / 3; + desc.triangles.stride = 3 * (input.Is16bitIndexData ? sizeof(uint16) : sizeof(uint32)); + desc.triangles.data = input.IndexData; + desc.flags = input.Is16bitIndexData ? PxMeshFlag::e16_BIT_INDICES : (PxMeshFlag::Enum)0; + PxCookingParams cookingParams = cooking->getParams(); + cookingParams.suppressTriangleMeshRemapTable = input.ConvexFlags & ConvexMeshGenerationFlags::SuppressFaceRemapTable; + cooking->setParams(cookingParams); + + // Perform cooking + PxDefaultMemoryOutputStream outputStream; + PxTriangleMeshCookingResult::Enum result; + if (!cooking->cookTriangleMesh(desc, outputStream, &result)) + { + LOG(Warning, "Triangle Mesh cooking failed. Error code: {0}, Input vertices count: {1}, indices count: {2}", result, input.VertexCount, input.IndexCount); + return true; + } + + // Copy result + output.Copy(outputStream.getData(), outputStream.getSize()); + + return false; +} + +bool CollisionCooking::CookHeightField(int32 cols, int32 rows, const PhysicsBackend::HeightFieldSample* data, WriteStream& stream) +{ + ENSURE_CAN_COOK; + + PxHeightFieldDesc heightFieldDesc; + heightFieldDesc.format = PxHeightFieldFormat::eS16_TM; + heightFieldDesc.flags = PxHeightFieldFlag::eNO_BOUNDARY_EDGES; + heightFieldDesc.nbColumns = cols; + heightFieldDesc.nbRows = rows; + heightFieldDesc.samples.data = data; + heightFieldDesc.samples.stride = sizeof(PhysicsBackend::HeightFieldSample); + + WriteStreamPhysX outputStream; + outputStream.Stream = &stream; + if (!Cooking->cookHeightField(heightFieldDesc, outputStream)) + { + LOG(Warning, "Height Field collision cooking failed."); + return true; + } + return false; +} + +#endif + +PxPhysics* PhysicsBackendPhysX::GetPhysics() +{ + return PhysX; +} + +#if COMPILE_WITH_PHYSICS_COOKING + +PxCooking* PhysicsBackendPhysX::GetCooking() +{ + return Cooking; +} + +#endif + +PxMaterial* PhysicsBackendPhysX::GetDefaultMaterial() +{ + return DefaultMaterial; +} + +bool PhysicsBackend::Init() +{ +#define CHECK_INIT(value, msg) if (!value) { LOG(Error, msg); return true; } + auto& settings = *PhysicsSettings::Get(); + + // Init PhysX foundation object + LOG(Info, "Setup NVIDIA PhysX {0}.{1}.{2}", PX_PHYSICS_VERSION_MAJOR, PX_PHYSICS_VERSION_MINOR, PX_PHYSICS_VERSION_BUGFIX); + Foundation = PxCreateFoundation(PX_PHYSICS_VERSION, AllocatorCallback, ErrorCallback); + CHECK_INIT(Foundation, "PxCreateFoundation failed!"); + + // Init debugger + PxPvd* pvd = nullptr; +#if WITH_PVD + { + // Init PVD + pvd = PxCreatePvd(*Foundation); + PxPvdTransport* transport = PxDefaultPvdSocketTransportCreate("127.0.0.1", 5425, 100); + //PxPvdTransport* transport = PxDefaultPvdFileTransportCreate("D:\\physx_sample.pxd2"); + if (transport) + { + const bool isConnected = pvd->connect(*transport, PxPvdInstrumentationFlag::eALL); + if (isConnected) + { + LOG(Info, "Connected to PhysX Visual Debugger (PVD)"); + } + } + PVD = pvd; + } + +#endif + + // Init PhysX + ToleranceScale.length = 100; + ToleranceScale.speed = 981; + PhysX = PxCreatePhysics(PX_PHYSICS_VERSION, *Foundation, ToleranceScale, false, pvd); + CHECK_INIT(PhysX, "PxCreatePhysics failed!"); + + // Init extensions + const bool extensionsInit = PxInitExtensions(*PhysX, pvd); + CHECK_INIT(extensionsInit, "PxInitExtensions failed!"); + + // Init collision cooking +#if COMPILE_WITH_PHYSICS_COOKING +#if !USE_EDITOR + if (settings.SupportCookingAtRuntime) +#endif + { + PxCookingParams cookingParams(ToleranceScale); + cookingParams.meshWeldTolerance = 0.1f; // 1mm precision + cookingParams.meshPreprocessParams = PxMeshPreprocessingFlags(PxMeshPreprocessingFlag::eWELD_VERTICES); + Cooking = PxCreateCooking(PX_PHYSICS_VERSION, *Foundation, cookingParams); + CHECK_INIT(Cooking, "PxCreateCooking failed!"); + } +#endif + + // Create default material + DefaultMaterial = PhysX->createMaterial(0.7f, 0.7f, 0.3f); + + return false; +} + +void PhysicsBackend::Shutdown() +{ + // Remove all scenes still registered + const int32 numScenes = PhysX ? PhysX->getNbScenes() : 0; + if (numScenes) + { + Array scenes; + scenes.Resize(numScenes); + scenes.SetAll(nullptr); + PhysX->getScenes(scenes.Get(), sizeof(PxScene*) * numScenes); + for (PxScene* scene : scenes) + { + if (scene) + scene->release(); + } + } + + // Cleanup any resources +#if WITH_VEHICLE + RELEASE_PHYSX(WheelTireFrictions); + WheelQueryResults.Resize(0); + WheelHitResults.Resize(0); + WheelVehiclesResultsPerWheel.Resize(0); + WheelVehiclesResultsPerVehicle.Resize(0); +#endif + RELEASE_PHYSX(DefaultMaterial); + + // Shutdown PhysX +#if WITH_VEHICLE + if (VehicleSDKInitialized) + { + VehicleSDKInitialized = false; + PxCloseVehicleSDK(); + } +#endif +#if COMPILE_WITH_PHYSICS_COOKING + RELEASE_PHYSX(Cooking); +#endif + if (PhysX) + { + PxCloseExtensions(); + PhysX->release(); + PhysX = nullptr; + } +#if WITH_PVD + RELEASE_PHYSX(PVD); +#endif + RELEASE_PHYSX(Foundation); +} + +void PhysicsBackend::ApplySettings(const PhysicsSettings& settings) +{ + _queriesHitTriggers = settings.QueriesHitTriggers; + _frictionCombineMode = settings.FrictionCombineMode; + _restitutionCombineMode = settings.RestitutionCombineMode; + + // TODO: setting eADAPTIVE_FORCE requires PxScene setup (physx docs: This flag is not mutable, and must be set in PxSceneDesc at scene creation.) + // TODO: update all shapes filter data + // TODO: update all shapes flags + + /* + { + get all actors and then: + + const PxU32 numShapes = actor->getNbShapes(); + PxShape** shapes = (PxShape**)SAMPLE_ALLOC(sizeof(PxShape*)*numShapes); + actor->getShapes(shapes, numShapes); + for (PxU32 i = 0; i < numShapes; i++) + { + .. + } + SAMPLE_FREE(shapes); + }*/ +} + +void* PhysicsBackend::CreateScene(const PhysicsSettings& settings) +{ +#define CHECK_INIT(value, msg) if (!value) { LOG(Error, msg); return nullptr; } + auto scenePhysX = New(); + + // Create scene description + PxSceneDesc sceneDesc(ToleranceScale); + sceneDesc.gravity = C2P(settings.DefaultGravity); + sceneDesc.flags |= PxSceneFlag::eENABLE_ACTIVE_ACTORS; + if (!settings.DisableCCD) + sceneDesc.flags |= PxSceneFlag::eENABLE_CCD; + if (settings.EnableAdaptiveForce) + sceneDesc.flags |= PxSceneFlag::eADAPTIVE_FORCE; + sceneDesc.simulationEventCallback = &scenePhysX->EventsCallback; + sceneDesc.filterShader = FilterShader; + sceneDesc.bounceThresholdVelocity = settings.BounceThresholdVelocity; + if (sceneDesc.cpuDispatcher == nullptr) + { + scenePhysX->CpuDispatcher = PxDefaultCpuDispatcherCreate(Math::Clamp(Platform::GetCPUInfo().ProcessorCoreCount - 1, 1, 4)); + CHECK_INIT(scenePhysX->CpuDispatcher, "PxDefaultCpuDispatcherCreate failed!"); + sceneDesc.cpuDispatcher = scenePhysX->CpuDispatcher; + } + + // Create scene + scenePhysX->Scene = PhysX->createScene(sceneDesc); + CHECK_INIT(scenePhysX->Scene, "createScene failed!"); +#if WITH_PVD + auto pvdClient = scenePhysX->Scene->getScenePvdClient(); + if (pvdClient) + { + pvdClient->setScenePvdFlags(PxPvdSceneFlag::eTRANSMIT_CONSTRAINTS | PxPvdSceneFlag::eTRANSMIT_SCENEQUERIES | PxPvdSceneFlag::eTRANSMIT_CONTACTS); + } + else + { + LOG(Info, "Missing PVD client scene."); + } +#endif + + // Init characters controller + scenePhysX->ControllerManager = PxCreateControllerManager(*scenePhysX->Scene); + +#undef CHECK_INIT + return scenePhysX; +} + +void PhysicsBackend::DestroyScene(void* scene) +{ + auto scenePhysX = (ScenePhysX*)scene; + + // Flush any latent actions related to this scene + FlushRequests(scene); + + // Release resources +#if WITH_VEHICLE + RELEASE_PHYSX(scenePhysX->WheelRaycastBatchQuery); +#endif + RELEASE_PHYSX(scenePhysX->ControllerManager); + SAFE_DELETE(scenePhysX->CpuDispatcher); + Allocator::Free(scenePhysX->ScratchMemory); + scenePhysX->Scene->release(); + + Delete(scene); +} + +void PhysicsBackend::StartSimulateScene(void* scene, float dt) +{ + auto scenePhysX = (ScenePhysX*)scene; + const auto& settings = *PhysicsSettings::Get(); + + // Clamp delta + dt = Math::Clamp(dt, 0.0f, settings.MaxDeltaTime); + + // Prepare util objects + if (scenePhysX->ScratchMemory == nullptr) + { + scenePhysX->ScratchMemory = Allocator::Allocate(PHYSX_SCRATCH_BLOCK_SIZE, 16); + } + if (settings.EnableSubstepping) + { + // Use substeps + scenePhysX->Stepper.Setup(settings.SubstepDeltaTime, settings.MaxSubsteps); + } + else + { + // Use single step + scenePhysX->Stepper.Setup(dt); + } + + // Start simulation (may not be fired due to too small delta time) + if (scenePhysX->Stepper.advance(scenePhysX->Scene, dt, scenePhysX->ScratchMemory, PHYSX_SCRATCH_BLOCK_SIZE) == false) + return; + scenePhysX->EventsCallback.Clear(); + scenePhysX->LastDeltaTime = dt; + + // TODO: move this call after rendering done + scenePhysX->Stepper.renderDone(); +} + +void PhysicsBackend::EndSimulateScene(void* scene) +{ + auto scenePhysX = (ScenePhysX*)scene; + + { + PROFILE_CPU_NAMED("Physics.Fetch"); + + // Gather results (with waiting for the end) + scenePhysX->Stepper.wait(scenePhysX->Scene); + } + +#if WITH_VEHICLE + if (scenePhysX->WheelVehicles.HasItems()) + { + PROFILE_CPU_NAMED("Physics.Vehicles"); + + // Update vehicles steering + WheelVehiclesCache.Clear(); + WheelVehiclesCache.EnsureCapacity(scenePhysX->WheelVehicles.Count()); + int32 wheelsCount = 0; + for (auto wheelVehicle : scenePhysX->WheelVehicles) + { + if (!wheelVehicle->IsActiveInHierarchy()) + continue; + auto drive = (PxVehicleWheels*)wheelVehicle->_vehicle; + ASSERT(drive); + WheelVehiclesCache.Add(drive); + wheelsCount += drive->mWheelsSimData.getNbWheels(); + + float throttle = wheelVehicle->_throttle; + float brake = wheelVehicle->_brake; + if (wheelVehicle->UseReverseAsBrake) + { + const float invalidDirectionThreshold = 80.0f; + const float breakThreshold = 8.0f; + const float forwardSpeed = wheelVehicle->GetForwardSpeed(); + + // Automatic gear change when changing driving direction + if (Math::Abs(forwardSpeed) < invalidDirectionThreshold) + { + if (throttle < -ZeroTolerance && wheelVehicle->GetCurrentGear() >= 0 && wheelVehicle->GetTargetGear() >= 0) + { + wheelVehicle->SetCurrentGear(-1); + } + else if (throttle > ZeroTolerance && wheelVehicle->GetCurrentGear() <= 0 && wheelVehicle->GetTargetGear() <= 0) + { + wheelVehicle->SetCurrentGear(1); + } + } + + // Automatic break when changing driving direction + if (throttle > 0.0f) + { + if (forwardSpeed < -invalidDirectionThreshold) + { + brake = 1.0f; + } + } + else if (throttle < 0.0f) + { + if (forwardSpeed > invalidDirectionThreshold) + { + brake = 1.0f; + } + } + else + { + if (forwardSpeed < breakThreshold && forwardSpeed > -breakThreshold) + { + brake = 1.0f; + } + } + + // Block throttle if user is changing driving direction + if ((throttle > 0.0f && wheelVehicle->GetTargetGear() < 0) || (throttle < 0.0f && wheelVehicle->GetTargetGear() > 0)) + { + throttle = 0.0f; + } + + throttle = Math::Abs(throttle); + } + else + { + throttle = Math::Max(throttle, 0.0f); + } + // @formatter:off + // Reference: PhysX SDK docs + // TODO: expose input control smoothing data + static constexpr PxVehiclePadSmoothingData padSmoothing = + { + { + 6.0f, // rise rate eANALOG_INPUT_ACCEL + 6.0f, // rise rate eANALOG_INPUT_BRAKE + 12.0f, // rise rate eANALOG_INPUT_HANDBRAKE + 2.5f, // rise rate eANALOG_INPUT_STEER_LEFT + 2.5f, // rise rate eANALOG_INPUT_STEER_RIGHT + }, + { + 10.0f, // fall rate eANALOG_INPUT_ACCEL + 10.0f, // fall rate eANALOG_INPUT_BRAKE + 12.0f, // fall rate eANALOG_INPUT_HANDBRAKE + 5.0f, // fall rate eANALOG_INPUT_STEER_LEFT + 5.0f, // fall rate eANALOG_INPUT_STEER_RIGHT + } + }; + PxVehicleKeySmoothingData keySmoothing = + { + { + 3.0f, // rise rate eANALOG_INPUT_ACCEL + 3.0f, // rise rate eANALOG_INPUT_BRAKE + 10.0f, // rise rate eANALOG_INPUT_HANDBRAKE + 2.5f, // rise rate eANALOG_INPUT_STEER_LEFT + 2.5f, // rise rate eANALOG_INPUT_STEER_RIGHT + }, + { + 5.0f, // fall rate eANALOG_INPUT__ACCEL + 5.0f, // fall rate eANALOG_INPUT__BRAKE + 10.0f, // fall rate eANALOG_INPUT__HANDBRAKE + 5.0f, // fall rate eANALOG_INPUT_STEER_LEFT + 5.0f // fall rate eANALOG_INPUT_STEER_RIGHT + } + }; + // Reference: PhysX SDK docs + // TODO: expose steer vs forward curve into per-vehicle (up to 8 points, values clamped into 0/1 range) + static constexpr PxF32 steerVsForwardSpeedData[] = + { + 0.0f, 1.0f, + 20.0f, 0.9f, + 65.0f, 0.8f, + 120.0f, 0.7f, + PX_MAX_F32, PX_MAX_F32, + PX_MAX_F32, PX_MAX_F32, + PX_MAX_F32, PX_MAX_F32, + PX_MAX_F32, PX_MAX_F32, + }; + const PxFixedSizeLookupTable<8> steerVsForwardSpeed(steerVsForwardSpeedData, 4); + // @formatter:on + if (wheelVehicle->UseAnalogSteering) + { + switch (wheelVehicle->_driveTypeCurrent) + { + case WheeledVehicle::DriveTypes::Drive4W: + { + PxVehicleDrive4WRawInputData rawInputData; + rawInputData.setAnalogAccel(throttle); + rawInputData.setAnalogBrake(brake); + rawInputData.setAnalogSteer(wheelVehicle->_steering); + rawInputData.setAnalogHandbrake(wheelVehicle->_handBrake); + PxVehicleDrive4WSmoothAnalogRawInputsAndSetAnalogInputs(padSmoothing, steerVsForwardSpeed, rawInputData, scenePhysX->LastDeltaTime, false, *(PxVehicleDrive4W*)drive); + break; + } + case WheeledVehicle::DriveTypes::DriveNW: + { + PxVehicleDriveNWRawInputData rawInputData; + rawInputData.setAnalogAccel(throttle); + rawInputData.setAnalogBrake(brake); + rawInputData.setAnalogSteer(wheelVehicle->_steering); + rawInputData.setAnalogHandbrake(wheelVehicle->_handBrake); + PxVehicleDriveNWSmoothAnalogRawInputsAndSetAnalogInputs(padSmoothing, steerVsForwardSpeed, rawInputData, scenePhysX->LastDeltaTime, false, *(PxVehicleDriveNW*)drive); + break; + } + } + } + else + { + const float deadZone = 0.1f; + switch (wheelVehicle->_driveTypeCurrent) + { + case WheeledVehicle::DriveTypes::Drive4W: + { + PxVehicleDrive4WRawInputData rawInputData; + rawInputData.setDigitalAccel(throttle > deadZone); + rawInputData.setDigitalBrake(brake > deadZone); + rawInputData.setDigitalSteerLeft(wheelVehicle->_steering < -deadZone); + rawInputData.setDigitalSteerRight(wheelVehicle->_steering > deadZone); + rawInputData.setDigitalHandbrake(wheelVehicle->_handBrake > deadZone); + PxVehicleDrive4WSmoothDigitalRawInputsAndSetAnalogInputs(keySmoothing, steerVsForwardSpeed, rawInputData, scenePhysX->LastDeltaTime, false, *(PxVehicleDrive4W*)drive); + break; + } + case WheeledVehicle::DriveTypes::DriveNW: + { + PxVehicleDriveNWRawInputData rawInputData; + rawInputData.setDigitalAccel(throttle > deadZone); + rawInputData.setDigitalBrake(brake > deadZone); + rawInputData.setDigitalSteerLeft(wheelVehicle->_steering < -deadZone); + rawInputData.setDigitalSteerRight(wheelVehicle->_steering > deadZone); + rawInputData.setDigitalHandbrake(wheelVehicle->_handBrake > deadZone); + PxVehicleDriveNWSmoothDigitalRawInputsAndSetAnalogInputs(keySmoothing, steerVsForwardSpeed, rawInputData, scenePhysX->LastDeltaTime, false, *(PxVehicleDriveNW*)drive); + break; + } + } + } + } + + // Update batches queries cache + if (wheelsCount > WheelQueryResults.Count()) + { + if (scenePhysX->WheelRaycastBatchQuery) + scenePhysX->WheelRaycastBatchQuery->release(); + WheelQueryResults.Resize(wheelsCount, false); + WheelHitResults.Resize(wheelsCount, false); + PxBatchQueryDesc desc(wheelsCount, 0, 0); + desc.queryMemory.userRaycastResultBuffer = WheelQueryResults.Get(); + desc.queryMemory.userRaycastTouchBuffer = WheelHitResults.Get(); + desc.queryMemory.raycastTouchBufferSize = wheelsCount; + desc.preFilterShader = WheelRaycastPreFilter; + scenePhysX->WheelRaycastBatchQuery = scenePhysX->Scene->createBatchQuery(desc); + } + + // TODO: expose vehicle tires configuration + if (!WheelTireFrictions) + { + PxVehicleDrivableSurfaceType surfaceTypes[1]; + surfaceTypes[0].mType = 0; + const PxMaterial* surfaceMaterials[1]; + surfaceMaterials[0] = DefaultMaterial; + WheelTireFrictions = PxVehicleDrivableSurfaceToTireFrictionPairs::allocate(1, 1); + WheelTireFrictions->setup(1, 1, surfaceMaterials, surfaceTypes); + WheelTireFrictions->setTypePairFriction(0, 0, 5.0f); + } + + // Setup cache for wheel states + WheelVehiclesResultsPerVehicle.Resize(WheelVehiclesCache.Count(), false); + WheelVehiclesResultsPerWheel.Resize(wheelsCount, false); + wheelsCount = 0; + for (int32 i = 0, ii = 0; i < scenePhysX->WheelVehicles.Count(); i++) + { + auto wheelVehicle = scenePhysX->WheelVehicles[i]; + if (!wheelVehicle->IsActiveInHierarchy()) + continue; + auto drive = (PxVehicleWheels*)scenePhysX->WheelVehicles[ii]->_vehicle; + auto& perVehicle = WheelVehiclesResultsPerVehicle[ii]; + ii++; + perVehicle.nbWheelQueryResults = drive->mWheelsSimData.getNbWheels(); + perVehicle.wheelQueryResults = WheelVehiclesResultsPerWheel.Get() + wheelsCount; + wheelsCount += perVehicle.nbWheelQueryResults; + } + + // Update vehicles + if (WheelVehiclesCache.Count() != 0) + { + PxVehicleSuspensionRaycasts(scenePhysX->WheelRaycastBatchQuery, WheelVehiclesCache.Count(), WheelVehiclesCache.Get(), WheelQueryResults.Count(), WheelQueryResults.Get()); + PxVehicleUpdates(scenePhysX->LastDeltaTime, scenePhysX->Scene->getGravity(), *WheelTireFrictions, WheelVehiclesCache.Count(), WheelVehiclesCache.Get(), WheelVehiclesResultsPerVehicle.Get()); + } + + // Synchronize state + for (int32 i = 0, ii = 0; i < scenePhysX->WheelVehicles.Count(); i++) + { + auto wheelVehicle = scenePhysX->WheelVehicles[i]; + if (!wheelVehicle->IsActiveInHierarchy()) + continue; + auto drive = WheelVehiclesCache[ii]; + auto& perVehicle = WheelVehiclesResultsPerVehicle[ii]; + ii++; +#if PHYSX_VEHICLE_DEBUG_TELEMETRY + LOG(Info, "Vehicle[{}] Gear={}, RPM={}", ii, wheelVehicle->GetCurrentGear(), (int32)wheelVehicle->GetEngineRotationSpeed()); +#endif + + // Update wheels + for (int32 j = 0; j < wheelVehicle->_wheelsData.Count(); j++) + { + auto& wheelData = wheelVehicle->_wheelsData[j]; + auto& perWheel = perVehicle.wheelQueryResults[j]; +#if PHYSX_VEHICLE_DEBUG_TELEMETRY + LOG(Info, "Vehicle[{}] Wheel[{}] longitudinalSlip={}, lateralSlip={}, suspSpringForce={}", ii, j, Utilities::RoundTo2DecimalPlaces(perWheel.longitudinalSlip), Utilities::RoundTo2DecimalPlaces(perWheel.lateralSlip), (int32)perWheel.suspSpringForce); +#endif + + auto& state = wheelData.State; + state.IsInAir = perWheel.isInAir; + state.TireContactCollider = perWheel.tireContactShape ? static_cast(perWheel.tireContactShape->userData) : nullptr; + state.TireContactPoint = P2C(perWheel.tireContactPoint); + 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); +#endif + + if (!wheelData.Collider) + continue; + auto shape = (PxShape*)wheelData.Collider->GetPhysicsShape(); + + // Update wheel collider transformation + auto localPose = shape->getLocalPose(); + Transform t = wheelData.Collider->GetLocalTransform(); + t.Orientation = Quaternion::Euler(0, state.SteerAngle, state.RotationAngle) * wheelData.LocalOrientation; + t.Translation = P2C(localPose.p) / wheelVehicle->GetScale() - t.Orientation * wheelData.Collider->GetCenter(); + wheelData.Collider->SetLocalTransform(t); + } + } + } +#endif + + { + PROFILE_CPU_NAMED("Physics.FlushActiveTransforms"); + + // Gather change info + PxU32 activeActorsCount; + PxActor** activeActors = scenePhysX->Scene->getActiveActors(activeActorsCount); + if (activeActorsCount > 0) + { + // Update changed transformations + // TODO: use jobs system if amount if huge + for (uint32 i = 0; i < activeActorsCount; i++) + { + const auto pxActor = (PxRigidActor*)*activeActors++; + auto actor = static_cast(pxActor->userData); + if (actor) + actor->OnActiveTransformChanged(); + } + } + } + + { + PROFILE_CPU_NAMED("Physics.SendEvents"); + + scenePhysX->EventsCallback.CollectResults(); + scenePhysX->EventsCallback.SendTriggerEvents(); + scenePhysX->EventsCallback.SendCollisionEvents(); + scenePhysX->EventsCallback.SendJointEvents(); + } +} + +Vector3 PhysicsBackend::GetSceneGravity(void* scene) +{ + auto scenePhysX = (ScenePhysX*)scene; + return P2C(scenePhysX->Scene->getGravity()); +} + +void PhysicsBackend::SetSceneGravity(void* scene, const Vector3& value) +{ + auto scenePhysX = (ScenePhysX*)scene; + scenePhysX->Scene->setGravity(C2P(value)); +} + +bool PhysicsBackend::GetSceneEnableCCD(void* scene) +{ + auto scenePhysX = (ScenePhysX*)scene; + return (scenePhysX->Scene->getFlags() & PxSceneFlag::eENABLE_CCD) == PxSceneFlag::eENABLE_CCD; +} + +void PhysicsBackend::SetSceneEnableCCD(void* scene, bool value) +{ + auto scenePhysX = (ScenePhysX*)scene; + scenePhysX->Scene->setFlag(PxSceneFlag::eENABLE_CCD, value); +} + +float PhysicsBackend::GetSceneBounceThresholdVelocity(void* scene) +{ + auto scenePhysX = (ScenePhysX*)scene; + return scenePhysX->Scene->getBounceThresholdVelocity(); +} + +void PhysicsBackend::SetSceneBounceThresholdVelocity(void* scene, float value) +{ + auto scenePhysX = (ScenePhysX*)scene; + scenePhysX->Scene->setBounceThresholdVelocity(value); +} + +void PhysicsBackend::AddSceneActor(void* scene, void* actor) +{ + auto scenePhysX = (ScenePhysX*)scene; + FlushLocker.Lock(); + scenePhysX->AddActors.Add((PxActor*)actor); + FlushLocker.Unlock(); +} + +void PhysicsBackend::RemoveSceneActor(void* scene, void* actor) +{ + auto scenePhysX = (ScenePhysX*)scene; + FlushLocker.Lock(); + scenePhysX->RemoveActors.Add((PxActor*)actor); + FlushLocker.Unlock(); +} + +void PhysicsBackend::AddSceneActorAction(void* scene, void* actor, ActionType action) +{ + auto scenePhysX = (ScenePhysX*)scene; + FlushLocker.Lock(); + auto& a = scenePhysX->Actions.AddOne(); + a.Actor = (PxActor*)actor; + a.Type = action; + FlushLocker.Unlock(); +} + +bool PhysicsBackend::RayCast(void* scene, const Vector3& origin, const Vector3& direction, const float maxDistance, uint32 layerMask, bool hitTriggers) +{ + SCENE_QUERY_SETUP(true); + PxRaycastBuffer buffer; + return scenePhysX->Scene->raycast(C2P(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)) + return false; + SCENE_QUERY_COLLECT_SINGLE(); + return true; +} + +bool PhysicsBackend::RayCastAll(void* scene, const Vector3& origin, const Vector3& direction, Array& results, const float maxDistance, uint32 layerMask, bool hitTriggers) +{ + SCENE_QUERY_SETUP(false); + DynamicHitBuffer buffer; + if (!scenePhysX->Scene->raycast(C2P(origin), C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter)) + return false; + SCENE_QUERY_COLLECT_ALL(); + return true; +} + +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 PxBoxGeometry geometry(C2P(halfExtents)); + return scenePhysX->Scene->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter); +} + +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 PxBoxGeometry geometry(C2P(halfExtents)); + if (!scenePhysX->Scene->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter)) + return false; + SCENE_QUERY_COLLECT_SINGLE(); + return true; +} + +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 PxBoxGeometry geometry(C2P(halfExtents)); + if (!scenePhysX->Scene->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter)) + return false; + SCENE_QUERY_COLLECT_ALL(); + return true; +} + +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 PxSphereGeometry geometry(radius); + return scenePhysX->Scene->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter); +} + +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 PxSphereGeometry geometry(radius); + if (!scenePhysX->Scene->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter)) + return false; + SCENE_QUERY_COLLECT_SINGLE(); + return true; +} + +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 PxSphereGeometry geometry(radius); + if (!scenePhysX->Scene->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter)) + return false; + SCENE_QUERY_COLLECT_ALL(); + return true; +} + +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 PxCapsuleGeometry geometry(radius, height * 0.5f); + return scenePhysX->Scene->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter); +} + +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 PxCapsuleGeometry geometry(radius, height * 0.5f); + if (!scenePhysX->Scene->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter)) + return false; + SCENE_QUERY_COLLECT_SINGLE(); + return true; +} + +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 PxCapsuleGeometry geometry(radius, height * 0.5f); + if (!scenePhysX->Scene->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter)) + return false; + SCENE_QUERY_COLLECT_ALL(); + return true; +} + +bool PhysicsBackend::ConvexCast(void* scene, const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Vector3& direction, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) +{ + CHECK_RETURN(convexMesh && convexMesh->GetOptions().Type == CollisionDataType::ConvexMesh, false) + SCENE_QUERY_SETUP_SWEEP_1(); + const PxTransform pose(C2P(center), C2P(rotation)); + const PxConvexMeshGeometry geometry((PxConvexMesh*)convexMesh->GetConvex(), PxMeshScale(C2P(scale))); + return scenePhysX->Scene->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter); +} + +bool PhysicsBackend::ConvexCast(void* scene, const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Vector3& direction, RayCastHit& hitInfo, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) +{ + CHECK_RETURN(convexMesh && convexMesh->GetOptions().Type == CollisionDataType::ConvexMesh, false) + SCENE_QUERY_SETUP_SWEEP_1(); + const PxTransform pose(C2P(center), 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; + SCENE_QUERY_COLLECT_SINGLE(); + return true; +} + +bool PhysicsBackend::ConvexCastAll(void* scene, const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Vector3& direction, Array& results, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) +{ + CHECK_RETURN(convexMesh && convexMesh->GetOptions().Type == CollisionDataType::ConvexMesh, false) + SCENE_QUERY_SETUP_SWEEP(); + const PxTransform pose(C2P(center), 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; + SCENE_QUERY_COLLECT_ALL(); + return true; +} + +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 PxBoxGeometry geometry(C2P(halfExtents)); + return scenePhysX->Scene->overlap(geometry, pose, buffer, filterData, &QueryFilter); +} + +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 PxSphereGeometry geometry(radius); + return scenePhysX->Scene->overlap(geometry, pose, buffer, filterData, &QueryFilter); +} + +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 PxCapsuleGeometry geometry(radius, height * 0.5f); + return scenePhysX->Scene->overlap(geometry, pose, buffer, filterData, &QueryFilter); +} + +bool PhysicsBackend::CheckConvex(void* scene, const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Quaternion& rotation, uint32 layerMask, bool hitTriggers) +{ + CHECK_RETURN(convexMesh && convexMesh->GetOptions().Type == CollisionDataType::ConvexMesh, false) + SCENE_QUERY_SETUP_OVERLAP_1(); + const PxTransform pose(C2P(center), C2P(rotation)); + const PxConvexMeshGeometry geometry((PxConvexMesh*)convexMesh->GetConvex(), PxMeshScale(C2P(scale))); + return scenePhysX->Scene->overlap(geometry, pose, buffer, filterData, &QueryFilter); +} + +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 PxBoxGeometry geometry(C2P(halfExtents)); + if (!scenePhysX->Scene->overlap(geometry, pose, buffer, filterData, &QueryFilter)) + return false; + SCENE_QUERY_COLLECT_OVERLAP_COLLIDER(); + return true; +} + +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 PxSphereGeometry geometry(radius); + if (!scenePhysX->Scene->overlap(geometry, pose, buffer, filterData, &QueryFilter)) + return false; + SCENE_QUERY_COLLECT_OVERLAP_COLLIDER(); + return true; +} + +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 PxCapsuleGeometry geometry(radius, height * 0.5f); + if (!scenePhysX->Scene->overlap(geometry, pose, buffer, filterData, &QueryFilter)) + return false; + SCENE_QUERY_COLLECT_OVERLAP_COLLIDER(); + return true; +} + +bool PhysicsBackend::OverlapConvex(void* scene, const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers) +{ + CHECK_RETURN(convexMesh && convexMesh->GetOptions().Type == CollisionDataType::ConvexMesh, false) + SCENE_QUERY_SETUP_OVERLAP(); + const PxTransform pose(C2P(center), C2P(rotation)); + const PxConvexMeshGeometry geometry((PxConvexMesh*)convexMesh->GetConvex(), PxMeshScale(C2P(scale))); + if (!scenePhysX->Scene->overlap(geometry, pose, buffer, filterData, &QueryFilter)) + return false; + SCENE_QUERY_COLLECT_OVERLAP_COLLIDER(); + return true; +} + +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 PxBoxGeometry geometry(C2P(halfExtents)); + if (!scenePhysX->Scene->overlap(geometry, pose, buffer, filterData, &QueryFilter)) + return false; + SCENE_QUERY_COLLECT_OVERLAP(); + return true; +} + +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 PxSphereGeometry geometry(radius); + if (!scenePhysX->Scene->overlap(geometry, pose, buffer, filterData, &QueryFilter)) + return false; + SCENE_QUERY_COLLECT_OVERLAP(); + return true; +} + +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 PxCapsuleGeometry geometry(radius, height * 0.5f); + if (!scenePhysX->Scene->overlap(geometry, pose, buffer, filterData, &QueryFilter)) + return false; + SCENE_QUERY_COLLECT_OVERLAP(); + return true; +} + +bool PhysicsBackend::OverlapConvex(void* scene, const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers) +{ + CHECK_RETURN(convexMesh && convexMesh->GetOptions().Type == CollisionDataType::ConvexMesh, false) + SCENE_QUERY_SETUP_OVERLAP(); + const PxTransform pose(C2P(center), C2P(rotation)); + const PxConvexMeshGeometry geometry((PxConvexMesh*)convexMesh->GetConvex(), PxMeshScale(C2P(scale))); + if (!scenePhysX->Scene->overlap(geometry, pose, buffer, filterData, &QueryFilter)) + return false; + SCENE_QUERY_COLLECT_OVERLAP(); + return true; +} + +PhysicsBackend::ActorFlags PhysicsBackend::GetActorFlags(void* actor) +{ + auto actorPhysX = (PxActor*)actor; + auto flags = actorPhysX->getActorFlags(); + auto result = ActorFlags::None; + if (flags & PxActorFlag::eDISABLE_GRAVITY) + result |= ActorFlags::NoGravity; + if (flags & PxActorFlag::eDISABLE_SIMULATION) + result |= ActorFlags::NoSimulation; + return result; +} + +void PhysicsBackend::SetActorFlags(void* actor, ActorFlags value) +{ + auto actorPhysX = (PxActor*)actor; + auto flags = (PxActorFlags)0; +#if WITH_PVD + flags |= PxActorFlag::eVISUALIZATION; +#endif + if (value & ActorFlags::NoGravity) + flags |= PxActorFlag::eDISABLE_GRAVITY; + if (value & ActorFlags::NoSimulation) + flags |= PxActorFlag::eDISABLE_SIMULATION; + actorPhysX->setActorFlags(flags); +} + +void PhysicsBackend::GetActorBounds(void* actor, BoundingBox& bounds) +{ + auto actorPhysX = (PxActor*)actor; + const float boundsScale = 1.02f; + bounds = P2C(actorPhysX->getWorldBounds(boundsScale)); +} + +void* PhysicsBackend::CreateRigidDynamicActor(IPhysicsActor* actor, const Vector3& position, const Quaternion& orientation) +{ + const PxTransform trans(C2P(position), C2P(orientation)); + PxRigidDynamic* actorPhysX = PhysX->createRigidDynamic(trans); + actorPhysX->userData = actor; +#if PHYSX_DEBUG_NAMING + actorPhysX->setName("RigidDynamicActor"); +#endif +#if WITH_PVD + actorPhysX->setActorFlag(PxActorFlag::eVISUALIZATION, true); +#endif + return actorPhysX; +} + +void* PhysicsBackend::CreateRigidStaticActor(IPhysicsActor* actor, const Vector3& position, const Quaternion& orientation) +{ + const PxTransform trans(C2P(position), C2P(orientation)); + PxRigidStatic* actorPhysX = PhysX->createRigidStatic(trans); + actorPhysX->userData = actor; +#if PHYSX_DEBUG_NAMING + actorPhysX->setName("RigidStaticActor"); +#endif +#if WITH_PVD + actorPhysX->setActorFlag(PxActorFlag::eVISUALIZATION, true); +#endif + return actorPhysX; +} + +PhysicsBackend::RigidDynamicFlags PhysicsBackend::GetRigidDynamicActorFlags(void* actor) +{ + auto actorPhysX = (PxRigidDynamic*)actor; + auto flags = actorPhysX->getRigidBodyFlags(); + auto result = RigidDynamicFlags::None; + if (flags & PxRigidBodyFlag::eKINEMATIC) + result |= RigidDynamicFlags::Kinematic; + if (flags & PxRigidBodyFlag::eENABLE_CCD) + result |= RigidDynamicFlags::CCD; + return result; +} + +void PhysicsBackend::SetRigidDynamicActorFlags(void* actor, RigidDynamicFlags value) +{ + auto actorPhysX = (PxRigidDynamic*)actor; + auto flags = (PxRigidBodyFlags)0; + if (value & RigidDynamicFlags::Kinematic) + flags |= PxRigidBodyFlag::eKINEMATIC; + if (value & RigidDynamicFlags::CCD) + flags |= PxRigidBodyFlag::eENABLE_CCD; + actorPhysX->setRigidBodyFlags(flags); +} + +void PhysicsBackend::GetRigidActorPose(void* actor, Vector3& position, Quaternion& orientation) +{ + auto actorPhysX = (PxRigidActor*)actor; + auto pose = actorPhysX->getGlobalPose(); + position = P2C(pose.p); + 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)); + if (kinematic) + { + auto actorPhysX = (PxRigidDynamic*)actor; + actorPhysX->setKinematicTarget(trans); + } + else + { + auto actorPhysX = (PxRigidActor*)actor; + actorPhysX->setGlobalPose(trans, wakeUp); + } +} + +void PhysicsBackend::SetRigidDynamicActorLinearDamping(void* actor, float value) +{ + auto actorPhysX = (PxRigidDynamic*)actor; + actorPhysX->setLinearDamping(value); +} + +void PhysicsBackend::SetRigidDynamicActorAngularDamping(void* actor, float value) +{ + auto actorPhysX = (PxRigidDynamic*)actor; + actorPhysX->setAngularDamping(value); +} + +void PhysicsBackend::SetRigidDynamicActorMaxAngularVelocity(void* actor, float value) +{ + auto actorPhysX = (PxRigidDynamic*)actor; + actorPhysX->setMaxAngularVelocity(value); +} + +void PhysicsBackend::SetRigidDynamicActorConstraints(void* actor, RigidbodyConstraints value) +{ + auto actorPhysX = (PxRigidDynamic*)actor; + actorPhysX->setRigidDynamicLockFlags(static_cast(value)); +} + +Vector3 PhysicsBackend::GetRigidDynamicActorLinearVelocity(void* actor) +{ + auto actorPhysX = (PxRigidDynamic*)actor; + return P2C(actorPhysX->getLinearVelocity()); +} + +void PhysicsBackend::SetRigidDynamicActorLinearVelocity(void* actor, const Vector3& value, bool wakeUp) +{ + auto actorPhysX = (PxRigidDynamic*)actor; + actorPhysX->setLinearVelocity(C2P(value), wakeUp); +} + +Vector3 PhysicsBackend::GetRigidDynamicActorAngularVelocity(void* actor) +{ + auto actorPhysX = (PxRigidDynamic*)actor; + return P2C(actorPhysX->getAngularVelocity()); +} + +void PhysicsBackend::SetRigidDynamicActorAngularVelocity(void* actor, const Vector3& value, bool wakeUp) +{ + auto actorPhysX = (PxRigidDynamic*)actor; + actorPhysX->setAngularVelocity(C2P(value), wakeUp); +} + +Vector3 PhysicsBackend::GetRigidDynamicActorCenterOfMass(void* actor) +{ + auto actorPhysX = (PxRigidDynamic*)actor; + return P2C(actorPhysX->getCMassLocalPose().p); +} + +void PhysicsBackend::SetRigidDynamicActorCenterOfMassOffset(void* actor, const Vector3& value) +{ + auto actorPhysX = (PxRigidDynamic*)actor; + auto pose = actorPhysX->getCMassLocalPose(); + pose.p += C2P(value); + actorPhysX->setCMassLocalPose(pose); +} + +bool PhysicsBackend::GetRigidDynamicActorIsSleeping(void* actor) +{ + auto actorPhysX = (PxRigidDynamic*)actor; + return actorPhysX->isSleeping(); +} + +void PhysicsBackend::GetRigidActorSleep(void* actor) +{ + auto actorPhysX = (PxRigidDynamic*)actor; + actorPhysX->putToSleep(); +} + +void PhysicsBackend::GetRigidDynamicActorWakeUp(void* actor) +{ + auto actorPhysX = (PxRigidDynamic*)actor; + actorPhysX->wakeUp(); +} + +float PhysicsBackend::GetRigidDynamicActorSleepThreshold(void* actor) +{ + auto actorPhysX = (PxRigidDynamic*)actor; + return actorPhysX->getSleepThreshold(); +} + +void PhysicsBackend::SetRigidDynamicActorSleepThreshold(void* actor, float value) +{ + auto actorPhysX = (PxRigidDynamic*)actor; + actorPhysX->setSleepThreshold(value); +} + +float PhysicsBackend::GetRigidDynamicActorMaxDepenetrationVelocity(void* actor) +{ + auto actorPhysX = (PxRigidDynamic*)actor; + return actorPhysX->getMaxDepenetrationVelocity(); +} + +void PhysicsBackend::SetRigidDynamicActorMaxDepenetrationVelocity(void* actor, float value) +{ + auto actorPhysX = (PxRigidDynamic*)actor; + actorPhysX->setMaxDepenetrationVelocity(value); +} + +void PhysicsBackend::SetRigidDynamicActorSolverIterationCounts(void* actor, int32 minPositionIters, int32 minVelocityIters) +{ + auto actorPhysX = (PxRigidDynamic*)actor; + actorPhysX->setSolverIterationCounts(Math::Clamp(minPositionIters, 1, 255), Math::Clamp(minVelocityIters, 1, 255)); +} + +void PhysicsBackend::UpdateRigidDynamicActorMass(void* actor, float& mass, float massScale, bool autoCalculate) +{ + auto actorPhysX = (PxRigidDynamic*)actor; + if (autoCalculate) + { + // Calculate per-shape densities (convert kg/m^3 into engine units) + const float minDensity = 0.08375f; // Hydrogen density + const float defaultDensity = 1000.0f; // Water density + Array> densities; + for (uint32 i = 0; i < actorPhysX->getNbShapes(); i++) + { + PxShape* shape; + actorPhysX->getShapes(&shape, 1, i); + if (shape->getFlags() & PxShapeFlag::eSIMULATION_SHAPE) + { + float density = defaultDensity; + PxMaterial* material; + if (shape->getMaterials(&material, 1, 0) == 1) + { + if (const auto mat = (PhysicalMaterial*)material->userData) + { + density = Math::Max(mat->Density, minDensity); + } + } + densities.Add(KgPerM3ToKgPerCm3(density)); + } + } + if (densities.IsEmpty()) + densities.Add(KgPerM3ToKgPerCm3(defaultDensity)); + + // Auto calculated mass + PxRigidBodyExt::updateMassAndInertia(*actorPhysX, densities.Get(), densities.Count()); + mass = actorPhysX->getMass(); + massScale = Math::Max(massScale, 0.001f); + if (!Math::IsOne(massScale)) + { + mass *= massScale; + actorPhysX->setMass(mass); + } + } + else + { + // Use fixed mass + PxRigidBodyExt::setMassAndUpdateInertia(*actorPhysX, Math::Max(mass * massScale, 0.001f)); + } +} + +void PhysicsBackend::AddRigidDynamicActorForce(void* actor, const Vector3& force, ForceMode mode) +{ + auto actorPhysX = (PxRigidDynamic*)actor; + actorPhysX->addForce(C2P(force), static_cast(mode)); +} + +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)); +} + +void PhysicsBackend::AddRigidDynamicActorTorque(void* actor, const Vector3& torque, ForceMode mode) +{ + auto actorPhysX = (PxRigidDynamic*)actor; + actorPhysX->addTorque(C2P(torque), static_cast(mode)); +} + +void* PhysicsBackend::CreateShape(PhysicsColliderActor* collider, const CollisionShape& geometry, JsonAsset* material, bool enabled, bool trigger) +{ + const PxShapeFlags shapeFlags = GetShapeFlags(trigger, enabled); + PxMaterial* materialPhysX = DefaultMaterial; + if (material && !material->WaitForLoaded() && material->Instance) + { + materialPhysX = (PxMaterial*)((PhysicalMaterial*)material->Instance)->GetPhysicsMaterial(); + } + PxGeometryHolder geometryPhysX; + GetShapeGeometry(geometry, geometryPhysX); + PxShape* shapePhysX = PhysX->createShape(geometryPhysX.any(), *materialPhysX, true, shapeFlags); + shapePhysX->userData = collider; +#if PHYSX_DEBUG_NAMING + shapePhysX->setName("Shape"); +#endif + return shapePhysX; +} + +void PhysicsBackend::SetShapeState(void* shape, bool enabled, bool trigger) +{ + auto shapePhysX = (PxShape*)shape; + const PxShapeFlags shapeFlags = GetShapeFlags(trigger, enabled); + shapePhysX->setFlags(shapeFlags); +} + +void PhysicsBackend::SetShapeFilterMask(void* shape, uint32 mask0, uint32 mask1) +{ + auto shapePhysX = (PxShape*)shape; + PxFilterData filterData; + filterData.word0 = mask0; + filterData.word1 = mask1; + shapePhysX->setSimulationFilterData(filterData); + shapePhysX->setQueryFilterData(filterData); +} + +void* PhysicsBackend::GetShapeActor(void* shape) +{ + auto shapePhysX = (PxShape*)shape; + return shapePhysX->getActor(); +} + +void PhysicsBackend::GetShapePose(void* shape, Vector3& position, Quaternion& orientation) +{ + auto shapePhysX = (PxShape*)shape; + PxRigidActor* actorPhysX = shapePhysX->getActor(); + PxTransform pose = actorPhysX->getGlobalPose().transform(shapePhysX->getLocalPose()); + position = P2C(pose.p); + orientation = P2C(pose.q); +} + +CollisionShape::Types PhysicsBackend::GetShapeType(void* shape) +{ + auto shapePhysX = (PxShape*)shape; + CollisionShape::Types type; + switch (shapePhysX->getGeometryType()) + { + case PxGeometryType::eSPHERE: + type = CollisionShape::Types::Sphere; + break; + case PxGeometryType::eCAPSULE: + type = CollisionShape::Types::Capsule; + break; + case PxGeometryType::eBOX: + type = CollisionShape::Types::Box; + break; + case PxGeometryType::eCONVEXMESH: + type = CollisionShape::Types::ConvexMesh; + break; + case PxGeometryType::eTRIANGLEMESH: + type = CollisionShape::Types::TriangleMesh; + break; + case PxGeometryType::eHEIGHTFIELD: + type = CollisionShape::Types::HeightField; + break; + default: ; + } + return type; +} + +void PhysicsBackend::GetShapeLocalPose(void* shape, Vector3& position, Quaternion& orientation) +{ + auto shapePhysX = (PxShape*)shape; + auto pose = shapePhysX->getLocalPose(); + position = P2C(pose.p); + orientation = P2C(pose.q); +} + +void PhysicsBackend::SetShapeLocalPose(void* shape, const Vector3& position, const Quaternion& orientation) +{ + auto shapePhysX = (PxShape*)shape; + shapePhysX->setLocalPose(PxTransform(C2P(position), C2P(orientation))); +} + +void PhysicsBackend::SetShapeContactOffset(void* shape, float value) +{ + auto shapePhysX = (PxShape*)shape; + shapePhysX->setContactOffset(Math::Max(shapePhysX->getRestOffset() + ZeroTolerance, value)); +} + +void PhysicsBackend::SetShapeMaterial(void* shape, JsonAsset* material) +{ + auto shapePhysX = (PxShape*)shape; + PxMaterial* materialPhysX = DefaultMaterial; + if (material && !material->WaitForLoaded() && material->Instance) + { + materialPhysX = (PxMaterial*)((PhysicalMaterial*)material->Instance)->GetPhysicsMaterial(); + } + shapePhysX->setMaterials(&materialPhysX, 1); +} + +void PhysicsBackend::SetShapeGeometry(void* shape, const CollisionShape& geometry) +{ + auto shapePhysX = (PxShape*)shape; + PxGeometryHolder geometryPhysX; + GetShapeGeometry(geometry, geometryPhysX); + shapePhysX->setGeometry(geometryPhysX.any()); +} + +void PhysicsBackend::AttachShape(void* shape, void* actor) +{ + auto shapePhysX = (PxShape*)shape; + auto actorPhysX = (PxRigidActor*)actor; + actorPhysX->attachShape(*shapePhysX); +} + +void PhysicsBackend::DetachShape(void* shape, void* actor) +{ + auto shapePhysX = (PxShape*)shape; + auto actorPhysX = (PxRigidActor*)actor; + actorPhysX->detachShape(*shapePhysX); +} + +bool PhysicsBackend::ComputeShapesPenetration(void* shapeA, void* shapeB, const Vector3& positionA, const Quaternion& orientationA, const Vector3& positionB, const Quaternion& orientationB, Vector3& direction, float& distance) +{ + auto shapeAPhysX = (PxShape*)shapeA; + auto shapeBPhysX = (PxShape*)shapeB; + const PxTransform poseA(C2P(positionA), C2P(orientationA)); + const PxTransform poseB(C2P(positionB), C2P(orientationB)); + return PxGeometryQuery::computePenetration(C2P(direction), distance, shapeAPhysX->getGeometry().any(), poseA, shapeBPhysX->getGeometry().any(), poseB); +} + +float PhysicsBackend::ComputeShapeSqrDistanceToPoint(void* shape, const Vector3& position, const Quaternion& orientation, const Vector3& point, Vector3* closestPoint) +{ + auto shapePhysX = (PxShape*)shape; + const PxTransform trans(C2P(position), C2P(orientation)); + return PxGeometryQuery::pointDistance(C2P(point), shapePhysX->getGeometry().any(), trans, (PxVec3*)closestPoint); +} + +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 PxHitFlags hitFlags = (PxHitFlags)0; + PxRaycastHit hit; + if (PxGeometryQuery::raycast(C2P(origin), C2P(direction), shapePhysX->getGeometry().any(), trans, maxDistance, hitFlags, 1, &hit) != 0) + { + resultHitDistance = hit.distance; + return true; + } + return false; +} + +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 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) + return false; + P2C(hit, hitInfo); + return true; +} + +void PhysicsBackend::SetJointFlags(void* joint, JointFlags value) +{ + auto jointPhysX = (PxJoint*)joint; + jointPhysX->setConstraintFlag(PxConstraintFlag::eCOLLISION_ENABLED, value & JointFlags::Collision); +} + +void PhysicsBackend::SetJointActors(void* joint, void* actors0, void* actor1) +{ + auto jointPhysX = (PxJoint*)joint; + jointPhysX->setActors((PxRigidActor*)actors0, (PxRigidActor*)actor1); +} + +void PhysicsBackend::SetJointActorPose(void* joint, const Vector3& position, const Quaternion& orientation, uint8 index) +{ + auto jointPhysX = (PxJoint*)joint; + jointPhysX->setLocalPose((PxJointActorIndex::Enum)index, PxTransform(C2P(position), C2P(orientation))); +} + +void PhysicsBackend::SetJointBreakForce(void* joint, float force, float torque) +{ + auto jointPhysX = (PxJoint*)joint; + jointPhysX->setBreakForce(force, torque); +} + +void PhysicsBackend::GetJointForce(void* joint, Vector3& linear, Vector3& angular) +{ + auto jointPhysX = (PxJoint*)joint; + if (jointPhysX->getConstraint()) + jointPhysX->getConstraint()->getForce(*(PxVec3*)&linear, *(PxVec3*)&angular); +} + +void* PhysicsBackend::CreateFixedJoint(const PhysicsJointDesc& desc) +{ + const PxTransform trans0(C2P(desc.Pos0), C2P(desc.Rot0)); + const PxTransform trans1(C2P(desc.Pos1), C2P(desc.Rot1)); + PxFixedJoint* joint = PxFixedJointCreate(*PhysX, (PxRigidActor*)desc.Actor0, trans0, (PxRigidActor*)desc.Actor1, trans1); + joint->userData = desc.Joint; +#if PHYSX_DEBUG_NAMING + joint->setName("FixedJoint"); +#endif + return joint; +} + +void* PhysicsBackend::CreateDistanceJoint(const PhysicsJointDesc& desc) +{ + const PxTransform trans0(C2P(desc.Pos0), C2P(desc.Rot0)); + const PxTransform trans1(C2P(desc.Pos1), C2P(desc.Rot1)); + PxDistanceJoint* joint = PxDistanceJointCreate(*PhysX, (PxRigidActor*)desc.Actor0, trans0, (PxRigidActor*)desc.Actor1, trans1); + joint->userData = desc.Joint; +#if PHYSX_DEBUG_NAMING + joint->setName("DistanceJoint"); +#endif + return joint; +} + +void* PhysicsBackend::CreateHingeJoint(const PhysicsJointDesc& desc) +{ + const PxTransform trans0(C2P(desc.Pos0), C2P(desc.Rot0)); + const PxTransform trans1(C2P(desc.Pos1), C2P(desc.Rot1)); + PxRevoluteJoint* joint = PxRevoluteJointCreate(*PhysX, (PxRigidActor*)desc.Actor0, trans0, (PxRigidActor*)desc.Actor1, trans1); + joint->userData = desc.Joint; +#if PHYSX_DEBUG_NAMING + joint->setName("HingeJoint"); +#endif + return joint; +} + +void* PhysicsBackend::CreateSliderJoint(const PhysicsJointDesc& desc) +{ + const PxTransform trans0(C2P(desc.Pos0), C2P(desc.Rot0)); + const PxTransform trans1(C2P(desc.Pos1), C2P(desc.Rot1)); + PxPrismaticJoint* joint = PxPrismaticJointCreate(*PhysX, (PxRigidActor*)desc.Actor0, trans0, (PxRigidActor*)desc.Actor1, trans1); + joint->userData = desc.Joint; +#if PHYSX_DEBUG_NAMING + joint->setName("SliderJoint"); +#endif + return joint; +} + +void* PhysicsBackend::CreateSphericalJoint(const PhysicsJointDesc& desc) +{ + const PxTransform trans0(C2P(desc.Pos0), C2P(desc.Rot0)); + const PxTransform trans1(C2P(desc.Pos1), C2P(desc.Rot1)); + PxSphericalJoint* joint = PxSphericalJointCreate(*PhysX, (PxRigidActor*)desc.Actor0, trans0, (PxRigidActor*)desc.Actor1, trans1); + joint->userData = desc.Joint; +#if PHYSX_DEBUG_NAMING + joint->setName("SphericalJoint"); +#endif + return joint; +} + +void* PhysicsBackend::CreateD6Joint(const PhysicsJointDesc& desc) +{ + const PxTransform trans0(C2P(desc.Pos0), C2P(desc.Rot0)); + const PxTransform trans1(C2P(desc.Pos1), C2P(desc.Rot1)); + PxD6Joint* joint = PxD6JointCreate(*PhysX, (PxRigidActor*)desc.Actor0, trans0, (PxRigidActor*)desc.Actor1, trans1); + joint->userData = desc.Joint; +#if PHYSX_DEBUG_NAMING + joint->setName("D6Joint"); +#endif + return joint; +} + +void PhysicsBackend::SetDistanceJointFlags(void* joint, DistanceJointFlag flags) +{ + auto jointPhysX = (PxDistanceJoint*)joint; + jointPhysX->setDistanceJointFlags((PxDistanceJointFlag::Enum)flags); +} + +void PhysicsBackend::SetDistanceJointMinDistance(void* joint, float value) +{ + auto jointPhysX = (PxDistanceJoint*)joint; + jointPhysX->setMinDistance(value); +} + +void PhysicsBackend::SetDistanceJointMaxDistance(void* joint, float value) +{ + auto jointPhysX = (PxDistanceJoint*)joint; + jointPhysX->setMaxDistance(value); +} + +void PhysicsBackend::SetDistanceJointTolerance(void* joint, float value) +{ + auto jointPhysX = (PxDistanceJoint*)joint; + jointPhysX->setTolerance(value); +} + +void PhysicsBackend::SetDistanceJointSpring(void* joint, const SpringParameters& value) +{ + auto jointPhysX = (PxDistanceJoint*)joint; + jointPhysX->setStiffness(value.Stiffness); + jointPhysX->setDamping(value.Damping); +} + +float PhysicsBackend::GetDistanceJointDistance(void* joint) +{ + auto jointPhysX = (PxDistanceJoint*)joint; + return jointPhysX->getDistance(); +} + +void PhysicsBackend::SetHingeJointFlags(void* joint, HingeJointFlag value, bool driveFreeSpin) +{ + auto jointPhysX = (PxRevoluteJoint*)joint; + PxRevoluteJointFlags flags = (PxRevoluteJointFlags)0; + if (value & HingeJointFlag::Limit) + flags |= PxRevoluteJointFlag::eLIMIT_ENABLED; + if (value & HingeJointFlag::Drive) + flags |= PxRevoluteJointFlag::eDRIVE_ENABLED; + if (driveFreeSpin) + flags |= PxRevoluteJointFlag::eDRIVE_FREESPIN; + jointPhysX->setRevoluteJointFlags(flags); +} + +void PhysicsBackend::SetHingeJointLimit(void* joint, const LimitAngularRange& value) +{ + auto jointPhysX = (PxRevoluteJoint*)joint; + PxJointAngularLimitPair limit(value.Lower * DegreesToRadians, Math::Max(value.Upper, value.Lower) * DegreesToRadians, value.ContactDist); + limit.stiffness = value.Spring.Stiffness; + limit.damping = value.Spring.Damping; + limit.restitution = value.Restitution; + ASSERT_LOW_LAYER(limit.isValid()); + jointPhysX->setLimit(limit); +} + +void PhysicsBackend::SetHingeJointDrive(void* joint, const HingeJointDrive& value) +{ + auto jointPhysX = (PxRevoluteJoint*)joint; + jointPhysX->setDriveVelocity(Math::Max(value.Velocity, 0.0f)); + jointPhysX->setDriveForceLimit(Math::Max(value.ForceLimit, 0.0f)); + jointPhysX->setDriveGearRatio(Math::Max(value.GearRatio, 0.0f)); + jointPhysX->setRevoluteJointFlag(PxRevoluteJointFlag::eDRIVE_FREESPIN, value.FreeSpin); +} + +float PhysicsBackend::GetHingeJointAngle(void* joint) +{ + auto jointPhysX = (PxRevoluteJoint*)joint; + return jointPhysX->getAngle(); +} + +float PhysicsBackend::GetHingeJointVelocity(void* joint) +{ + auto jointPhysX = (PxRevoluteJoint*)joint; + return jointPhysX->getVelocity(); +} + +void PhysicsBackend::SetSliderJointFlags(void* joint, SliderJointFlag value) +{ + auto jointPhysX = (PxPrismaticJoint*)joint; + jointPhysX->setPrismaticJointFlag(PxPrismaticJointFlag::eLIMIT_ENABLED, (value & SliderJointFlag::Limit) != 0); +} + +void PhysicsBackend::SetSliderJointLimit(void* joint, const LimitLinearRange& value) +{ + auto jointPhysX = (PxPrismaticJoint*)joint; + PxJointLinearLimitPair limit(ToleranceScale, value.Lower, value.Upper, value.ContactDist); + limit.stiffness = value.Spring.Stiffness; + limit.damping = value.Spring.Damping; + limit.restitution = value.Restitution; + ASSERT_LOW_LAYER(limit.isValid()); + jointPhysX->setLimit(limit); +} + +float PhysicsBackend::GetSliderJointPosition(void* joint) +{ + auto jointPhysX = (PxPrismaticJoint*)joint; + return jointPhysX->getPosition(); +} + +float PhysicsBackend::GetSliderJointVelocity(void* joint) +{ + auto jointPhysX = (PxPrismaticJoint*)joint; + return jointPhysX->getVelocity(); +} + +void PhysicsBackend::SetSphericalJointFlags(void* joint, SphericalJointFlag value) +{ + auto jointPhysX = (PxSphericalJoint*)joint; + jointPhysX->setSphericalJointFlag(PxSphericalJointFlag::eLIMIT_ENABLED, (value & SphericalJointFlag::Limit) != 0); +} + +void PhysicsBackend::SetSphericalJointLimit(void* joint, const LimitConeRange& value) +{ + auto jointPhysX = (PxSphericalJoint*)joint; + PxJointLimitCone limit(Math::Clamp(value.YLimitAngle * DegreesToRadians, ZeroTolerance, PI - ZeroTolerance), Math::Clamp(value.ZLimitAngle * DegreesToRadians, ZeroTolerance, PI - ZeroTolerance), value.ContactDist); + limit.stiffness = value.Spring.Stiffness; + limit.damping = value.Spring.Damping; + limit.restitution = value.Restitution; + ASSERT_LOW_LAYER(limit.isValid()); + jointPhysX->setLimitCone(limit); +} + +void PhysicsBackend::SetD6JointMotion(void* joint, D6JointAxis axis, D6JointMotion value) +{ + auto jointPhysX = (PxD6Joint*)joint; + jointPhysX->setMotion(static_cast(axis), static_cast(value)); +} + +void PhysicsBackend::SetD6JointDrive(void* joint, const D6JointDriveType index, const D6JointDrive& value) +{ + auto jointPhysX = (PxD6Joint*)joint; + PxD6JointDrive drive; + if (value.Acceleration) + drive.flags = PxD6JointDriveFlag::eACCELERATION; + drive.stiffness = value.Stiffness; + drive.damping = value.Damping; + drive.forceLimit = value.ForceLimit; + ASSERT_LOW_LAYER(drive.isValid()); + jointPhysX->setDrive(static_cast(index), drive); +} + +void PhysicsBackend::SetD6JointLimitLinear(void* joint, const LimitLinear& value) +{ + auto jointPhysX = (PxD6Joint*)joint; + PxJointLinearLimit limit(ToleranceScale, Math::Max(value.Extent, ZeroTolerance), value.ContactDist); + limit.stiffness = value.Spring.Stiffness; + limit.damping = value.Spring.Damping; + limit.restitution = value.Restitution; + ASSERT_LOW_LAYER(limit.isValid()); + jointPhysX->setLinearLimit(limit); +} + +void PhysicsBackend::SetD6JointLimitTwist(void* joint, const LimitAngularRange& value) +{ + auto jointPhysX = (PxD6Joint*)joint; + PxJointAngularLimitPair limit(value.Lower * DegreesToRadians, Math::Max(value.Upper, value.Lower) * DegreesToRadians, value.ContactDist); + limit.stiffness = value.Spring.Stiffness; + limit.damping = value.Spring.Damping; + limit.restitution = value.Restitution; + ASSERT_LOW_LAYER(limit.isValid()); + jointPhysX->setTwistLimit(limit); +} + +void PhysicsBackend::SetD6JointLimitSwing(void* joint, const LimitConeRange& value) +{ + auto jointPhysX = (PxD6Joint*)joint; + PxJointLimitCone limit(Math::Clamp(value.YLimitAngle * DegreesToRadians, ZeroTolerance, PI - ZeroTolerance), Math::Clamp(value.ZLimitAngle * DegreesToRadians, ZeroTolerance, PI - ZeroTolerance), value.ContactDist); + limit.stiffness = value.Spring.Stiffness; + limit.damping = value.Spring.Damping; + limit.restitution = value.Restitution; + ASSERT_LOW_LAYER(limit.isValid()); + jointPhysX->setSwingLimit(limit); +} + +Vector3 PhysicsBackend::GetD6JointDrivePosition(void* joint) +{ + auto jointPhysX = (PxD6Joint*)joint; + return P2C(jointPhysX->getDrivePosition().p); +} + +void PhysicsBackend::SetD6JointDrivePosition(void* joint, const Vector3& value) +{ + auto jointPhysX = (PxD6Joint*)joint; + PxTransform t = jointPhysX->getDrivePosition(); + t.p = C2P(value); + jointPhysX->setDrivePosition(t); +} + +Quaternion PhysicsBackend::GetD6JointDriveRotation(void* joint) +{ + auto jointPhysX = (PxD6Joint*)joint; + return P2C(jointPhysX->getDrivePosition().q); +} + +void PhysicsBackend::SetD6JointDriveRotation(void* joint, const Quaternion& value) +{ + auto jointPhysX = (PxD6Joint*)joint; + PxTransform t = jointPhysX->getDrivePosition(); + t.q = C2P(value); + jointPhysX->setDrivePosition(t); +} + +void PhysicsBackend::GetD6JointDriveVelocity(void* joint, Vector3& linear, Vector3& angular) +{ + auto jointPhysX = (PxD6Joint*)joint; + PxVec3 linearPhysX, angularPhysX; + jointPhysX->getDriveVelocity(linearPhysX, angularPhysX); + linear = P2C(linearPhysX); + angular = P2C(angularPhysX); +} + +void PhysicsBackend::SetD6JointDriveVelocity(void* joint, const Vector3& linear, const Vector3& angular) +{ + auto jointPhysX = (PxD6Joint*)joint; + jointPhysX->setDriveVelocity(C2P(linear), C2P(angular)); +} + +float PhysicsBackend::GetD6JointTwist(void* joint) +{ + auto jointPhysX = (PxD6Joint*)joint; + return jointPhysX->getTwistAngle(); +} + +float PhysicsBackend::GetD6JointSwingY(void* joint) +{ + auto jointPhysX = (PxD6Joint*)joint; + return jointPhysX->getSwingYAngle(); +} + +float PhysicsBackend::GetD6JointSwingZ(void* joint) +{ + auto jointPhysX = (PxD6Joint*)joint; + return jointPhysX->getSwingZAngle(); +} + +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; + PxCapsuleControllerDesc desc; + desc.userData = actor; + desc.contactOffset = Math::Max(contactOffset, ZeroTolerance); + desc.position = PxExtendedVec3(position.X, position.Y, position.Z); + desc.slopeLimit = Math::Cos(slopeLimit * DegreesToRadians); + desc.nonWalkableMode = static_cast(nonWalkableMode); + desc.climbingMode = PxCapsuleClimbingMode::eEASY; + if (material && !material->WaitForLoaded()) + desc.material = (PxMaterial*)((PhysicalMaterial*)material->Instance)->GetPhysicsMaterial(); + else + desc.material = DefaultMaterial; + const float minSize = 0.001f; + desc.height = Math::Max(height, minSize); + desc.radius = Math::Max(radius - desc.contactOffset, minSize); + desc.stepOffset = Math::Min(stepOffset, desc.height + desc.radius * 2.0f - minSize); + auto controllerPhysX = (PxCapsuleController*)scenePhysX->ControllerManager->createController(desc); + PxRigidActor* actorPhysX = controllerPhysX->getActor(); + ASSERT(actorPhysX && actorPhysX->getNbShapes() == 1); + actorPhysX->getShapes((PxShape**)&shape, 1); + actorPhysX->userData = actor; + auto shapePhysX = (PxShape*)shape; + shapePhysX->userData = collider; +#if PHYSX_DEBUG_NAMING + actorPhysX->setName("CCActor"); + shapePhysX->setName("CCShape"); +#endif + return controllerPhysX; +} + +void* PhysicsBackend::GetControllerRigidDynamicActor(void* controller) +{ + auto controllerPhysX = (PxCapsuleController*)controller; + return controllerPhysX->getActor(); +} + +void PhysicsBackend::SetControllerSize(void* controller, float radius, float height) +{ + auto controllerPhysX = (PxCapsuleController*)controller; + controllerPhysX->setRadius(radius); + controllerPhysX->resize(height); +} + +void PhysicsBackend::SetControllerSlopeLimit(void* controller, float value) +{ + auto controllerPhysX = (PxCapsuleController*)controller; + controllerPhysX->setSlopeLimit(Math::Cos(value * DegreesToRadians)); +} + +void PhysicsBackend::SetControllerNonWalkableMode(void* controller, int32 value) +{ + auto controllerPhysX = (PxCapsuleController*)controller; + controllerPhysX->setNonWalkableMode(static_cast(value)); +} + +void PhysicsBackend::SetControllerStepOffset(void* controller, float value) +{ + auto controllerPhysX = (PxCapsuleController*)controller; + controllerPhysX->setStepOffset(value); +} + +Vector3 PhysicsBackend::GetControllerUpDirection(void* controller) +{ + auto controllerPhysX = (PxCapsuleController*)controller; + return P2C(controllerPhysX->getUpDirection()); +} + +void PhysicsBackend::SetControllerUpDirection(void* controller, const Vector3& value) +{ + auto controllerPhysX = (PxCapsuleController*)controller; + controllerPhysX->setUpDirection(C2P(value)); +} + +Vector3 PhysicsBackend::GetControllerPosition(void* controller) +{ + auto controllerPhysX = (PxCapsuleController*)controller; + return P2C(controllerPhysX->getPosition()); +} + +void PhysicsBackend::SetControllerPosition(void* controller, const Vector3& value) +{ + auto controllerPhysX = (PxCapsuleController*)controller; + controllerPhysX->setPosition(PxExtendedVec3(value.X, value.Y, value.Z)); +} + +int32 PhysicsBackend::MoveController(void* controller, void* shape, const Vector3& displacement, float minMoveDistance, float deltaTime) +{ + auto controllerPhysX = (PxCapsuleController*)controller; + auto shapePhysX = (PxShape*)shape; + PxFilterData filterData = shapePhysX->getSimulationFilterData(); + PxControllerFilters filters; + filters.mFilterData = &filterData; + filters.mFilterCallback = &CharacterQueryFilter; + filters.mFilterFlags = PxQueryFlag::eDYNAMIC | PxQueryFlag::eSTATIC | PxQueryFlag::ePREFILTER; + filters.mCCTFilterCallback = &CharacterControllerFilter; + return (byte)controllerPhysX->move(C2P(displacement), minMoveDistance, deltaTime, filters); +} + +#if WITH_VEHICLE + +void* PhysicsBackend::CreateVehicle(WheeledVehicle* actor) +{ + // Get wheels + Array> wheels; + for (auto& wheel : actor->_wheels) + { + if (!wheel.Collider) + { + LOG(Warning, "Missing wheel collider in vehicle {0}", actor->ToString()); + continue; + } + if (wheel.Collider->GetParent() != actor) + { + LOG(Warning, "Invalid wheel collider {1} in vehicle {0} attached to {2} (wheels needs to be added as children to vehicle)", actor->ToString(), wheel.Collider->ToString(), wheel.Collider->GetParent() ? wheel.Collider->GetParent()->ToString() : String::Empty); + continue; + } + if (wheel.Collider->GetIsTrigger()) + { + LOG(Warning, "Invalid wheel collider {1} in vehicle {0} cannot be a trigger", actor->ToString(), wheel.Collider->ToString()); + continue; + } + if (wheel.Collider->IsDuringPlay()) + { + wheels.Add(&wheel); + } + } + if (wheels.IsEmpty()) + { + // No wheel, no car + // No woman, no cry + return nullptr; + } + actor->_wheelsData.Resize(wheels.Count()); + auto actorPhysX = (PxRigidDynamic*)actor->GetPhysicsActor(); + + InitVehicleSDK(); + + // Get linked shapes for the wheels mapping + Array> shapes; + shapes.Resize(actorPhysX->getNbShapes()); + actorPhysX->getShapes(shapes.Get(), shapes.Count(), 0); + const PxTransform centerOfMassOffset = actorPhysX->getCMassLocalPose(); + + // Initialize wheels simulation data + PxVec3 offsets[PX_MAX_NB_WHEELS]; + for (int32 i = 0; i < wheels.Count(); i++) + { + auto& wheel = *wheels[i]; + offsets[i] = C2P(wheel.Collider->GetLocalPosition()); + } + PxF32 sprungMasses[PX_MAX_NB_WHEELS]; + const float mass = actorPhysX->getMass(); + PxVehicleComputeSprungMasses(wheels.Count(), offsets, centerOfMassOffset.p, mass, 1, sprungMasses); + PxVehicleWheelsSimData* wheelsSimData = PxVehicleWheelsSimData::allocate(wheels.Count()); + for (int32 i = 0; i < wheels.Count(); i++) + { + auto& wheel = *wheels[i]; + + auto& data = actor->_wheelsData[i]; + data.Collider = wheel.Collider; + data.LocalOrientation = wheel.Collider->GetLocalOrientation(); + + PxVehicleSuspensionData suspensionData; + const float suspensionFrequency = 7.0f; + suspensionData.mMaxCompression = wheel.SuspensionMaxRaise; + suspensionData.mMaxDroop = wheel.SuspensionMaxDrop; + suspensionData.mSprungMass = sprungMasses[i]; + suspensionData.mSpringStrength = Math::Square(suspensionFrequency) * suspensionData.mSprungMass; + suspensionData.mSpringDamperRate = wheel.SuspensionDampingRate * 2.0f * Math::Sqrt(suspensionData.mSpringStrength * suspensionData.mSprungMass); + + PxVehicleTireData tire; + tire.mType = 0; + tire.mLatStiffX = wheel.TireLateralMax; + tire.mLatStiffY = wheel.TireLateralStiffness; + tire.mLongitudinalStiffnessPerUnitGravity = wheel.TireLongitudinalStiffness; + + PxVehicleWheelData wheelData; + wheelData.mMass = wheel.Mass; + wheelData.mRadius = wheel.Radius; + wheelData.mWidth = wheel.Width; + wheelData.mMOI = 0.5f * wheelData.mMass * Math::Square(wheelData.mRadius); + wheelData.mDampingRate = M2ToCm2(wheel.DampingRate); + wheelData.mMaxSteer = wheel.MaxSteerAngle * DegreesToRadians; + wheelData.mMaxBrakeTorque = M2ToCm2(wheel.MaxBrakeTorque); + wheelData.mMaxHandBrakeTorque = M2ToCm2(wheel.MaxHandBrakeTorque); + + PxVec3 centreOffset = centerOfMassOffset.transformInv(offsets[i]); + PxVec3 forceAppPointOffset(centreOffset.x, wheel.SuspensionForceOffset, centreOffset.z); + + wheelsSimData->setTireData(i, tire); + wheelsSimData->setWheelData(i, wheelData); + wheelsSimData->setSuspensionData(i, suspensionData); + wheelsSimData->setSuspTravelDirection(i, centerOfMassOffset.rotate(PxVec3(0.0f, -1.0f, 0.0f))); + wheelsSimData->setWheelCentreOffset(i, centreOffset); + wheelsSimData->setSuspForceAppPointOffset(i, forceAppPointOffset); + wheelsSimData->setTireForceAppPointOffset(i, forceAppPointOffset); + wheelsSimData->setSubStepCount(4.0f * 100.0f, 3, 1); + wheelsSimData->setMinLongSlipDenominator(4.0f * 100.0f); + + PxShape* wheelShape = (PxShape*)wheel.Collider->GetPhysicsShape(); + if (wheel.Collider->IsActiveInHierarchy()) + { + wheelsSimData->setWheelShapeMapping(i, shapes.Find(wheelShape)); + + // Setup Vehicle ID inside word3 for suspension raycasts to ignore self + PxFilterData filter = wheelShape->getQueryFilterData(); + filter.word3 = actor->GetID().D + 1; + wheelShape->setQueryFilterData(filter); + wheelShape->setSimulationFilterData(filter); + wheelsSimData->setSceneQueryFilterData(i, filter); + + // Remove wheels from the simulation (suspension force hold the vehicle) + wheelShape->setFlag(PxShapeFlag::eSIMULATION_SHAPE, false); + } + else + { + wheelsSimData->setWheelShapeMapping(i, -1); + wheelsSimData->disableWheel(i); + } + } + for (auto child : actor->Children) + { + auto collider = ScriptingObject::Cast(child); + if (collider && collider->GetAttachedRigidBody() == actor) + { + bool isWheel = false; + for (auto& w : wheels) + { + if (w->Collider == collider) + { + isWheel = true; + break; + } + } + if (!isWheel) + { + // Setup Vehicle ID inside word3 for suspension raycasts to ignore self + PxShape* shape = (PxShape*)collider->GetPhysicsShape(); + PxFilterData filter = shape->getQueryFilterData(); + filter.word3 = actor->GetID().D + 1; + shape->setQueryFilterData(filter); + shape->setSimulationFilterData(filter); + } + } + } + + // Initialize vehicle drive + void* vehicle = nullptr; + const auto& differential = actor->_differential; + const auto& engine = actor->_engine; + const auto& gearbox = actor->_gearbox; + switch (actor->_driveType) + { + case WheeledVehicle::DriveTypes::Drive4W: + { + PxVehicleDriveSimData4W driveSimData; + + // Differential + PxVehicleDifferential4WData differential4WData; + differential4WData.mType = (PxVehicleDifferential4WData::Enum)differential.Type; + differential4WData.mFrontRearSplit = differential.FrontRearSplit; + differential4WData.mFrontLeftRightSplit = differential.FrontLeftRightSplit; + differential4WData.mRearLeftRightSplit = differential.RearLeftRightSplit; + differential4WData.mCentreBias = differential.CentreBias; + differential4WData.mFrontBias = differential.FrontBias; + differential4WData.mRearBias = differential.RearBias; + driveSimData.setDiffData(differential4WData); + + // Engine + PxVehicleEngineData engineData; + engineData.mMOI = M2ToCm2(engine.MOI); + engineData.mPeakTorque = M2ToCm2(engine.MaxTorque); + engineData.mMaxOmega = RpmToRadPerS(engine.MaxRotationSpeed); + engineData.mDampingRateFullThrottle = M2ToCm2(0.15f); + engineData.mDampingRateZeroThrottleClutchEngaged = M2ToCm2(2.0f); + engineData.mDampingRateZeroThrottleClutchDisengaged = M2ToCm2(0.35f); + driveSimData.setEngineData(engineData); + + // Gears + PxVehicleGearsData gears; + gears.mSwitchTime = Math::Max(gearbox.SwitchTime, 0.0f); + driveSimData.setGearsData(gears); + + // Auto Box + PxVehicleAutoBoxData autoBox; + driveSimData.setAutoBoxData(autoBox); + + // Clutch + PxVehicleClutchData clutch; + clutch.mStrength = M2ToCm2(gearbox.ClutchStrength); + driveSimData.setClutchData(clutch); + + // Ackermann steer accuracy + PxVehicleAckermannGeometryData ackermann; + ackermann.mAxleSeparation = Math::Abs(wheelsSimData->getWheelCentreOffset(PxVehicleDrive4WWheelOrder::eFRONT_LEFT).x - wheelsSimData->getWheelCentreOffset(PxVehicleDrive4WWheelOrder::eREAR_LEFT).x); + ackermann.mFrontWidth = Math::Abs(wheelsSimData->getWheelCentreOffset(PxVehicleDrive4WWheelOrder::eFRONT_RIGHT).z - wheelsSimData->getWheelCentreOffset(PxVehicleDrive4WWheelOrder::eFRONT_LEFT).z); + ackermann.mRearWidth = Math::Abs(wheelsSimData->getWheelCentreOffset(PxVehicleDrive4WWheelOrder::eREAR_RIGHT).z - wheelsSimData->getWheelCentreOffset(PxVehicleDrive4WWheelOrder::eREAR_LEFT).z); + driveSimData.setAckermannGeometryData(ackermann); + + // Create vehicle drive + auto drive4W = PxVehicleDrive4W::allocate(wheels.Count()); + drive4W->setup(PhysX, actorPhysX, *wheelsSimData, driveSimData, Math::Max(wheels.Count() - 4, 0)); + drive4W->setToRestState(); + drive4W->mDriveDynData.forceGearChange(PxVehicleGearsData::eFIRST); + drive4W->mDriveDynData.setUseAutoGears(gearbox.AutoGear); + vehicle = drive4W; + break; + } + case WheeledVehicle::DriveTypes::DriveNW: + { + PxVehicleDriveSimDataNW driveSimData; + + // Differential + PxVehicleDifferentialNWData differentialNwData; + for (int32 i = 0; i < wheels.Count(); i++) + differentialNwData.setDrivenWheel(i, true); + driveSimData.setDiffData(differentialNwData); + + // Engine + PxVehicleEngineData engineData; + engineData.mMOI = M2ToCm2(engine.MOI); + engineData.mPeakTorque = M2ToCm2(engine.MaxTorque); + engineData.mMaxOmega = RpmToRadPerS(engine.MaxRotationSpeed); + engineData.mDampingRateFullThrottle = M2ToCm2(0.15f); + engineData.mDampingRateZeroThrottleClutchEngaged = M2ToCm2(2.0f); + engineData.mDampingRateZeroThrottleClutchDisengaged = M2ToCm2(0.35f); + driveSimData.setEngineData(engineData); + + // Gears + PxVehicleGearsData gears; + gears.mSwitchTime = Math::Max(gearbox.SwitchTime, 0.0f); + driveSimData.setGearsData(gears); + + // Auto Box + PxVehicleAutoBoxData autoBox; + driveSimData.setAutoBoxData(autoBox); + + // Clutch + PxVehicleClutchData clutch; + clutch.mStrength = M2ToCm2(gearbox.ClutchStrength); + driveSimData.setClutchData(clutch); + + // Create vehicle drive + auto driveNW = PxVehicleDriveNW::allocate(wheels.Count()); + driveNW->setup(PhysX, actorPhysX, *wheelsSimData, driveSimData, wheels.Count()); + driveNW->setToRestState(); + driveNW->mDriveDynData.forceGearChange(PxVehicleGearsData::eFIRST); + driveNW->mDriveDynData.setUseAutoGears(gearbox.AutoGear); + vehicle = driveNW; + break; + } + case WheeledVehicle::DriveTypes::NoDrive: + { + // Create vehicle drive + auto driveNo = PxVehicleNoDrive::allocate(wheels.Count()); + driveNo->setup(PhysX, actorPhysX, *wheelsSimData); + driveNo->setToRestState(); + vehicle = driveNo; + break; + } + default: + CRASH; + } + wheelsSimData->free(); + + return vehicle; +} + +void PhysicsBackend::DestroyVehicle(void* vehicle, int32 driveType) +{ + switch ((WheeledVehicle::DriveTypes)driveType) + { + case WheeledVehicle::DriveTypes::Drive4W: + ((PxVehicleDrive4W*)vehicle)->free(); + break; + case WheeledVehicle::DriveTypes::DriveNW: + ((PxVehicleDriveNW*)vehicle)->free(); + break; + case WheeledVehicle::DriveTypes::NoDrive: + ((PxVehicleNoDrive*)vehicle)->free(); + break; + } +} + +void PhysicsBackend::SetVehicleGearbox(void* vehicle, const void* value) +{ + auto drive = (PxVehicleDrive*)vehicle; + auto& gearbox = *(const WheeledVehicle::GearboxSettings*)value; + drive->mDriveDynData.setUseAutoGears(gearbox.AutoGear); + drive->mDriveDynData.setAutoBoxSwitchTime(Math::Max(gearbox.SwitchTime, 0.0f)); +} + +int32 PhysicsBackend::GetVehicleTargetGear(void* vehicle) +{ + auto drive = (PxVehicleDrive*)vehicle; + return (int32)drive->mDriveDynData.getTargetGear() - 1; +} + +void PhysicsBackend::SetVehicleTargetGear(void* vehicle, int32 value) +{ + auto drive = (PxVehicleDrive*)vehicle; + drive->mDriveDynData.startGearChange((PxU32)(value + 1)); +} + +int32 PhysicsBackend::GetVehicleCurrentGear(void* vehicle) +{ + auto drive = (PxVehicleDrive*)vehicle; + return (int32)drive->mDriveDynData.getCurrentGear() - 1; +} + +void PhysicsBackend::SetVehicleCurrentGear(void* vehicle, int32 value) +{ + auto drive = (PxVehicleDrive*)vehicle; + drive->mDriveDynData.forceGearChange((PxU32)(value + 1)); +} + +float PhysicsBackend::GetVehicleForwardSpeed(void* vehicle) +{ + auto drive = (PxVehicleDrive*)vehicle; + return drive->computeForwardSpeed(); +} + +float PhysicsBackend::GetVehicleSidewaysSpeed(void* vehicle) +{ + auto drive = (PxVehicleDrive*)vehicle; + return drive->computeSidewaysSpeed(); +} + +float PhysicsBackend::GetVehicleEngineRotationSpeed(void* vehicle) +{ + auto drive = (PxVehicleDrive*)vehicle; + return RadPerSToRpm(drive->mDriveDynData.getEngineRotationSpeed()); +} + +void PhysicsBackend::AddVehicle(void* scene, WheeledVehicle* actor) +{ + auto scenePhysX = (ScenePhysX*)scene; + scenePhysX->WheelVehicles.Add(actor); +} + +void PhysicsBackend::RemoveVehicle(void* scene, WheeledVehicle* actor) +{ + auto scenePhysX = (ScenePhysX*)scene; + scenePhysX->WheelVehicles.Remove(actor); +} + +#endif + +void* PhysicsBackend::CreateConvexMesh(byte* data, int32 dataSize, BoundingBox& localBounds) +{ + PxDefaultMemoryInputData input(data, dataSize); + PxConvexMesh* convexMesh = PhysX->createConvexMesh(input); + localBounds = P2C(convexMesh->getLocalBounds()); + return convexMesh; +} + +void* PhysicsBackend::CreateTriangleMesh(byte* data, int32 dataSize, BoundingBox& localBounds) +{ + PxDefaultMemoryInputData input(data, dataSize); + PxTriangleMesh* triangleMesh = PhysX->createTriangleMesh(input); + localBounds = P2C(triangleMesh->getLocalBounds()); + return triangleMesh; +} + +void* PhysicsBackend::CreateHeightField(byte* data, int32 dataSize) +{ + PxDefaultMemoryInputData input(data, dataSize); + PxHeightField* heightField = PhysX->createHeightField(input); + return heightField; +} + +void PhysicsBackend::GetConvexMeshTriangles(void* contextMesh, Array& vertexBuffer, Array& indexBuffer) +{ + auto contextMeshPhysX = (PxConvexMesh*)contextMesh; + uint32 numIndices = 0; + uint32 numVertices = contextMeshPhysX->getNbVertices(); + const uint32 numPolygons = contextMeshPhysX->getNbPolygons(); + for (uint32 i = 0; i < numPolygons; i++) + { + PxHullPolygon face; + const bool status = contextMeshPhysX->getPolygonData(i, face); + ASSERT(status); + numIndices += (face.mNbVerts - 2) * 3; + } + + vertexBuffer.Resize(numVertices); + indexBuffer.Resize(numIndices); + auto outVertices = vertexBuffer.Get(); + auto outIndices = indexBuffer.Get(); + const PxVec3* convexVertices = contextMeshPhysX->getVertices(); + const byte* convexIndices = contextMeshPhysX->getIndexBuffer(); + + for (uint32 i = 0; i < numVertices; i++) + *outVertices++ = P2C(convexVertices[i]); + + for (uint32 i = 0; i < numPolygons; i++) + { + PxHullPolygon face; + contextMeshPhysX->getPolygonData(i, face); + + const PxU8* faceIndices = convexIndices + face.mIndexBase; + for (uint32 j = 2; j < face.mNbVerts; j++) + { + *outIndices++ = faceIndices[0]; + *outIndices++ = faceIndices[j]; + *outIndices++ = faceIndices[j - 1]; + } + } +} + +void PhysicsBackend::GetTriangleMeshTriangles(void* triangleMesh, Array& vertexBuffer, Array& indexBuffer) +{ + auto triangleMeshPhysX = (PxTriangleMesh*)triangleMesh; + uint32 numVertices = triangleMeshPhysX->getNbVertices(); + uint32 numIndices = triangleMeshPhysX->getNbTriangles() * 3; + + vertexBuffer.Resize(numVertices); + indexBuffer.Resize(numIndices); + auto outVertices = vertexBuffer.Get(); + auto outIndices = indexBuffer.Get(); + const PxVec3* vertices = triangleMeshPhysX->getVertices(); + for (uint32 i = 0; i < numVertices; i++) + *outVertices++ = P2C(vertices[i]); + + if (triangleMeshPhysX->getTriangleMeshFlags() & PxTriangleMeshFlag::e16_BIT_INDICES) + { + const uint16* indices = (const uint16*)triangleMeshPhysX->getTriangles(); + + uint32 numTriangles = numIndices / 3; + for (uint32 i = 0; i < numTriangles; i++) + { + outIndices[i * 3 + 0] = (uint32)indices[i * 3 + 0]; + outIndices[i * 3 + 1] = (uint32)indices[i * 3 + 1]; + outIndices[i * 3 + 2] = (uint32)indices[i * 3 + 2]; + } + } + else + { + const uint32* indices = (const uint32*)triangleMeshPhysX->getTriangles(); + + uint32 numTriangles = numIndices / 3; + for (uint32 i = 0; i < numTriangles; i++) + { + outIndices[i * 3 + 0] = indices[i * 3 + 0]; + outIndices[i * 3 + 1] = indices[i * 3 + 1]; + outIndices[i * 3 + 2] = indices[i * 3 + 2]; + } + } +} + +const uint32* PhysicsBackend::GetTriangleMeshRemap(void* triangleMesh, uint32& count) +{ + auto triangleMeshPhysX = (PxTriangleMesh*)triangleMesh; + count = triangleMeshPhysX->getNbTriangles(); + return triangleMeshPhysX->getTrianglesRemap(); +} + +void PhysicsBackend::GetHeightFieldSize(void* heightField, int32& rows, int32& columns) +{ + auto heightFieldPhysX = (PxHeightField*)heightField; + rows = (int32)heightFieldPhysX->getNbRows(); + columns = (int32)heightFieldPhysX->getNbColumns(); +} + +float PhysicsBackend::GetHeightFieldHeight(void* heightField, float x, float z) +{ + auto heightFieldPhysX = (PxHeightField*)heightField; + return heightFieldPhysX->getHeight(x, z); +} + +bool PhysicsBackend::ModifyHeightField(void* heightField, int32 startCol, int32 startRow, int32 cols, int32 rows, const HeightFieldSample* data) +{ + auto heightFieldPhysX = (PxHeightField*)heightField; + PxHeightFieldDesc heightFieldDesc; + heightFieldDesc.format = PxHeightFieldFormat::eS16_TM; + heightFieldDesc.flags = PxHeightFieldFlag::eNO_BOUNDARY_EDGES; + heightFieldDesc.nbColumns = cols; + heightFieldDesc.nbRows = rows; + heightFieldDesc.samples.data = data; + heightFieldDesc.samples.stride = sizeof(HeightFieldSample); + return !heightFieldPhysX->modifySamples(startCol, startRow, heightFieldDesc, true); +} + +void PhysicsBackend::FlushRequests() +{ + FlushLocker.Lock(); + + // Delete objects + for (int32 i = 0; i < DeleteObjects.Count(); i++) + DeleteObjects[i]->release(); + DeleteObjects.Clear(); + + FlushLocker.Unlock(); +} + +void PhysicsBackend::FlushRequests(void* scene) +{ + auto scenePhysX = (ScenePhysX*)scene; + FlushLocker.Lock(); + + // Add objects + if (scenePhysX->AddActors.HasItems()) + { + scenePhysX->Scene->addActors(scenePhysX->AddActors.Get(), scenePhysX->AddActors.Count()); + scenePhysX->AddActors.Clear(); + } + + // Perform latent actions + for (int32 i = 0; i < scenePhysX->Actions.Count(); i++) + { + const auto action = scenePhysX->Actions[i]; + switch (action.Type) + { + case ActionType::Sleep: + static_cast(action.Actor)->putToSleep(); + break; + } + } + scenePhysX->Actions.Clear(); + + // Remove objects + if (scenePhysX->RemoveActors.HasItems()) + { + scenePhysX->Scene->removeActors(scenePhysX->RemoveActors.Get(), scenePhysX->RemoveActors.Count(), true); + scenePhysX->RemoveActors.Clear(); + } + if (scenePhysX->RemoveColliders.HasItems()) + { + for (int32 i = 0; i < scenePhysX->RemoveColliders.Count(); i++) + scenePhysX->EventsCallback.OnColliderRemoved(scenePhysX->RemoveColliders[i]); + scenePhysX->RemoveColliders.Clear(); + } + if (scenePhysX->RemoveJoints.HasItems()) + { + for (int32 i = 0; i < scenePhysX->RemoveJoints.Count(); i++) + scenePhysX->EventsCallback.OnJointRemoved(scenePhysX->RemoveJoints[i]); + scenePhysX->RemoveJoints.Clear(); + } + + FlushLocker.Unlock(); +} + +void PhysicsBackend::DestroyActor(void* actor) +{ + ASSERT_LOW_LAYER(actor); + auto actorPhysX = (PxActor*)actor; + actorPhysX->userData = nullptr; + FlushLocker.Lock(); + DeleteObjects.Add(actorPhysX); + FlushLocker.Unlock(); +} + +void PhysicsBackend::DestroyShape(void* shape) +{ + ASSERT_LOW_LAYER(shape); + auto shapePhysX = (PxShape*)shape; + shapePhysX->userData = nullptr; + FlushLocker.Lock(); + DeleteObjects.Add(shapePhysX); + FlushLocker.Unlock(); +} + +void PhysicsBackend::DestroyJoint(void* joint) +{ + ASSERT_LOW_LAYER(joint); + auto jointPhysX = (PxJoint*)joint; + jointPhysX->userData = nullptr; + FlushLocker.Lock(); + DeleteObjects.Add(jointPhysX); + FlushLocker.Unlock(); +} + +void PhysicsBackend::DestroyController(void* controller) +{ + ASSERT_LOW_LAYER(controller); + auto controllerPhysX = (PxController*)controller; + controllerPhysX->getActor()->userData = nullptr; + controllerPhysX->release(); +} + +void PhysicsBackend::DestroyObject(void* object) +{ + ASSERT_LOW_LAYER(object); + auto objectPhysX = (PxBase*)object; + FlushLocker.Lock(); + DeleteObjects.Add(objectPhysX); + FlushLocker.Unlock(); +} + +void PhysicsBackend::RemoveCollider(PhysicsColliderActor* collider) +{ + for (auto scene : Physics::Scenes) + { + auto scenePhysX = (ScenePhysX*)scene->GetPhysicsScene(); + scenePhysX->RemoveColliders.Add(collider); + } +} + +void PhysicsBackend::RemoveJoint(Joint* joint) +{ + for (auto scene : Physics::Scenes) + { + auto scenePhysX = (ScenePhysX*)scene->GetPhysicsScene(); + scenePhysX->RemoveJoints.Add(joint); + } +} + +#endif diff --git a/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.h b/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.h new file mode 100644 index 000000000..c8d71a7ec --- /dev/null +++ b/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.h @@ -0,0 +1,23 @@ +// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved. + +#pragma once + +#if COMPILE_WITH_PHYSX + +#include "Engine/Physics/PhysicsBackend.h" +#include "Types.h" + +/// +/// Implementation of the physical simulation using PhysX. +/// +class PhysicsBackendPhysX +{ +public: + static PxPhysics* GetPhysics(); +#if COMPILE_WITH_PHYSICS_COOKING + static PxCooking* GetCooking(); +#endif + static PxMaterial* GetDefaultMaterial(); +}; + +#endif diff --git a/Source/Engine/Physics/PhysicsStepper.cpp b/Source/Engine/Physics/PhysX/PhysicsStepperPhysX.cpp similarity index 94% rename from Source/Engine/Physics/PhysicsStepper.cpp rename to Source/Engine/Physics/PhysX/PhysicsStepperPhysX.cpp index 7a864e4b8..887353f49 100644 --- a/Source/Engine/Physics/PhysicsStepper.cpp +++ b/Source/Engine/Physics/PhysX/PhysicsStepperPhysX.cpp @@ -1,7 +1,9 @@ -// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. +// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved. -#include "PhysicsStepper.h" -#include "Physics.h" +#if COMPILE_WITH_PHYSX + +#include "PhysicsStepperPhysX.h" +#include "Engine/Physics/Physics.h" #include "Engine/Profiler/ProfilerCPU.h" #include #include @@ -138,3 +140,5 @@ void FixedStepper::substepStrategy(const PxReal stepSize, PxU32& substepCount, P mAccumulator -= PxReal(substepCount) * substepSize; } + +#endif diff --git a/Source/Engine/Physics/PhysicsStepper.h b/Source/Engine/Physics/PhysX/PhysicsStepperPhysX.h similarity index 98% rename from Source/Engine/Physics/PhysicsStepper.h rename to Source/Engine/Physics/PhysX/PhysicsStepperPhysX.h index 7e394fdcf..d871591b4 100644 --- a/Source/Engine/Physics/PhysicsStepper.h +++ b/Source/Engine/Physics/PhysX/PhysicsStepperPhysX.h @@ -1,7 +1,9 @@ -// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. +// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved. #pragma once +#if COMPILE_WITH_PHYSX + #include "Types.h" #include #include @@ -215,3 +217,5 @@ public: mMaxSubSteps = maxSteps; } }; + +#endif diff --git a/Source/Engine/Physics/SimulationEventCallback.cpp b/Source/Engine/Physics/PhysX/SimulationEventCallbackPhysX.cpp similarity index 94% rename from Source/Engine/Physics/SimulationEventCallback.cpp rename to Source/Engine/Physics/PhysX/SimulationEventCallbackPhysX.cpp index 27c8aa785..b17ef3ce3 100644 --- a/Source/Engine/Physics/SimulationEventCallback.cpp +++ b/Source/Engine/Physics/PhysX/SimulationEventCallbackPhysX.cpp @@ -1,10 +1,11 @@ -// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. +// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved. -#include "SimulationEventCallback.h" -#include "Utilities.h" -#include "Colliders/Collider.h" -#include "Joints/Joint.h" -#include "Actors/RigidBody.h" +#if COMPILE_WITH_PHYSX + +#include "SimulationEventCallbackPhysX.h" +#include "Engine/Physics/Colliders/Collider.h" +#include "Engine/Physics/Joints/Joint.h" +#include "Engine/Physics/Actors/RigidBody.h" #include #include @@ -136,7 +137,6 @@ void SimulationEventCallback::onConstraintBreak(PxConstraintInfo* constraints, P for (uint32 i = 0; i < count; i++) { PxJoint* joint = reinterpret_cast(constraints[i].externalReference); - if (joint->userData) BrokenJoints.Add(static_cast(joint->userData)); } @@ -177,6 +177,7 @@ void SimulationEventCallback::onContact(const PxContactPairHeader& pairHeader, c c.ThisActor = static_cast(pair.shapes[0]->userData); c.OtherActor = static_cast(pair.shapes[1]->userData); + ASSERT_LOW_LAYER(c.ThisActor && c.OtherActor); while (i.hasNextPatch()) { @@ -219,6 +220,7 @@ void SimulationEventCallback::onContact(const PxContactPairHeader& pairHeader, c const PxContactPair& pair = pairs[i.contactPairIndex]; c.ThisActor = static_cast(pair.shapes[0]->userData); c.OtherActor = static_cast(pair.shapes[1]->userData); + ASSERT_LOW_LAYER(c.ThisActor && c.OtherActor); Collision& collision = Collisions[CollidersPair(c.ThisActor, c.OtherActor)]; collision.ThisVelocity = P2C(linearVelocityActor0); @@ -239,6 +241,7 @@ void SimulationEventCallback::onTrigger(PxTriggerPair* pairs, PxU32 count) auto trigger = static_cast(pair.triggerShape->userData); auto otherCollider = static_cast(pair.otherShape->userData); + ASSERT_LOW_LAYER(trigger && otherCollider); CollidersPair collidersPair(trigger, otherCollider); if (pair.status & PxPairFlag::eNOTIFY_TOUCH_LOST) @@ -256,3 +259,5 @@ void SimulationEventCallback::onAdvance(const PxRigidBody* const* bodyBuffer, co { // Not used } + +#endif diff --git a/Source/Engine/Physics/SimulationEventCallback.h b/Source/Engine/Physics/PhysX/SimulationEventCallbackPhysX.h similarity index 94% rename from Source/Engine/Physics/SimulationEventCallback.h rename to Source/Engine/Physics/PhysX/SimulationEventCallbackPhysX.h index c2705d255..c6f3019c5 100644 --- a/Source/Engine/Physics/SimulationEventCallback.h +++ b/Source/Engine/Physics/PhysX/SimulationEventCallbackPhysX.h @@ -1,10 +1,12 @@ -// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. +// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved. #pragma once +#if COMPILE_WITH_PHYSX + #include "Types.h" -#include "Collisions.h" -#include "Colliders/Collider.h" +#include "Engine/Physics/Collisions.h" +#include "Engine/Physics/Colliders/Collider.h" #include "Engine/Core/Types/Pair.h" #include "Engine/Core/Collections/Dictionary.h" #include @@ -12,7 +14,6 @@ /// /// Default implementation of the PxSimulationEventCallback to send physics events to the other engine services. /// -/// class SimulationEventCallback : public PxSimulationEventCallback { public: @@ -106,3 +107,5 @@ public: void onTrigger(PxTriggerPair* pairs, PxU32 count) override; void onAdvance(const PxRigidBody* const* bodyBuffer, const PxTransform* poseBuffer, const PxU32 count) override; }; + +#endif diff --git a/Source/Engine/Physics/PhysX/Types.h b/Source/Engine/Physics/PhysX/Types.h new file mode 100644 index 000000000..9d049e6d0 --- /dev/null +++ b/Source/Engine/Physics/PhysX/Types.h @@ -0,0 +1,174 @@ +// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved. + +#pragma once + +#if COMPILE_WITH_PHYSX + +#include "Engine/Physics/Types.h" +#include "Engine/Core/Math/Vector2.h" +#include "Engine/Core/Math/Vector3.h" +#include "Engine/Core/Math/Vector4.h" +#include "Engine/Core/Math/Quaternion.h" +#include "Engine/Core/Math/BoundingBox.h" +#include +#include +#include +#include +#include +#include +#include +#include + +namespace physx +{ + class PxScene; + class PxConvexMesh; + class PxTriangleMesh; + class PxCooking; + class PxPhysics; + class PxVec3; + class PxVec4; + class PxTransform; + class PxJoint; + class PxMat44; + class PxCpuDispatcher; + class PxGpuDispatcher; + class PxSimulationEventCallback; + struct PxActiveTransform; + class PxActor; + class PxRigidActor; + class PxRigidDynamic; + class PxRigidStatic; + class PxFoundation; + class PxShape; + class PxGeometry; + class PxGeometryHolder; + class PxProfileZoneManager; + class PxMaterial; + class PxPvd; + class PxBase; + class PxTolerancesScale; + class PxBaseTask; + class PxControllerManager; + class PxController; + class PxCapsuleController; + class PxQueryFilterCallback; + class PxControllerFilterCallback; + class PxHeightField; + struct PxFilterData; + struct PxRaycastHit; + struct PxSweepHit; +} + +using namespace physx; + +#define RELEASE_PHYSX(x) if(x) { (x)->release(); x = nullptr; } + +inline PxVec2& C2P(const Vector2& v) +{ + return *(PxVec2*)&v; +} + +inline PxVec3& C2P(const Vector3& v) +{ + return *(PxVec3*)&v; +} + +inline PxVec4& C2P(const Vector4& v) +{ + return *(PxVec4*)&v; +} + +inline PxQuat& C2P(const Quaternion& v) +{ + return *(PxQuat*)&v; +} + +inline PxBounds3& C2P(const BoundingBox& v) +{ + return *(PxBounds3*)&v; +} + +inline Vector2& P2C(const PxVec2& v) +{ + return *(Vector2*)&v; +} + +inline Vector3& P2C(const PxVec3& v) +{ + return *(Vector3*)&v; +} + +inline Vector4& P2C(const PxVec4& v) +{ + return *(Vector4*)&v; +} + +inline Quaternion& P2C(const PxQuat& v) +{ + return *(Quaternion*)&v; +} + +inline BoundingBox& P2C(const PxBounds3& v) +{ + return *(BoundingBox*)&v; +} + +inline Vector3 P2C(const PxExtendedVec3& v) +{ +#ifdef PX_BIG_WORLDS + return Vector3((float)v.x, (float)v.y, (float)v.z); +#else + return *(Vector3*)&v; +#endif +} + +inline float M2ToCm2(float v) +{ + return v * (100.0f * 100.0f); +} + +inline float Cm2ToM2(float v) +{ + return v / (100.0f * 100.0f); +} + +inline float KgPerM3ToKgPerCm3(float v) +{ + return v / (100.0f * 100.0f * 100.0f); +} + +inline float RpmToRadPerS(float v) +{ + return v * (PI / 30.0f); +} + +inline float RadPerSToRpm(float v) +{ + return v * (30.0f / PI); +} + +inline void P2C(const PxRaycastHit& hit, RayCastHit& result) +{ + result.Point = P2C(hit.position); + result.Normal = P2C(hit.normal); + result.Distance = hit.distance; + result.Collider = hit.shape ? static_cast(hit.shape->userData) : nullptr; + result.FaceIndex = hit.faceIndex; + result.UV.X = hit.u; + result.UV.Y = hit.v; +} + +inline void P2C(const PxSweepHit& hit, RayCastHit& result) +{ + result.Point = P2C(hit.position); + result.Normal = P2C(hit.normal); + result.Distance = hit.distance; + result.Collider = hit.shape ? static_cast(hit.shape->userData) : nullptr; + result.FaceIndex = hit.faceIndex; + result.UV = Vector2::Zero; +} + +extern PxShapeFlags GetShapeFlags(bool isTrigger, bool isEnabled); + +#endif diff --git a/Source/Engine/Physics/PhysicalMaterial.h b/Source/Engine/Physics/PhysicalMaterial.h index 66b8e5c1c..9e49a1da6 100644 --- a/Source/Engine/Physics/PhysicalMaterial.h +++ b/Source/Engine/Physics/PhysicalMaterial.h @@ -14,7 +14,7 @@ API_AUTO_SERIALIZATION(); DECLARE_SCRIPTING_TYPE_MINIMAL(PhysicalMaterial); private: - PxMaterial* _material; + void* _material; public: @@ -78,10 +78,10 @@ public: /// Gets the PhysX material. /// /// The native material object. - PxMaterial* GetPhysXMaterial(); + void* GetPhysicsMaterial(); /// - /// Updates the PhysX material (after any property change). + /// Updates the physics material (after any property change). /// - void UpdatePhysXMaterial(); + void UpdatePhysicsMaterial(); }; diff --git a/Source/Engine/Physics/Physics.Build.cs b/Source/Engine/Physics/Physics.Build.cs index 555b605ba..6363e3775 100644 --- a/Source/Engine/Physics/Physics.Build.cs +++ b/Source/Engine/Physics/Physics.Build.cs @@ -1,5 +1,6 @@ // Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. +using System; using Flax.Build; using Flax.Build.NativeCpp; @@ -13,16 +14,26 @@ public class Physics : EngineModule /// public static bool WithCooking = true; + /// + /// Physics system extension event to override for custom physics backend plugin. + /// + public static Action SetupPhysicsBackend = SetupPhysicsBackendPhysX; + /// public override void Setup(BuildOptions options) { base.Setup(options); - options.PrivateDependencies.Add("PhysX"); + SetupPhysicsBackend(this, options); if (WithCooking) { options.PublicDefinitions.Add("COMPILE_WITH_PHYSICS_COOKING"); } } + + private static void SetupPhysicsBackendPhysX(Physics physics, BuildOptions options) + { + options.PrivateDependencies.Add("PhysX"); + } } diff --git a/Source/Engine/Physics/Physics.Queries.cpp b/Source/Engine/Physics/Physics.Queries.cpp deleted file mode 100644 index b8c691c21..000000000 --- a/Source/Engine/Physics/Physics.Queries.cpp +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. - -#include "Physics.h" -#include "Utilities.h" -#include "CollisionData.h" -#include "PhysicsScene.h" -#include "Actors/PhysicsColliderActor.h" - -bool Physics::RayCast(const Vector3& origin, const Vector3& direction, const float maxDistance, uint32 layerMask, bool hitTriggers) -{ - return DefaultScene->RayCast(origin, direction, maxDistance, layerMask, hitTriggers); -} - -bool Physics::RayCast(const Vector3& origin, const Vector3& direction, RayCastHit& hitInfo, const float maxDistance, uint32 layerMask, bool hitTriggers) -{ - return DefaultScene->RayCast(origin, direction, hitInfo, maxDistance, layerMask, hitTriggers); -} - -bool Physics::RayCastAll(const Vector3& origin, const Vector3& direction, Array& results, const float maxDistance, uint32 layerMask, bool hitTriggers) -{ - return DefaultScene->RayCastAll(origin, direction, results, maxDistance, layerMask, hitTriggers); -} - -bool Physics::BoxCast(const Vector3& center, const Vector3& halfExtents, const Vector3& direction, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) -{ - return DefaultScene->BoxCast(center, halfExtents, direction, rotation, maxDistance, layerMask, hitTriggers); -} - -bool Physics::BoxCast(const Vector3& center, const Vector3& halfExtents, const Vector3& direction, RayCastHit& hitInfo, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) -{ - return DefaultScene->BoxCast(center, halfExtents, direction, hitInfo, rotation, maxDistance, layerMask, hitTriggers); -} - -bool Physics::BoxCastAll(const Vector3& center, const Vector3& halfExtents, const Vector3& direction, Array& results, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) -{ - return DefaultScene->BoxCastAll(center, halfExtents, direction, results, rotation, maxDistance, layerMask, hitTriggers); -} - -bool Physics::SphereCast(const Vector3& center, const float radius, const Vector3& direction, const float maxDistance, uint32 layerMask, bool hitTriggers) -{ - return DefaultScene->SphereCast(center, radius, direction, maxDistance, layerMask, hitTriggers); -} - -bool Physics::SphereCast(const Vector3& center, const float radius, const Vector3& direction, RayCastHit& hitInfo, const float maxDistance, uint32 layerMask, bool hitTriggers) -{ - return DefaultScene->SphereCast(center, radius, direction, hitInfo, maxDistance, layerMask, hitTriggers); -} - -bool Physics::SphereCastAll(const Vector3& center, const float radius, const Vector3& direction, Array& results, const float maxDistance, uint32 layerMask, bool hitTriggers) -{ - return DefaultScene->SphereCastAll(center, radius, direction, results, maxDistance, layerMask, hitTriggers); -} - -bool Physics::CapsuleCast(const Vector3& center, const float radius, const float height, const Vector3& direction, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) -{ - return DefaultScene->CapsuleCast(center, radius, height, direction, rotation, maxDistance, layerMask, hitTriggers); -} - -bool Physics::CapsuleCast(const Vector3& center, const float radius, const float height, const Vector3& direction, RayCastHit& hitInfo, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) -{ - return DefaultScene->CapsuleCast(center, radius, height, direction, hitInfo, rotation, maxDistance, layerMask, hitTriggers); -} - -bool Physics::CapsuleCastAll(const Vector3& center, const float radius, const float height, const Vector3& direction, Array& results, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) -{ - return DefaultScene->CapsuleCastAll(center, radius, height, direction, results, rotation, maxDistance, layerMask, hitTriggers); -} - -bool Physics::ConvexCast(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Vector3& direction, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) -{ - return DefaultScene->ConvexCast(center, convexMesh, scale, direction, rotation, maxDistance, layerMask, hitTriggers); -} - -bool Physics::ConvexCast(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Vector3& direction, RayCastHit& hitInfo, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) -{ - return DefaultScene->ConvexCast(center, convexMesh, scale, direction, hitInfo, rotation, maxDistance, layerMask, hitTriggers); -} - -bool Physics::ConvexCastAll(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Vector3& direction, Array& results, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) -{ - return DefaultScene->ConvexCastAll(center, convexMesh, scale, direction, results, rotation, maxDistance, layerMask, hitTriggers); -} - -bool Physics::CheckBox(const Vector3& center, const Vector3& halfExtents, const Quaternion& rotation, uint32 layerMask, bool hitTriggers) -{ - return DefaultScene->CheckBox(center, halfExtents, rotation, layerMask, hitTriggers); -} - -bool Physics::CheckSphere(const Vector3& center, const float radius, uint32 layerMask, bool hitTriggers) -{ - return DefaultScene->CheckSphere(center, radius, layerMask, hitTriggers); -} - -bool Physics::CheckCapsule(const Vector3& center, const float radius, const float height, const Quaternion& rotation, uint32 layerMask, bool hitTriggers) -{ - return DefaultScene->CheckCapsule(center, radius, height, rotation, layerMask, hitTriggers); -} - -bool Physics::CheckConvex(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Quaternion& rotation, uint32 layerMask, bool hitTriggers) -{ - return DefaultScene->CheckConvex(center, convexMesh, scale, rotation, layerMask, hitTriggers); -} - -bool Physics::OverlapBox(const Vector3& center, const Vector3& halfExtents, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers) -{ - return DefaultScene->OverlapBox(center, halfExtents, results, rotation, layerMask, hitTriggers); -} - -bool Physics::OverlapSphere(const Vector3& center, const float radius, Array& results, uint32 layerMask, bool hitTriggers) -{ - return DefaultScene->OverlapSphere(center, radius, results, layerMask, hitTriggers); -} - -bool Physics::OverlapCapsule(const Vector3& center, const float radius, const float height, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers) -{ - return DefaultScene->OverlapCapsule(center, radius, height, results, rotation, layerMask, hitTriggers); -} - -bool Physics::OverlapConvex(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers) -{ - return DefaultScene->OverlapConvex(center, convexMesh, scale, results, rotation, layerMask, hitTriggers); -} - -bool Physics::OverlapBox(const Vector3& center, const Vector3& halfExtents, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers) -{ - return DefaultScene->OverlapBox(center, halfExtents, results, rotation, layerMask, hitTriggers); -} - -bool Physics::OverlapSphere(const Vector3& center, const float radius, Array& results, uint32 layerMask, bool hitTriggers) -{ - return DefaultScene->OverlapSphere(center, radius, results, layerMask, hitTriggers); -} - -bool Physics::OverlapCapsule(const Vector3& center, const float radius, const float height, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers) -{ - return DefaultScene->OverlapCapsule(center, radius, height, results, rotation, layerMask, hitTriggers); -} - -bool Physics::OverlapConvex(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers) -{ - return DefaultScene->OverlapConvex(center, convexMesh, scale, results, rotation, layerMask, hitTriggers); -} diff --git a/Source/Engine/Physics/Physics.cpp b/Source/Engine/Physics/Physics.cpp index 6198accfc..7ef1d4910 100644 --- a/Source/Engine/Physics/Physics.cpp +++ b/Source/Engine/Physics/Physics.cpp @@ -2,94 +2,14 @@ #include "Physics.h" #include "PhysicsScene.h" +#include "PhysicsBackend.h" #include "PhysicalMaterial.h" - -#include "Engine/Core/Log.h" -#include "Engine/Platform/CPUInfo.h" #include "PhysicsSettings.h" -#include "Utilities.h" -#include "PhysicsStepper.h" - -#include "Engine/Level/Level.h" -#include "Engine/Profiler/ProfilerCPU.h" -#include "Engine/Core/Memory/Memory.h" -#include "Engine/Engine/EngineService.h" -#include "Engine/Serialization/Serialization.h" #include "Engine/Engine/Time.h" -#include -#if WITH_PVD -#include -#endif - -#define PHYSX_VEHICLE_DEBUG_TELEMETRY 0 - -#if PHYSX_VEHICLE_DEBUG_TELEMETRY -#include "Engine/Core/Utilities.h" -#endif - -class PhysXAllocator : public PxAllocatorCallback -{ -public: - - void* allocate(size_t size, const char* typeName, const char* filename, int line) override - { - return Allocator::Allocate(size, 16); - } - - void deallocate(void* ptr) override - { - Allocator::Free(ptr); - } -}; - -class PhysXError : public PxErrorCallback -{ -public: - - PhysXError() - { - } - - ~PhysXError() - { - } - -public: - - // [PxErrorCallback] - void reportError(PxErrorCode::Enum code, const char* message, const char* file, int line) override - { - LOG(Error, "PhysX Error! Code: {0}.\n{1}\nSource: {2} : {3}.", static_cast(code), String(message), String(file), line); - } -}; - -PxPhysics* CPhysX = nullptr; -#if WITH_PVD -PxPvd* CPVD = nullptr; -#endif - -namespace -{ - PhysXAllocator PhysXAllocatorCallback; - PhysXError PhysXErrorCallback; - PxTolerancesScale ToleranceScale; - bool _queriesHitTriggers = true; - PhysicsCombineMode _frictionCombineMode = PhysicsCombineMode::Average; - PhysicsCombineMode _restitutionCombineMode = PhysicsCombineMode::Average; - PxFoundation* _foundation = nullptr; -#if COMPILE_WITH_PHYSICS_COOKING - PxCooking* Cooking = nullptr; -#endif - PxMaterial* DefaultMaterial = nullptr; -#if WITH_VEHICLE - bool VehicleSDKInitialized = false; -#endif - - void reset() - { - Physics::Scenes.Resize(1); - } -} +#include "Engine/Engine/EngineService.h" +#include "Engine/Profiler/ProfilerCPU.h" +#include "Engine/Serialization/Serialization.h" +#include "Engine/Threading/Threading.h" PhysicsScene* Physics::DefaultScene = nullptr; Array Physics::Scenes; @@ -98,7 +18,6 @@ uint32 Physics::LayerMasks[32]; class PhysicsService : public EngineService { public: - PhysicsService() : EngineService(TEXT("Physics"), 0) { @@ -113,74 +32,14 @@ public: PhysicsService PhysicsServiceInstance; -PxShapeFlags GetShapeFlags(bool isTrigger, bool isEnabled) -{ -#if WITH_PVD - PxShapeFlags flags = PxShapeFlag::eVISUALIZATION; -#else - PxShapeFlags flags = static_cast(0); -#endif - - if (isEnabled) - { - if (isTrigger) - { - flags |= PxShapeFlag::eTRIGGER_SHAPE; - if (_queriesHitTriggers) - flags |= PxShapeFlag::eSCENE_QUERY_SHAPE; - } - else - { - flags = PxShapeFlag::eSIMULATION_SHAPE | PxShapeFlag::eSCENE_QUERY_SHAPE; - } - } - - return flags; -} - -#if WITH_VEHICLE - -void InitVehicleSDK() -{ - if (!VehicleSDKInitialized) - { - VehicleSDKInitialized = true; - PxInitVehicleSDK(*CPhysX); - PxVehicleSetBasisVectors(PxVec3(0, 1, 0), PxVec3(1, 0, 0)); - PxVehicleSetUpdateMode(PxVehicleUpdateMode::eVELOCITY_CHANGE); - } -} - -#endif - void PhysicsSettings::Apply() { Time::_physicsMaxDeltaTime = MaxDeltaTime; - _queriesHitTriggers = QueriesHitTriggers; - _frictionCombineMode = FrictionCombineMode; - _restitutionCombineMode = RestitutionCombineMode; Platform::MemoryCopy(Physics::LayerMasks, LayerMasks, sizeof(LayerMasks)); Physics::SetGravity(DefaultGravity); Physics::SetBounceThresholdVelocity(BounceThresholdVelocity); Physics::SetEnableCCD(!DisableCCD); - - // TODO: setting eADAPTIVE_FORCE requires PxScene setup (physx docs: This flag is not mutable, and must be set in PxSceneDesc at scene creation.) - // TODO: update all shapes filter data - // TODO: update all shapes flags - - /* - { - get all actors and then: - - const PxU32 numShapes = actor->getNbShapes(); - PxShape** shapes = (PxShape**)SAMPLE_ALLOC(sizeof(PxShape*)*numShapes); - actor->getShapes(shapes, numShapes); - for (PxU32 i = 0; i < numShapes; i++) - { - .. - } - SAMPLE_FREE(shapes); - }*/ + PhysicsBackend::ApplySettings(*this); } PhysicsSettings::PhysicsSettings() @@ -225,193 +84,77 @@ PhysicalMaterial::PhysicalMaterial() PhysicalMaterial::~PhysicalMaterial() { if (_material) - { - for (auto scene : Physics::Scenes) - scene->RemoveMaterial(_material); - } -} - -PxMaterial* PhysicalMaterial::GetPhysXMaterial() -{ - if (_material == nullptr && CPhysX) - { - _material = CPhysX->createMaterial(Friction, Friction, Restitution); - _material->userData = this; - - const PhysicsCombineMode useFrictionCombineMode = OverrideFrictionCombineMode ? FrictionCombineMode : _frictionCombineMode; - _material->setFrictionCombineMode(static_cast(useFrictionCombineMode)); - - const PhysicsCombineMode useRestitutionCombineMode = OverrideRestitutionCombineMode ? RestitutionCombineMode : _restitutionCombineMode; - _material->setRestitutionCombineMode(static_cast(useRestitutionCombineMode)); - } - - return _material; -} - -void PhysicalMaterial::UpdatePhysXMaterial() -{ - if (_material != nullptr) - { - _material->setStaticFriction(Friction); - _material->setDynamicFriction(Friction); - - const PhysicsCombineMode useFrictionCombineMode = OverrideFrictionCombineMode ? FrictionCombineMode : _frictionCombineMode; - _material->setFrictionCombineMode(static_cast(useFrictionCombineMode)); - - _material->setRestitution(Restitution); - const PhysicsCombineMode useRestitutionCombineMode = OverrideRestitutionCombineMode ? RestitutionCombineMode : _restitutionCombineMode; - _material->setRestitutionCombineMode(static_cast(useRestitutionCombineMode)); - } + PhysicsBackend::DestroyObject(_material); } bool PhysicsService::Init() { -#define CHECK_INIT(value, msg) if(!value) { LOG(Error, msg); return true; } - - auto& settings = *PhysicsSettings::Get(); - - // Send info - LOG(Info, "Setup NVIDIA PhysX {0}.{1}.{2}", PX_PHYSICS_VERSION_MAJOR, PX_PHYSICS_VERSION_MINOR, PX_PHYSICS_VERSION_BUGFIX); - - // Init PhysX foundation object - _foundation = PxCreateFoundation(PX_PHYSICS_VERSION, PhysXAllocatorCallback, PhysXErrorCallback); - CHECK_INIT(_foundation, "PxCreateFoundation failed!"); - - // Config - ToleranceScale.length = 100; - ToleranceScale.speed = 981; - - PxPvd* pvd = nullptr; -#if WITH_PVD - { - // Init PVD - pvd = PxCreatePvd(*_foundation); - PxPvdTransport* transport = PxDefaultPvdSocketTransportCreate("127.0.0.1", 5425, 100); - //PxPvdTransport* transport = PxDefaultPvdFileTransportCreate("D:\\physx_sample.pxd2"); - if (transport) - { - const bool isConnected = pvd->connect(*transport, PxPvdInstrumentationFlag::eALL); - if (isConnected) - { - LOG(Info, "Connected to PhysX Visual Debugger (PVD)"); - } - } - CPVD = pvd; - } - -#endif - - // Init PhysX - CPhysX = PxCreatePhysics(PX_PHYSICS_VERSION, *_foundation, ToleranceScale, false, pvd); - CHECK_INIT(CPhysX, "PxCreatePhysics failed!"); - - // Init extensions - const bool extensionsInit = PxInitExtensions(*CPhysX, pvd); - CHECK_INIT(extensionsInit, "PxInitExtensions failed!"); - - // Init collision cooking -#if COMPILE_WITH_PHYSICS_COOKING -#if !USE_EDITOR - if (settings.SupportCookingAtRuntime) -#endif - { - PxCookingParams cookingParams(ToleranceScale); - cookingParams.meshWeldTolerance = 0.1f; // Weld to 1mm precision - cookingParams.meshPreprocessParams = PxMeshPreprocessingFlags(PxMeshPreprocessingFlag::eWELD_VERTICES); - Cooking = PxCreateCooking(PX_PHYSICS_VERSION, *_foundation, cookingParams); - CHECK_INIT(Cooking, "PxCreateCooking failed!"); - } -#endif + // Initialize backend + if (PhysicsBackend::Init()) + return true; + // Create default scene Physics::DefaultScene = Physics::FindOrCreateScene(TEXT("Default")); - - // Create default resources - DefaultMaterial = CPhysX->createMaterial(0.7f, 0.7f, 0.3f); - - return false; - -#undef CHECK_INIT + return Physics::DefaultScene == nullptr; } void PhysicsService::LateUpdate() { - for (auto scene : Physics::Scenes) - scene->FlushRequests(); + Physics::FlushRequests(); } void PhysicsService::Dispose() { // Ensure to finish (wait for simulation end) - - for (auto scene : Physics::Scenes) + for (PhysicsScene* scene : Physics::Scenes) { scene->CollectResults(); - - if (CPhysX) - scene->FlushRequests(); } -#if WITH_VEHICLE - if (VehicleSDKInitialized) + // Dispose scenes + for (PhysicsScene* scene : Physics::Scenes) { - VehicleSDKInitialized = false; - PxCloseVehicleSDK(); + Delete(scene); } -#endif - - // Cleanup - RELEASE_PHYSX(DefaultMaterial); - Physics::Scenes.Resize(0); Physics::DefaultScene = nullptr; - // Remove all scenes still registered - const int32 numScenes = CPhysX ? CPhysX->getNbScenes() : 0; - if (numScenes) - { - Array PScenes; - PScenes.Resize(numScenes); - PScenes.SetAll(nullptr); - CPhysX->getScenes(PScenes.Get(), sizeof(PxScene*) * numScenes); + // Dispose backend + PhysicsBackend::Shutdown(); +} - for (int32 i = 0; i < numScenes; i++) +PhysicsScene* Physics::FindOrCreateScene(const StringView& name) +{ + auto scene = FindScene(name); + if (scene == nullptr) + { + const auto& settings = *PhysicsSettings::Get(); + scene = New(); + if (scene->Init(name, settings)) { - if (PScenes[i]) - { - PScenes[i]->release(); - } + Delete(scene); + scene = nullptr; } + else + Scenes.Add(scene); + return scene; } + return scene; +} -#if COMPILE_WITH_PHYSICS_COOKING - RELEASE_PHYSX(Cooking); -#endif - - if (CPhysX) +PhysicsScene* Physics::FindScene(const StringView& name) +{ + for (PhysicsScene* scene : Scenes) { - PxCloseExtensions(); + if (scene->GetName() == name) + return scene; } - - RELEASE_PHYSX(CPhysX); -#if WITH_PVD - RELEASE_PHYSX(CPVD); -#endif - RELEASE_PHYSX(_foundation); + return nullptr; } -PxPhysics* Physics::GetPhysics() +bool Physics::GetAutoSimulation() { - return CPhysX; -} - -PxCooking* Physics::GetCooking() -{ - return Cooking; -} - -PxTolerancesScale* Physics::GetTolerancesScale() -{ - return &ToleranceScale; + return !DefaultScene || DefaultScene->GetAutoSimulation(); } Vector3 Physics::GetGravity() @@ -449,13 +192,7 @@ void Physics::SetBounceThresholdVelocity(const float value) void Physics::Simulate(float dt) { - if (DefaultScene) - DefaultScene->Simulate(dt); -} - -void Physics::SimulateAll(float dt) -{ - for (auto scene : Scenes) + for (PhysicsScene* scene : Scenes) { if (scene->GetAutoSimulation()) scene->Simulate(dt); @@ -468,67 +205,373 @@ void Physics::CollectResults() DefaultScene->CollectResults(); } -void Physics::CollectResultsAll() -{ - for (auto scene : Scenes) - scene->CollectResults(); -} - bool Physics::IsDuringSimulation() { - if (DefaultScene) - return DefaultScene->IsDuringSimulation(); - - return false; + return DefaultScene && DefaultScene->IsDuringSimulation(); } -PxMaterial* Physics::GetDefaultMaterial() +void Physics::FlushRequests() { - return DefaultMaterial; + PROFILE_CPU_NAMED("Physics.FlushRequests"); + for (PhysicsScene* scene : Scenes) + PhysicsBackend::FlushRequests(scene->GetPhysicsScene()); + PhysicsBackend::FlushRequests(); } -bool Physics::GetAutoSimulation() +bool Physics::RayCast(const Vector3& origin, const Vector3& direction, const float maxDistance, uint32 layerMask, bool hitTriggers) { - if (DefaultScene) - return DefaultScene->GetAutoSimulation(); - - return false; + return DefaultScene->RayCast(origin, direction, maxDistance, layerMask, hitTriggers); } -void Physics::FlushRequestsAll() +bool Physics::RayCast(const Vector3& origin, const Vector3& direction, RayCastHit& hitInfo, const float maxDistance, uint32 layerMask, bool hitTriggers) { - for (auto scene : Scenes) - scene->FlushRequests(); + return DefaultScene->RayCast(origin, direction, hitInfo, maxDistance, layerMask, hitTriggers); } -void Physics::RemoveJoint(Joint* joint) +bool Physics::RayCastAll(const Vector3& origin, const Vector3& direction, Array& results, const float maxDistance, uint32 layerMask, bool hitTriggers) { - for (auto scene : Scenes) - scene->RemoveJoint(joint); + return DefaultScene->RayCastAll(origin, direction, results, maxDistance, layerMask, hitTriggers); } -PhysicsScene* Physics::FindOrCreateScene(const String& name) +bool Physics::BoxCast(const Vector3& center, const Vector3& halfExtents, const Vector3& direction, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) { - auto scene = FindScene(name); + return DefaultScene->BoxCast(center, halfExtents, direction, rotation, maxDistance, layerMask, hitTriggers); +} - if (scene == nullptr) +bool Physics::BoxCast(const Vector3& center, const Vector3& halfExtents, const Vector3& direction, RayCastHit& hitInfo, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) +{ + return DefaultScene->BoxCast(center, halfExtents, direction, hitInfo, rotation, maxDistance, layerMask, hitTriggers); +} + +bool Physics::BoxCastAll(const Vector3& center, const Vector3& halfExtents, const Vector3& direction, Array& results, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) +{ + return DefaultScene->BoxCastAll(center, halfExtents, direction, results, rotation, maxDistance, layerMask, hitTriggers); +} + +bool Physics::SphereCast(const Vector3& center, const float radius, const Vector3& direction, const float maxDistance, uint32 layerMask, bool hitTriggers) +{ + return DefaultScene->SphereCast(center, radius, direction, maxDistance, layerMask, hitTriggers); +} + +bool Physics::SphereCast(const Vector3& center, const float radius, const Vector3& direction, RayCastHit& hitInfo, const float maxDistance, uint32 layerMask, bool hitTriggers) +{ + return DefaultScene->SphereCast(center, radius, direction, hitInfo, maxDistance, layerMask, hitTriggers); +} + +bool Physics::SphereCastAll(const Vector3& center, const float radius, const Vector3& direction, Array& results, const float maxDistance, uint32 layerMask, bool hitTriggers) +{ + return DefaultScene->SphereCastAll(center, radius, direction, results, maxDistance, layerMask, hitTriggers); +} + +bool Physics::CapsuleCast(const Vector3& center, const float radius, const float height, const Vector3& direction, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) +{ + return DefaultScene->CapsuleCast(center, radius, height, direction, rotation, maxDistance, layerMask, hitTriggers); +} + +bool Physics::CapsuleCast(const Vector3& center, const float radius, const float height, const Vector3& direction, RayCastHit& hitInfo, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) +{ + return DefaultScene->CapsuleCast(center, radius, height, direction, hitInfo, rotation, maxDistance, layerMask, hitTriggers); +} + +bool Physics::CapsuleCastAll(const Vector3& center, const float radius, const float height, const Vector3& direction, Array& results, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) +{ + return DefaultScene->CapsuleCastAll(center, radius, height, direction, results, rotation, maxDistance, layerMask, hitTriggers); +} + +bool Physics::ConvexCast(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Vector3& direction, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) +{ + return DefaultScene->ConvexCast(center, convexMesh, scale, direction, rotation, maxDistance, layerMask, hitTriggers); +} + +bool Physics::ConvexCast(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Vector3& direction, RayCastHit& hitInfo, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) +{ + return DefaultScene->ConvexCast(center, convexMesh, scale, direction, hitInfo, rotation, maxDistance, layerMask, hitTriggers); +} + +bool Physics::ConvexCastAll(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Vector3& direction, Array& results, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) +{ + return DefaultScene->ConvexCastAll(center, convexMesh, scale, direction, results, rotation, maxDistance, layerMask, hitTriggers); +} + +bool Physics::CheckBox(const Vector3& center, const Vector3& halfExtents, const Quaternion& rotation, uint32 layerMask, bool hitTriggers) +{ + return DefaultScene->CheckBox(center, halfExtents, rotation, layerMask, hitTriggers); +} + +bool Physics::CheckSphere(const Vector3& center, const float radius, uint32 layerMask, bool hitTriggers) +{ + return DefaultScene->CheckSphere(center, radius, layerMask, hitTriggers); +} + +bool Physics::CheckCapsule(const Vector3& center, const float radius, const float height, const Quaternion& rotation, uint32 layerMask, bool hitTriggers) +{ + return DefaultScene->CheckCapsule(center, radius, height, rotation, layerMask, hitTriggers); +} + +bool Physics::CheckConvex(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Quaternion& rotation, uint32 layerMask, bool hitTriggers) +{ + return DefaultScene->CheckConvex(center, convexMesh, scale, rotation, layerMask, hitTriggers); +} + +bool Physics::OverlapBox(const Vector3& center, const Vector3& halfExtents, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers) +{ + return DefaultScene->OverlapBox(center, halfExtents, results, rotation, layerMask, hitTriggers); +} + +bool Physics::OverlapSphere(const Vector3& center, const float radius, Array& results, uint32 layerMask, bool hitTriggers) +{ + return DefaultScene->OverlapSphere(center, radius, results, layerMask, hitTriggers); +} + +bool Physics::OverlapCapsule(const Vector3& center, const float radius, const float height, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers) +{ + return DefaultScene->OverlapCapsule(center, radius, height, results, rotation, layerMask, hitTriggers); +} + +bool Physics::OverlapConvex(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers) +{ + return DefaultScene->OverlapConvex(center, convexMesh, scale, results, rotation, layerMask, hitTriggers); +} + +bool Physics::OverlapBox(const Vector3& center, const Vector3& halfExtents, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers) +{ + return DefaultScene->OverlapBox(center, halfExtents, results, rotation, layerMask, hitTriggers); +} + +bool Physics::OverlapSphere(const Vector3& center, const float radius, Array& results, uint32 layerMask, bool hitTriggers) +{ + return DefaultScene->OverlapSphere(center, radius, results, layerMask, hitTriggers); +} + +bool Physics::OverlapCapsule(const Vector3& center, const float radius, const float height, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers) +{ + return DefaultScene->OverlapCapsule(center, radius, height, results, rotation, layerMask, hitTriggers); +} + +bool Physics::OverlapConvex(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers) +{ + return DefaultScene->OverlapConvex(center, convexMesh, scale, results, rotation, layerMask, hitTriggers); +} + +PhysicsScene::PhysicsScene(const SpawnParams& params) + : ScriptingObject(params) +{ +} + +PhysicsScene::~PhysicsScene() +{ + if (_scene) + PhysicsBackend::DestroyScene(_scene); +} + +String PhysicsScene::GetName() const +{ + return _name; +} + +bool PhysicsScene::GetAutoSimulation() const +{ + return _autoSimulation; +} + +void PhysicsScene::SetAutoSimulation(bool value) +{ + _autoSimulation = value; +} + +void PhysicsScene::SetGravity(const Vector3& value) +{ + PhysicsBackend::SetSceneGravity(_scene, value); +} + +Vector3 PhysicsScene::GetGravity() +{ + return PhysicsBackend::GetSceneGravity(_scene); +} + +bool PhysicsScene::GetEnableCCD() +{ + return PhysicsBackend::GetSceneEnableCCD(_scene); +} + +void PhysicsScene::SetEnableCCD(bool value) +{ + PhysicsBackend::SetSceneEnableCCD(_scene, value); +} + +float PhysicsScene::GetBounceThresholdVelocity() +{ + return PhysicsBackend::GetSceneBounceThresholdVelocity(_scene); +} + +void PhysicsScene::SetBounceThresholdVelocity(float value) +{ + PhysicsBackend::SetSceneBounceThresholdVelocity(_scene, value); +} + +bool PhysicsScene::Init(const StringView& name, const PhysicsSettings& settings) +{ + if (_scene) { - auto& settings = *PhysicsSettings::Get(); - - scene = New(name, settings); - Scenes.Add(scene); + PhysicsBackend::DestroyScene(_scene); } - - return scene; + _name = name; + _scene = PhysicsBackend::CreateScene(settings); + return _scene == nullptr; } -PhysicsScene* Physics::FindScene(const String& name) +void PhysicsScene::Simulate(float dt) { - for (auto scene : Scenes) - { - if (scene->GetName() == name) - return scene; - } - - return nullptr; + ASSERT(IsInMainThread() && !_isDuringSimulation); + _isDuringSimulation = true; + PhysicsBackend::StartSimulateScene(_scene, dt); +} + +bool PhysicsScene::IsDuringSimulation() const +{ + return _isDuringSimulation; +} + +void PhysicsScene::CollectResults() +{ + if (!_isDuringSimulation) + return; + ASSERT(IsInMainThread()); + PhysicsBackend::EndSimulateScene(_scene); + _isDuringSimulation = false; +} + +bool PhysicsScene::RayCast(const Vector3& origin, const Vector3& direction, const float maxDistance, uint32 layerMask, bool hitTriggers) +{ + return PhysicsBackend::RayCast(_scene, origin, direction, maxDistance, layerMask, hitTriggers); +} + +bool PhysicsScene::RayCast(const Vector3& origin, const Vector3& direction, RayCastHit& hitInfo, const float maxDistance, uint32 layerMask, bool hitTriggers) +{ + return PhysicsBackend::RayCast(_scene, origin, direction, hitInfo, maxDistance, layerMask, hitTriggers); +} + +bool PhysicsScene::RayCastAll(const Vector3& origin, const Vector3& direction, Array& results, const float maxDistance, uint32 layerMask, bool hitTriggers) +{ + return PhysicsBackend::RayCastAll(_scene, origin, direction, results, maxDistance, layerMask, hitTriggers); +} + +bool PhysicsScene::BoxCast(const Vector3& center, const Vector3& halfExtents, const Vector3& direction, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) +{ + return PhysicsBackend::BoxCast(_scene, center, halfExtents, direction, rotation, maxDistance, layerMask, hitTriggers); +} + +bool PhysicsScene::BoxCast(const Vector3& center, const Vector3& halfExtents, const Vector3& direction, RayCastHit& hitInfo, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) +{ + return PhysicsBackend::BoxCast(_scene, center, halfExtents, direction, hitInfo, rotation, maxDistance, layerMask, hitTriggers); +} + +bool PhysicsScene::BoxCastAll(const Vector3& center, const Vector3& halfExtents, const Vector3& direction, Array& results, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) +{ + return PhysicsBackend::BoxCastAll(_scene, center, halfExtents, direction, results, rotation, maxDistance, layerMask, hitTriggers); +} + +bool PhysicsScene::SphereCast(const Vector3& center, const float radius, const Vector3& direction, const float maxDistance, uint32 layerMask, bool hitTriggers) +{ + return PhysicsBackend::SphereCast(_scene, center, radius, direction, maxDistance, layerMask, hitTriggers); +} + +bool PhysicsScene::SphereCast(const Vector3& center, const float radius, const Vector3& direction, RayCastHit& hitInfo, const float maxDistance, uint32 layerMask, bool hitTriggers) +{ + return PhysicsBackend::SphereCast(_scene, center, radius, direction, hitInfo, maxDistance, layerMask, hitTriggers); +} + +bool PhysicsScene::SphereCastAll(const Vector3& center, const float radius, const Vector3& direction, Array& results, const float maxDistance, uint32 layerMask, bool hitTriggers) +{ + return PhysicsBackend::SphereCastAll(_scene, center, radius, direction, results, maxDistance, layerMask, hitTriggers); +} + +bool PhysicsScene::CapsuleCast(const Vector3& center, const float radius, const float height, const Vector3& direction, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) +{ + return PhysicsBackend::CapsuleCast(_scene, center, radius, height, direction, rotation, maxDistance, layerMask, hitTriggers); +} + +bool PhysicsScene::CapsuleCast(const Vector3& center, const float radius, const float height, const Vector3& direction, RayCastHit& hitInfo, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) +{ + return PhysicsBackend::CapsuleCast(_scene, center, radius, height, direction, hitInfo, rotation, maxDistance, layerMask, hitTriggers); +} + +bool PhysicsScene::CapsuleCastAll(const Vector3& center, const float radius, const float height, const Vector3& direction, Array& results, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) +{ + return PhysicsBackend::CapsuleCastAll(_scene, center, radius, height, direction, results, rotation, maxDistance, layerMask, hitTriggers); +} + +bool PhysicsScene::ConvexCast(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Vector3& direction, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) +{ + return PhysicsBackend::ConvexCast(_scene, center, convexMesh, scale, direction, rotation, maxDistance, layerMask, hitTriggers); +} + +bool PhysicsScene::ConvexCast(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Vector3& direction, RayCastHit& hitInfo, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) +{ + return PhysicsBackend::ConvexCast(_scene, center, convexMesh, scale, direction, hitInfo, rotation, maxDistance, layerMask, hitTriggers); +} + +bool PhysicsScene::ConvexCastAll(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Vector3& direction, Array& results, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) +{ + return PhysicsBackend::ConvexCastAll(_scene, center, convexMesh, scale, direction, results, rotation, maxDistance, layerMask, hitTriggers); +} + +bool PhysicsScene::CheckBox(const Vector3& center, const Vector3& halfExtents, const Quaternion& rotation, uint32 layerMask, bool hitTriggers) +{ + return PhysicsBackend::CheckBox(_scene, center, halfExtents, rotation, layerMask, hitTriggers); +} + +bool PhysicsScene::CheckSphere(const Vector3& center, const float radius, uint32 layerMask, bool hitTriggers) +{ + return PhysicsBackend::CheckSphere(_scene, center, radius, layerMask, hitTriggers); +} + +bool PhysicsScene::CheckCapsule(const Vector3& center, const float radius, const float height, const Quaternion& rotation, uint32 layerMask, bool hitTriggers) +{ + return PhysicsBackend::CheckCapsule(_scene, center, radius, height, rotation, layerMask, hitTriggers); +} + +bool PhysicsScene::CheckConvex(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Quaternion& rotation, uint32 layerMask, bool hitTriggers) +{ + return PhysicsBackend::CheckConvex(_scene, center, convexMesh, scale, rotation, layerMask, hitTriggers); +} + +bool PhysicsScene::OverlapBox(const Vector3& center, const Vector3& halfExtents, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers) +{ + return PhysicsBackend::OverlapBox(_scene, center, halfExtents, results, rotation, layerMask, hitTriggers); +} + +bool PhysicsScene::OverlapSphere(const Vector3& center, const float radius, Array& results, uint32 layerMask, bool hitTriggers) +{ + return PhysicsBackend::OverlapSphere(_scene, center, radius, results, layerMask, hitTriggers); +} + +bool PhysicsScene::OverlapCapsule(const Vector3& center, const float radius, const float height, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers) +{ + return PhysicsBackend::OverlapCapsule(_scene, center, radius, height, results, rotation, layerMask, hitTriggers); +} + +bool PhysicsScene::OverlapConvex(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers) +{ + return PhysicsBackend::OverlapConvex(_scene, center, convexMesh, scale, results, rotation, layerMask, hitTriggers); +} + +bool PhysicsScene::OverlapBox(const Vector3& center, const Vector3& halfExtents, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers) +{ + return PhysicsBackend::OverlapBox(_scene, center, halfExtents, results, rotation, layerMask, hitTriggers); +} + +bool PhysicsScene::OverlapSphere(const Vector3& center, const float radius, Array& results, uint32 layerMask, bool hitTriggers) +{ + return PhysicsBackend::OverlapSphere(_scene, center, radius, results, layerMask, hitTriggers); +} + +bool PhysicsScene::OverlapCapsule(const Vector3& center, const float radius, const float height, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers) +{ + return PhysicsBackend::OverlapCapsule(_scene, center, radius, height, results, rotation, layerMask, hitTriggers); +} + +bool PhysicsScene::OverlapConvex(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers) +{ + return PhysicsBackend::OverlapConvex(_scene, center, convexMesh, scale, results, rotation, layerMask, hitTriggers); } diff --git a/Source/Engine/Physics/Physics.h b/Source/Engine/Physics/Physics.h index f2317288a..01b8d6e4b 100644 --- a/Source/Engine/Physics/Physics.h +++ b/Source/Engine/Physics/Physics.h @@ -2,125 +2,35 @@ #pragma once -#include "Engine/Core/Math/Vector2.h" -#include "Engine/Core/Math/Vector3.h" #include "Engine/Core/Math/Quaternion.h" -#include "Engine/Scripting/ScriptingType.h" #include "Types.h" -class PhysicsColliderActor; -class PhysicsScene; -class Joint; -class Collider; -class CollisionData; - -/// -/// Raycast hit result data. -/// -API_STRUCT() struct RayCastHit -{ -DECLARE_SCRIPTING_TYPE_NO_SPAWN(RayCastHit); - - /// - /// The collider that was hit. - /// - API_FIELD() PhysicsColliderActor* Collider = nullptr; - - /// - /// The normal of the surface the ray hit. - /// - API_FIELD() Vector3 Normal; - - /// - /// The distance from the ray's origin to the hit location. - /// - API_FIELD() float Distance; - - /// - /// The point in the world space where ray hit the collider. - /// - API_FIELD() Vector3 Point; - - /// - /// The index of the face that was hit. Valid only for convex mesh (polygon index), triangle mesh (triangle index) and height field (triangle index). - /// - /// - API_FIELD() uint32 FaceIndex; - - /// - /// The barycentric coordinates of hit triangle. Valid only for triangle mesh and height field. - /// - API_FIELD() Vector2 UV; - -public: - - /// - /// Gathers the data from the specified hit (PhysX). - /// - /// The hit. - void Gather(const PxRaycastHit& hit); - - /// - /// Gathers the data from the specified hit (PhysX). - /// - /// The hit. - void Gather(const PxSweepHit& hit); -}; - /// /// Physics simulation system. /// API_CLASS(Static) class FLAXENGINE_API Physics { -DECLARE_SCRIPTING_TYPE_NO_SPAWN(Physics); + DECLARE_SCRIPTING_TYPE_NO_SPAWN(Physics); - /// - /// Gets the master physics object. - /// - static PxPhysics* GetPhysics(); - -#if COMPILE_WITH_PHYSICS_COOKING - - /// - /// Gets physics cooking object - /// - static PxCooking* GetCooking(); - -#endif - - /// - /// Gets the physics tolerances scale. - /// - static PxTolerancesScale* GetTolerancesScale(); - - /// - /// Gets the default physical material. - /// - static PxMaterial* GetDefaultMaterial(); - -public: - /// /// The default physics scene. /// - API_FIELD(ReadOnly) - static PhysicsScene* DefaultScene; + API_FIELD(ReadOnly) static PhysicsScene* DefaultScene; /// /// List with all physics scenes (readonly). /// - API_FIELD(ReadOnly) - static Array Scenes; + API_FIELD(ReadOnly) static Array Scenes; /// /// Finds an existing or creates it if it does not exist. /// - API_FUNCTION() static PhysicsScene* FindOrCreateScene(const String& name); + API_FUNCTION() static PhysicsScene* FindOrCreateScene(const StringView& name); /// - ///Finds an existing scene. + /// Finds an existing scene. /// - API_FUNCTION() static PhysicsScene* FindScene(const String& name); + API_FUNCTION() static PhysicsScene* FindScene(const StringView& name); public: /// @@ -162,9 +72,29 @@ public: /// The collision layers masks. Used to define layer-based collision detection. /// static uint32 LayerMasks[32]; +public: + /// + /// Called during main engine loop to start physic simulation. Use CollectResults after. + /// + /// The delta time (in seconds). + API_FUNCTION() static void Simulate(float dt); + + /// + /// Called during main engine loop to collect physic simulation results and apply them as well as fire collision events. + /// + API_FUNCTION() static void CollectResults(); + + /// + /// Checks if physical simulation is running. + /// + API_PROPERTY() static bool IsDuringSimulation(); + + /// + /// Flushes any latent physics actions (eg. object destroy, actor add/remove to the scene, etc.). + /// + API_FUNCTION() static void FlushRequests(); public: - /// /// Performs a raycast against objects in the scene. /// @@ -509,84 +439,4 @@ public: /// If set to true triggers will be hit, otherwise will skip them. /// True if convex mesh overlaps any matching object, otherwise false. API_FUNCTION() static bool OverlapConvex(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, API_PARAM(Out) Array& results, const Quaternion& rotation = Quaternion::Identity, uint32 layerMask = MAX_uint32, bool hitTriggers = true); - -public: - - /// - /// Called during main engine loop to start physic simulation. Use CollectResults after. - /// - /// The delta time (in seconds). - API_FUNCTION() static void Simulate(float dt); - - /// - /// Called during main engine loop to start physic simulation on all registered scenes. - /// - /// The delta time (in seconds). - static void SimulateAll(float dt); - - /// - /// Called during main engine loop to collect physic simulation results and apply them as well as fire collision events. - /// - API_FUNCTION() static void CollectResults(); - - /// - /// Called during main engine loop to collect physic simulation results on all registered scenes and apply them as well as fire collision events. - /// - static void CollectResultsAll(); - - /// - /// Checks if physical simulation is running - /// - /// True if simulation is active, otherwise false - API_PROPERTY() static bool IsDuringSimulation(); - -public: - - /// - /// Flushes the async requests to add/remove actors, remove materials, etc.. - /// - static void FlushRequestsAll(); - - /// - /// Removes the material (using safe async request). - /// - /// The material. - static void RemoveMaterial(PxMaterial* material); - - /// - /// Removes the physX object via calling release() on it (using safe async request). - /// - /// The obj. - static void RemoveObject(PxBase* obj); - - /// - /// Adds the actor (using safe async request). - /// - /// The actor. - static void AddActor(PxActor* actor); - - /// - /// Adds the actor (using safe async request). - /// - /// The actor. - /// If set to true will put actor to sleep after spawning. - static void AddActor(PxRigidDynamic* actor, bool putToSleep = false); - - /// - /// Removes the actor (using safe async request). - /// - /// The actor. - static void RemoveActor(PxActor* actor); - - /// - /// Marks that collider has been removed (all collision events should be cleared to prevent leaks of using removed object). - /// - /// The collider. - static void RemoveCollider(PhysicsColliderActor* collider); - - /// - /// Marks that joint has been removed (all collision events should be cleared to prevent leaks of using removed object). - /// - /// The joint. - static void RemoveJoint(Joint* joint); }; diff --git a/Source/Engine/Physics/PhysicsBackend.h b/Source/Engine/Physics/PhysicsBackend.h new file mode 100644 index 000000000..1e9993fb0 --- /dev/null +++ b/Source/Engine/Physics/PhysicsBackend.h @@ -0,0 +1,294 @@ +// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved. + +#pragma once + +#include "Physics.h" +#include "PhysicsSettings.h" + +struct HingeJointDrive; +struct SpringParameters; +struct LimitLinearRange; +struct LimitAngularRange; +struct LimitConeRange; +struct LimitLinear; +struct D6JointDrive; +enum class HingeJointFlag; +enum class DistanceJointFlag; +enum class SliderJointFlag; +enum class SphericalJointFlag; +enum class D6JointAxis; +enum class D6JointMotion; +enum class D6JointDriveType; +class IPhysicsActor; +class PhysicalMaterial; +class JsonAsset; + +struct PhysicsJointDesc +{ + Joint* Joint; + void* Actor0; + void* Actor1; + Quaternion Rot0; + Quaternion Rot1; + Vector3 Pos0; + Vector3 Pos1; +}; + +/// +/// Interface for the physical simulation backend implementation. +/// +class PhysicsBackend +{ +public: + enum class ActorFlags + { + None = 0, + NoGravity = 1 << 0, + NoSimulation = 1 << 1, + }; + + enum class RigidDynamicFlags + { + None = 0, + Kinematic = 1 << 0, + CCD = 1 << 1, + }; + + enum class JointFlags + { + None = 0, + Collision = 1 << 0, + }; + + enum class ActionType + { + Sleep, + }; + + struct HeightFieldSample + { + int16 Height; + uint8 MaterialIndex0; + uint8 MaterialIndex1; + }; + + enum class HeightFieldMaterial + { + Hole = 127, + }; + +public: + // General + static bool Init(); + static void Shutdown(); + static void ApplySettings(const PhysicsSettings& settings); + + // Scene + static void* CreateScene(const PhysicsSettings& settings); + static void DestroyScene(void* scene); + static void StartSimulateScene(void* scene, float dt); + static void EndSimulateScene(void* scene); + static Vector3 GetSceneGravity(void* scene); + static void SetSceneGravity(void* scene, const Vector3& value); + static bool GetSceneEnableCCD(void* scene); + static void SetSceneEnableCCD(void* scene, bool value); + static float GetSceneBounceThresholdVelocity(void* scene); + static void SetSceneBounceThresholdVelocity(void* scene, float value); + static void AddSceneActor(void* scene, void* actor); + static void RemoveSceneActor(void* scene, void* actor); + static void AddSceneActorAction(void* scene, void* actor, ActionType action); + + // Scene Queries + static bool RayCast(void* scene, const Vector3& origin, const Vector3& direction, float maxDistance, uint32 layerMask, bool hitTriggers); + static bool RayCast(void* scene, const Vector3& origin, const Vector3& direction, RayCastHit& hitInfo, float maxDistance, uint32 layerMask, bool hitTriggers); + static bool RayCastAll(void* scene, const Vector3& origin, const Vector3& direction, Array& results, float maxDistance, uint32 layerMask, bool hitTriggers); + static bool BoxCast(void* scene, const Vector3& center, const Vector3& halfExtents, const Vector3& direction, const Quaternion& rotation, float maxDistance, uint32 layerMask, bool hitTriggers); + static bool BoxCast(void* scene, const Vector3& center, const Vector3& halfExtents, const Vector3& direction, RayCastHit& hitInfo, const Quaternion& rotation, float maxDistance, uint32 layerMask, bool hitTriggers); + static bool BoxCastAll(void* scene, const Vector3& center, const Vector3& halfExtents, const Vector3& direction, Array& results, const Quaternion& rotation, float maxDistance, uint32 layerMask, bool hitTriggers); + static bool SphereCast(void* scene, const Vector3& center, float radius, const Vector3& direction, float maxDistance, uint32 layerMask, bool hitTriggers); + static bool SphereCast(void* scene, const Vector3& center, float radius, const Vector3& direction, RayCastHit& hitInfo, float maxDistance, uint32 layerMask, bool hitTriggers); + static bool SphereCastAll(void* scene, const Vector3& center, float radius, const Vector3& direction, Array& results, float maxDistance, uint32 layerMask, bool hitTriggers); + static bool CapsuleCast(void* scene, const Vector3& center, float radius, float height, const Vector3& direction, const Quaternion& rotation, float maxDistance, uint32 layerMask, bool hitTriggers); + static bool CapsuleCast(void* scene, const Vector3& center, float radius, float height, const Vector3& direction, RayCastHit& hitInfo, const Quaternion& rotation, float maxDistance, uint32 layerMask, bool hitTriggers); + static bool CapsuleCastAll(void* scene, const Vector3& center, float radius, float height, const Vector3& direction, Array& results, const Quaternion& rotation, float maxDistance, uint32 layerMask, bool hitTriggers); + static bool ConvexCast(void* scene, const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Vector3& direction, const Quaternion& rotation, float maxDistance, uint32 layerMask, bool hitTriggers); + static bool ConvexCast(void* scene, const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Vector3& direction, RayCastHit& hitInfo, const Quaternion& rotation, float maxDistance, uint32 layerMask, bool hitTriggers); + static bool ConvexCastAll(void* scene, const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Vector3& direction, Array& results, const Quaternion& rotation, float maxDistance, uint32 layerMask, bool hitTriggers); + static bool CheckBox(void* scene, const Vector3& center, const Vector3& halfExtents, const Quaternion& rotation, uint32 layerMask, bool hitTriggers); + static bool CheckSphere(void* scene, const Vector3& center, float radius, uint32 layerMask, bool hitTriggers); + static bool CheckCapsule(void* scene, const Vector3& center, float radius, float height, const Quaternion& rotation, uint32 layerMask, bool hitTriggers); + static bool CheckConvex(void* scene, const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Quaternion& rotation, uint32 layerMask, bool hitTriggers); + static bool OverlapBox(void* scene, const Vector3& center, const Vector3& halfExtents, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers); + static bool OverlapSphere(void* scene, const Vector3& center, float radius, Array& results, uint32 layerMask, bool hitTriggers); + static bool OverlapCapsule(void* scene, const Vector3& center, float radius, float height, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers); + static bool OverlapConvex(void* scene, const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers); + static bool OverlapBox(void* scene, const Vector3& center, const Vector3& halfExtents, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers); + static bool OverlapSphere(void* scene, const Vector3& center, float radius, Array& results, uint32 layerMask, bool hitTriggers); + static bool OverlapCapsule(void* scene, const Vector3& center, float radius, float height, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers); + static bool OverlapConvex(void* scene, const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers); + + // Actors + static ActorFlags GetActorFlags(void* actor); + static void SetActorFlags(void* actor, ActorFlags value); + static void GetActorBounds(void* actor, BoundingBox& bounds); + static void* CreateRigidDynamicActor(IPhysicsActor* actor, const Vector3& position, const Quaternion& orientation); + static void* CreateRigidStaticActor(IPhysicsActor* actor, const Vector3& position, const Quaternion& orientation); + static RigidDynamicFlags GetRigidDynamicActorFlags(void* actor); + static void SetRigidDynamicActorFlags(void* actor, RigidDynamicFlags value); + static void GetRigidActorPose(void* actor, Vector3& position, Quaternion& orientation); + static void SetRigidActorPose(void* actor, const Vector3& position, const Quaternion& orientation, bool kinematic = false, bool wakeUp = false); + static void SetRigidDynamicActorLinearDamping(void* actor, float value); + static void SetRigidDynamicActorAngularDamping(void* actor, float value); + static void SetRigidDynamicActorMaxAngularVelocity(void* actor, float value); + static void SetRigidDynamicActorConstraints(void* actor, RigidbodyConstraints value); + static Vector3 GetRigidDynamicActorLinearVelocity(void* actor); + static void SetRigidDynamicActorLinearVelocity(void* actor, const Vector3& value, bool wakeUp); + static Vector3 GetRigidDynamicActorAngularVelocity(void* actor); + static void SetRigidDynamicActorAngularVelocity(void* actor, const Vector3& value, bool wakeUp); + static Vector3 GetRigidDynamicActorCenterOfMass(void* actor); + static void SetRigidDynamicActorCenterOfMassOffset(void* actor, const Vector3& value); + static bool GetRigidDynamicActorIsSleeping(void* actor); + static void GetRigidActorSleep(void* actor); + static void GetRigidDynamicActorWakeUp(void* actor); + static float GetRigidDynamicActorSleepThreshold(void* actor); + static void SetRigidDynamicActorSleepThreshold(void* actor, float value); + static float GetRigidDynamicActorMaxDepenetrationVelocity(void* actor); + static void SetRigidDynamicActorMaxDepenetrationVelocity(void* actor, float value); + static void SetRigidDynamicActorSolverIterationCounts(void* actor, int32 minPositionIters, int32 minVelocityIters); + static void UpdateRigidDynamicActorMass(void* actor, float& mass, float massScale, bool autoCalculate); + static void AddRigidDynamicActorForce(void* actor, const Vector3& force, ForceMode mode); + static void AddRigidDynamicActorForceAtPosition(void* actor, const Vector3& force, const Vector3& position, ForceMode mode); + static void AddRigidDynamicActorTorque(void* actor, const Vector3& torque, ForceMode mode); + + // Shapes + static void* CreateShape(PhysicsColliderActor* collider, const CollisionShape& geometry, JsonAsset* material, bool enabled, bool trigger); + static void SetShapeState(void* shape, bool enabled, bool trigger); + static void SetShapeFilterMask(void* shape, uint32 mask0, uint32 mask1); + static void* GetShapeActor(void* shape); + static void GetShapePose(void* shape, Vector3& position, Quaternion& orientation); + static CollisionShape::Types GetShapeType(void* shape); + static void GetShapeLocalPose(void* shape, Vector3& position, Quaternion& orientation); + static void SetShapeLocalPose(void* shape, const Vector3& position, const Quaternion& orientation); + static void SetShapeContactOffset(void* shape, float value); + static void SetShapeMaterial(void* shape, JsonAsset* material); + static void SetShapeGeometry(void* shape, const CollisionShape& geometry); + static void AttachShape(void* shape, void* actor); + static void DetachShape(void* shape, void* actor); + static bool ComputeShapesPenetration(void* shapeA, void* shapeB, const Vector3& positionA, const Quaternion& orientationA, const Vector3& positionB, const Quaternion& orientationB, Vector3& direction, float& distance); + static float ComputeShapeSqrDistanceToPoint(void* shape, const Vector3& position, const Quaternion& orientation, const Vector3& point, Vector3* closestPoint = nullptr); + static bool RayCastShape(void* shape, const Vector3& position, const Quaternion& orientation, const Vector3& origin, const Vector3& direction, float& resultHitDistance, float maxDistance); + static bool RayCastShape(void* shape, const Vector3& position, const Quaternion& orientation, const Vector3& origin, const Vector3& direction, RayCastHit& hitInfo, float maxDistance); + + // Joints + static void SetJointFlags(void* joint, JointFlags value); + static void SetJointActors(void* joint, void* actors0, void* actor1); + static void SetJointActorPose(void* joint, const Vector3& position, const Quaternion& orientation, uint8 index); + static void SetJointBreakForce(void* joint, float force, float torque); + static void GetJointForce(void* joint, Vector3& linear, Vector3& angular); + static void* CreateFixedJoint(const PhysicsJointDesc& desc); + static void* CreateDistanceJoint(const PhysicsJointDesc& desc); + static void* CreateHingeJoint(const PhysicsJointDesc& desc); + static void* CreateSliderJoint(const PhysicsJointDesc& desc); + static void* CreateSphericalJoint(const PhysicsJointDesc& desc); + static void* CreateD6Joint(const PhysicsJointDesc& desc); + static void SetDistanceJointFlags(void* joint, DistanceJointFlag flags); + static void SetDistanceJointMinDistance(void* joint, float value); + static void SetDistanceJointMaxDistance(void* joint, float value); + static void SetDistanceJointTolerance(void* joint, float value); + static void SetDistanceJointSpring(void* joint, const SpringParameters& value); + static float GetDistanceJointDistance(void* joint); + static void SetHingeJointFlags(void* joint, HingeJointFlag value, bool driveFreeSpin); + static void SetHingeJointLimit(void* joint, const LimitAngularRange& value); + static void SetHingeJointDrive(void* joint, const HingeJointDrive& value); + static float GetHingeJointAngle(void* joint); + static float GetHingeJointVelocity(void* joint); + static void SetSliderJointFlags(void* joint, SliderJointFlag value); + static void SetSliderJointLimit(void* joint, const LimitLinearRange& value); + static float GetSliderJointPosition(void* joint); + static float GetSliderJointVelocity(void* joint); + static void SetSphericalJointFlags(void* joint, SphericalJointFlag value); + static void SetSphericalJointLimit(void* joint, const LimitConeRange& value); + static void SetD6JointMotion(void* joint, D6JointAxis axis, D6JointMotion value); + static void SetD6JointDrive(void* joint, const D6JointDriveType index, const D6JointDrive& value); + static void SetD6JointLimitLinear(void* joint, const LimitLinear& value); + static void SetD6JointLimitTwist(void* joint, const LimitAngularRange& value); + static void SetD6JointLimitSwing(void* joint, const LimitConeRange& value); + static Vector3 GetD6JointDrivePosition(void* joint); + static void SetD6JointDrivePosition(void* joint, const Vector3& value); + static Quaternion GetD6JointDriveRotation(void* joint); + static void SetD6JointDriveRotation(void* joint, const Quaternion& value); + static void GetD6JointDriveVelocity(void* joint, Vector3& linear, Vector3& angular); + static void SetD6JointDriveVelocity(void* joint, const Vector3& linear, const Vector3& angular); + static float GetD6JointTwist(void* joint); + static float GetD6JointSwingY(void* joint); + static float GetD6JointSwingZ(void* joint); + + // Character Controllers + static void* 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); + static void* GetControllerRigidDynamicActor(void* controller); + static void SetControllerSize(void* controller, float radius, float height); + static void SetControllerSlopeLimit(void* controller, float value); + static void SetControllerNonWalkableMode(void* controller, int32 value); + static void SetControllerStepOffset(void* controller, float value); + static Vector3 GetControllerUpDirection(void* controller); + static void SetControllerUpDirection(void* controller, const Vector3& value); + static Vector3 GetControllerPosition(void* controller); + static void SetControllerPosition(void* controller, const Vector3& value); + static int32 MoveController(void* controller, void* shape, const Vector3& displacement, float minMoveDistance, float deltaTime); + +#if WITH_VEHICLE + // Vehicles + static void* CreateVehicle(class WheeledVehicle* actor); + static void DestroyVehicle(void* vehicle, int32 driveType); + static void SetVehicleGearbox(void* vehicle, const void* value); + static int32 GetVehicleTargetGear(void* vehicle); + static void SetVehicleTargetGear(void* vehicle, int32 value); + static int32 GetVehicleCurrentGear(void* vehicle); + static void SetVehicleCurrentGear(void* vehicle, int32 value); + static float GetVehicleForwardSpeed(void* vehicle); + static float GetVehicleSidewaysSpeed(void* vehicle); + static float GetVehicleEngineRotationSpeed(void* vehicle); + static void AddVehicle(void* scene, WheeledVehicle* actor); + static void RemoveVehicle(void* scene, WheeledVehicle* actor); +#endif + + // Resources + static void* CreateConvexMesh(byte* data, int32 dataSize, BoundingBox& localBounds); + static void* CreateTriangleMesh(byte* data, int32 dataSize, BoundingBox& localBounds); + static void* CreateHeightField(byte* data, int32 dataSize); + static void GetConvexMeshTriangles(void* contextMesh, Array& vertexBuffer, Array& indexBuffer); + static void GetTriangleMeshTriangles(void* triangleMesh, Array& vertexBuffer, Array& indexBuffer); + static const uint32* GetTriangleMeshRemap(void* triangleMesh, uint32& count); + static void GetHeightFieldSize(void* heightField, int32& rows, int32& columns); + static float GetHeightFieldHeight(void* heightField, float x, float z); + static bool ModifyHeightField(void* heightField, int32 startCol, int32 startRow, int32 cols, int32 rows, const HeightFieldSample* data); + static void FlushRequests(); + static void FlushRequests(void* scene); + static void DestroyActor(void* actor); + static void DestroyShape(void* shape); + static void DestroyJoint(void* joint); + static void DestroyController(void* controller); + static void DestroyObject(void* object); + static void RemoveCollider(PhysicsColliderActor* collider); + static void RemoveJoint(Joint* joint); + +public: + // Utilities + FORCE_INLINE static void SetActorFlag(void* actor, ActorFlags flag, bool value) + { + auto flags = GetActorFlags(actor); + flags = (ActorFlags)(((uint32)flags & ~(uint32)flag) | (value ? (uint32)flag : 0)); + SetActorFlags(actor, flags); + } + + FORCE_INLINE static void SetRigidDynamicActorFlag(void* actor, RigidDynamicFlags flag, bool value) + { + auto flags = GetRigidDynamicActorFlags(actor); + flags = (RigidDynamicFlags)(((uint32)flags & ~(uint32)flag) | (value ? (uint32)flag : 0)); + SetRigidDynamicActorFlags(actor, flags); + } +}; + +DECLARE_ENUM_OPERATORS(PhysicsBackend::ActorFlags); +DECLARE_ENUM_OPERATORS(PhysicsBackend::RigidDynamicFlags); +DECLARE_ENUM_OPERATORS(PhysicsBackend::JointFlags); diff --git a/Source/Engine/Physics/PhysicsScene.Queries.cpp b/Source/Engine/Physics/PhysicsScene.Queries.cpp deleted file mode 100644 index 87fa78529..000000000 --- a/Source/Engine/Physics/PhysicsScene.Queries.cpp +++ /dev/null @@ -1,697 +0,0 @@ -// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. - -#include "Physics.h" -#include "PhysicsScene.h" -#include "Utilities.h" -#include "CollisionData.h" -#include "Actors/PhysicsColliderActor.h" -#include -#include - -// Temporary result buffer size -#define HIT_BUFFER_SIZE 128 - -template -class DynamicHitBuffer : public PxHitCallback -{ -private: - - uint32 _count; - HitType _buffer[HIT_BUFFER_SIZE]; - -public: - - DynamicHitBuffer() - : PxHitCallback(_buffer, HIT_BUFFER_SIZE) - , _count(0) - { - } - -public: - - // Computes the number of any hits in this result, blocking or touching. - PX_INLINE PxU32 getNbAnyHits() const - { - return getNbTouches(); - } - - // Convenience iterator used to access any hits in this result, blocking or touching. - PX_INLINE const HitType& getAnyHit(const PxU32 index) const - { - PX_ASSERT(index < getNbTouches() + PxU32(this->hasBlock)); - return index < getNbTouches() ? getTouches()[index] : this->block; - } - - PX_INLINE PxU32 getNbTouches() const - { - return _count; - } - - PX_INLINE const HitType* getTouches() const - { - return _buffer; - } - - PX_INLINE const HitType& getTouch(const PxU32 index) const - { - PX_ASSERT(index < getNbTouches()); - return _buffer[index]; - } - - PX_INLINE PxU32 getMaxNbTouches() const - { - return HIT_BUFFER_SIZE; - } - -protected: - - PxAgain processTouches(const HitType* buffer, PxU32 nbHits) override - { - nbHits = Math::Min(nbHits, HIT_BUFFER_SIZE - _count); - for (PxU32 i = 0; i < nbHits; i++) - { - _buffer[_count + i] = buffer[i]; - } - _count += nbHits; - return true; - } - - void finalizeQuery() override - { - if (this->hasBlock) - { - // Blocking hits go to hits - processTouches(&this->block, 1); - } - } -}; - -#define SCENE_QUERY_SETUP(blockSingle) if (GetScene() == nullptr) return false; \ - const PxHitFlags hitFlags = PxHitFlag::ePOSITION | PxHitFlag::eNORMAL | PxHitFlag::eUV; \ - PxQueryFilterData filterData = PxQueryFilterData(); \ - filterData.flags |= PxQueryFlag::ePREFILTER; \ - filterData.data.word0 = layerMask; \ - filterData.data.word1 = blockSingle ? 1 : 0; \ - filterData.data.word2 = hitTriggers ? 1 : 0 - -#define SCENE_QUERY_SETUP_SWEEP_1() SCENE_QUERY_SETUP(true); \ - PxSweepBufferN<1> buffer - -#define SCENE_QUERY_SETUP_SWEEP() SCENE_QUERY_SETUP(false); \ - DynamicHitBuffer buffer - -#define SCENE_QUERY_SETUP_OVERLAP_1() SCENE_QUERY_SETUP(false); \ - PxOverlapBufferN<1> buffer - -#define SCENE_QUERY_SETUP_OVERLAP() SCENE_QUERY_SETUP(false); \ - DynamicHitBuffer buffer - -#define SCENE_QUERY_COLLECT_SINGLE() const auto& hit = buffer.getAnyHit(0); \ - hitInfo.Gather(hit) - -#define SCENE_QUERY_COLLECT_ALL() results.Clear(); \ - results.Resize(buffer.getNbAnyHits(), false); \ - for (int32 i = 0; i < results.Count(); i++) \ - { \ - const auto& hit = buffer.getAnyHit(i); \ - results[i].Gather(hit); \ - } - -#define SCENE_QUERY_COLLECT_OVERLAP() results.Clear(); \ - results.Resize(buffer.getNbTouches(), false); \ - for (int32 i = 0; i < results.Count(); i++) \ - { \ - auto& hitInfo = results[i]; \ - const auto& hit = buffer.getTouch(i); \ - hitInfo = hit.shape ? static_cast<::PhysicsColliderActor*>(hit.shape->userData) : nullptr; \ - } - -#define SCENE_QUERY_COLLECT_OVERLAP_COLLIDER() results.Clear(); \ - results.Resize(buffer.getNbTouches(), false); \ - for (int32 i = 0; i < results.Count(); i++) \ - { \ - auto& hitInfo = results[i]; \ - const auto& hit = buffer.getTouch(i); \ - hitInfo = hit.shape ? static_cast<::Collider*>(hit.shape->userData) : nullptr; \ - } - -void RayCastHit::Gather(const PxRaycastHit& hit) -{ - Point = P2C(hit.position); - Normal = P2C(hit.normal); - Distance = hit.distance; - Collider = hit.shape ? static_cast(hit.shape->userData) : nullptr; - FaceIndex = hit.faceIndex; - UV.X = hit.u; - UV.Y = hit.v; -} - -void RayCastHit::Gather(const PxSweepHit& hit) -{ - Point = P2C(hit.position); - Normal = P2C(hit.normal); - Distance = hit.distance; - Collider = hit.shape ? static_cast(hit.shape->userData) : nullptr; - FaceIndex = hit.faceIndex; - UV = Vector2::Zero; -} - -class QueryFilter : public PxQueryFilterCallback -{ -public: - - PxQueryHitType::Enum preFilter(const PxFilterData& filterData, const PxShape* shape, const PxRigidActor* actor, PxHitFlags& queryFlags) override - { - // Early out to avoid crashing - if (!shape) - return PxQueryHitType::eNONE; - - // Check mask - const PxFilterData shapeFilter = shape->getQueryFilterData(); - if ((filterData.word0 & shapeFilter.word0) == 0) - { - return PxQueryHitType::eNONE; - } - - // Check if skip triggers - const bool hitTriggers = filterData.word2 != 0; - if (!hitTriggers && shape->getFlags() & PxShapeFlag::eTRIGGER_SHAPE) - return PxQueryHitType::eNONE; - - const bool blockSingle = filterData.word1 != 0; - return blockSingle ? PxQueryHitType::eBLOCK : PxQueryHitType::eTOUCH; - } - - PxQueryHitType::Enum postFilter(const PxFilterData& filterData, const PxQueryHit& hit) override - { - // Not used - return PxQueryHitType::eNONE; - } -}; - -class CharacterQueryFilter : public PxQueryFilterCallback -{ -public: - - PxQueryHitType::Enum preFilter(const PxFilterData& filterData, const PxShape* shape, const PxRigidActor* actor, PxHitFlags& queryFlags) override - { - // Early out to avoid crashing - if (!shape) - return PxQueryHitType::eNONE; - - // Let triggers through - if (PxFilterObjectIsTrigger(shape->getFlags())) - return PxQueryHitType::eNONE; - - // Trigger the contact callback for pairs (A,B) where the filtermask of A contains the ID of B and vice versa - const PxFilterData shapeFilter = shape->getQueryFilterData(); - if (filterData.word0 & shapeFilter.word1) - return PxQueryHitType::eBLOCK; - - return PxQueryHitType::eNONE; - } - - PxQueryHitType::Enum postFilter(const PxFilterData& filterData, const PxQueryHit& hit) override - { - // Not used - return PxQueryHitType::eNONE; - } -}; - -class CharacterControllerFilter : public PxControllerFilterCallback -{ -private: - - PxShape* getShape(const PxController& controller) - { - PxRigidDynamic* actor = controller.getActor(); - - // Early out if no actor or no shapes - if (!actor || actor->getNbShapes() < 1) - return nullptr; - - // Get first shape only. - PxShape* shape = nullptr; - actor->getShapes(&shape, 1); - - return shape; - } - -public: - - bool filter(const PxController& a, const PxController& b) override - { - // Early out to avoid crashing - PxShape* shapeA = getShape(a); - if (!shapeA) - return false; - - PxShape* shapeB = getShape(b); - if (!shapeB) - return false; - - // Let triggers through - if (PxFilterObjectIsTrigger(shapeB->getFlags())) - return false; - - // Trigger the contact callback for pairs (A,B) where the filtermask of A contains the ID of B and vice versa - const PxFilterData shapeFilterA = shapeA->getQueryFilterData(); - const PxFilterData shapeFilterB = shapeB->getQueryFilterData(); - if (shapeFilterA.word0 & shapeFilterB.word1) - return true; - - return false; - } -}; - -PxQueryFilterCallback* PhysicsScene::GetQueryFilterCallback() -{ - static QueryFilter Filter; - return &Filter; -} - -PxQueryFilterCallback* PhysicsScene::GetCharacterQueryFilterCallback() -{ - static CharacterQueryFilter Filter; - return &Filter; -} - -PxControllerFilterCallback* PhysicsScene::GetCharacterControllerFilterCallback() -{ - static CharacterControllerFilter Filter; - return &Filter; -} - -bool PhysicsScene::RayCast(const Vector3& origin, const Vector3& direction, const float maxDistance, uint32 layerMask, bool hitTriggers) -{ - // Prepare data - SCENE_QUERY_SETUP(true); - PxRaycastBuffer buffer; - - // Perform raycast test - return GetScene()->raycast(C2P(origin), C2P(direction), maxDistance, buffer, hitFlags, filterData, GetQueryFilterCallback()); -} - -bool PhysicsScene::RayCast(const Vector3& origin, const Vector3& direction, RayCastHit& hitInfo, const float maxDistance, uint32 layerMask, bool hitTriggers) -{ - // Prepare data - SCENE_QUERY_SETUP(true); - PxRaycastBuffer buffer; - - // Perform raycast test - if (!GetScene()->raycast(C2P(origin), C2P(direction), maxDistance, buffer, hitFlags, filterData, GetQueryFilterCallback())) - return false; - - // Collect results - SCENE_QUERY_COLLECT_SINGLE(); - - return true; -} - -bool PhysicsScene::RayCastAll(const Vector3& origin, const Vector3& direction, Array& results, const float maxDistance, uint32 layerMask, bool hitTriggers) -{ - // Prepare data - SCENE_QUERY_SETUP(false); - DynamicHitBuffer buffer; - - // Perform raycast test - if (!GetScene()->raycast(C2P(origin), C2P(direction), maxDistance, buffer, hitFlags, filterData, GetQueryFilterCallback())) - return false; - - // Collect results - SCENE_QUERY_COLLECT_ALL(); - - return true; -} - -bool PhysicsScene::BoxCast(const Vector3& center, const Vector3& halfExtents, const Vector3& direction, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) -{ - // Prepare data - SCENE_QUERY_SETUP_SWEEP_1(); - const PxTransform pose(C2P(center), C2P(rotation)); - const PxBoxGeometry geometry(C2P(halfExtents)); - - // Perform sweep test - return GetScene()->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, GetQueryFilterCallback()); -} - -bool PhysicsScene::BoxCast(const Vector3& center, const Vector3& halfExtents, const Vector3& direction, RayCastHit& hitInfo, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) -{ - // Prepare data - SCENE_QUERY_SETUP_SWEEP_1(); - const PxTransform pose(C2P(center), C2P(rotation)); - const PxBoxGeometry geometry(C2P(halfExtents)); - - // Perform sweep test - if (!GetScene()->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, GetQueryFilterCallback())) - return false; - - // Collect results - SCENE_QUERY_COLLECT_SINGLE(); - - return true; -} - -bool PhysicsScene::BoxCastAll(const Vector3& center, const Vector3& halfExtents, const Vector3& direction, Array& results, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) -{ - // Prepare data - SCENE_QUERY_SETUP_SWEEP(); - const PxTransform pose(C2P(center), C2P(rotation)); - const PxBoxGeometry geometry(C2P(halfExtents)); - - // Perform sweep test - if (!GetScene()->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, GetQueryFilterCallback())) - return false; - - // Collect results - SCENE_QUERY_COLLECT_ALL(); - - return true; -} - -bool PhysicsScene::SphereCast(const Vector3& center, const float radius, const Vector3& direction, const float maxDistance, uint32 layerMask, bool hitTriggers) -{ - // Prepare data - SCENE_QUERY_SETUP_SWEEP_1(); - const PxTransform pose(C2P(center)); - const PxSphereGeometry geometry(radius); - - // Perform sweep test - return GetScene()->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, GetQueryFilterCallback()); -} - -bool PhysicsScene::SphereCast(const Vector3& center, const float radius, const Vector3& direction, RayCastHit& hitInfo, const float maxDistance, uint32 layerMask, bool hitTriggers) -{ - // Prepare data - SCENE_QUERY_SETUP_SWEEP_1(); - const PxTransform pose(C2P(center)); - const PxSphereGeometry geometry(radius); - - // Perform sweep test - if (!GetScene()->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, GetQueryFilterCallback())) - return false; - - // Collect results - SCENE_QUERY_COLLECT_SINGLE(); - - return true; -} - -bool PhysicsScene::SphereCastAll(const Vector3& center, const float radius, const Vector3& direction, Array& results, const float maxDistance, uint32 layerMask, bool hitTriggers) -{ - // Prepare data - SCENE_QUERY_SETUP_SWEEP(); - const PxTransform pose(C2P(center)); - const PxSphereGeometry geometry(radius); - - // Perform sweep test - if (!GetScene()->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, GetQueryFilterCallback())) - return false; - - // Collect results - SCENE_QUERY_COLLECT_ALL(); - - return true; -} - -bool PhysicsScene::CapsuleCast(const Vector3& center, const float radius, const float height, const Vector3& direction, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) -{ - // Prepare data - SCENE_QUERY_SETUP_SWEEP_1(); - const PxTransform pose(C2P(center), C2P(rotation)); - const PxCapsuleGeometry geometry(radius, height * 0.5f); - - // Perform sweep test - return GetScene()->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, GetQueryFilterCallback()); -} - -bool PhysicsScene::CapsuleCast(const Vector3& center, const float radius, const float height, const Vector3& direction, RayCastHit& hitInfo, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) -{ - // Prepare data - SCENE_QUERY_SETUP_SWEEP_1(); - const PxTransform pose(C2P(center), C2P(rotation)); - const PxCapsuleGeometry geometry(radius, height * 0.5f); - - // Perform sweep test - if (!GetScene()->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, GetQueryFilterCallback())) - return false; - - // Collect results - SCENE_QUERY_COLLECT_SINGLE(); - - return true; -} - -bool PhysicsScene::CapsuleCastAll(const Vector3& center, const float radius, const float height, const Vector3& direction, Array& results, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) -{ - // Prepare data - SCENE_QUERY_SETUP_SWEEP(); - const PxTransform pose(C2P(center), C2P(rotation)); - const PxCapsuleGeometry geometry(radius, height * 0.5f); - - // Perform sweep test - if (!GetScene()->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, GetQueryFilterCallback())) - return false; - - // Collect results - SCENE_QUERY_COLLECT_ALL(); - - return true; -} - -bool PhysicsScene::ConvexCast(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Vector3& direction, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) -{ - CHECK_RETURN(convexMesh && convexMesh->GetOptions().Type == CollisionDataType::ConvexMesh, false) - - // Prepare data - SCENE_QUERY_SETUP_SWEEP_1(); - const PxTransform pose(C2P(center), C2P(rotation)); - const PxConvexMeshGeometry geometry(convexMesh->GetConvex(), PxMeshScale(C2P(scale))); - - // Perform sweep test - return GetScene()->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, GetQueryFilterCallback()); -} - -bool PhysicsScene::ConvexCast(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Vector3& direction, RayCastHit& hitInfo, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) -{ - CHECK_RETURN(convexMesh && convexMesh->GetOptions().Type == CollisionDataType::ConvexMesh, false) - - // Prepare data - SCENE_QUERY_SETUP_SWEEP_1(); - const PxTransform pose(C2P(center), C2P(rotation)); - const PxConvexMeshGeometry geometry(convexMesh->GetConvex(), PxMeshScale(C2P(scale))); - - // Perform sweep test - if (!GetScene()->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, GetQueryFilterCallback())) - return false; - - // Collect results - SCENE_QUERY_COLLECT_SINGLE(); - - return true; -} - -bool PhysicsScene::ConvexCastAll(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Vector3& direction, Array& results, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) -{ - CHECK_RETURN(convexMesh && convexMesh->GetOptions().Type == CollisionDataType::ConvexMesh, false) - - // Prepare data - SCENE_QUERY_SETUP_SWEEP(); - const PxTransform pose(C2P(center), C2P(rotation)); - const PxConvexMeshGeometry geometry(convexMesh->GetConvex(), PxMeshScale(C2P(scale))); - - // Perform sweep test - if (!GetScene()->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, GetQueryFilterCallback())) - return false; - - // Collect results - SCENE_QUERY_COLLECT_ALL(); - - return true; -} - -bool PhysicsScene::CheckBox(const Vector3& center, const Vector3& halfExtents, const Quaternion& rotation, uint32 layerMask, bool hitTriggers) -{ - // Prepare data - SCENE_QUERY_SETUP_OVERLAP_1(); - const PxTransform pose(C2P(center), C2P(rotation)); - const PxBoxGeometry geometry(C2P(halfExtents)); - - // Perform overlap test - return GetScene()->overlap(geometry, pose, buffer, filterData, GetQueryFilterCallback()); -} - -bool PhysicsScene::CheckSphere(const Vector3& center, const float radius, uint32 layerMask, bool hitTriggers) -{ - // Prepare data - SCENE_QUERY_SETUP_OVERLAP_1(); - const PxTransform pose(C2P(center)); - const PxSphereGeometry geometry(radius); - - // Perform overlap test - return GetScene()->overlap(geometry, pose, buffer, filterData, GetQueryFilterCallback()); -} - -bool PhysicsScene::CheckCapsule(const Vector3& center, const float radius, const float height, const Quaternion& rotation, uint32 layerMask, bool hitTriggers) -{ - // Prepare data - SCENE_QUERY_SETUP_OVERLAP_1(); - const PxTransform pose(C2P(center), C2P(rotation)); - const PxCapsuleGeometry geometry(radius, height * 0.5f); - - // Perform overlap test - return GetScene()->overlap(geometry, pose, buffer, filterData, GetQueryFilterCallback()); -} - -bool PhysicsScene::CheckConvex(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Quaternion& rotation, uint32 layerMask, bool hitTriggers) -{ - CHECK_RETURN(convexMesh && convexMesh->GetOptions().Type == CollisionDataType::ConvexMesh, false) - - // Prepare data - SCENE_QUERY_SETUP_OVERLAP_1(); - const PxTransform pose(C2P(center), C2P(rotation)); - const PxConvexMeshGeometry geometry(convexMesh->GetConvex(), PxMeshScale(C2P(scale))); - - // Perform overlap test - return GetScene()->overlap(geometry, pose, buffer, filterData, GetQueryFilterCallback()); -} - -bool PhysicsScene::OverlapBox(const Vector3& center, const Vector3& halfExtents, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers) -{ - // Prepare data - SCENE_QUERY_SETUP_OVERLAP(); - const PxTransform pose(C2P(center), C2P(rotation)); - const PxBoxGeometry geometry(C2P(halfExtents)); - - // Perform overlap test - if (!GetScene()->overlap(geometry, pose, buffer, filterData, GetQueryFilterCallback())) - return false; - - // Collect results - SCENE_QUERY_COLLECT_OVERLAP_COLLIDER(); - - return true; -} - -bool PhysicsScene::OverlapSphere(const Vector3& center, const float radius, Array& results, uint32 layerMask, bool hitTriggers) -{ - // Prepare data - SCENE_QUERY_SETUP_OVERLAP(); - const PxTransform pose(C2P(center)); - const PxSphereGeometry geometry(radius); - - // Perform overlap test - if (!GetScene()->overlap(geometry, pose, buffer, filterData, GetQueryFilterCallback())) - return false; - - // Collect results - SCENE_QUERY_COLLECT_OVERLAP_COLLIDER(); - - return true; -} - -bool PhysicsScene::OverlapCapsule(const Vector3& center, const float radius, const float height, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers) -{ - // Prepare data - SCENE_QUERY_SETUP_OVERLAP(); - const PxTransform pose(C2P(center), C2P(rotation)); - const PxCapsuleGeometry geometry(radius, height * 0.5f); - - // Perform overlap test - if (!GetScene()->overlap(geometry, pose, buffer, filterData, GetQueryFilterCallback())) - return false; - - // Collect results - SCENE_QUERY_COLLECT_OVERLAP_COLLIDER(); - - return true; -} - -bool PhysicsScene::OverlapConvex(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers) -{ - CHECK_RETURN(convexMesh && convexMesh->GetOptions().Type == CollisionDataType::ConvexMesh, false) - - // Prepare data - SCENE_QUERY_SETUP_OVERLAP(); - const PxTransform pose(C2P(center), C2P(rotation)); - const PxConvexMeshGeometry geometry(convexMesh->GetConvex(), PxMeshScale(C2P(scale))); - - // Perform overlap test - if (!GetScene()->overlap(geometry, pose, buffer, filterData, GetQueryFilterCallback())) - return false; - - // Collect results - SCENE_QUERY_COLLECT_OVERLAP_COLLIDER(); - - return true; -} - -bool PhysicsScene::OverlapBox(const Vector3& center, const Vector3& halfExtents, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers) -{ - // Prepare data - SCENE_QUERY_SETUP_OVERLAP(); - const PxTransform pose(C2P(center), C2P(rotation)); - const PxBoxGeometry geometry(C2P(halfExtents)); - - // Perform overlap test - if (!GetScene()->overlap(geometry, pose, buffer, filterData, GetQueryFilterCallback())) - return false; - - // Collect results - SCENE_QUERY_COLLECT_OVERLAP(); - - return true; -} - -bool PhysicsScene::OverlapSphere(const Vector3& center, const float radius, Array& results, uint32 layerMask, bool hitTriggers) -{ - // Prepare data - SCENE_QUERY_SETUP_OVERLAP(); - const PxTransform pose(C2P(center)); - const PxSphereGeometry geometry(radius); - - // Perform overlap test - if (!GetScene()->overlap(geometry, pose, buffer, filterData, GetQueryFilterCallback())) - return false; - - // Collect results - SCENE_QUERY_COLLECT_OVERLAP(); - - return true; -} - -bool PhysicsScene::OverlapCapsule(const Vector3& center, const float radius, const float height, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers) -{ - // Prepare data - SCENE_QUERY_SETUP_OVERLAP(); - const PxTransform pose(C2P(center), C2P(rotation)); - const PxCapsuleGeometry geometry(radius, height * 0.5f); - - // Perform overlap test - if (!GetScene()->overlap(geometry, pose, buffer, filterData, GetQueryFilterCallback())) - return false; - - // Collect results - SCENE_QUERY_COLLECT_OVERLAP(); - - return true; -} - -bool PhysicsScene::OverlapConvex(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, Array& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers) -{ - CHECK_RETURN(convexMesh && convexMesh->GetOptions().Type == CollisionDataType::ConvexMesh, false) - - // Prepare data - SCENE_QUERY_SETUP_OVERLAP(); - const PxTransform pose(C2P(center), C2P(rotation)); - const PxConvexMeshGeometry geometry(convexMesh->GetConvex(), PxMeshScale(C2P(scale))); - - // Perform overlap test - if (!GetScene()->overlap(geometry, pose, buffer, filterData, GetQueryFilterCallback())) - return false; - - // Collect results - SCENE_QUERY_COLLECT_OVERLAP(); - - return true; -} diff --git a/Source/Engine/Physics/PhysicsScene.cpp b/Source/Engine/Physics/PhysicsScene.cpp deleted file mode 100644 index 7b5520c0a..000000000 --- a/Source/Engine/Physics/PhysicsScene.cpp +++ /dev/null @@ -1,818 +0,0 @@ -#include "Physics.h" -#include "PhysicsScene.h" -#include "PhysicsSettings.h" -#include "PhysicsStepper.h" -#include "SimulationEventCallback.h" -#include "Utilities.h" - -#include "Actors/IPhysicsActor.h" - -#include "Engine/Core/Log.h" -#include "Engine/Platform/CPUInfo.h" -#include "Engine/Profiler/ProfilerCPU.h" -#include "Engine/Threading/Threading.h" -#include - -#if WITH_VEHICLE -#include "Actors/WheeledVehicle.h" -#include -#endif - -// Temporary memory size used by the PhysX during the simulation. Must be multiply of 4kB and 16bit aligned. -#define SCRATCH_BLOCK_SIZE (1024 * 128) - -PxFilterFlags FilterShader( - PxFilterObjectAttributes attributes0, PxFilterData filterData0, - PxFilterObjectAttributes attributes1, PxFilterData filterData1, - PxPairFlags& pairFlags, const void* constantBlock, PxU32 constantBlockSize) -{ - // Let triggers through - if (PxFilterObjectIsTrigger(attributes0) || PxFilterObjectIsTrigger(attributes1)) - { - pairFlags |= PxPairFlag::eNOTIFY_TOUCH_FOUND; - pairFlags |= PxPairFlag::eNOTIFY_TOUCH_LOST; - pairFlags |= PxPairFlag::eDETECT_DISCRETE_CONTACT; - return PxFilterFlag::eDEFAULT; - } - - // Send events for the kinematic actors but don't solve the contact - if (PxFilterObjectIsKinematic(attributes0) && PxFilterObjectIsKinematic(attributes1)) - { - pairFlags |= PxPairFlag::eNOTIFY_TOUCH_FOUND; - pairFlags |= PxPairFlag::eNOTIFY_TOUCH_PERSISTS; - pairFlags |= PxPairFlag::eNOTIFY_TOUCH_LOST; - pairFlags |= PxPairFlag::eDETECT_DISCRETE_CONTACT; - return PxFilterFlag::eSUPPRESS; - } - - // Trigger the contact callback for pairs (A,B) where the filtermask of A contains the ID of B and vice versa - if ((filterData0.word0 & filterData1.word1) && (filterData1.word0 & filterData0.word1)) - { - pairFlags |= PxPairFlag::eSOLVE_CONTACT; - pairFlags |= PxPairFlag::eDETECT_DISCRETE_CONTACT; - pairFlags |= PxPairFlag::eNOTIFY_TOUCH_FOUND; - pairFlags |= PxPairFlag::eNOTIFY_TOUCH_PERSISTS; - pairFlags |= PxPairFlag::ePOST_SOLVER_VELOCITY; - pairFlags |= PxPairFlag::eNOTIFY_CONTACT_POINTS; - return PxFilterFlag::eDEFAULT; - } - - // Ignore pair (no collisions nor events) - return PxFilterFlag::eKILL; -} - -enum class ActionType -{ - Sleep, -}; - -struct ActionData -{ - ActionType Type; - PxActor* Actor; -}; - -#if WITH_VEHICLE - -static PxQueryHitType::Enum WheelRaycastPreFilter(PxFilterData filterData0, PxFilterData filterData1, const void* constantBlock, PxU32 constantBlockSize, PxHitFlags& queryFlags) -{ - // Hardcoded id for vehicle shapes masking - if (filterData0.word3 == filterData1.word3) - { - return PxQueryHitType::eNONE; - } - - // Collide for pairs (A,B) where the filtermask of A contains the ID of B and vice versa - if ((filterData0.word0 & filterData1.word1) && (filterData1.word0 & filterData0.word1)) - { - return PxQueryHitType::eBLOCK; - } - - return PxQueryHitType::eNONE; -} - -#endif - -class PhysicsScenePhysX -{ - friend PhysicsScene; - -private: - PxScene* Scene; - PxCpuDispatcher* CpuDispatcher; - PxControllerManager* ControllerManager; - PxSimulationFilterShader PhysXDefaultFilterShader = PxDefaultSimulationFilterShader; - SimulationEventCallback EventsCallback; - CriticalSection FlushLocker; - - Array NewActors; - Array DeadActors; - Array DeadMaterials; - Array DeadColliders; - Array DeadJoints; - Array Actions; - Array DeadObjects; - -#if WITH_VEHICLE - Array WheelVehiclesCache; - Array WheelQueryResults; - Array WheelHitResults; - Array WheelVehiclesResultsPerWheel; - Array WheelVehiclesResultsPerVehicle; - PxBatchQuery* WheelRaycastBatchQuery = nullptr; - PxVehicleDrivableSurfaceToTireFrictionPairs* WheelTireFrictions = nullptr; - Array WheelVehicles; -#endif -}; - -PhysicsScene::PhysicsScene(const String& name, const PhysicsSettings& settings) - : PersistentScriptingObject(SpawnParams(Guid::New(), TypeInitializer)) -{ -#define CHECK_INIT(value, msg) if(!value) { LOG(Error, msg); return; } - - mName = name; - mPhysxImpl = New(); - - // Create scene description - PxSceneDesc sceneDesc(CPhysX->getTolerancesScale()); - sceneDesc.gravity = C2P(settings.DefaultGravity); - sceneDesc.flags |= PxSceneFlag::eENABLE_ACTIVE_ACTORS; - if (!settings.DisableCCD) - sceneDesc.flags |= PxSceneFlag::eENABLE_CCD; - if (settings.EnableAdaptiveForce) - sceneDesc.flags |= PxSceneFlag::eADAPTIVE_FORCE; - sceneDesc.simulationEventCallback = &mPhysxImpl->EventsCallback; - sceneDesc.filterShader = FilterShader; - sceneDesc.bounceThresholdVelocity = settings.BounceThresholdVelocity; - if (sceneDesc.cpuDispatcher == nullptr) - { - mPhysxImpl->CpuDispatcher = PxDefaultCpuDispatcherCreate(Math::Clamp(Platform::GetCPUInfo().ProcessorCoreCount - 1, 1, 4)); - CHECK_INIT(mPhysxImpl->CpuDispatcher, "PxDefaultCpuDispatcherCreate failed!"); - sceneDesc.cpuDispatcher = mPhysxImpl->CpuDispatcher; - } - if (sceneDesc.filterShader == nullptr) - { - sceneDesc.filterShader = mPhysxImpl->PhysXDefaultFilterShader; - } - - // Create scene - mPhysxImpl->Scene = CPhysX->createScene(sceneDesc); - CHECK_INIT(mPhysxImpl->Scene, "createScene failed!"); -#if WITH_PVD - auto pvdClient = PhysicsScene->getScenePvdClient(); - if (pvdClient) - { - pvdClient->setScenePvdFlags(PxPvdSceneFlag::eTRANSMIT_CONSTRAINTS | PxPvdSceneFlag::eTRANSMIT_SCENEQUERIES | PxPvdSceneFlag::eTRANSMIT_CONTACTS); - } - else - { - LOG(Info, "Missing PVD client scene."); - } -#endif - - // Init characters controller - mPhysxImpl->ControllerManager = PxCreateControllerManager(*mPhysxImpl->Scene); -} - -PhysicsScene::~PhysicsScene() -{ -#if WITH_VEHICLE - RELEASE_PHYSX(mPhysxImpl->WheelRaycastBatchQuery); - RELEASE_PHYSX(mPhysxImpl->WheelTireFrictions); - mPhysxImpl->WheelQueryResults.Resize(0); - mPhysxImpl->WheelHitResults.Resize(0); - mPhysxImpl->WheelVehiclesResultsPerWheel.Resize(0); - mPhysxImpl->WheelVehiclesResultsPerVehicle.Resize(0); -#endif - - RELEASE_PHYSX(mPhysxImpl->ControllerManager); - SAFE_DELETE(mPhysxImpl->CpuDispatcher); - SAFE_DELETE(mStepper); - Allocator::Free(mScratchMemory); - - mScratchMemory = nullptr; - mPhysxImpl->Scene->release(); - - SAFE_DELETE(mPhysxImpl); -} - -String PhysicsScene::GetName() const -{ - return mName; -} - -PxScene* PhysicsScene::GetScene() -{ - return mPhysxImpl->Scene; -} - -bool PhysicsScene::GetAutoSimulation() -{ - return mAutoSimulation; -} - -void PhysicsScene::SetAutoSimulation(bool value) -{ - mAutoSimulation = value; -} - -void PhysicsScene::SetGravity(const Vector3& value) -{ - if(mPhysxImpl->Scene) - { - mPhysxImpl->Scene->setGravity(C2P(value)); - } -} - -Vector3 PhysicsScene::GetGravity() -{ - return mPhysxImpl->Scene ? P2C(mPhysxImpl->Scene->getGravity()) : Vector3::Zero; -} - -bool PhysicsScene::GetEnableCCD() -{ - return mPhysxImpl->Scene ? (mPhysxImpl->Scene->getFlags() & PxSceneFlag::eENABLE_CCD) == PxSceneFlag::eENABLE_CCD : !PhysicsSettings::Get()->DisableCCD; -} - -void PhysicsScene::SetEnableCCD(const bool value) -{ - if (mPhysxImpl->Scene) - mPhysxImpl->Scene->setFlag(PxSceneFlag::eENABLE_CCD, value); -} - -float PhysicsScene::GetBounceThresholdVelocity() -{ - return mPhysxImpl->Scene ? mPhysxImpl->Scene->getBounceThresholdVelocity() : PhysicsSettings::Get()->BounceThresholdVelocity; -} - -void PhysicsScene::SetBounceThresholdVelocity(const float value) -{ - if (mPhysxImpl->Scene) - mPhysxImpl->Scene->setBounceThresholdVelocity(value); -} - -void PhysicsScene::Simulate(float dt) -{ - ASSERT(IsInMainThread() && !mIsDuringSimulation); - ASSERT(CPhysX); - const auto& settings = *PhysicsSettings::Get(); - - // Flush the old/new objects and the other requests before the simulation - FlushRequests(); - - // Clamp delta - dt = Math::Clamp(dt, 0.0f, settings.MaxDeltaTime); - - // Prepare util objects - if (mScratchMemory == nullptr) - { - mScratchMemory = Allocator::Allocate(SCRATCH_BLOCK_SIZE, 16); - } - if (mStepper == nullptr) - { - mStepper = New(); - } - if (settings.EnableSubstepping) - { - // Use substeps - mStepper->Setup(settings.SubstepDeltaTime, settings.MaxSubsteps); - } - else - { - // Use single step - mStepper->Setup(dt); - } - - // Start simulation (may not be fired due to too small delta time) - mIsDuringSimulation = true; - if (mStepper->advance(mPhysxImpl->Scene, dt, mScratchMemory, SCRATCH_BLOCK_SIZE) == false) - return; - mPhysxImpl->EventsCallback.Clear(); - mLastDeltaTime = dt; - - // TODO: move this call after rendering done - mStepper->renderDone(); -} - -bool PhysicsScene::IsDuringSimulation() -{ - return mIsDuringSimulation; -} - -void PhysicsScene::CollectResults() -{ - if (!mIsDuringSimulation) - return; - ASSERT(IsInMainThread()); - ASSERT(CPhysX && mStepper); - - { - PROFILE_CPU_NAMED("Physics.Fetch"); - - // Gather results (with waiting for the end) - mStepper->wait(mPhysxImpl->Scene); - } - -#if WITH_VEHICLE - if (mPhysxImpl->WheelVehicles.HasItems()) - { - PROFILE_CPU_NAMED("Physics.Vehicles"); - - // Update vehicles steering - mPhysxImpl->WheelVehiclesCache.Clear(); - mPhysxImpl->WheelVehiclesCache.EnsureCapacity(mPhysxImpl->WheelVehicles.Count()); - int32 wheelsCount = 0; - for (auto wheelVehicle : mPhysxImpl->WheelVehicles) - { - if (!wheelVehicle->IsActiveInHierarchy()) - continue; - auto drive = (PxVehicleWheels*)wheelVehicle->_drive; - ASSERT(drive); - mPhysxImpl->WheelVehiclesCache.Add(drive); - wheelsCount += drive->mWheelsSimData.getNbWheels(); - - float throttle = wheelVehicle->_throttle; - float brake = wheelVehicle->_brake; - if (wheelVehicle->UseReverseAsBrake) - { - const float invalidDirectionThreshold = 80.0f; - const float breakThreshold = 8.0f; - const float forwardSpeed = wheelVehicle->GetForwardSpeed(); - - // Automatic gear change when changing driving direction - if (Math::Abs(forwardSpeed) < invalidDirectionThreshold) - { - if (throttle < -ZeroTolerance && wheelVehicle->GetCurrentGear() >= 0 && wheelVehicle->GetTargetGear() >= 0) - { - wheelVehicle->SetCurrentGear(-1); - } - else if (throttle > ZeroTolerance && wheelVehicle->GetCurrentGear() <= 0 && wheelVehicle->GetTargetGear() <= 0) - { - wheelVehicle->SetCurrentGear(1); - } - } - - // Automatic break when changing driving direction - if (throttle > 0.0f) - { - if (forwardSpeed < -invalidDirectionThreshold) - { - brake = 1.0f; - } - } - else if (throttle < 0.0f) - { - if (forwardSpeed > invalidDirectionThreshold) - { - brake = 1.0f; - } - } - else - { - if (forwardSpeed < breakThreshold && forwardSpeed > -breakThreshold) - { - brake = 1.0f; - } - } - - // Block throttle if user is changing driving direction - if ((throttle > 0.0f && wheelVehicle->GetTargetGear() < 0) || (throttle < 0.0f && wheelVehicle->GetTargetGear() > 0)) - { - throttle = 0.0f; - } - - throttle = Math::Abs(throttle); - } - else - { - throttle = Math::Max(throttle, 0.0f); - } - // @formatter:off - // Reference: PhysX SDK docs - // TODO: expose input control smoothing data - static constexpr PxVehiclePadSmoothingData padSmoothing = - { - { - 6.0f, // rise rate eANALOG_INPUT_ACCEL - 6.0f, // rise rate eANALOG_INPUT_BRAKE - 12.0f, // rise rate eANALOG_INPUT_HANDBRAKE - 2.5f, // rise rate eANALOG_INPUT_STEER_LEFT - 2.5f, // rise rate eANALOG_INPUT_STEER_RIGHT - }, - { - 10.0f, // fall rate eANALOG_INPUT_ACCEL - 10.0f, // fall rate eANALOG_INPUT_BRAKE - 12.0f, // fall rate eANALOG_INPUT_HANDBRAKE - 5.0f, // fall rate eANALOG_INPUT_STEER_LEFT - 5.0f, // fall rate eANALOG_INPUT_STEER_RIGHT - } - }; - PxVehicleKeySmoothingData keySmoothing = - { - { - 3.0f, // rise rate eANALOG_INPUT_ACCEL - 3.0f, // rise rate eANALOG_INPUT_BRAKE - 10.0f, // rise rate eANALOG_INPUT_HANDBRAKE - 2.5f, // rise rate eANALOG_INPUT_STEER_LEFT - 2.5f, // rise rate eANALOG_INPUT_STEER_RIGHT - }, - { - 5.0f, // fall rate eANALOG_INPUT__ACCEL - 5.0f, // fall rate eANALOG_INPUT__BRAKE - 10.0f, // fall rate eANALOG_INPUT__HANDBRAKE - 5.0f, // fall rate eANALOG_INPUT_STEER_LEFT - 5.0f // fall rate eANALOG_INPUT_STEER_RIGHT - } - }; - // Reference: PhysX SDK docs - // TODO: expose steer vs forward curve into per-vehicle (up to 8 points, values clamped into 0/1 range) - static constexpr PxF32 steerVsForwardSpeedData[] = - { - 0.0f, 1.0f, - 20.0f, 0.9f, - 65.0f, 0.8f, - 120.0f, 0.7f, - PX_MAX_F32, PX_MAX_F32, - PX_MAX_F32, PX_MAX_F32, - PX_MAX_F32, PX_MAX_F32, - PX_MAX_F32, PX_MAX_F32, - }; - const PxFixedSizeLookupTable<8> steerVsForwardSpeed(steerVsForwardSpeedData, 4); - // @formatter:on - if (wheelVehicle->UseAnalogSteering) - { - switch (wheelVehicle->_driveTypeCurrent) - { - case WheeledVehicle::DriveTypes::Drive4W: - { - PxVehicleDrive4WRawInputData rawInputData; - rawInputData.setAnalogAccel(throttle); - rawInputData.setAnalogBrake(brake); - rawInputData.setAnalogSteer(wheelVehicle->_steering); - rawInputData.setAnalogHandbrake(wheelVehicle->_handBrake); - PxVehicleDrive4WSmoothAnalogRawInputsAndSetAnalogInputs(padSmoothing, steerVsForwardSpeed, rawInputData, mLastDeltaTime, false, *(PxVehicleDrive4W*)drive); - break; - } - case WheeledVehicle::DriveTypes::DriveNW: - { - PxVehicleDriveNWRawInputData rawInputData; - rawInputData.setAnalogAccel(throttle); - rawInputData.setAnalogBrake(brake); - rawInputData.setAnalogSteer(wheelVehicle->_steering); - rawInputData.setAnalogHandbrake(wheelVehicle->_handBrake); - PxVehicleDriveNWSmoothAnalogRawInputsAndSetAnalogInputs(padSmoothing, steerVsForwardSpeed, rawInputData, mLastDeltaTime, false, *(PxVehicleDriveNW*)drive); - break; - } - } - } - else - { - const float deadZone = 0.1f; - switch (wheelVehicle->_driveTypeCurrent) - { - case WheeledVehicle::DriveTypes::Drive4W: - { - PxVehicleDrive4WRawInputData rawInputData; - rawInputData.setDigitalAccel(throttle > deadZone); - rawInputData.setDigitalBrake(brake > deadZone); - rawInputData.setDigitalSteerLeft(wheelVehicle->_steering < -deadZone); - rawInputData.setDigitalSteerRight(wheelVehicle->_steering > deadZone); - rawInputData.setDigitalHandbrake(wheelVehicle->_handBrake > deadZone); - PxVehicleDrive4WSmoothDigitalRawInputsAndSetAnalogInputs(keySmoothing, steerVsForwardSpeed, rawInputData, mLastDeltaTime, false, *(PxVehicleDrive4W*)drive); - break; - } - case WheeledVehicle::DriveTypes::DriveNW: - { - PxVehicleDriveNWRawInputData rawInputData; - rawInputData.setDigitalAccel(throttle > deadZone); - rawInputData.setDigitalBrake(brake > deadZone); - rawInputData.setDigitalSteerLeft(wheelVehicle->_steering < -deadZone); - rawInputData.setDigitalSteerRight(wheelVehicle->_steering > deadZone); - rawInputData.setDigitalHandbrake(wheelVehicle->_handBrake > deadZone); - PxVehicleDriveNWSmoothDigitalRawInputsAndSetAnalogInputs(keySmoothing, steerVsForwardSpeed, rawInputData, mLastDeltaTime, false, *(PxVehicleDriveNW*)drive); - break; - } - } - } - } - - // Update batches queries cache - if (wheelsCount > mPhysxImpl->WheelQueryResults.Count()) - { - if (mPhysxImpl->WheelRaycastBatchQuery) - mPhysxImpl->WheelRaycastBatchQuery->release(); - mPhysxImpl->WheelQueryResults.Resize(wheelsCount, false); - mPhysxImpl->WheelHitResults.Resize(wheelsCount, false); - PxBatchQueryDesc desc(wheelsCount, 0, 0); - desc.queryMemory.userRaycastResultBuffer = mPhysxImpl->WheelQueryResults.Get(); - desc.queryMemory.userRaycastTouchBuffer = mPhysxImpl->WheelHitResults.Get(); - desc.queryMemory.raycastTouchBufferSize = wheelsCount; - desc.preFilterShader = WheelRaycastPreFilter; - mPhysxImpl->WheelRaycastBatchQuery = mPhysxImpl->Scene->createBatchQuery(desc); - } - - // TODO: expose vehicle tires configuration - if (!mPhysxImpl->WheelTireFrictions) - { - PxVehicleDrivableSurfaceType surfaceTypes[1]; - surfaceTypes[0].mType = 0; - const PxMaterial* surfaceMaterials[1]; - surfaceMaterials[0] = Physics::GetDefaultMaterial(); - mPhysxImpl->WheelTireFrictions = PxVehicleDrivableSurfaceToTireFrictionPairs::allocate(1, 1); - mPhysxImpl->WheelTireFrictions->setup(1, 1, surfaceMaterials, surfaceTypes); - mPhysxImpl->WheelTireFrictions->setTypePairFriction(0, 0, 5.0f); - } - - // Setup cache for wheel states - mPhysxImpl->WheelVehiclesResultsPerVehicle.Resize(mPhysxImpl->WheelVehiclesCache.Count(), false); - mPhysxImpl->WheelVehiclesResultsPerWheel.Resize(wheelsCount, false); - wheelsCount = 0; - for (int32 i = 0, ii = 0; i < mPhysxImpl->WheelVehicles.Count(); i++) - { - auto wheelVehicle = mPhysxImpl->WheelVehicles[i]; - if (!wheelVehicle->IsActiveInHierarchy()) - continue; - auto drive = (PxVehicleWheels*)mPhysxImpl->WheelVehicles[ii]->_drive; - auto& perVehicle = mPhysxImpl->WheelVehiclesResultsPerVehicle[ii]; - ii++; - perVehicle.nbWheelQueryResults = drive->mWheelsSimData.getNbWheels(); - perVehicle.wheelQueryResults = mPhysxImpl->WheelVehiclesResultsPerWheel.Get() + wheelsCount; - wheelsCount += perVehicle.nbWheelQueryResults; - } - - // Update vehicles - if (mPhysxImpl->WheelVehiclesCache.Count() != 0) - { - PxVehicleSuspensionRaycasts(mPhysxImpl->WheelRaycastBatchQuery, mPhysxImpl->WheelVehiclesCache.Count(), mPhysxImpl->WheelVehiclesCache.Get(), mPhysxImpl->WheelQueryResults.Count(), mPhysxImpl->WheelQueryResults.Get()); - PxVehicleUpdates(mLastDeltaTime, mPhysxImpl->Scene->getGravity(), *mPhysxImpl->WheelTireFrictions, mPhysxImpl->WheelVehiclesCache.Count(), mPhysxImpl->WheelVehiclesCache.Get(), mPhysxImpl->WheelVehiclesResultsPerVehicle.Get()); - } - - // Synchronize state - for (int32 i = 0, ii = 0; i < mPhysxImpl->WheelVehicles.Count(); i++) - { - auto wheelVehicle = mPhysxImpl->WheelVehicles[i]; - if (!wheelVehicle->IsActiveInHierarchy()) - continue; - auto drive = mPhysxImpl->WheelVehiclesCache[ii]; - auto& perVehicle = mPhysxImpl->WheelVehiclesResultsPerVehicle[ii]; - ii++; -#if PHYSX_VEHICLE_DEBUG_TELEMETRY - LOG(Info, "Vehicle[{}] Gear={}, RPM={}", ii, wheelVehicle->GetCurrentGear(), (int32)wheelVehicle->GetEngineRotationSpeed()); -#endif - - // Update wheels - for (int32 j = 0; j < wheelVehicle->_wheelsData.Count(); j++) - { - auto& wheelData = wheelVehicle->_wheelsData[j]; - auto& perWheel = perVehicle.wheelQueryResults[j]; -#if PHYSX_VEHICLE_DEBUG_TELEMETRY - LOG(Info, "Vehicle[{}] Wheel[{}] longitudinalSlip={}, lateralSlip={}, suspSpringForce={}", ii, j, Utilities::RoundTo2DecimalPlaces(perWheel.longitudinalSlip), Utilities::RoundTo2DecimalPlaces(perWheel.lateralSlip), (int32)perWheel.suspSpringForce); -#endif - - auto& state = wheelData.State; - state.IsInAir = perWheel.isInAir; - state.TireContactCollider = perWheel.tireContactShape ? static_cast(perWheel.tireContactShape->userData) : nullptr; - state.TireContactPoint = P2C(perWheel.tireContactPoint); - 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); -#endif - - if (!wheelData.Collider) - continue; - auto shape = wheelData.Collider->GetPxShape(); - - // Update wheel collider transformation - auto localPose = shape->getLocalPose(); - Transform t = wheelData.Collider->GetLocalTransform(); - t.Orientation = Quaternion::Euler(0, state.SteerAngle, state.RotationAngle) * wheelData.LocalOrientation; - t.Translation = P2C(localPose.p) / wheelVehicle->GetScale() - t.Orientation * wheelData.Collider->GetCenter(); - wheelData.Collider->SetLocalTransform(t); - } - } - } -#endif - - { - PROFILE_CPU_NAMED("Physics.FlushActiveTransforms"); - - // Gather change info - PxU32 activeActorsCount; - PxActor** activeActors = mPhysxImpl->Scene->getActiveActors(activeActorsCount); - if (activeActorsCount > 0) - { - // Update changed transformations - // TODO: use jobs system if amount if huge - for (uint32 i = 0; i < activeActorsCount; i++) - { - const auto pxActor = (PxRigidActor*)*activeActors++; - auto actor = dynamic_cast((Actor*)pxActor->userData); - ASSERT(actor); - actor->OnActiveTransformChanged(pxActor->getGlobalPose()); - } - } - } - - { - PROFILE_CPU_NAMED("Physics.SendEvents"); - - mPhysxImpl->EventsCallback.CollectResults(); - mPhysxImpl->EventsCallback.SendTriggerEvents(); - mPhysxImpl->EventsCallback.SendCollisionEvents(); - mPhysxImpl->EventsCallback.SendJointEvents(); - } - - // End - mIsDuringSimulation = false; -} - -void PhysicsScene::FlushRequests() -{ - ASSERT(!IsDuringSimulation()); - ASSERT(CPhysX); - - PROFILE_CPU(); - - mPhysxImpl->FlushLocker.Lock(); - - // Note: this does not handle case when actor is removed and added to the scene at the same time - - if (mPhysxImpl->NewActors.HasItems()) - { - GetScene()->addActors(mPhysxImpl->NewActors.Get(), mPhysxImpl->NewActors.Count()); - mPhysxImpl->NewActors.Clear(); - } - - for (int32 i = 0; i < mPhysxImpl->Actions.Count(); i++) - { - const auto action = mPhysxImpl->Actions[i]; - switch (action.Type) - { - case ActionType::Sleep: - static_cast(action.Actor)->putToSleep(); - break; - } - } - mPhysxImpl->Actions.Clear(); - - if (mPhysxImpl->DeadActors.HasItems()) - { - GetScene()->removeActors(mPhysxImpl->DeadActors.Get(), mPhysxImpl->DeadActors.Count(), true); - for (int32 i = 0; i < mPhysxImpl->DeadActors.Count(); i++) - { - mPhysxImpl->DeadActors[i]->release(); - } - mPhysxImpl->DeadActors.Clear(); - } - - if (mPhysxImpl->DeadColliders.HasItems()) - { - for (int32 i = 0; i < mPhysxImpl->DeadColliders.Count(); i++) - { - mPhysxImpl->EventsCallback.OnColliderRemoved(mPhysxImpl->DeadColliders[i]); - } - mPhysxImpl->DeadColliders.Clear(); - } - - if (mPhysxImpl->DeadJoints.HasItems()) - { - for (int32 i = 0; i < mPhysxImpl->DeadJoints.Count(); i++) - { - mPhysxImpl->EventsCallback.OnJointRemoved(mPhysxImpl->DeadJoints[i]); - } - mPhysxImpl->DeadJoints.Clear(); - } - - for (int32 i = 0; i < mPhysxImpl->DeadMaterials.Count(); i++) - { - auto material = mPhysxImpl->DeadMaterials[i]; - - // Unlink ref to flax object - material->userData = nullptr; - - material->release(); - } - mPhysxImpl->DeadMaterials.Clear(); - - for (int32 i = 0; i < mPhysxImpl->DeadObjects.Count(); i++) - { - mPhysxImpl->DeadObjects[i]->release(); - } - mPhysxImpl->DeadObjects.Clear(); - - mPhysxImpl->FlushLocker.Unlock(); -} - -void PhysicsScene::RemoveMaterial(PxMaterial* material) -{ - ASSERT(material); - - mPhysxImpl->FlushLocker.Lock(); - mPhysxImpl->DeadMaterials.Add(material); - mPhysxImpl->FlushLocker.Unlock(); -} - -void PhysicsScene::RemoveObject(PxBase* obj) -{ - ASSERT(obj); - - mPhysxImpl->FlushLocker.Lock(); - mPhysxImpl->DeadObjects.Add(obj); - mPhysxImpl->FlushLocker.Unlock(); -} - -void PhysicsScene::AddActor(PxActor* actor) -{ - ASSERT(actor); - - mPhysxImpl->FlushLocker.Lock(); - if (IsInMainThread()) - { - GetScene()->addActor(*actor); - } - else - { - mPhysxImpl->NewActors.Add(actor); - } - mPhysxImpl->FlushLocker.Unlock(); -} - -void PhysicsScene::AddActor(PxRigidDynamic* actor, bool putToSleep) -{ - ASSERT(actor); - - mPhysxImpl->FlushLocker.Lock(); - if (IsInMainThread()) - { - GetScene()->addActor(*actor); - if (putToSleep) - actor->putToSleep(); - } - else - { - mPhysxImpl->NewActors.Add(actor); - if (putToSleep) - mPhysxImpl->Actions.Add({ ActionType::Sleep, actor }); - } - mPhysxImpl->FlushLocker.Unlock(); -} - -void PhysicsScene::UnlinkActor(PxActor* actor) -{ - ASSERT(IsInMainThread()) - ASSERT(actor); - - GetScene()->removeActor(*actor); -} - -void PhysicsScene::RemoveActor(PxActor* actor) -{ - ASSERT(actor); - - // Unlink ref to flax object - actor->userData = nullptr; - - mPhysxImpl->FlushLocker.Lock(); - mPhysxImpl->DeadActors.Add(actor); - mPhysxImpl->FlushLocker.Unlock(); -} - -void PhysicsScene::RemoveCollider(PhysicsColliderActor* collider) -{ - ASSERT(collider); - - mPhysxImpl->FlushLocker.Lock(); - mPhysxImpl->DeadColliders.Add(collider); - mPhysxImpl->FlushLocker.Unlock(); -} - -void PhysicsScene::RemoveJoint(Joint* joint) -{ - ASSERT(joint); - - mPhysxImpl->FlushLocker.Lock(); - mPhysxImpl->DeadJoints.Add(joint); - mPhysxImpl->FlushLocker.Unlock(); -} - -PxControllerManager* PhysicsScene::GetControllerManager() -{ - return mPhysxImpl->ControllerManager; -} - -#if WITH_VEHICLE -void PhysicsScene::AddWheeledVehicle(WheeledVehicle* vehicle) -{ - mPhysxImpl->WheelVehicles.Add(vehicle); -} - -void PhysicsScene::RemoveWheeledVehicle(WheeledVehicle* vehicle) -{ - mPhysxImpl->WheelVehicles.Remove(vehicle); -} -#endif diff --git a/Source/Engine/Physics/PhysicsScene.h b/Source/Engine/Physics/PhysicsScene.h index 1c95e7ece..db17c7ac1 100644 --- a/Source/Engine/Physics/PhysicsScene.h +++ b/Source/Engine/Physics/PhysicsScene.h @@ -1,33 +1,36 @@ +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. + #pragma once -#include "Engine/Scripting/ScriptingObject.h" -#include "Engine/Scripting/ScriptingType.h" #include "Engine/Core/Math/Vector3.h" #include "Engine/Core/Math/Quaternion.h" +#include "Engine/Scripting/ScriptingObject.h" #include "Types.h" +struct ActionData; +struct RayCastHit; +class PhysicsSettings; +class PhysicsColliderActor; +class Joint; +class Collider; +class CollisionData; #if WITH_VEHICLE class WheeledVehicle; #endif -struct ActionData; -struct RayCastHit; -class FixedStepper; -class PhysicsSettings; -class PhysicsColliderActor; -class PhysicsScenePhysX; -class Joint; -class Collider; -class CollisionData; - /// -/// Isolated physics scene. +/// Physical simulation scene. /// -API_CLASS(NoSpawn) class FLAXENGINE_API PhysicsScene : public PersistentScriptingObject +API_CLASS() class FLAXENGINE_API PhysicsScene : public ScriptingObject { - DECLARE_SCRIPTING_TYPE_NO_SPAWN(PhysicsScene); + DECLARE_SCRIPTING_TYPE(PhysicsScene); +private: + String _name; + bool _autoSimulation = true; + bool _isDuringSimulation = false; + void* _scene = nullptr; - explicit PhysicsScene(const String& name, const PhysicsSettings& settings); +public: ~PhysicsScene(); /// @@ -35,30 +38,34 @@ API_CLASS(NoSpawn) class FLAXENGINE_API PhysicsScene : public PersistentScriptin /// API_PROPERTY() String GetName() const; -public: - String ToString() const override + /// + /// Gets the native physics system scene object. + /// + FORCE_INLINE void* GetPhysicsScene() const { - return GetName(); + return _scene; } - PxScene* GetScene(); + /// + /// Gets the automatic simulation feature that perform physics simulation after on fixed update by auto, otherwise user should do it. + /// + API_PROPERTY() bool GetAutoSimulation() const; /// - /// The automatic simulation feature. True if perform physics simulation after on fixed update by auto, otherwise user should do it. + /// Sets the automatic simulation feature that perform physics simulation after on fixed update by auto, otherwise user should do it. /// - API_PROPERTY() bool GetAutoSimulation(); API_PROPERTY() void SetAutoSimulation(bool value); - /// - /// Sets the current gravity force. - /// - API_PROPERTY() void SetGravity(const Vector3& value); - /// /// Gets the current gravity force. /// API_PROPERTY() Vector3 GetGravity(); + /// + /// Sets the current gravity force. + /// + API_PROPERTY() void SetGravity(const Vector3& value); + /// /// Gets the CCD feature enable flag. /// @@ -67,7 +74,7 @@ public: /// /// Sets the CCD feature enable flag. /// - API_PROPERTY() void SetEnableCCD(const bool value); + API_PROPERTY() void SetEnableCCD(bool value); /// /// Gets the minimum relative velocity required for an object to bounce. @@ -77,7 +84,16 @@ public: /// /// Sets the minimum relative velocity required for an object to bounce. /// - API_PROPERTY() void SetBounceThresholdVelocity(const float value); + API_PROPERTY() void SetBounceThresholdVelocity(float value); + +public: + /// + /// Initializes the scene. + /// + /// The name. + /// The physics settings. + /// True if failed, otherwise false. + bool Init(const StringView& name, const PhysicsSettings& settings); /// /// Called during main engine loop to start physic simulation. Use CollectResults after. @@ -86,90 +102,16 @@ public: API_FUNCTION() void Simulate(float dt); /// - /// Checks if physical simulation is running + /// Checks if physical simulation is running. /// - /// True if simulation is active, otherwise false - API_PROPERTY() bool IsDuringSimulation(); + API_PROPERTY() bool IsDuringSimulation() const; /// /// Called to collect physic simulation results and apply them as well as fire collision events. /// API_FUNCTION() void CollectResults(); - /// - /// Flushes the async requests to add/remove actors, remove materials, etc.. - /// - void FlushRequests(); - - /// - /// Removes the material (using safe async request). - /// - /// The material. - void RemoveMaterial(PxMaterial* material); - - /// - /// Removes the physX object via calling release() on it (using safe async request). - /// - /// The obj. - void RemoveObject(PxBase* obj); - - /// - /// Adds the actor (using safe async request). - /// - /// The actor. - void AddActor(PxActor* actor); - - /// - /// Adds the actor (using safe async request). - /// - /// The actor. - /// If set to true will put actor to sleep after spawning. - void AddActor(PxRigidDynamic* actor, bool putToSleep = false); - - /// - /// Removes the actor (using safe async request). - /// - /// The actor. - void RemoveActor(PxActor* actor); - - /// - /// Removes the actor from the underlying physics scene without destroying it. - /// - void UnlinkActor(PxActor* actor); - - /// - /// Marks that collider has been removed (all collision events should be cleared to prevent leaks of using removed object). - /// - /// The collider. - void RemoveCollider(PhysicsColliderActor* collider); - - /// - /// Marks that joint has been removed (all collision events should be cleared to prevent leaks of using removed object). - /// - /// The joint. - void RemoveJoint(Joint* joint); - - /// - /// Gets PhysX characters controller manager object - /// - PxControllerManager* GetControllerManager(); - public: - /// - /// Gets the default query filter callback used for the scene queries. - /// - PxQueryFilterCallback* GetQueryFilterCallback(); - - /// - /// Gets the default query filter callback used for the character controller collisions detection. - /// - PxQueryFilterCallback* GetCharacterQueryFilterCallback(); - - /// - /// Gets the default controller filter callback used for the character controller collisions detection. - /// - static PxControllerFilterCallback* GetCharacterControllerFilterCallback(); - /// /// Performs a raycast against objects in the scene. /// @@ -514,20 +456,4 @@ public: /// If set to true triggers will be hit, otherwise will skip them. /// True if convex mesh overlaps any matching object, otherwise false. API_FUNCTION() bool OverlapConvex(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, API_PARAM(Out) Array& results, const Quaternion& rotation = Quaternion::Identity, uint32 layerMask = MAX_uint32, bool hitTriggers = true); - -public: -#if WITH_VEHICLE - void AddWheeledVehicle(WheeledVehicle* vehicle); - void RemoveWheeledVehicle(WheeledVehicle* vehicle); -#endif - -private: - String mName; - bool mAutoSimulation = true; - void* mScratchMemory = nullptr; - FixedStepper* mStepper = nullptr; - float mLastDeltaTime = 0.0f; - bool mIsDuringSimulation = false; - - PhysicsScenePhysX* mPhysxImpl; }; diff --git a/Source/Engine/Physics/Types.h b/Source/Engine/Physics/Types.h index 614322488..f7abc9062 100644 --- a/Source/Engine/Physics/Types.h +++ b/Source/Engine/Physics/Types.h @@ -4,54 +4,15 @@ #include "Engine/Core/Enums.h" #include "Engine/Core/Config.h" +#include "Engine/Core/Math/Vector2.h" +#include "Engine/Core/Math/Vector3.h" +#include "Engine/Scripting/ScriptingType.h" -namespace physx -{ - class PxScene; - class PxConvexMesh; - class PxTriangleMesh; - class PxCooking; - class PxPhysics; - class PxVec3; - class PxVec4; - class PxTransform; - class PxJoint; - class PxMat44; - class PxCpuDispatcher; - class PxGpuDispatcher; - class PxSimulationEventCallback; - struct PxActiveTransform; - class PxActor; - class PxRigidActor; - class PxRigidDynamic; - class PxRigidStatic; - class PxFoundation; - class PxShape; - class PxGeometry; - class PxGeometryHolder; - class PxProfileZoneManager; - class PxMaterial; - class PxPvd; - class PxBase; - class PxTolerancesScale; - class PxBaseTask; - class PxControllerManager; - class PxController; - class PxCapsuleController; - class PxQueryFilterCallback; - class PxControllerFilterCallback; - class PxHeightField; - struct PxFilterData; - struct PxRaycastHit; - struct PxSweepHit; -} - -using namespace physx; - -#define RELEASE_PHYSX(x) if(x) { (x)->release(); x = nullptr; } - -// Global pointer to PhysX SDK object -extern PxPhysics* CPhysX; +class PhysicsColliderActor; +class PhysicsScene; +class Joint; +class Collider; +class CollisionData; /// /// Enumeration that determines the way in which two material properties will be combined to yield a friction or restitution coefficient for a collision. @@ -167,3 +128,147 @@ API_ENUM(Attributes="Flags") enum class RigidbodyConstraints }; DECLARE_ENUM_OPERATORS(RigidbodyConstraints); + +/// +/// Raycast hit result data. +/// +API_STRUCT() struct RayCastHit +{ + DECLARE_SCRIPTING_TYPE_NO_SPAWN(RayCastHit); + + /// + /// The collider that was hit. + /// + API_FIELD() PhysicsColliderActor* Collider = nullptr; + + /// + /// The normal of the surface the ray hit. + /// + API_FIELD() Vector3 Normal; + + /// + /// The distance from the ray's origin to the hit location. + /// + API_FIELD() float Distance; + + /// + /// The point in the world space where ray hit the collider. + /// + API_FIELD() Vector3 Point; + + /// + /// The index of the face that was hit. Valid only for convex mesh (polygon index), triangle mesh (triangle index) and height field (triangle index). + /// + /// + API_FIELD() uint32 FaceIndex; + + /// + /// The barycentric coordinates of hit triangle. Valid only for triangle mesh and height field. + /// + API_FIELD() Vector2 UV; +}; + +/// +/// Physics collision shape variant for different shapes such as box, sphere, capsule. +/// +struct FLAXENGINE_API CollisionShape +{ + enum class Types : uint8 + { + Sphere, + Box, + Capsule, + ConvexMesh, + TriangleMesh, + HeightField, + }; + + Types Type; + + union + { + struct + { + float Radius; + } Sphere; + + struct + { + float HalfExtents[3]; + } Box; + + struct + { + float Radius; + float HalfHeight; + } Capsule; + + struct + { + void* ConvexMesh; + float Scale[3]; + } ConvexMesh; + + struct + { + void* TriangleMesh; + float Scale[3]; + } TriangleMesh; + + struct + { + void* HeightField; + float HeightScale; + float RowScale; + float ColumnScale; + } HeightField; + }; + + void SetSphere(float radius) + { + Type = Types::Sphere; + Sphere.Radius = radius; + } + + void SetBox(float halfExtents[3]) + { + Type = Types::Box; + Box.HalfExtents[0] = halfExtents[0]; + Box.HalfExtents[1] = halfExtents[1]; + Box.HalfExtents[2] = halfExtents[2]; + } + + void SetCapsule(float radius, float halfHeight) + { + Type = Types::Capsule; + Capsule.Radius = radius; + Capsule.HalfHeight = halfHeight; + } + + void SetConvexMesh(void* contextMesh, float scale[3]) + { + Type = Types::ConvexMesh; + ConvexMesh.ConvexMesh = contextMesh; + ConvexMesh.Scale[0] = scale[0]; + ConvexMesh.Scale[1] = scale[1]; + ConvexMesh.Scale[2] = scale[2]; + } + + void SetTriangleMesh(void* triangleMesh, float scale[3]) + { + Type = Types::TriangleMesh; + TriangleMesh.TriangleMesh = triangleMesh; + TriangleMesh.Scale[0] = scale[0]; + TriangleMesh.Scale[1] = scale[1]; + TriangleMesh.Scale[2] = scale[2]; + } + + void SetHeightField(void* heightField, float heightScale, float rowScale, float columnScale) + { + Type = Types::HeightField; + HeightField.HeightField = heightField; + HeightField.HeightScale = heightScale; + HeightField.RowScale = rowScale; + HeightField.ColumnScale = columnScale; + } +}; diff --git a/Source/Engine/Physics/Utilities.h b/Source/Engine/Physics/Utilities.h deleted file mode 100644 index fd38a55cd..000000000 --- a/Source/Engine/Physics/Utilities.h +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. - -#pragma once - -#include "Engine/Core/Math/Vector2.h" -#include "Engine/Core/Math/Vector3.h" -#include "Engine/Core/Math/Vector4.h" -#include "Engine/Core/Math/Quaternion.h" -#include "Engine/Core/Math/BoundingBox.h" -#include -#include -#include -#include -#include -#include -#include - -inline PxVec2& C2P(const Vector2& v) -{ - return *(PxVec2*)&v; -} - -inline PxVec3& C2P(const Vector3& v) -{ - return *(PxVec3*)&v; -} - -inline PxVec4& C2P(const Vector4& v) -{ - return *(PxVec4*)&v; -} - -inline PxQuat& C2P(const Quaternion& v) -{ - return *(PxQuat*)&v; -} - -inline PxBounds3& C2P(const BoundingBox& v) -{ - return *(PxBounds3*)&v; -} - -inline Vector2& P2C(const PxVec2& v) -{ - return *(Vector2*)&v; -} - -inline Vector3& P2C(const PxVec3& v) -{ - return *(Vector3*)&v; -} - -inline Vector4& P2C(const PxVec4& v) -{ - return *(Vector4*)&v; -} - -inline Quaternion& P2C(const PxQuat& v) -{ - return *(Quaternion*)&v; -} - -inline BoundingBox& P2C(const PxBounds3& v) -{ - return *(BoundingBox*)&v; -} - -inline Vector3 P2C(const PxExtendedVec3& v) -{ -#ifdef PX_BIG_WORLDS - return Vector3((float)v.x, (float)v.y, (float)v.z); -#else - return *(Vector3*)&v; -#endif -} - -inline float M2ToCm2(float v) -{ - return v * (100.0f * 100.0f); -} - -inline float Cm2ToM2(float v) -{ - return v / (100.0f * 100.0f); -} - -inline float KgPerM3ToKgPerCm3(float v) -{ - return v / (100.0f * 100.0f * 100.0f); -} - -inline float RpmToRadPerS(float v) -{ - return v * (PI / 30.0f); -} - -inline float RadPerSToRpm(float v) -{ - return v * (30.0f / PI); -} - -extern PxShapeFlags GetShapeFlags(bool isTrigger, bool isEnabled); diff --git a/Source/Engine/Terrain/Terrain.cpp b/Source/Engine/Terrain/Terrain.cpp index c09e20609..b7ec73a36 100644 --- a/Source/Engine/Terrain/Terrain.cpp +++ b/Source/Engine/Terrain/Terrain.cpp @@ -7,13 +7,12 @@ #include "Engine/Level/Scene/SceneRendering.h" #include "Engine/Serialization/Serialization.h" #include "Engine/Physics/Physics.h" -#include "Engine/Physics/Utilities.h" #include "Engine/Physics/PhysicalMaterial.h" +#include "Engine/Physics/PhysicsBackend.h" #include "Engine/Graphics/RenderView.h" #include "Engine/Graphics/RenderTask.h" #include "Engine/Graphics/Textures/GPUTexture.h" #include "Engine/Profiler/ProfilerCPU.h" -#include Terrain::Terrain(const SpawnParams& params) : PhysicsColliderActor(params) @@ -69,13 +68,11 @@ void Terrain::UpdateLayerBits() if (_patches.IsEmpty()) return; - PxFilterData filterData; - // Own layer ID - filterData.word0 = GetLayerMask(); + const uint32 mask0 = GetLayerMask(); // Own layer mask - filterData.word1 = Physics::LayerMasks[GetLayer()]; + const uint32 mask1 = Physics::LayerMasks[GetLayer()]; // Update the shapes layer bits for (int32 pathIndex = 0; pathIndex < _patches.Count(); pathIndex++) @@ -83,8 +80,7 @@ void Terrain::UpdateLayerBits() const auto patch = _patches[pathIndex]; if (patch->HasCollision()) { - patch->_physicsShape->setSimulationFilterData(filterData); - patch->_physicsShape->setQueryFilterData(filterData); + PhysicsBackend::SetShapeFilterMask(patch->_physicsShape, mask0, mask1); } } } @@ -170,7 +166,6 @@ bool Terrain::RayCast(const Vector3& origin, const Vector3& direction, RayCastHi bool result = false; RayCastHit tmpHit; const Ray ray(origin, direction); - for (int32 pathIndex = 0; pathIndex < _patches.Count(); pathIndex++) { const auto patch = _patches[pathIndex]; @@ -184,7 +179,6 @@ bool Terrain::RayCast(const Vector3& origin, const Vector3& direction, RayCastHi result = true; } } - return result; } @@ -192,13 +186,12 @@ void Terrain::ClosestPoint(const Vector3& position, Vector3& result) const { float minDistance = MAX_float; Vector3 tmp; - for (int32 pathIndex = 0; pathIndex < _patches.Count(); pathIndex++) { const auto patch = _patches[pathIndex]; if (patch->HasCollision()) { - patch->ClosestPoint(position, &tmp); + patch->ClosestPoint(position, tmp); const auto distance = Vector3::DistanceSquared(position, tmp); if (distance < minDistance) { @@ -237,22 +230,13 @@ void Terrain::OnPhysicalMaterialChanged() if (_patches.IsEmpty()) return; - PxMaterial* material = Physics::GetDefaultMaterial(); - if (PhysicalMaterial) - { - if (!PhysicalMaterial->WaitForLoaded()) - { - material = ((::PhysicalMaterial*)PhysicalMaterial->Instance)->GetPhysXMaterial(); - } - } - // Update the shapes material for (int32 pathIndex = 0; pathIndex < _patches.Count(); pathIndex++) { const auto patch = _patches[pathIndex]; if (patch->HasCollision()) { - patch->_physicsShape->setMaterials(&material, 1); + PhysicsBackend::SetShapeMaterial(patch->_physicsShape, PhysicalMaterial.Get()); } } } @@ -819,13 +803,12 @@ void Terrain::OnActiveInTreeChanged() Actor::OnActiveInTreeChanged(); // Update physics - const PxShapeFlags shapeFlags = GetShapeFlags(false, IsActiveInHierarchy()); for (int32 pathIndex = 0; pathIndex < _patches.Count(); pathIndex++) { const auto patch = _patches[pathIndex]; if (patch->HasCollision()) { - patch->_physicsShape->setFlags(shapeFlags); + PhysicsBackend::SetShapeState(patch->_physicsShape, IsActiveInHierarchy(), false); } } } diff --git a/Source/Engine/Terrain/TerrainPatch.cpp b/Source/Engine/Terrain/TerrainPatch.cpp index 82b379d39..aed8b7a60 100644 --- a/Source/Engine/Terrain/TerrainPatch.cpp +++ b/Source/Engine/Terrain/TerrainPatch.cpp @@ -5,11 +5,12 @@ #include "Engine/Serialization/Serialization.h" #include "Engine/Core/Math/Color32.h" #include "Engine/Profiler/ProfilerCPU.h" -#include "Engine/Physics/Utilities.h" #include "Engine/Physics/Physics.h" #include "Engine/Physics/PhysicsScene.h" -#include "Engine/Physics/PhysicalMaterial.h" +#include "Engine/Physics/PhysicsBackend.h" +#include "Engine/Physics/CollisionCooking.h" #include "Engine/Level/Scene/Scene.h" +#include "Engine/Level/Level.h" #include "Engine/Graphics/Async/GPUTask.h" #include "Engine/Threading/Threading.h" #if TERRAIN_EDITING @@ -19,6 +20,7 @@ #include "Engine/Graphics/RenderView.h" #include "Engine/Graphics/Textures/GPUTexture.h" #include "Engine/Graphics/Textures/TextureData.h" +#include "Engine/Serialization/MemoryWriteStream.h" #if USE_EDITOR #include "Editor/Editor.h" #include "Engine/ContentImporters/AssetsImportingManager.h" @@ -27,21 +29,10 @@ #if USE_EDITOR #include "Engine/Debug/DebugDraw.h" #endif -#include "Engine/Physics/CollisionCooking.h" #include "Engine/Content/Content.h" #include "Engine/Content/Assets/RawDataAsset.h" -#include "Engine/Level/Level.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#define TERRAIN_PATCH_COLLISION_QUANTIZATION ((PxReal)0x7fff) +#define TERRAIN_PATCH_COLLISION_QUANTIZATION ((float)0x7fff) struct TerrainCollisionDataHeader { @@ -128,8 +119,7 @@ void TerrainPatch::UpdateTransform() if (_physicsActor) { const Transform& terrainTransform = _terrain->_transform; - const PxTransform trans(C2P(terrainTransform.LocalToWorld(_offset)), C2P(terrainTransform.Orientation)); - _physicsActor->setGlobalPose(trans); + PhysicsBackend::SetRigidActorPose(_physicsActor, terrainTransform.LocalToWorld(_offset), terrainTransform.Orientation); } // Update chunks cache @@ -565,10 +555,10 @@ bool CookCollision(const TerrainDataUpdateInfo& info, TextureBase::InitData* ini const int32 heightFieldChunkSize = ((info.ChunkSize + 1) >> collisionLOD) - 1; const int32 heightFieldSize = heightFieldChunkSize * TerrainPatch::CHUNKS_COUNT_EDGE + 1; const int32 heightFieldLength = heightFieldSize * heightFieldSize; - GET_TERRAIN_SCRATCH_BUFFER(heightFieldData, heightFieldLength, PxHeightFieldSample); - PxHeightFieldSample sample; - Platform::MemoryClear(&sample, sizeof(PxHeightFieldSample)); - Platform::MemoryClear(heightFieldData, sizeof(PxHeightFieldSample) * heightFieldLength); + GET_TERRAIN_SCRATCH_BUFFER(heightFieldData, heightFieldLength, PhysicsBackend::HeightFieldSample); + PhysicsBackend::HeightFieldSample sample; + Platform::MemoryClear(&sample, sizeof(PhysicsBackend::HeightFieldSample)); + Platform::MemoryClear(heightFieldData, sizeof(PhysicsBackend::HeightFieldSample) * heightFieldLength); // Setup terrain collision information auto& mip = initData->Mips[collisionLOD]; @@ -598,47 +588,38 @@ bool CookCollision(const TerrainDataUpdateInfo& info, TextureBase::InitData* ini const int32 heightmapZ = chunkStartZ + z; const int32 dstIndex = (heightmapX * heightFieldSize) + heightmapZ; - sample.height = PxI16(TERRAIN_PATCH_COLLISION_QUANTIZATION * normalizedHeight); - sample.materialIndex0 = sample.materialIndex1 = isHole ? PxHeightFieldMaterial::eHOLE : 0; + sample.Height = int16(TERRAIN_PATCH_COLLISION_QUANTIZATION * normalizedHeight); + sample.MaterialIndex0 = sample.MaterialIndex1 = isHole ? (uint8)PhysicsBackend::HeightFieldMaterial::Hole : 0; heightFieldData[dstIndex] = sample; } } } } - PxHeightFieldDesc heightFieldDesc; - heightFieldDesc.format = PxHeightFieldFormat::eS16_TM; - heightFieldDesc.flags = PxHeightFieldFlag::eNO_BOUNDARY_EDGES; - heightFieldDesc.nbColumns = heightFieldSize; - heightFieldDesc.nbRows = heightFieldSize; - heightFieldDesc.samples.data = heightFieldData; - heightFieldDesc.samples.stride = sizeof(PxHeightFieldSample); // Cook height field - PxDefaultMemoryOutputStream outputStream; - if (CollisionCooking::CookHeightField(heightFieldDesc, outputStream)) + MemoryWriteStream outputStream; + if (CollisionCooking::CookHeightField(heightFieldSize, heightFieldSize, heightFieldData, outputStream)) { return true; } // Write results - collisionData->Resize(sizeof(TerrainCollisionDataHeader) + outputStream.getSize(), false); + collisionData->Resize(sizeof(TerrainCollisionDataHeader) + outputStream.GetPosition(), false); const auto header = (TerrainCollisionDataHeader*)collisionData->Get(); header->LOD = collisionLOD; header->ScaleXZ = (float)info.HeightmapSize / heightFieldSize; - Platform::MemoryCopy(collisionData->Get() + sizeof(TerrainCollisionDataHeader), outputStream.getData(), outputStream.getSize()); + Platform::MemoryCopy(collisionData->Get() + sizeof(TerrainCollisionDataHeader), outputStream.GetHandle(), outputStream.GetPosition()); return false; #else - - LOG(Warning, "Collision cooking is disabled."); - return true; - + LOG(Warning, "Collision cooking is disabled."); + return true; #endif } -bool ModifyCollision(const TerrainDataUpdateInfo& info, TextureBase::InitData* initData, int32 collisionLod, const Int2& modifiedOffset, const Int2& modifiedSize, PxHeightField* heightField) +bool ModifyCollision(const TerrainDataUpdateInfo& info, TextureBase::InitData* initData, int32 collisionLod, const Int2& modifiedOffset, const Int2& modifiedSize, void* heightField) { PROFILE_CPU_NAMED("Terrain.ModifyCollision"); @@ -658,10 +639,10 @@ bool ModifyCollision(const TerrainDataUpdateInfo& info, TextureBase::InitData* i // Allocate data const int32 heightFieldDataLength = samplesSize.X * samplesSize.Y; - GET_TERRAIN_SCRATCH_BUFFER(heightFieldData, info.HeightmapLength, PxHeightFieldSample); - PxHeightFieldSample sample; - Platform::MemoryClear(&sample, sizeof(PxHeightFieldSample)); - Platform::MemoryClear(heightFieldData, sizeof(PxHeightFieldSample) * heightFieldDataLength); + GET_TERRAIN_SCRATCH_BUFFER(heightFieldData, info.HeightmapLength, PhysicsBackend::HeightFieldSample); + PhysicsBackend::HeightFieldSample sample; + Platform::MemoryClear(&sample, sizeof(PhysicsBackend::HeightFieldSample)); + Platform::MemoryClear(heightFieldData, sizeof(PhysicsBackend::HeightFieldSample) * heightFieldDataLength); // Setup terrain collision information auto& mip = initData->Mips[collisionLOD]; @@ -711,24 +692,17 @@ bool ModifyCollision(const TerrainDataUpdateInfo& info, TextureBase::InitData* i const int32 dstIndex = (heightmapLocalX * samplesSize.Y) + heightmapLocalZ; - sample.height = PxI16(TERRAIN_PATCH_COLLISION_QUANTIZATION * normalizedHeight); - sample.materialIndex0 = sample.materialIndex1 = isHole ? PxHeightFieldMaterial::eHOLE : 0; + sample.Height = int16(TERRAIN_PATCH_COLLISION_QUANTIZATION * normalizedHeight); + sample.MaterialIndex0 = sample.MaterialIndex1 = isHole ? (uint8)PhysicsBackend::HeightFieldMaterial::Hole : 0; heightFieldData[dstIndex] = sample; } } } } - PxHeightFieldDesc heightFieldDesc; - heightFieldDesc.format = PxHeightFieldFormat::eS16_TM; - heightFieldDesc.flags = PxHeightFieldFlag::eNO_BOUNDARY_EDGES; - heightFieldDesc.nbColumns = samplesSize.Y; - heightFieldDesc.nbRows = samplesSize.X; - heightFieldDesc.samples.data = heightFieldData; - heightFieldDesc.samples.stride = sizeof(PxHeightFieldSample); // Update height field range - if (!heightField->modifySamples(samplesOffset.Y, samplesOffset.X, heightFieldDesc, true)) + if (PhysicsBackend::ModifyHeightField(heightField, samplesOffset.Y, samplesOffset.X, samplesSize.Y, samplesSize.X, heightFieldData)) { LOG(Warning, "Height Field collision modification failed."); return true; @@ -1958,7 +1932,7 @@ bool TerrainPatch::UpdateCollision() _collisionVertices.Resize(0); // Recreate height field - _terrain->GetPhysicsScene()->RemoveObject(_physicsHeightField); + PhysicsBackend::DestroyObject(_physicsHeightField); _physicsHeightField = nullptr; if (CreateHeightField()) { @@ -1981,42 +1955,26 @@ bool TerrainPatch::RayCast(const Vector3& origin, const Vector3& direction, floa { if (_physicsShape == nullptr) return false; - - // Prepare data - PxTransform trans = _physicsActor->getGlobalPose(); - trans.p = trans.transform(_physicsShape->getLocalPose().p); - const PxHitFlags hitFlags = (PxHitFlags)0; - - // Perform raycast test - PxRaycastHit hit; - if (PxGeometryQuery::raycast(C2P(origin), C2P(direction), _physicsShape->getGeometry().any(), trans, maxDistance, hitFlags, 1, &hit) != 0) - { - resultHitDistance = hit.distance; - return true; - } - - return false; + Vector3 shapePos; + Quaternion shapeRot; + PhysicsBackend::GetShapePose(_physicsShape, shapePos, shapeRot); + return PhysicsBackend::RayCastShape(_physicsShape, shapePos, shapeRot, origin, direction, resultHitDistance, maxDistance); } bool TerrainPatch::RayCast(const Vector3& origin, const Vector3& direction, float& resultHitDistance, Vector3& resultHitNormal, float maxDistance) const { if (_physicsShape == nullptr) return false; - - // Prepare data - PxTransform trans = _physicsActor->getGlobalPose(); - trans.p = trans.transform(_physicsShape->getLocalPose().p); - const PxHitFlags hitFlags = PxHitFlag::eNORMAL; - - // Perform raycast test - PxRaycastHit hit; - if (PxGeometryQuery::raycast(C2P(origin), C2P(direction), _physicsShape->getGeometry().any(), trans, maxDistance, hitFlags, 1, &hit) != 0) + Vector3 shapePos; + Quaternion shapeRot; + PhysicsBackend::GetShapePose(_physicsShape, shapePos, shapeRot); + RayCastHit hit; + if (PhysicsBackend::RayCastShape(_physicsShape, shapePos, shapeRot, origin, direction, hit, maxDistance)) { - resultHitDistance = hit.distance; - resultHitNormal = P2C(hit.normal); + resultHitDistance = hit.Distance; + resultHitNormal = hit.Normal; return true; } - return false; } @@ -2024,19 +1982,17 @@ bool TerrainPatch::RayCast(const Vector3& origin, const Vector3& direction, floa { if (_physicsShape == nullptr) return false; - - // Prepare data - PxTransform trans = _physicsActor->getGlobalPose(); - trans.p = trans.transform(_physicsShape->getLocalPose().p); - const PxHitFlags hitFlags = (PxHitFlags)0; + Vector3 shapePos; + Quaternion shapeRot; + PhysicsBackend::GetShapePose(_physicsShape, shapePos, shapeRot); // Perform raycast test - PxRaycastHit hit; - if (PxGeometryQuery::raycast(C2P(origin), C2P(direction), _physicsShape->getGeometry().any(), trans, maxDistance, hitFlags, 1, &hit) != 0) + float hitDistance; + if (PhysicsBackend::RayCastShape(_physicsShape, shapePos, shapeRot, origin, direction, hitDistance, maxDistance)) { // Find hit chunk resultChunk = nullptr; - const auto hitPoint = origin + direction * hit.distance; + const auto hitPoint = origin + direction * hitDistance; for (int32 chunkIndex = 0; chunkIndex < CHUNKS_COUNT; chunkIndex++) { const auto box = Chunks[chunkIndex]._bounds; @@ -2052,7 +2008,7 @@ bool TerrainPatch::RayCast(const Vector3& origin, const Vector3& direction, floa if (resultChunk == nullptr) return false; - resultHitDistance = hit.distance; + resultHitDistance = hitDistance; return true; } @@ -2063,44 +2019,28 @@ bool TerrainPatch::RayCast(const Vector3& origin, const Vector3& direction, RayC { if (_physicsShape == nullptr) return false; - - // Prepare data - PxTransform trans = _physicsActor->getGlobalPose(); - trans.p = trans.transform(_physicsShape->getLocalPose().p); - const PxHitFlags hitFlags = PxHitFlag::ePOSITION | PxHitFlag::eNORMAL | PxHitFlag::eUV; - PxRaycastHit hit; - - // Perform raycast test - if (PxGeometryQuery::raycast(C2P(origin), C2P(direction), _physicsShape->getGeometry().any(), trans, maxDistance, hitFlags, 1, &hit) == 0) - return false; - - // Gather results - hitInfo.Gather(hit); - return true; + Vector3 shapePos; + Quaternion shapeRot; + PhysicsBackend::GetShapePose(_physicsShape, shapePos, shapeRot); + return PhysicsBackend::RayCastShape(_physicsShape, shapePos, shapeRot, origin, direction, hitInfo, maxDistance); } -void TerrainPatch::ClosestPoint(const Vector3& position, Vector3* result) const +void TerrainPatch::ClosestPoint(const Vector3& position, Vector3& result) const { if (_physicsShape == nullptr) + { + result = Vector3::Maximum; return; - - // Prepare data - PxTransform trans = _physicsActor->getGlobalPose(); - trans.p = trans.transform(_physicsShape->getLocalPose().p); - PxVec3 closestPoint; - - // Compute distance between a point and a geometry object - const float distanceSqr = PxGeometryQuery::pointDistance(C2P(position), _physicsShape->getGeometry().any(), trans, &closestPoint); + } + Vector3 shapePos; + Quaternion shapeRot; + PhysicsBackend::GetShapePose(_physicsShape, shapePos, shapeRot); + Vector3 closestPoint; + const float distanceSqr = PhysicsBackend::ComputeShapeSqrDistanceToPoint(_physicsShape, shapePos, shapeRot, position, &closestPoint); if (distanceSqr > 0.0f) - { - // Use calculated point - *result = P2C(closestPoint); - } + result = closestPoint; else - { - // Fallback to the input location - *result = position; - } + result = position; } #if USE_EDITOR @@ -2130,7 +2070,7 @@ void TerrainPatch::UpdatePostManualDeserialization() _collisionVertices.Resize(0); // Recreate height field - _terrain->GetPhysicsScene()->RemoveObject(_physicsHeightField); + PhysicsBackend::DestroyObject(_physicsHeightField); _physicsHeightField = nullptr; if (CreateHeightField()) { @@ -2152,45 +2092,27 @@ void TerrainPatch::UpdatePostManualDeserialization() void TerrainPatch::CreateCollision() { ASSERT(!HasCollision()); - if (CreateHeightField()) return; ASSERT(_physicsHeightField); // Create geometry const Transform terrainTransform = _terrain->_transform; - PxHeightFieldGeometry geometry; - geometry.heightField = _physicsHeightField; - geometry.rowScale = Math::Max(Math::Abs(terrainTransform.Scale.X) * _collisionScaleXZ, PX_MIN_HEIGHTFIELD_XZ_SCALE); - geometry.heightScale = Math::Max(Math::Abs(terrainTransform.Scale.Y) * _yHeight / TERRAIN_PATCH_COLLISION_QUANTIZATION, PX_MIN_HEIGHTFIELD_Y_SCALE); - geometry.columnScale = Math::Max(Math::Abs(terrainTransform.Scale.Z) * _collisionScaleXZ, PX_MIN_HEIGHTFIELD_XZ_SCALE); - - // Prepare - const PxShapeFlags shapeFlags = GetShapeFlags(false, _terrain->IsActiveInHierarchy()); - PxMaterial* material = Physics::GetDefaultMaterial(); - if (_terrain->PhysicalMaterial) - { - if (!_terrain->PhysicalMaterial->WaitForLoaded()) - { - material = ((::PhysicalMaterial*)_terrain->PhysicalMaterial->Instance)->GetPhysXMaterial(); - } - } + CollisionShape shape; + const float rowScale = Math::Abs(terrainTransform.Scale.X) * _collisionScaleXZ; + const float heightScale = Math::Abs(terrainTransform.Scale.Y) * _yHeight / TERRAIN_PATCH_COLLISION_QUANTIZATION; + const float columnScale = Math::Abs(terrainTransform.Scale.Z) * _collisionScaleXZ; + shape.SetHeightField(_physicsHeightField, heightScale, rowScale, columnScale); // Create shape - _physicsShape = CPhysX->createShape(geometry, *material, true, shapeFlags); - ASSERT(_physicsShape); - _physicsShape->userData = _terrain; - _physicsShape->setLocalPose(PxTransform(0, _yOffset * terrainTransform.Scale.Y, 0)); + _physicsShape = PhysicsBackend::CreateShape(_terrain, shape, _terrain->PhysicalMaterial.Get(), _terrain->IsActiveInHierarchy(), false); + PhysicsBackend::SetShapeLocalPose(_physicsShape, Vector3(0, _yOffset * terrainTransform.Scale.Y, 0), Quaternion::Identity); // Create static actor - const PxTransform trans(C2P(terrainTransform.LocalToWorld(_offset)), C2P(terrainTransform.Orientation)); - _physicsActor = CPhysX->createRigidStatic(trans); - ASSERT(_physicsActor); - _physicsActor->userData = _terrain; -#if WITH_PVD - _physicsActor->setActorFlag(PxActorFlag::eVISUALIZATION, true); -#endif - _physicsActor->attachShape(*_physicsShape); + _physicsActor = PhysicsBackend::CreateRigidStaticActor(nullptr, terrainTransform.LocalToWorld(_offset), terrainTransform.Orientation); + PhysicsBackend::AttachShape(_physicsShape, _physicsActor); + void* scene = _terrain->GetPhysicsScene()->GetPhysicsScene(); + PhysicsBackend::AddSceneActor(scene, _physicsActor); } bool TerrainPatch::CreateHeightField() @@ -2208,9 +2130,7 @@ bool TerrainPatch::CreateHeightField() const auto collisionHeader = (TerrainCollisionDataHeader*)_heightfield->Data.Get(); _collisionScaleXZ = collisionHeader->ScaleXZ * TERRAIN_UNITS_PER_VERTEX; - - PxDefaultMemoryInputData heightFieldData(_heightfield->Data.Get() + sizeof(TerrainCollisionDataHeader), _heightfield->Data.Count() - sizeof(TerrainCollisionDataHeader)); - _physicsHeightField = CPhysX->createHeightField(heightFieldData); + _physicsHeightField = PhysicsBackend::CreateHeightField(_heightfield->Data.Get() + sizeof(TerrainCollisionDataHeader), _heightfield->Data.Count() - sizeof(TerrainCollisionDataHeader)); if (_physicsHeightField == nullptr) { LOG(Error, "Failed to create terrain collision height field."); @@ -2226,15 +2146,15 @@ void TerrainPatch::UpdateCollisionScale() const // Create geometry const Transform terrainTransform = _terrain->_transform; - PxHeightFieldGeometry geometry; - geometry.heightField = _physicsHeightField; - geometry.rowScale = Math::Max(Math::Abs(terrainTransform.Scale.X) * _collisionScaleXZ, PX_MIN_HEIGHTFIELD_XZ_SCALE); - geometry.heightScale = Math::Max(Math::Abs(terrainTransform.Scale.Y) * _yHeight / TERRAIN_PATCH_COLLISION_QUANTIZATION, PX_MIN_HEIGHTFIELD_Y_SCALE); - geometry.columnScale = Math::Max(Math::Abs(terrainTransform.Scale.Z) * _collisionScaleXZ, PX_MIN_HEIGHTFIELD_XZ_SCALE); + CollisionShape geometry; + const float rowScale = Math::Abs(terrainTransform.Scale.X) * _collisionScaleXZ; + const float heightScale = Math::Abs(terrainTransform.Scale.Y) * _yHeight / TERRAIN_PATCH_COLLISION_QUANTIZATION; + const float columnScale = Math::Abs(terrainTransform.Scale.Z) * _collisionScaleXZ; + geometry.SetHeightField(_physicsHeightField, heightScale, rowScale, columnScale); // Update shape - _physicsShape->setGeometry(geometry); - _physicsShape->setLocalPose(PxTransform(0, _yOffset * terrainTransform.Scale.Y, 0)); + PhysicsBackend::SetShapeGeometry(_physicsShape, geometry); + PhysicsBackend::SetShapeLocalPose(_physicsShape, Vector3(0, _yOffset * terrainTransform.Scale.Y, 0), Quaternion::Identity); } void TerrainPatch::DestroyCollision() @@ -2242,10 +2162,12 @@ void TerrainPatch::DestroyCollision() ScopeLock lock(_collisionLocker); ASSERT(HasCollision()); - _terrain->GetPhysicsScene()->RemoveCollider(_terrain); - _terrain->GetPhysicsScene()->RemoveActor(_physicsActor); - _terrain->GetPhysicsScene()->RemoveObject(_physicsShape); - _terrain->GetPhysicsScene()->RemoveObject(_physicsHeightField); + void* scene = _terrain->GetPhysicsScene()->GetPhysicsScene(); + PhysicsBackend::RemoveCollider(_terrain); + PhysicsBackend::RemoveSceneActor(scene, _physicsActor); + PhysicsBackend::DestroyActor(_physicsActor); + PhysicsBackend::DestroyShape(_physicsShape); + PhysicsBackend::DestroyObject(_physicsHeightField); _physicsActor = nullptr; _physicsShape = nullptr; @@ -2265,17 +2187,17 @@ void TerrainPatch::CacheDebugLines() { ASSERT(_debugLines.IsEmpty() && _physicsHeightField); - const uint32 rows = _physicsHeightField->getNbRows(); - const uint32 cols = _physicsHeightField->getNbColumns(); + int32 rows, cols; + PhysicsBackend::GetHeightFieldSize(_physicsHeightField, rows, cols); _debugLines.Resize((rows - 1) * (cols - 1) * 6 + (cols + rows - 2) * 2); Vector3* data = _debugLines.Get(); -#define GET_VERTEX(x, y) const Vector3 v##x##y((float)(row + (x)), _physicsHeightField->getHeight((PxReal)(row + (x)), (PxReal)(col + (y))) / TERRAIN_PATCH_COLLISION_QUANTIZATION, (float)(col + (y))) +#define GET_VERTEX(x, y) const Vector3 v##x##y((float)(row + (x)), PhysicsBackend::GetHeightFieldHeight(_physicsHeightField, (float)(row + (x)), (float)(col + (y))) / TERRAIN_PATCH_COLLISION_QUANTIZATION, (float)(col + (y))) - for (uint32 row = 0; row < rows - 1; row++) + for (int32 row = 0; row < rows - 1; row++) { - for (uint32 col = 0; col < cols - 1; col++) + for (int32 col = 0; col < cols - 1; col++) { GET_VERTEX(0, 0); GET_VERTEX(0, 1); @@ -2293,9 +2215,9 @@ void TerrainPatch::CacheDebugLines() } } - for (uint32 row = 0; row < rows - 1; row++) + for (int32 row = 0; row < rows - 1; row++) { - const uint32 col = cols - 1; + const int32 col = cols - 1; GET_VERTEX(0, 0); GET_VERTEX(1, 0); @@ -2303,9 +2225,9 @@ void TerrainPatch::CacheDebugLines() *data++ = v10; } - for (uint32 col = 0; col < cols - 1; col++) + for (int32 col = 0; col < cols - 1; col++) { - const uint32 row = rows - 1; + const int32 row = rows - 1; GET_VERTEX(0, 0); GET_VERTEX(0, 1); @@ -2352,22 +2274,22 @@ const Array& TerrainPatch::GetCollisionTriangles() if (!_physicsShape || _collisionTriangles.HasItems()) return _collisionTriangles; - const uint32 rows = _physicsHeightField->getNbRows(); - const uint32 cols = _physicsHeightField->getNbColumns(); + int32 rows, cols; + PhysicsBackend::GetHeightFieldSize(_physicsHeightField, rows, cols); _collisionTriangles.Resize((rows - 1) * (cols - 1) * 6); Vector3* data = _collisionTriangles.Get(); -#define GET_VERTEX(x, y) Vector3 v##x##y((float)(row + (x)), _physicsHeightField->getHeight((PxReal)(row + (x)), (PxReal)(col + (y))) / TERRAIN_PATCH_COLLISION_QUANTIZATION, (float)(col + (y))); Vector3::Transform(v##x##y, world, v##x##y) +#define GET_VERTEX(x, y) Vector3 v##x##y((float)(row + (x)), PhysicsBackend::GetHeightFieldHeight(_physicsHeightField, (float)(row + (x)), (float)(col + (y))) / TERRAIN_PATCH_COLLISION_QUANTIZATION, (float)(col + (y))); Vector3::Transform(v##x##y, world, v##x##y) const float size = _terrain->_chunkSize * TERRAIN_UNITS_PER_VERTEX * CHUNKS_COUNT_EDGE; const Transform terrainTransform = _terrain->_transform; Transform localTransform(Vector3(_x * size, _yOffset, _z * size), Quaternion::Identity, Vector3(_collisionScaleXZ, _yHeight, _collisionScaleXZ)); const Matrix world = localTransform.GetWorld() * terrainTransform.GetWorld(); - for (uint32 row = 0; row < rows - 1; row++) + for (int32 row = 0; row < rows - 1; row++) { - for (uint32 col = 0; col < cols - 1; col++) + for (int32 col = 0; col < cols - 1; col++) { GET_VERTEX(0, 0); GET_VERTEX(0, 1); @@ -2394,9 +2316,8 @@ void TerrainPatch::GetCollisionTriangles(const BoundingSphere& bounds, ArraygetNbRows(); - const int32 cols = _physicsHeightField->getNbColumns(); + int32 rows, cols; + PhysicsBackend::GetHeightFieldSize(_physicsHeightField, rows, cols); int32 startRow = Math::FloorToInt(min.X / size * rows); int32 startCol = Math::FloorToInt(min.Z / size * cols); int32 endRow = Math::CeilToInt(max.X / size * rows); @@ -2495,8 +2416,8 @@ void TerrainPatch::ExtractCollisionGeometry(Array& vertexBuffer, Array< if (!_physicsShape) return; - const uint32 rows = _physicsHeightField->getNbRows(); - const uint32 cols = _physicsHeightField->getNbColumns(); + int32 rows, cols; + PhysicsBackend::GetHeightFieldSize(_physicsHeightField, rows, cols); // Cache pre-transformed collision heightfield vertices locations if (_collisionVertices.IsEmpty()) @@ -2513,11 +2434,11 @@ void TerrainPatch::ExtractCollisionGeometry(Array& vertexBuffer, Array< const int32 vertexCount = rows * cols; _collisionVertices.Resize(vertexCount); Vector3* vb = _collisionVertices.Get(); - for (uint32 row = 0; row < rows; row++) + for (int32 row = 0; row < rows; row++) { - for (uint32 col = 0; col < cols; col++) + for (int32 col = 0; col < cols; col++) { - Vector3 v((float)row, _physicsHeightField->getHeight((PxReal)row, (PxReal)col) / TERRAIN_PATCH_COLLISION_QUANTIZATION, (float)col); + Vector3 v((float)row, PhysicsBackend::GetHeightFieldHeight(_physicsHeightField, (float)row, (float)col) / TERRAIN_PATCH_COLLISION_QUANTIZATION, (float)col); Vector3::Transform(v, world, v); *vb++ = v; } @@ -2532,9 +2453,9 @@ void TerrainPatch::ExtractCollisionGeometry(Array& vertexBuffer, Array< const int32 indexCount = (rows - 1) * (cols - 1) * 6; indexBuffer.Resize(indexCount); int32* ib = indexBuffer.Get(); - for (uint32 row = 0; row < rows - 1; row++) + for (int32 row = 0; row < rows - 1; row++) { - for (uint32 col = 0; col < cols - 1; col++) + for (int32 col = 0; col < cols - 1; col++) { #define GET_INDEX(x, y) *ib++ = (col + (y)) + (row + (x)) * cols @@ -2612,6 +2533,7 @@ void TerrainPatch::Deserialize(DeserializeStream& stream, ISerializeModifier* mo void TerrainPatch::OnPhysicsSceneChanged(PhysicsScene* previous) { - previous->UnlinkActor(_physicsActor); - _terrain->GetPhysicsScene()->AddActor(_physicsActor); + PhysicsBackend::RemoveSceneActor(previous->GetPhysicsScene(), _physicsActor); + void* scene = _terrain->GetPhysicsScene()->GetPhysicsScene(); + PhysicsBackend::AddSceneActor(scene, _physicsActor); } diff --git a/Source/Engine/Terrain/TerrainPatch.h b/Source/Engine/Terrain/TerrainPatch.h index 7e27220ca..b77cc191a 100644 --- a/Source/Engine/Terrain/TerrainPatch.h +++ b/Source/Engine/Terrain/TerrainPatch.h @@ -6,7 +6,6 @@ #include "TerrainChunk.h" #include "Engine/Core/Math/Color32.h" #include "Engine/Core/Math/Int2.h" -#include "Engine/Physics/Types.h" #include "Engine/Level/Scene/Lightmap.h" #include "Engine/Content/Assets/RawDataAsset.h" @@ -38,9 +37,9 @@ private: BoundingBox _bounds; Vector3 _offset; AssetReference _heightfield; - PxShape* _physicsShape; - PxRigidStatic* _physicsActor; - PxHeightField* _physicsHeightField; + void* _physicsShape; + void* _physicsActor; + void* _physicsHeightField; CriticalSection _collisionLocker; float _collisionScaleXZ; #if TERRAIN_UPDATING @@ -331,7 +330,7 @@ public: /// /// The position to find the closest point to it. /// The result point on the collider that is closest to the specified location. - void ClosestPoint(const Vector3& position, Vector3* result) const; + void ClosestPoint(const Vector3& position, Vector3& result) const; #if USE_EDITOR @@ -373,7 +372,6 @@ private: /// /// Determines whether this patch has created collision representation. /// - /// true if this patch has collider; otherwise, false. FORCE_INLINE bool HasCollision() const { return _physicsShape != nullptr; diff --git a/Source/ThirdParty/PhysX/PhysX.Build.cs b/Source/ThirdParty/PhysX/PhysX.Build.cs index 888893f59..34522dd81 100644 --- a/Source/ThirdParty/PhysX/PhysX.Build.cs +++ b/Source/ThirdParty/PhysX/PhysX.Build.cs @@ -48,6 +48,8 @@ public class PhysX : DepsModule if (useVehicle) options.PublicDefinitions.Add("WITH_VEHICLE"); + options.PublicDefinitions.Add("COMPILE_WITH_PHYSX"); + string archPostFix = string.Empty; switch (options.Platform.Target) {