S01E19:直线与球体相交的代数解法

1,196 阅读1分钟

说明

求解直线与球体相交问题,不仅可以用几何方式,也可以用代数方式,也就是通过求解一元二次方程的形式来解决问题。

方程

一元二次方程求解比较简单,可以直接套用公式来解决问题: 那么,最后交点坐标其实就是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)
}