
3D 物理核心流程每个固定时间步里做这几件事1. 清空/累积外力 2. 重力、推力、冲量影响速度 3. 根据速度更新位置 4. 检测碰撞 5. 修正穿透 6. 根据质量、反弹系数、摩擦修正速度 7. 把结果同步到 Transform最基础的 3D 刚体数据public class SimpleBody3D { public Vector3 Position; public Vector3 Velocity; public Vector3 Force; public float Mass 1f; public float Restitution 0.3f; // 反弹0 不弹1 完全弹性 public float Friction 0.5f; public bool IsStatic; public float Radius 0.5f; // 先只做球体 public float InvMass IsStatic || Mass 0 ? 0f : 1f / Mass; }第一步积分运动物理里最基本的是牛顿第二定律F m * a a F / m所以速度和位置这样推进private void Integrate(SimpleBody3D body, float dt) { if (body.IsStatic) return; Vector3 gravity new Vector3(0, -9.81f, 0); Vector3 acceleration gravity body.Force * body.InvMass; body.Velocity acceleration * dt; body.Position body.Velocity * dt; body.Force Vector3.zero; }这就是 UnityRigidbody背后的核心之一。真实 PhysX 会更复杂比如阻尼、Sleep、连续碰撞、约束迭代、旋转积分等但基础仍然是这套。第二步球体和球体碰撞两个球是否碰撞看中心点距离是否小于半径之和distance radiusA radiusB如果碰撞需要得到三个东西碰撞法线 normal从 A 指向 B 的方向 穿透深度 penetration两个球重叠了多少 相对速度 relativeVelocityB 相对 A 的速度简单求解代码private void ResolveSphereSphere(SimpleBody3D a, SimpleBody3D b) { Vector3 delta b.Position - a.Position; float distance delta.magnitude; float minDistance a.Radius b.Radius; if (distance minDistance || distance 0.0001f) return; Vector3 normal delta / distance; float penetration minDistance - distance; float totalInvMass a.InvMass b.InvMass; if (totalInvMass 0f) return; // 1. 位置修正避免物体一直卡在一起 Vector3 correction normal * (penetration / totalInvMass); if (!a.IsStatic) a.Position - correction * a.InvMass; if (!b.IsStatic) b.Position correction * b.InvMass; // 2. 速度冲量决定碰撞后怎么弹开 Vector3 relativeVelocity b.Velocity - a.Velocity; float velocityAlongNormal Vector3.Dot(relativeVelocity, normal); // 已经在分离不需要再加反弹 if (velocityAlongNormal 0f) return; float restitution Mathf.Min(a.Restitution, b.Restitution); float impulseMagnitude -(1f restitution) * velocityAlongNormal; impulseMagnitude / totalInvMass; Vector3 impulse impulseMagnitude * normal; if (!a.IsStatic) a.Velocity - impulse * a.InvMass; if (!b.IsStatic) b.Velocity impulse * b.InvMass; }重点是这个公式j -(1 e) * dot(relativeVelocity, normal) / (invMassA invMassB)其中j是冲量大小。e是反弹系数。normal是碰撞法线。relativeVelocity是两个物体之间的相对速度。invMass是质量倒数质量越大受冲量影响越小。第三步球体和平面碰撞地面可以先用一个无限平面表示Plane: normal Vector3.up, distance 0如果球心到平面的距离小于半径就说明球撞地了。private void ResolveSpherePlane(SimpleBody3D body, Vector3 planeNormal, float planeDistance) { if (body.IsStatic) return; float signedDistance Vector3.Dot(body.Position, planeNormal) - planeDistance; if (signedDistance body.Radius) return; float penetration body.Radius - signedDistance; // 位置修正 body.Position planeNormal * penetration; // 速度修正 float velocityAlongNormal Vector3.Dot(body.Velocity, planeNormal); if (velocityAlongNormal 0f) { Vector3 normalVelocity velocityAlongNormal * planeNormal; Vector3 tangentVelocity body.Velocity - normalVelocity; normalVelocity -normalVelocity * body.Restitution; tangentVelocity * Mathf.Clamp01(1f - body.Friction); body.Velocity normalVelocity tangentVelocity; } }这里额外处理了摩擦速度 法线方向速度 切线方向速度法线方向速度控制弹起。切线方向速度控制滑动。摩擦就是削弱切线速度。第四步世界更新器完整一点的物理世界可以这样写public class SimplePhysicsWorld3D { public readonly ListSimpleBody3D Bodies new(); public void Step(float dt) { foreach (var body in Bodies) Integrate(body, dt); // 球体 vs 地面 foreach (var body in Bodies) ResolveSpherePlane(body, Vector3.up, 0f); // 球体 vs 球体 for (int i 0; i Bodies.Count; i) { for (int j i 1; j Bodies.Count; j) { ResolveSphereSphere(Bodies[i], Bodies[j]); } } } // 把上面的 Integrate / ResolveSphereSphere / ResolveSpherePlane 放进来 }在 Unity 里可以用一个MonoBehaviour驱动它public class SimplePhysicsRunner : MonoBehaviour { public Transform[] Objects; private SimplePhysicsWorld3D _world new(); private readonly ListSimpleBody3D _bodies new(); private void Start() { foreach (var obj in Objects) { var body new SimpleBody3D { Position obj.position, Radius 0.5f, Mass 1f, Restitution 0.5f, Friction 0.2f }; _bodies.Add(body); _world.Bodies.Add(body); } } private void FixedUpdate() { _world.Step(Time.fixedDeltaTime); for (int i 0; i Objects.Length; i) Objects[i].position _bodies[i].Position; } }如果要继续接近 Unity 的 3D 物理你可以按这个顺序升级Sphere Collider最简单适合入门。Plane Collider做地面、墙面、边界。AABB Collider不旋转的盒子检测很简单。OBB Collider可旋转盒子需要 SAT 分离轴检测。Capsule Collider角色控制器常用本质是线段 半径。旋转物理加上AngularVelocity Torque InertiaTensor Orientation多接触点求解一个盒子落地不是一个点接触而是多个接触点需要迭代解约束。Broad Phase现在两两检测是O(n²)。物体多了会爆炸。可以加空间网格八叉树Sweep and PruneBVH连续碰撞检测高速物体可能一帧穿过墙。需要做 swept collision比如球从上一帧位置到当前帧位置扫过去。简单总结3D 简易物理系统可以先做“球体刚体系统”。核心不是 Collider 多复杂而是理解这几个概念位置 Position 速度 Velocity 力 Force 质量 Mass 碰撞法线 Normal 穿透深度 Penetration 冲量 Impulse 固定时间步 Fixed Step把这几个打通之后再扩展盒子、旋转、摩擦、关节就会越来越像一个小型版 PhysX。