现在我想引入连续碰撞检测(CCD),它可以操作动态点/动态线段。我的问题是:我不确定该如何实现。我知道如何在两个移动点之间进行连续碰撞、移动点和静态线段之间进行连续碰撞,但不知道如何在移动点(由点P定义)和移动线段(由点U和V定义,两者都可以完全自由移动)之间进行CCD。 问题示意图 我看到类似的问题在SO和其他平台上被问过,但没有这些确切的要求。
- 点和线段都在移动
- 线段可以旋转和拉伸(因为 U 和 V 自由移动)
- 需要在两帧之间准确地找到碰撞时间和碰撞点(CCD,无静态碰撞测试)
- 如果可能,我更喜欢数学上完美的解决方案(没有迭代逼近算法,扫描体积)
- 注意:扫描线形状不总是一个凸多边形,因为 U、V 点的自由度(见图像)
- 注意:使用扫描体积测试进行碰撞检测是不准确的,因为与多边形相交的碰撞点并不意味着实际运动中的碰撞点(见图像,一旦实际线段越过点的轨迹,该点就已经离开了多边形)
到目前为止,我想出了以下方法,假设:
- sP (帧开始时的P),
- eP (帧结束时的P),
- sU (帧开始时的U),
- eU (帧结束时的U),
- sV (帧开始时的V),
- eV (帧结束时的V)
问题: 它们会碰撞吗?如果是,何时和在哪里?
为了回答“是否”的问题,我发现这篇论文很有用:https://www.cs.ubc.ca/~rbridson/docs/brochu-siggraph2012-ccd.pdf(第3.1节),但我无法得出“何时”和“在哪里”的答案。 我也在这里找到了一个替代性的解释:http://15462.courses.cs.cmu.edu/fall2018/article/13(第三个问题)。
解决方案:
将每个点在帧期间的时间轨迹建模为线性运动(对于 0 <= t <= 1 的线路轨迹)。
- P(t) = sP * (1 - t) + eP * t
- U(t) = sU * (1 - t) + eU * t
- V(t) = sV * (1 - t) + eV * t
(0 <= a <= 1 表示由 U 和 V 定义的线段上的位置):
- UV(a, t) = U(t) * (1 - a) + V(t) * a
通过等式化点和线段方程来建模碰撞:
- P(t) = UV(a, t)
- P(t) = U(t) * (1 - a) + V(t) * a
导出从点P到线段上一点的向量函数(见F图片):
- F(a, t) = P(t) - (1 - a) * U(t) - a * V(t)
现在需要找到a和t,使得F(a, t) = (0, 0),且a,t在[0,1]范围内。这可以建模为一个具有2个变量的根查找问题。
将时间轨迹方程插入F(a, t)中:
- F(a, t) = (sP * (1 - t) + eP * t) - (1 - a) * (sU * (1 - t) + eU * t) - a * (sV * (1 - t) + eV * t)
按维度(x和y)分离时间轨迹方程:
Fx(a, t) = (sP.x * (1 - t) + eP.x * t) - (1 - a) * (sU.x * (1 - t) + eU.x * t) - a * (sV.x * (1 - t) + eV.x * t)
Fy(a, t) = (sP.y * (1 - t) + eP.y * t) - (1 - a) * (sU.y * (1 - t) + eU.y * t) - a * (sV.y * (1 - t) + eV.y * t)
现在我们有两个方程和两个变量需要求解 (Fx,Fy 分别对应 a,t),因此我们可以使用求解器来得到 a 和 t,然后再检查它们是否在 [0, 1] 范围内。对吗?
当我将其输入到 Python sympy 中进行求解时:
from sympy import symbols, Eq, solve, nsolve
def main():
sxP = symbols("sxP")
syP = symbols("syP")
exP = symbols("exP")
eyP = symbols("eyP")
sxU = symbols("sxU")
syU = symbols("syU")
exU = symbols("exU")
eyU = symbols("eyU")
sxV = symbols("sxV")
syV = symbols("syV")
exV = symbols("exV")
eyV = symbols("eyV")
a = symbols("a")
t = symbols("t")
eq1 = Eq((sxP * (1 - t) + exP * t) - (1 - a) * (sxU * (1 - t) + exU * t) - a * (sxV * (1 - t) + exV * t))
eq2 = Eq((syP * (1 - t) + eyP * t) - (1 - a) * (syU * (1 - t) + eyU * t) - a * (syV * (1 - t) + eyV * t))
sol = solve((eq1, eq2), (a, t), dict=True)
print(sol)
if __name__ == "__main__":
main()
我得到了一个解决方案,它非常庞大,花费sympy约5分钟来评估。 我不能在我的实际引擎代码中使用这样一个大表达式,这个解决方案对我来说似乎不正确。 我想知道的是: 我错过了什么吗?我认为这个问题似乎很容易理解,但我无法找到一种数学上准确的方法来找到动态点/动态线段的时间(t)和点(a)的撞击解决方案。任何帮助都将不胜感激,即使有人告诉我这样做是不可能的。
b^2 - (a^2+c^2) == 0
应该是b- (a+c) == 0
对此我感到非常抱歉 :( - Blindman67A = -l-(h*k)+g*l+h; B = -k*b-h*e+l*a+g*f+b-f-a; C = a*f-b*e
,因为c = d = j = 0
&i = 1
。如果您正在重复问题的某些部分,则效果很好。例如,1条移动线和许多移动点。 - Blindman67