在 3D 中找到从点到截锥的最短向量
Finding the shortest vector from a point to a truncated cone in 3D
我正在尝试了解计算 3D 中点和截锥之间的最短向量的特定实现。原意介绍于this paper.
所以如果我们有两个球形物体:半径为 rA、位置为 pA 和速度为 vA 的物体 A 和半径为 rB、位置为 pB 和速度为 vB 的物体 B,那么我们可以用更简单的方式表示计算相对位置和相对速度,假设物体A是一个点,物体B的半径为rA + rB.
在 2D 中,这看起来像是从图 (a) 到图 (b) 的转换,其中 tau 只是一个标量因子:
A
3D 图形类似,但不是圆形,而是球体。
现在,如果相对速度矢量位于灰色截锥内,我们应该找到矢量 u,它是相对速度 V 的最小变化移动到圆锥的圆周上,如下图所示(注意:P是相对位置):
这有两种情况:
如果相对速度低于截止圆的中心(蓝色虚线下方)。在这种情况下 u 将在截止圆(较小的圆)上。
第二种情况,我不明白它是如何计算的,是当相对速度在小圆(球)的中心上方时,在这种情况下 u 将投影到圆锥体的切线上。 P和V向量所代表的平面与大球体的交点是一个圆u会躺着的。
const Vector3 relativePosition = other->position_ - position_;
const Vector3 relativeVelocity = velocity_ - other->velocity_;
const float distSq = absSq(relativePosition);
const float combinedRadius = radius_ + other->radius_;
const float combinedRadiusSq = sqr(combinedRadius);
Plane plane;
Vector3 u;
if (distSq > combinedRadiusSq) {
/* No collision. */
const Vector3 w = relativeVelocity - tau * relativePosition;
/* Vector from cutoff center to relative velocity. */
const float wLengthSq = absSq(w);
const float dotProduct = w * relativePosition;
if (dotProduct < 0.0f && sqr(dotProduct) > combinedRadiusSq * wLengthSq) {
/* Project on cut-off circle. */
const float wLength = std::sqrt(wLengthSq);
const Vector3 unitW = w / wLength;
plane.normal = unitW;
u = (combinedRadius * tau - wLength) * unitW;
}
else {
**/* Project on cone. I Don't understand this! */
const float a = distSq;
const float b = relativePosition * relativeVelocity;
const float c = absSq(relativeVelocity) - absSq(cross(relativePosition, relativeVelocity)) / (distSq - combinedRadiusSq);
const float t = (b + std::sqrt(sqr(b) - a * c)) / a;
const Vector3 ww = relativeVelocity - t * relativePosition;
const float wwLength = abs(ww);
const Vector3 unitWW = ww / wwLength;
plane.normal = unitWW;
u = (combinedRadius * t - wwLength) * unitWW;**
}
}
我知道最后我们需要找到 t(如代码中所示)来缩放 P。但是,我不明白这里的叉积是怎么用的,我们要解的二次方程代表什么。
这个函数可以找到here。
…虽然我不明白collision avoidance
模型是如何工作的,但似乎可以通过考虑围绕轴的一些角度来获得相关方程
顺便说一句,它看起来像一个不适合SO的纯数学问题。如果您想问这种问题,Mathematics Stack Exchange 可能是更好的地方。
附录:另一种方法
为了让 problem/answer 更加有意识,我想考虑另一种编码方法的可能性。由于我们可以在实际程序中毫不犹豫地使用很多数学函数(例如 asin()
、sqrt()
),因此也可以通过使用数学函数和 vector algebra
,如下.
/* Project on cone. */
const float sin_phi = combinedRadius / std::sqrt(distSq);
const float cos_phi = std::cos(std::asin(sin_phi));
Vector3 E_axial = normalize(relativePosition);
Vector3 E_inplane = normalize(cross(cross(relativePosition, relativeVelocity), E_axial));
Vector3 E_dir = E_axial * cos_phi + E_inplane * sin_phi;
// Based on math: (s * E_dir - relativeVelocity) * E_dir = 0
const float s = relativeVelocity * E_dir;
u = s * E_dir - relativeVelocity;
plane.normal = -normalize(u);
我正在尝试了解计算 3D 中点和截锥之间的最短向量的特定实现。原意介绍于this paper.
所以如果我们有两个球形物体:半径为 rA、位置为 pA 和速度为 vA 的物体 A 和半径为 rB、位置为 pB 和速度为 vB 的物体 B,那么我们可以用更简单的方式表示计算相对位置和相对速度,假设物体A是一个点,物体B的半径为rA + rB.
在 2D 中,这看起来像是从图 (a) 到图 (b) 的转换,其中 tau 只是一个标量因子:
3D 图形类似,但不是圆形,而是球体。
现在,如果相对速度矢量位于灰色截锥内,我们应该找到矢量 u,它是相对速度 V 的最小变化移动到圆锥的圆周上,如下图所示(注意:P是相对位置):
这有两种情况:
如果相对速度低于截止圆的中心(蓝色虚线下方)。在这种情况下 u 将在截止圆(较小的圆)上。
第二种情况,我不明白它是如何计算的,是当相对速度在小圆(球)的中心上方时,在这种情况下 u 将投影到圆锥体的切线上。 P和V向量所代表的平面与大球体的交点是一个圆u会躺着的。
const Vector3 relativePosition = other->position_ - position_; const Vector3 relativeVelocity = velocity_ - other->velocity_; const float distSq = absSq(relativePosition); const float combinedRadius = radius_ + other->radius_; const float combinedRadiusSq = sqr(combinedRadius); Plane plane; Vector3 u; if (distSq > combinedRadiusSq) { /* No collision. */ const Vector3 w = relativeVelocity - tau * relativePosition; /* Vector from cutoff center to relative velocity. */ const float wLengthSq = absSq(w); const float dotProduct = w * relativePosition; if (dotProduct < 0.0f && sqr(dotProduct) > combinedRadiusSq * wLengthSq) { /* Project on cut-off circle. */ const float wLength = std::sqrt(wLengthSq); const Vector3 unitW = w / wLength; plane.normal = unitW; u = (combinedRadius * tau - wLength) * unitW; } else { **/* Project on cone. I Don't understand this! */ const float a = distSq; const float b = relativePosition * relativeVelocity; const float c = absSq(relativeVelocity) - absSq(cross(relativePosition, relativeVelocity)) / (distSq - combinedRadiusSq); const float t = (b + std::sqrt(sqr(b) - a * c)) / a; const Vector3 ww = relativeVelocity - t * relativePosition; const float wwLength = abs(ww); const Vector3 unitWW = ww / wwLength; plane.normal = unitWW; u = (combinedRadius * t - wwLength) * unitWW;** } }
我知道最后我们需要找到 t(如代码中所示)来缩放 P。但是,我不明白这里的叉积是怎么用的,我们要解的二次方程代表什么。
这个函数可以找到here。
…虽然我不明白collision avoidance
模型是如何工作的,但似乎可以通过考虑围绕轴的一些角度来获得相关方程
顺便说一句,它看起来像一个不适合SO的纯数学问题。如果您想问这种问题,Mathematics Stack Exchange 可能是更好的地方。
附录:另一种方法
为了让 problem/answer 更加有意识,我想考虑另一种编码方法的可能性。由于我们可以在实际程序中毫不犹豫地使用很多数学函数(例如 asin()
、sqrt()
),因此也可以通过使用数学函数和 vector algebra
,如下.
/* Project on cone. */
const float sin_phi = combinedRadius / std::sqrt(distSq);
const float cos_phi = std::cos(std::asin(sin_phi));
Vector3 E_axial = normalize(relativePosition);
Vector3 E_inplane = normalize(cross(cross(relativePosition, relativeVelocity), E_axial));
Vector3 E_dir = E_axial * cos_phi + E_inplane * sin_phi;
// Based on math: (s * E_dir - relativeVelocity) * E_dir = 0
const float s = relativeVelocity * E_dir;
u = s * E_dir - relativeVelocity;
plane.normal = -normalize(u);