说明
三维空间中,直线可能与球体相交,也可能不相交。如果相交的话,会有两个交点,恰好相切则是一个。
几何
最简单的方法,就是将球心当成一个点,计算球心到直线的距离。然后与球体半径进行比较。当然,如果只需要比较大小的话,可以用距离的平方来代替距离进行计算。
不过,如果你还记得如何计算点到直线距离的话,我们实际用到了点到直线的垂足(投影点),计算过程用到了向量归一化和点乘。
那么如果要求相交点的坐标呢?其实这只是个简单的二维几何问题,我们已经知道了球心A到直线CD的垂足坐标G,也知道了距离AG(的平方),只要用球体半径的平方 - 距离平方,再开方就得到了交点距离垂足的距离EG、FG。 最后得到了交点 E、F 的坐标。
代码
static func isIntersection2(line:Line, sphere:Sphere) -> Bool {
let distanceSquared = Line.distanceSquaredBetween(point: sphere.position, line: line)
return distanceSquared <= sphere.radius * sphere.radius
}
static func intersectionPoint2(line:Line, sphere:Sphere) -> (simd_float3, simd_float3)? {
let vector = sphere.position - line.position
let normalizedDirection = normalize(line.direction)
let dotValue = dot(vector, normalizedDirection)
let nearPoint = line.position + dotValue * normalizedDirection
let distanceSquared = distance_squared(nearPoint, sphere.position)
let radiusSquared = sphere.radius * sphere.radius
if distanceSquared > radiusSquared {
return nil
}
let x = sqrtf(radiusSquared - distanceSquared)
let point1 = nearPoint + x * normalizedDirection
let point2 = nearPoint - x * normalizedDirection
return (point1, point2)
}