浮力计算核心是F浮=ρ液gV排,其中V排指物体浸在液面下的体积,非总体积;V排随浸没程度变化,决定浮力大小,与物体密度、形状、深度无关。

浮力计算的核心逻辑:浸没体积决定浮力大小
阿基米德原理说白了就一句话:F_b = ρ_fluid × g × V_submerged。关键难点不在公式,而在 V_submerged —— 它不是物体总体积,而是**当前姿态下严格位于液面以下的那部分体积**。C++ 本身不提供几何体求交或体积分割功能,必须靠你选对建模方式和计算策略。
常见错误是直接用 bounding_box.volume() 或假设“z
简单规则形状:手写解析解最稳最快
如果你的物体是轴对齐长方体、球、圆柱(且轴线垂直液面),直接推导 V_submerged 公式是唯一推荐做法。没有精度损失,零运行时开销,还能处理任意倾角(只要公式覆盖)。
- 轴对齐立方体(边长
L,底面 z 坐标z_min,液面高度h):V_submerged = std::max(0.0, std::min(L, h - z_min)) * L * L; - 球体(半径
R,球心 z 坐标z_c):
当z_c + R → 全浸,<code>V = 4/3*π*R³;
当z_c - R >= h→ 零浸;
否则用球冠公式:V = π*(h - z_c + R)²*(3*R - h + z_c)/3; - 注意:所有坐标系必须统一(比如 z 向上,液面是平面
z = h)
复杂网格模型:用 Signed Distance Field(SDF)采样估算
对任意三角网格(如 OBJ 导入的船体),解析解不可行。此时主流做法是构建物体的 SignedDistanceField,再在液面下方做均匀采样或自适应体素积分。
立即学习“C++免费学习笔记(深入)”;
别碰“逐三角形求交+剖分体积”——实现爆炸、数值不稳定、边界漏算多。SDF 虽要预处理,但查询快、鲁棒、支持旋转平移(只需变换采样点)。
- 用
OpenVDB或nanovdb生成物体 SDF(离线或启动时) - 定义采样区域:以物体 AABB 为界,z ∈ [z_min, h],xy 覆盖投影范围
- 对每个采样点
p,查sdf(p) 判定是否在物体内;再检查 <code>p.z 判定是否在液下 → 双条件成立则计入 - 体积估算 = 满足条件的体素数 × 单个体素体积;分辨率建议 ≥ 128³,太低会漏细节(比如薄龙骨)
物理引擎集成时的坑:浮力不是独立力,得参与约束求解
很多新手把 F_b 算出来后直接加到刚体 force_accumulator,结果物体抖动、穿透液面或悬浮不动。问题在于:浮力本质是分布力,且与物体姿态强耦合,必须作为外力输入给物理求解器(如 Bullet、PhysX 的 addForce 或自研 impulse solver)。
- Bullet 中,应在
btRigidBody::setGravity之外,每帧调用rigidBody->applyCentralForce(force_vec),其中force_vec是F_b,方向向上(+z) - 但更准的做法是:计算浮心(
center_of_buoyancy)——即浸没部分的几何中心,然后用applyForce(force_vec, buoyancy_center)施加偏心力,这样才能产生正确倾覆力矩 - 切记:浮力大小随浸没体积实时变化,而浸没体积又依赖当前位姿 → 必须在物理步开始前更新,不能缓存旧值
最易被忽略的一点:液体密度 ρ_fluid 和重力 g 单位必须一致(比如 SI 单位制下用 kg/m³ 和 m/s²),混用 g=9.8 与 cm/g 单位会导致浮力差 10⁶ 倍。调试时先固定 ρ=1000, g=9.8, h=0,验证静平衡位置是否合理。


















