浮漂测试代码1

This commit is contained in:
2026-03-01 08:51:19 +08:00
parent 7ea3a7868c
commit 01a1c1c341
4 changed files with 246 additions and 34 deletions

View File

@@ -27,11 +27,11 @@ public class BobberBuoyancyStable : MonoBehaviour
[Header("Center Of Mass")]
public bool driveCenterOfMassFromCapsule = true;
public Vector3 extraCenterOfMassOffset = new Vector3(0f, -0.01f, 0f);
public Vector3 extraCenterOfMassOffset = new Vector3(0f, -0.01f, 0f); // 恢复原来的重心下移
[Header("Righting")]
public float rightingTorque = 1.5f;
public float rightingDamping = 0.5f;
public float rightingTorque = 3f; // 适中的归正扭矩
public float rightingDamping = 0.8f;
Rigidbody rb;
CapsuleCollider cap;
@@ -50,6 +50,7 @@ public class BobberBuoyancyStable : MonoBehaviour
ApplyCenterOfMass();
rb.maxAngularVelocity = 50f;
// 移除了强制设置物理参数的代码保留用户在Inspector中的设置
}
void FixedUpdate()
@@ -60,57 +61,76 @@ public class BobberBuoyancyStable : MonoBehaviour
float bottomY = b.min.y;
float topY = b.max.y;
// 用底部点判定是否真正入水(必须超过阈值)
float bottomSubmersion = waterLevelY - bottomY; // >0 表示底部在水下
// 用"底部点"判定是否真正入水
float bottomSubmersion = waterLevelY - bottomY;
if (bottomSubmersion <= enterWaterDepth)
{
// 认为未入水:不施加浮力,恢复空气阻尼
rb.linearDamping = airLinearDamping;
rb.angularDamping = airAngularDamping;
return;
}
// 进入水中:阻尼随浸入增强
// 这里用一个0~1的平滑权重避免刚入水就“猛顶”
float w = Smooth01((bottomSubmersion - enterWaterDepth) / Mathf.Max(1e-4f, smoothDepth));
rb.linearDamping = airLinearDamping + extraLinearDampingInWater * w;
rb.angularDamping = airAngularDamping + extraAngularDampingInWater * w;
// 垂直速度(用刚体自身速度就够稳定)
float vY = rb.linearVelocity.y;
// 弹簧+阻尼浮力(仅向上)
float forceY = buoyancySpring * bottomSubmersion - buoyancyDamping * vY;
if (forceY < 0f) forceY = 0f;
// 平滑权重:刚入水时逐渐接管
forceY *= w;
// 限制最大上浮加速度(可选
// 关键修正:正确的浮力计算
float volume = Mathf.PI * cap.radius * cap.radius * cap.height;
float submergedVolume = volume * Mathf.Clamp01(bottomSubmersion / cap.height);
// 浮力 = 排开液体重量 = 体积 × 密度 × 重力
float buoyantForce = submergedVolume * 1000f * 9.81f;
// 物体重量
float weight = rb.mass * 9.81f;
// 净浮力(浮力 - 重量
float netBuoyancy = buoyantForce - weight;
// 添加弹簧阻尼系统
float velocity = Vector3.Dot(rb.linearVelocity, Vector3.up);
float springForce = buoyancySpring * bottomSubmersion;
float dampingForce = buoyancyDamping * velocity;
float totalForce = netBuoyancy + springForce - dampingForce;
totalForce *= w; // 平滑过渡
// 限制向上的力
if (totalForce < 0) totalForce = 0;
// 限制最大加速度
if (maxUpAcceleration > 0f)
{
float maxForce = rb.mass * maxUpAcceleration;
if (forceY > maxForce) forceY = maxForce;
if (totalForce > maxForce) totalForce = maxForce;
}
// 浮力作用点:必须放在水面下(否则会出现奇怪力矩)
float buoyY = Mathf.Min(waterLevelY - 0.001f, topY); // 强制在水面下1mm
buoyY = Mathf.Max(buoyY, bottomY); // 不低于底部
// 浮力作用点
float buoyY = Mathf.Min(waterLevelY - 0.001f, topY);
buoyY = Mathf.Max(buoyY, bottomY);
Vector3 buoyPoint = new Vector3(b.center.x, buoyY, b.center.z);
rb.AddForceAtPosition(Vector3.up * forceY, buoyPoint, ForceMode.Force);
rb.AddForceAtPosition(Vector3.up * totalForce, buoyPoint, ForceMode.Force);
// 归正扭矩(只在水里生效)
// 简化的归正扭矩系统
SimpleRightingSystem(w);
}
void SimpleRightingSystem(float weight)
{
Vector3 up = transform.up;
Vector3 axis = Vector3.Cross(up, Vector3.up);
float mag = axis.magnitude;
if (mag > 1e-4f)
{
axis /= mag;
float angle = Mathf.Asin(Mathf.Clamp(mag, -1f, 1f));
float angle = Mathf.Asin(Mathf.Clamp(mag, -1f, 1f)) * Mathf.Rad2Deg;
float angVelOnAxis = Vector3.Dot(rb.angularVelocity, axis);
float torque = (rightingTorque * angle - rightingDamping * angVelOnAxis) * w;
// 归正扭矩
float torque = (rightingTorque * angle - rightingDamping * angVelOnAxis) * weight;
rb.AddTorque(axis * torque, ForceMode.Acceleration);
}
}
@@ -124,7 +144,40 @@ public class BobberBuoyancyStable : MonoBehaviour
static float Smooth01(float t)
{
t = Mathf.Clamp01(t);
// smoothstep
return t * t * (3f - 2f * t);
}
}
void OnDrawGizmos()
{
if (cap == null) return;
Gizmos.color = Color.blue;
Bounds bounds = cap.bounds;
// 绘制浸入部分
float bottomY = bounds.min.y;
float submergedHeight = Mathf.Max(0, waterLevelY - bottomY);
Vector3 submergedCenter = new Vector3(
bounds.center.x,
bottomY + submergedHeight * 0.5f,
bounds.center.z
);
Vector3 submergedSize = new Vector3(
bounds.size.x,
submergedHeight,
bounds.size.z
);
Gizmos.DrawWireCube(submergedCenter, submergedSize);
// 显示重心
if (rb != null)
{
Gizmos.color = Color.red;
Vector3 comWorld = transform.TransformPoint(rb.centerOfMass);
Gizmos.DrawSphere(comWorld, 0.005f);
}
}
}