接触与隧穿:球在两帧之间穿过去了,谁该为此负责
全课骨架:物理模拟每一帧只做三件事 —— ① 对每个物体积分;② 找出接触(谁压着谁、压多深);③ 解约束(按质量分配地纠回来)。 上一课讲完了 ① 积分 —— 球会掉、会弹、不会爆了。可它永远不会碰到任何东西,因为还缺 ② 找接触。 保真度:真机可证(画面与读数都由本页自己的检测与积分给出,对照物是给定的几何与守恒量,读者能拿笔复核)。
本页的原理与数值表照常可读(画面只是把同一个数画出来)。
定点观察:把「初速度 v₀」推到 12 以上 → 看画面里那块薄板与面板上的「判定」 → 离散检测版时不时就整个穿板掉下去(同一个速度,重开一次结果可能不同 —— 漏是按相位发生的);TOI 版次次都停在板上表面;子步版要 n ≥ 3 才次次接得住。
本帧的读数
(脚本启动中…)
2.1 段 · 离散检测:只查终点
本段只增加一样东西:球的速度(检测方法冻成"每帧末查一次球心是否落在板内",其余控件一致)。 保真度:真机可证。上一课球会弹,是因为每帧末检查"球心有没有掉到板里",掉进去就贴回。 但这个检查有个盲区:如果一帧之内球移动的距离超过了板的厚度,球心就从板的上面直接落到了板的下面 —— 终点检查看到的是"在板下面",于是判定没碰到。球就这么穿过去了。
| v_y (m/s) | 一帧位移 |v·h| (m) | |v·h| ÷ 板厚 t | 接住率(实测) | 接住率(算式 min(1, t ÷ |v·h|)) |
|---|
算式:接住率 = min(1, t ÷ |v·h|) = min(1, t / (|v|·h))。 直觉就是一句:球要正好落在厚 t 的板里;它每帧走 |v·h| 这么远,落在板里的机会就是"板厚占这一帧位移的比例"。 临界速度 v* = t / h = 0.15 × 60 = 9 m/s:低于它 |v·h| ≤ t,一帧必然落在板内(接住率 100%); 高于它,接住率就等于 t/(|v|·h) —— 拿笔算一行就能核对表① 最后两列。 实测与算式只差一点点,且差得有理由:步骤本身还多走 g·h² = 0.0027 m(步内重力), 所以以 v = 9 那一档为例,分母其实是 0.15 + 0.0027 而不是 0.15 ⇒ 实测 98.0%、算式 100%; v 越大这个修正越可忽略(v=30 时 29.5% vs 30.0%)。 这条规律最要紧的地方:|v·h| 越大接住率越低,不可能靠"调参数"补回到 100%。
2.2 段 · TOI:不再只查终点,去解那一刻
本段只增加一样东西:检测方法(速度冻回 2.1 里会漏的那一档,其余控件一致)。 保真度:真机可证。2.1 的问题是"只在帧末看一眼" —— 那如果沿运动轨迹解出"第一次碰到板上表面的时刻"呢? 这就是 TOI(Time of Impact):把这一帧的运动看成一段匀速直线,求它与板上表面的交点时刻 t。
| 检测方法 | 两次检查之间走过的距离 (m) | 接住率(实测) | 接住率(算式) | 接住时最大下探 (m) |
|---|
算式:同样是接住率 = min(1, t ÷ 每次检查之间走过的距离),只是"距离"换了:
离散 = |v|·h = 0.333 m(一帧)⇒ 0.15 / 0.333 ≈ 45%;
子步 n=8 = |v|·h/8 = 0.042 m ⇒ 0.15 / 0.042 > 1 ⇒ 100%;
TOI 的距离 ≈ 0(它解出碰撞那一刻就停下,不"走过去")⇒ 100%。
「接住时下探」那一列要当心一个陷阱:离散印的是 0.149 m,看着比子步的 0.042 只差 3.5 倍、好得很 ——
可这恰恰是它只有 44% 的另一面:能进入这一列统计的,只有那些"恰好落进这 0.15 m 板里"的幸运次,
下探自然 ≤ 板厚;下探更大的那些根本没被接住,压根不在统计里。
TOI 那一格是 0.00000(残差窗口太窄、本次未命中,理论上限 g·h² 已标在件一上)。
三条都由同一段运动量出来:同一相位扫描范围、同一 h、同一块板,只有"怎么看"不同。
2.3 段 · 子步内检测:当 TOI 解不出来时
本段只增加一样东西:检测策略(速度冻回 2.2 那一档,其余控件一致)。 保真度:真机可证。2.2 的 TOI 只对"球 + 平面"有效 —— 换个复杂形状(多边形、网格、布料)就没有闭式交点公式了。 工程上的通用退路:把一帧拆成 n 个子步,每子步后都查一次。于是"一帧能漏多深"这件事,被换成了"一个子步能漏多深"。
| 子步数 n | 子步长 hh (s) | |v|·h ÷ n (m) | 接住率(实测) | 接住率(算式 min(1, t·n ÷ |v|·h)) | 接住时最大下探 (m) |
|---|
算式:接住率 = min(1, t·n ÷ (|v|·h)) —— 把"每次检查之间走过的距离"从 |v|·h 换成 |v|·h/n,接住率就整体抬了 n 倍。 恢复到 100% 的门槛是 t·n ≥ |v|·h,即 n ≥ |v|·h / t = 20/(60×0.15) = 2.22 ⇒ 取整 n ≥ 3。 实测正好卡在这条线上:n=1 → 44.0%、n=2 → 89.5%(都还差一点)、n=4 与 n=8 → 100%。 顺带两条自洽检查:n = 1 那一行与表② 的「离散检测」行逐位相同(子步数取 1 就是离散检测,两条路径跑同一份判据); n ≥ 4 之后「接住时下探」每翻一倍减半(0.0835 → 0.0417,比值 0.499)。
课末:三条路的地图
2.1 看见离散检测的盲区 —— 接住率 = 板厚 ÷ 两次检查之间走过的距离,一帧走多远就漏多远,且永远补不回 100%; 2.2 用 TOI 把"距离"压到 0(接住率 100%,残留下探只剩 g·h²); 2.3 用子步内检测做通用退路:把距离换成 |v|·h/n,于是要先过 n > |v|·h/t 这道门槛,代价 ×n。 至此骨架②「找接触」收齐。下一课讲骨架③:知道了球陷进去多少之后,"把它推出来"有多少种分法、为什么堆塔会抖 —— 约束求解。 (本页已经露出了它的影子:2.2 里那句"兜底贴回"就是一次最朴素的位置级修正。)