三維空間中,小球做平拋運動(受重力、初速度,無空氣阻力)。場景中存在多個平面,包括水平面、任意傾斜面。需**實時判斷小球與平面是否處於「接觸」狀態**(持續接觸、滾動、靜止),而非瞬間「碰撞」(彈射、反彈)。已知:平面法向量、傾斜角、小球位置/速度/加速度。
小球半徑 r,球心位置 P,平面方程 n·(X - P0) = 0(n 歸一化法向量,P0 平面上任意點)。
球心到平面有向距離:d = n·(P - P0)。
**接觸幾何條件**:|d| ≤ r + ε(ε 為數值容差,如 1e-4)。
d ≈ r 且 v·n < 0(相對速度指向平面內部),瞬時發生,需施加脈衝改變速度方向(反彈系數)。|d - r| ≤ ε 且 v·n ≈ 0(法向相對速度趨近零),且**合外力法向分量指向平面內部**(F_total·n < 0),小球被「壓」在平面上,無法分離。此時應施加**約束力**(法向支持力)抵消穿透趨勢,使法向加速度為零,切向受摩擦力/重力分量驅動滾動/滑動。對小球受力分析:
G = m*g(方向 (0, -g, 0) 或自定義)。N:方向 n,大小未知,由約束條件決定。f:方向反切向相對速度,大小 μ*|N|(庫侖摩擦)或黏滯摩擦模型。約束方程(接觸保持):
a·n = 0 (法向加速度為零,不穿透、不分離)
展開:(G + N + f)·n / m = 0 → N·n = - (G·n + f·n)
因 f·n = 0(摩擦力垂直於法向),得 N = - G·n**(標量,方向 n)。
即:**支持力大小恰好抵消重力在法向的分量**。
**切向加速度**:
a_tangent = (G + f)_tangent / m
其中 G_tangent = G - (G·n)n,f = -μ*N*v_tangent/|v_tangent|(滑動摩擦)或靜摩擦判斷。
為每個球-平面對維護狀態:
enum ContactState { SEPARATED, COLLIDING, CONTACT_SLIDING, CONTACT_ROLLING, CONTACT_RESTING }
每幀更新邏輯:
d = n·(P - P0)。d > r + ε → SEPARATED,僅受重力運動。d ≤ r + ε 且 v·n < -ε → COLLIDING,施加脈衝反彈,轉 SEPARATED 或 CONTACT。|d - r| ≤ ε 且 |v·n| ≤ ε:
N = -G·n。若 N < 0(重力拉離平面)→ 實際應分離,設 N=0,狀態轉 SEPARATED。N ≥ 0 → CONTACT。計算切向加速度,更新切向速度/位置。根據切向速度大小判斷 SLIDING/ROLLING/RESTING。v_tangent = ω × r(角速度叉積半徑),需維護角速度狀態,施加扭矩 τ = r × f。btPersistentManifold、ContactConstraint 實現。總結:**接觸 ≠ 碰撞**。接觸是持續的幾何貼合 + 動力學約束(法向加速度為零 + 支持力平衡法向外力)。核心在於每幀求解支持力 N = -G·n 並施加切向摩擦,維護狀態機處理分離/碰撞/滑動/滾動/靜止轉換。建議直接集成成熟物理引擎(Bullet/PhysX)而非手寫求解器,專注於業務邏輯層的接觸事件回調。