Explorar o código

Add possibility to disable RigidBody mass update to optimize performance when using several collisionshapes in the same node. Closes #489.

Lasse Öörni %!s(int64=11) %!d(string=hai) anos
pai
achega
64929dc50d

+ 2 - 0
Docs/Reference.dox

@@ -1551,6 +1551,8 @@ To prevent tunneling of a fast moving rigid body through obstacles, continuous c
 
 All physics calculations are performed in world space. Nodes containing a RigidBody component should preferably be parented to the Scene (root node) to ensure independent motion. For ragdolls this is not absolute, as retaining proper bone hierarchy is more important, but be aware that the ragdoll bones may drift far from the animated model's root scene node.
 
+When several collision shapes are present in the same node, edits to them can cause redundant mass/inertia update computation in the RigidBody. To optimize performance in these cases, the edits can be enclosed between calls to \ref RigidBody::DisableMassUpdate "DisableMassUpdate()" and \ref RigidBody::EnableMassUpdate "EnableMassUpdate()".
+
 \section Physics_ConstraintParameters Constraint parameters
 
 %Constraint position (and rotation if relevant) need to be defined in relation to both connected bodies, see \ref Constraint::SetPosition "SetPosition()" and \ref Constraint::SetOtherPosition "SetOtherPosition()". If the constraint connects a body to the static world, then the "other body position" and "other body rotation" mean the static end's transform in world space. There is also a helper function \ref Constraint::SetWorldPosition "SetWorldPosition()" to assign the constraint to a world-space position; this sets both relative positions.

+ 2 - 0
Source/Engine/LuaScript/pkgs/Physics/RigidBody.pkg

@@ -36,6 +36,8 @@ class RigidBody : public Component
     void SetCollisionMask(unsigned mask);
     void SetCollisionLayerAndMask(unsigned layer, unsigned mask);
     void SetCollisionEventMode(CollisionEventMode mode);
+    void DisableMassUpdate();
+    void EnableMassUpdate();
 
     void ApplyForce(const Vector3& force);
     void ApplyForce(const Vector3& force, const Vector3& position);

+ 17 - 2
Source/Engine/Physics/RigidBody.cpp

@@ -78,7 +78,8 @@ RigidBody::RigidBody(Context* context) :
     useGravity_(true),
     hasSmoothedTransform_(false),
     readdBody_(false),
-    inWorld_(false)
+    inWorld_(false),
+    enableMassUpdate_(true)
 {
     compoundShape_ = new btCompoundShape();
     shiftedCompoundShape_ = new btCompoundShape();
@@ -575,6 +576,20 @@ void RigidBody::ReAddBodyToWorld()
         AddBodyToWorld();
 }
 
+void RigidBody::DisableMassUpdate()
+{
+    enableMassUpdate_ = false;
+}
+
+void RigidBody::EnableMassUpdate()
+{
+    if (!enableMassUpdate_)
+    {
+        enableMassUpdate_ = true;
+        UpdateMass();
+    }
+}
+
 Vector3 RigidBody::GetPosition() const
 {
     if (body_)
@@ -713,7 +728,7 @@ void RigidBody::ApplyWorldTransform(const Vector3& newWorldPosition, const Quate
 
 void RigidBody::UpdateMass()
 {
-    if (!body_)
+    if (!body_ || !enableMassUpdate_)
         return;
 
     btTransform principal;

+ 6 - 0
Source/Engine/Physics/RigidBody.h

@@ -144,6 +144,10 @@ public:
     void Activate();
     /// Readd rigid body to the physics world to clean up internal state like stale contacts.
     void ReAddBodyToWorld();
+    /// Disable mass update. Call this to optimize performance when adding or editing multiple collision shapes in the same node.
+    void DisableMassUpdate();
+    /// Re-enable mass update and recalculate the mass/inertia by calling UpdateMass(). Call when collision shape changes are finished.
+    void EnableMassUpdate();
     
     /// Return physics world.
     PhysicsWorld* GetPhysicsWorld() const { return physicsWorld_; }
@@ -283,6 +287,8 @@ private:
     bool readdBody_;
     /// Body exists in world flag.
     bool inWorld_;
+    /// Mass update enable flag.
+    bool enableMassUpdate_;
 };
 
 }

+ 2 - 0
Source/Engine/Script/PhysicsAPI.cpp

@@ -130,6 +130,8 @@ static void RegisterRigidBody(asIScriptEngine* engine)
     engine->RegisterObjectMethod("RigidBody", "void ResetForces()", asMETHOD(RigidBody, ResetForces), asCALL_THISCALL);
     engine->RegisterObjectMethod("RigidBody", "void Activate()", asMETHOD(RigidBody, Activate), asCALL_THISCALL);
     engine->RegisterObjectMethod("RigidBody", "void ReAddBodyToWorld()", asMETHOD(RigidBody, ReAddBodyToWorld), asCALL_THISCALL);
+    engine->RegisterObjectMethod("RigidBody", "void DisableMassUpdate()", asMETHOD(RigidBody, DisableMassUpdate), asCALL_THISCALL);
+    engine->RegisterObjectMethod("RigidBody", "void EnableMassUpdate()", asMETHOD(RigidBody, EnableMassUpdate), asCALL_THISCALL);
     engine->RegisterObjectMethod("RigidBody", "Vector3 GetVelocityAtPoint(const Vector3&in) const", asMETHOD(RigidBody, GetVelocityAtPoint), asCALL_THISCALL);
     engine->RegisterObjectMethod("RigidBody", "void set_mass(float)", asMETHOD(RigidBody, SetMass), asCALL_THISCALL);
     engine->RegisterObjectMethod("RigidBody", "float get_mass() const", asMETHOD(RigidBody, GetMass), asCALL_THISCALL);