说明
求解直线与球体相交问题,不仅可以用几何方式,也可以用代数方式,也就是通过求解一元二次方程的形式来解决问题。
方程
一元二次方程求解比较简单,可以直接套用公式来解决问题:
那么,最后交点坐标其实就是P±t*d
。而 t 是否存在,也就是是否相交,则需要根据一元二次方程求根公式的判别式来判断:
如果判别式大于 0,则存在两个交点;等于 0,一个交点(相切);小于 0,无交点。
用代数方法,本质上是用平方来代替向量归一化,理论上精度更高。
代码
static func isIntersection(line:Line, sphere:Sphere) -> Bool {
let vector = line.position - sphere.position
let a = length_squared(line.direction)
let b = dot(line.direction, vector)
let c = length_squared(vector) - sphere.radius * sphere.radius
let discriminant = b * b - 4 * a * c
return discriminant >= 0
}
static func intersectionPoint(line:Line, sphere:Sphere) -> (simd_float3, simd_float3)? {
let vector = line.position - sphere.position
let a = length_squared(line.direction)
let b = dot(line.direction, vector)
let c = length_squared(vector) - sphere.radius * sphere.radius
let discriminant = b * b - 4 * a * c
if discriminant < 0 {
return nil
}
let x = sqrtf(discriminant)
let t1 = (-b + x)/(2*a)
let t2 = (-b - x)/(2*a)
let point1 = line.position + t1 * line.direction
let point2 = line.position + t2 * line.direction
return (point1, point2)
}