瀏覽代碼

Split up ApplyBuoyancyImpulse into GetSubmergedVolume/ApplyBuoyancyImpulse (#1327)

This allows you to use the submerged volume for other purposes

Fixes #1322
Jorrit Rouwe 10 月之前
父節點
當前提交
3c259735b1
共有 2 個文件被更改,包括 51 次插入19 次删除
  1. 29 19
      Jolt/Physics/Body/Body.cpp
  2. 22 0
      Jolt/Physics/Body/Body.h

+ 29 - 19
Jolt/Physics/Body/Body.cpp

@@ -183,51 +183,50 @@ ECanSleep Body::UpdateSleepStateInternal(float inDeltaTime, float inMaxMovement,
 	return mMotionProperties->AccumulateSleepTime(inDeltaTime, inTimeBeforeSleep);
 }
 
-bool Body::ApplyBuoyancyImpulse(RVec3Arg inSurfacePosition, Vec3Arg inSurfaceNormal, float inBuoyancy, float inLinearDrag, float inAngularDrag, Vec3Arg inFluidVelocity, Vec3Arg inGravity, float inDeltaTime)
+void Body::GetSubmergedVolume(RVec3Arg inSurfacePosition, Vec3Arg inSurfaceNormal, float &outTotalVolume, float &outSubmergedVolume, Vec3 &outRelativeCenterOfBuoyancy) const
 {
-	JPH_PROFILE_FUNCTION();
-
-	JPH_ASSERT(IsRigidBody()); // Only implemented for rigid bodies currently
-
-	// We follow the approach from 'Game Programming Gems 6' 2.5 Exact Buoyancy for Polyhedra
-	// All quantities below are in world space
-
 	// For GetSubmergedVolume we transform the surface relative to the body position for increased precision
 	Mat44 rotation = Mat44::sRotation(mRotation);
 	Plane surface_relative_to_body = Plane::sFromPointAndNormal(inSurfacePosition - mPosition, inSurfaceNormal);
 
 	// Calculate amount of volume that is submerged and what the center of buoyancy is
-	float total_volume, submerged_volume;
-	Vec3 relative_center_of_buoyancy;
-	mShape->GetSubmergedVolume(rotation, Vec3::sReplicate(1.0f), surface_relative_to_body, total_volume, submerged_volume, relative_center_of_buoyancy JPH_IF_DEBUG_RENDERER(, mPosition));
+	mShape->GetSubmergedVolume(rotation, Vec3::sReplicate(1.0f), surface_relative_to_body, outTotalVolume, outSubmergedVolume, outRelativeCenterOfBuoyancy JPH_IF_DEBUG_RENDERER(, mPosition));
+}
+
+bool Body::ApplyBuoyancyImpulse(float inTotalVolume, float inSubmergedVolume, Vec3Arg inRelativeCenterOfBuoyancy, float inBuoyancy, float inLinearDrag, float inAngularDrag, Vec3Arg inFluidVelocity, Vec3Arg inGravity, float inDeltaTime)
+{
+	JPH_ASSERT(IsRigidBody()); // Only implemented for rigid bodies currently
+
+	// We follow the approach from 'Game Programming Gems 6' 2.5 Exact Buoyancy for Polyhedra
+	// All quantities below are in world space
 
 	// If we're not submerged, there's no point in doing the rest of the calculations
-	if (submerged_volume > 0.0f)
+	if (inSubmergedVolume > 0.0f)
 	{
 	#ifdef JPH_DEBUG_RENDERER
 		// Draw submerged volume properties
 		if (Shape::sDrawSubmergedVolumes)
 		{
-			RVec3 center_of_buoyancy = mPosition + relative_center_of_buoyancy;
+			RVec3 center_of_buoyancy = mPosition + inRelativeCenterOfBuoyancy;
 			DebugRenderer::sInstance->DrawMarker(center_of_buoyancy, Color::sWhite, 2.0f);
-			DebugRenderer::sInstance->DrawText3D(center_of_buoyancy, StringFormat("%.3f / %.3f", (double)submerged_volume, (double)total_volume));
+			DebugRenderer::sInstance->DrawText3D(center_of_buoyancy, StringFormat("%.3f / %.3f", (double)inSubmergedVolume, (double)inTotalVolume));
 		}
 	#endif // JPH_DEBUG_RENDERER
 
 		// When buoyancy is 1 we want neutral buoyancy, this means that the density of the liquid is the same as the density of the body at that point.
 		// Buoyancy > 1 should make the object float, < 1 should make it sink.
 		float inverse_mass = mMotionProperties->GetInverseMass();
-		float fluid_density = inBuoyancy / (total_volume * inverse_mass);
+		float fluid_density = inBuoyancy / (inTotalVolume * inverse_mass);
 
 		// Buoyancy force = Density of Fluid * Submerged volume * Magnitude of gravity * Up direction (eq 2.5.1)
 		// Impulse = Force * Delta time
 		// We should apply this at the center of buoyancy (= center of mass of submerged volume)
-		Vec3 buoyancy_impulse = -fluid_density * submerged_volume * mMotionProperties->GetGravityFactor() * inGravity * inDeltaTime;
+		Vec3 buoyancy_impulse = -fluid_density * inSubmergedVolume * mMotionProperties->GetGravityFactor() * inGravity * inDeltaTime;
 
 		// Calculate the velocity of the center of buoyancy relative to the fluid
 		Vec3 linear_velocity = mMotionProperties->GetLinearVelocity();
 		Vec3 angular_velocity = mMotionProperties->GetAngularVelocity();
-		Vec3 center_of_buoyancy_velocity = linear_velocity + angular_velocity.Cross(relative_center_of_buoyancy);
+		Vec3 center_of_buoyancy_velocity = linear_velocity + angular_velocity.Cross(inRelativeCenterOfBuoyancy);
 		Vec3 relative_center_of_buoyancy_velocity = inFluidVelocity - center_of_buoyancy_velocity;
 
 		// Here we deviate from the article, instead of eq 2.5.14 we use a quadratic drag formula: https://en.wikipedia.org/wiki/Drag_%28physics%29
@@ -264,7 +263,7 @@ bool Body::ApplyBuoyancyImpulse(RVec3Arg inSurfacePosition, Vec3Arg inSurfaceNor
 		float l = (size.GetX() + size.GetY() + size.GetZ()) / 3.0f;
 
 		// Drag torque = -Angular Drag * Mass * Submerged volume / Total volume * (Average width of body)^2 * Angular velocity (eq 2.5.15)
-		Vec3 drag_angular_impulse = (-inAngularDrag * submerged_volume / total_volume * inDeltaTime * Square(l) / inverse_mass) * angular_velocity;
+		Vec3 drag_angular_impulse = (-inAngularDrag * inSubmergedVolume / inTotalVolume * inDeltaTime * Square(l) / inverse_mass) * angular_velocity;
 		Mat44 inv_inertia = GetInverseInertia();
 		Vec3 drag_delta_angular_velocity = inv_inertia * drag_angular_impulse;
 
@@ -275,7 +274,7 @@ bool Body::ApplyBuoyancyImpulse(RVec3Arg inSurfacePosition, Vec3Arg inSurfaceNor
 			drag_delta_angular_velocity *= sqrt(angular_velocity_len_sq / drag_delta_angular_velocity_len_sq);
 
 		// Calculate total delta angular velocity due to drag and buoyancy
-		Vec3 delta_angular_velocity = drag_delta_angular_velocity + inv_inertia * relative_center_of_buoyancy.Cross(buoyancy_impulse + drag_impulse);
+		Vec3 delta_angular_velocity = drag_delta_angular_velocity + inv_inertia * inRelativeCenterOfBuoyancy.Cross(buoyancy_impulse + drag_impulse);
 		mMotionProperties->AddAngularVelocityStep(delta_angular_velocity);
 		return true;
 	}
@@ -283,6 +282,17 @@ bool Body::ApplyBuoyancyImpulse(RVec3Arg inSurfacePosition, Vec3Arg inSurfaceNor
 	return false;
 }
 
+bool Body::ApplyBuoyancyImpulse(RVec3Arg inSurfacePosition, Vec3Arg inSurfaceNormal, float inBuoyancy, float inLinearDrag, float inAngularDrag, Vec3Arg inFluidVelocity, Vec3Arg inGravity, float inDeltaTime)
+{
+	JPH_PROFILE_FUNCTION();
+
+	float total_volume, submerged_volume;
+	Vec3 relative_center_of_buoyancy;
+	GetSubmergedVolume(inSurfacePosition, inSurfaceNormal, total_volume, submerged_volume, relative_center_of_buoyancy);
+
+	return ApplyBuoyancyImpulse(total_volume, submerged_volume, relative_center_of_buoyancy, inBuoyancy, inLinearDrag, inAngularDrag, inFluidVelocity, inGravity, inDeltaTime);
+}
+
 void Body::SaveState(StateRecorder &inStream) const
 {
 	// Only write properties that can change at runtime

+ 22 - 0
Jolt/Physics/Body/Body.h

@@ -216,6 +216,14 @@ public:
 	/// If you want the body to wake up when it is sleeping, use BodyInterface::MoveKinematic instead.
 	void					MoveKinematic(RVec3Arg inTargetPosition, QuatArg inTargetRotation, float inDeltaTime);
 
+	/// Gets the properties needed to do buoyancy calculations
+	/// @param inSurfacePosition Position of the fluid surface in world space
+	/// @param inSurfaceNormal Normal of the fluid surface (should point up)
+	/// @param outTotalVolume On return this contains the total volume of the shape
+	/// @param outSubmergedVolume On return this contains the submerged volume of the shape
+	/// @param outRelativeCenterOfBuoyancy On return this contains the center of mass of the submerged volume relative to the center of mass of the body
+	void					GetSubmergedVolume(RVec3Arg inSurfacePosition, Vec3Arg inSurfaceNormal, float &outTotalVolume, float &outSubmergedVolume, Vec3 &outRelativeCenterOfBuoyancy) const;
+
 	/// Applies an impulse to the body that simulates fluid buoyancy and drag.
 	/// If you want the body to wake up when it is sleeping, use BodyInterface::ApplyBuoyancyImpulse instead.
 	/// @param inSurfacePosition Position of the fluid surface in world space
@@ -229,6 +237,20 @@ public:
 	/// @return true if an impulse was applied, false if the body was not in the fluid
 	bool					ApplyBuoyancyImpulse(RVec3Arg inSurfacePosition, Vec3Arg inSurfaceNormal, float inBuoyancy, float inLinearDrag, float inAngularDrag, Vec3Arg inFluidVelocity, Vec3Arg inGravity, float inDeltaTime);
 
+	/// Applies an impulse to the body that simulates fluid buoyancy and drag.
+	/// If you want the body to wake up when it is sleeping, use BodyInterface::ApplyBuoyancyImpulse instead.
+	/// @param inTotalVolume Total volume of the shape of this body (m^3)
+	/// @param inSubmergedVolume Submerged volume of the shape of this body (m^3)
+	/// @param inRelativeCenterOfBuoyancy The center of mass of the submerged volume relative to the center of mass of the body
+	/// @param inBuoyancy The buoyancy factor for the body. 1 = neutral body, < 1 sinks, > 1 floats. Note that we don't use the fluid density since it is harder to configure than a simple number between [0, 2]
+	/// @param inLinearDrag Linear drag factor that slows down the body when in the fluid (approx. 0.5)
+	/// @param inAngularDrag Angular drag factor that slows down rotation when the body is in the fluid (approx. 0.01)
+	/// @param inFluidVelocity The average velocity of the fluid (in m/s) in which the body resides
+	/// @param inGravity The gravity vector (pointing down)
+	/// @param inDeltaTime Delta time of the next simulation step (in s)
+	/// @return true if an impulse was applied, false if the body was not in the fluid
+	bool					ApplyBuoyancyImpulse(float inTotalVolume, float inSubmergedVolume, Vec3Arg inRelativeCenterOfBuoyancy, float inBuoyancy, float inLinearDrag, float inAngularDrag, Vec3Arg inFluidVelocity, Vec3Arg inGravity, float inDeltaTime);
+
 	/// Check if this body has been added to the physics system
 	inline bool				IsInBroadPhase() const											{ return (mFlags.load(memory_order_relaxed) & uint8(EFlags::IsInBroadPhase)) != 0; }