From e21c9d24deb0d38e612faedbd3a569a9485a54b2 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 26 Mar 2021 17:11:26 +0100 Subject: [PATCH] Add proper vehicle setup after editing wheel colliders --- Source/Engine/Physics/Actors/RigidBody.cpp | 11 +++- Source/Engine/Physics/Actors/RigidBody.h | 3 ++ .../Engine/Physics/Actors/WheeledVehicle.cpp | 51 +++++++++++++------ Source/Engine/Physics/Actors/WheeledVehicle.h | 1 + Source/Engine/Physics/Colliders/Collider.cpp | 34 ++++--------- Source/Engine/Physics/Colliders/Collider.h | 6 --- 6 files changed, 60 insertions(+), 46 deletions(-) diff --git a/Source/Engine/Physics/Actors/RigidBody.cpp b/Source/Engine/Physics/Actors/RigidBody.cpp index 5ea064e73..eecce480a 100644 --- a/Source/Engine/Physics/Actors/RigidBody.cpp +++ b/Source/Engine/Physics/Actors/RigidBody.cpp @@ -383,6 +383,15 @@ void RigidBody::OnTriggerExit(PhysicsColliderActor* c) TriggerExit(c); } +void RigidBody::OnColliderChanged(Collider* c) +{ + UpdateMass(); + + // TODO: maybe wake up only if one ore more shapes attached is active? + //if (GetStartAwake()) + // WakeUp(); +} + void RigidBody::CreateActor() { ASSERT(_actor == nullptr); @@ -394,7 +403,7 @@ void RigidBody::CreateActor() // Setup flags #if WITH_PVD - PxActorFlags actorFlags = PxActorFlag::eVISUALIZATION; + PxActorFlags actorFlags = PxActorFlag::eVISUALIZATION; #else PxActorFlags actorFlags = static_cast(0); #endif diff --git a/Source/Engine/Physics/Actors/RigidBody.h b/Source/Engine/Physics/Actors/RigidBody.h index 70f54837e..19e22e506 100644 --- a/Source/Engine/Physics/Actors/RigidBody.h +++ b/Source/Engine/Physics/Actors/RigidBody.h @@ -551,6 +551,9 @@ public: void OnTriggerEnter(PhysicsColliderActor* c); void OnTriggerExit(PhysicsColliderActor* c); + // Called when collider gets detached from this rigidbody or activated/deactivated. Used to update rigidbody mass. + virtual void OnColliderChanged(Collider* c); + protected: /// diff --git a/Source/Engine/Physics/Actors/WheeledVehicle.cpp b/Source/Engine/Physics/Actors/WheeledVehicle.cpp index ea04d10e2..dd518a1f9 100644 --- a/Source/Engine/Physics/Actors/WheeledVehicle.cpp +++ b/Source/Engine/Physics/Actors/WheeledVehicle.cpp @@ -182,6 +182,14 @@ void WheeledVehicle::Setup() return; auto& drive = (PxVehicleDrive4W*&)_drive; + // Release previous + if (drive) + { + WheelVehicles.Remove(this); + drive->free(); + drive = nullptr; + } + // Get wheels Array> wheels; _wheelsData.Clear(); @@ -202,18 +210,15 @@ void WheeledVehicle::Setup() LOG(Warning, "Invalid wheel collider {1} in vehicle {0} cannot be a trigger", ToString(), wheel.Collider->ToString()); continue; } - wheels.Add(&wheel); + if (wheel.Collider->IsDuringPlay()) + { + wheels.Add(&wheel); + } } if (wheels.IsEmpty()) { // No wheel, no car // No woman, no cry - if (drive) - { - WheelVehicles.Remove(this); - drive->free(); - drive = nullptr; - } return; } _wheelsData.Resize(wheels.Count()); @@ -294,14 +299,22 @@ void WheeledVehicle::Setup() wheelsSimData->setTireForceAppPointOffset(i, forceAppPointOffset); PxShape* wheelShape = wheel.Collider->GetPxShape(); - wheelsSimData->setWheelShapeMapping(i, shapes.Find(wheelShape)); + 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); + // 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); + } + else + { + wheelsSimData->setWheelShapeMapping(i, -1); + wheelsSimData->disableWheel(i); + } } for (auto child : Children) { @@ -375,7 +388,7 @@ void WheeledVehicle::Setup() // Create vehicle drive drive = PxVehicleDrive4W::allocate(wheels.Count()); _actor->setSolverIterationCounts(12, 4); - drive->setup(CPhysX, _actor, *wheelsSimData, driveSimData, wheels.Count() - 4); + drive->setup(CPhysX, _actor, *wheelsSimData, driveSimData, Math::Max(wheels.Count() - 4, 0)); WheelVehicles.Add(this); // Initialize @@ -442,6 +455,14 @@ void WheeledVehicle::Deserialize(DeserializeStream& stream, ISerializeModifier* DESERIALIZE_MEMBER(Gearbox, _gearbox); } +void WheeledVehicle::OnColliderChanged(Collider* c) +{ + RigidBody::OnColliderChanged(c); + + // Rebuild vehicle when someone adds/removed wheels + Setup(); +} + void WheeledVehicle::BeginPlay(SceneBeginData* data) { RigidBody::BeginPlay(data); diff --git a/Source/Engine/Physics/Actors/WheeledVehicle.h b/Source/Engine/Physics/Actors/WheeledVehicle.h index e9b254d3b..b9752c691 100644 --- a/Source/Engine/Physics/Actors/WheeledVehicle.h +++ b/Source/Engine/Physics/Actors/WheeledVehicle.h @@ -254,6 +254,7 @@ public: #endif void Serialize(SerializeStream& stream, const void* otherObj) override; void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) override; + void OnColliderChanged(Collider* c) override; protected: diff --git a/Source/Engine/Physics/Colliders/Collider.cpp b/Source/Engine/Physics/Colliders/Collider.cpp index a41d2b342..acf6af5d1 100644 --- a/Source/Engine/Physics/Colliders/Collider.cpp +++ b/Source/Engine/Physics/Colliders/Collider.cpp @@ -170,19 +170,7 @@ bool Collider::ComputePenetration(const Collider* colliderA, const Collider* col 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 - ); -} - -bool Collider::IsAttached() const -{ - return _shape && _shape->getActor() != nullptr; + return PxGeometryQuery::computePenetration(C2P(direction), distance, shapeA->getGeometry().any(), poseA, shapeB->getGeometry().any(), poseB); } bool Collider::CanAttach(RigidBody* rigidBody) const @@ -442,15 +430,18 @@ void Collider::BeginPlay(SceneBeginData* data) void Collider::EndPlay() { + // Base + PhysicsColliderActor::EndPlay(); + if (_shape) { // Detach from the actor auto actor = _shape->getActor(); if (actor) actor->detachShape(*_shape); - - // Check if was using a static actor and cleanup it - if (_staticActor) + if (actor && actor->is()) + static_cast(actor->userData)->OnColliderChanged(this); + else if (_staticActor) { RemoveStaticActor(); } @@ -460,9 +451,6 @@ void Collider::EndPlay() _shape->release(); _shape = nullptr; } - - // Base - PhysicsColliderActor::EndPlay(); } void Collider::OnActiveInTreeChanged() @@ -479,11 +467,7 @@ void Collider::OnActiveInTreeChanged() auto rigidBody = GetAttachedRigidBody(); if (rigidBody) { - rigidBody->UpdateMass(); - - // TODO: maybe wake up only if one ore more shapes attached is active? - //if (rigidBody->GetStartAwake()) - // rigidBody->WakeUp(); + rigidBody->OnColliderChanged(this); } } } @@ -500,6 +484,8 @@ void Collider::OnParentChanged() auto actor = _shape->getActor(); if (actor) actor->detachShape(*_shape); + if (actor && actor->is()) + static_cast(actor->userData)->OnColliderChanged(this); // Check if the new parent is a rigidbody const auto rigidBody = dynamic_cast(GetParent()); diff --git a/Source/Engine/Physics/Colliders/Collider.h b/Source/Engine/Physics/Colliders/Collider.h index 3e7b5ecfd..ca88ea66c 100644 --- a/Source/Engine/Physics/Colliders/Collider.h +++ b/Source/Engine/Physics/Colliders/Collider.h @@ -149,12 +149,6 @@ public: public: - /// - /// Determines whether this collider is attached to the body. - /// - /// true if this instance is attached; otherwise, false. - API_PROPERTY() bool IsAttached() const; - /// /// Determines whether this collider can be attached the specified rigid body. ///