You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Cannon.js与Three.js实现物体间的引力吸引效果?

实现天体间引力模拟的实用方案

核心:基于万有引力定律的力计算

先明确核心公式:F = G * (m1*m2)/r²,其中G是引力常数,m1/m2为两个物体质量,r是质心间距。实际编码要注意两个关键点:

  • 先计算方向向量:从当前物体指向目标物体的向量,归一化后再乘以力的大小,保证力的方向正确
  • 防除零崩溃:当两个物体重合或距离过近时,直接跳过计算,避免数值异常

以下是通用逻辑的伪代码(以Unity为例,其他引擎可直接复用逻辑):

// 给每个天体挂载的引力组件
public class GravitationalBody : MonoBehaviour
{
    public float mass;
    private Rigidbody _rb;

    void Awake()
    {
        _rb = GetComponent<Rigidbody>();
        _rb.mass = mass;
        // 自动加入全局管理列表
        GravitationManager.RegisterBody(this);
    }

    void OnDestroy()
    {
        GravitationManager.UnregisterBody(this);
    }

    public Rigidbody GetRigidbody() => _rb;
}

// 全局引力管理类,彻底解决手动添加的麻烦
public static class GravitationManager
{
    private static List<GravitationalBody> _allBodies = new();
    // 真实引力常数太小,游戏里可根据场景缩放调整,比如改成100
    public const float G = 6.67430e-11f;

    public static void RegisterBody(GravitationalBody body)
    {
        if (!_allBodies.Contains(body))
            _allBodies.Add(body);
    }

    public static void UnregisterBody(GravitationalBody body)
    {
        _allBodies.Remove(body);
    }

    // 每帧批量计算所有物体间的引力
    public static void UpdateAllGravity()
    {
        // 双层循环避免重复计算(A对B和B对A的力只算一次)
        for (int i = 0; i < _allBodies.Count; i++)
        {
            var bodyA = _allBodies[i];
            for (int j = i + 1; j < _allBodies.Count; j++)
            {
                var bodyB = _allBodies[j];
                ApplyMutualGravity(bodyA, bodyB);
            }
        }
    }

    private static void ApplyMutualGravity(GravitationalBody a, GravitationalBody b)
    {
        Vector3 direction = b.transform.position - a.transform.position;
        float distanceSq = direction.sqrMagnitude;

        // 距离过近时跳过,防止力过大导致物体飞出去
        if (distanceSq < 0.1f) return;

        float forceMag = G * (a.mass * b.mass) / distanceSq;
        Vector3 force = direction.normalized * forceMag;

        a.GetRigidbody().AddForce(force);
        b.GetRigidbody().AddForce(-force); // 作用力与反作用力
    }
}

解决“逐个添加物体”的繁琐问题

  • 自动注册机制:每个天体脚本在初始化时自动加入全局管理列表,销毁时自动移除,完全不用手动维护
  • 扩展方案:如果是批量生成的天体,可以给它们统一加标签,启动时遍历场景中带该标签的物体完成注册;或者结合对象池,在生成物体时自动调用注册方法

性能与体验优化建议

  • 避免重复计算:用i从0开始,j从i+1开始的双层循环,减少一半计算量
  • 适配游戏场景:真实引力常数G极小,游戏里可根据天体大小、移动速度放大数值(比如改成100),否则引力效果会不明显
  • 海量天体优化:如果场景内天体数量超过50个,可采用空间分区算法(比如四叉树、八叉树),只计算邻近天体间的引力,大幅降低计算量

内容的提问来源于stack exchange,提问作者Majesto

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 20:27:08