Bingo, Computer Graphics & Game Developer

射线与圆求交

假定已求解出交点,最后一步还需要将距离最短的交点筛选出来,有一个特殊情况如下图





实际交点应该是A,因此要剔除B的情况。比较简单,令交点到射线起始点向量为P,那么和射线方向向量d点积,看\( \mathtt{cos \theta} \)的符号即可(-90, 90)。


联立方程组无脑求解

在没有查阅之前,用的就是最基本的直线和圆方程强行联立求解,根据delta值来判断交点情况,最后根据交点与射线起始点的向量夹角筛选合适交点。

class ray
{
public:
    // ...
    // 0 = ax + by + c
    float a, b, c;
}

强行联立

float k = -r.a / r.b, t = -r.c / r.b;

float A = k * k + 1.0f;
float B = 2 * k * t - 2 * c->y * k - 2 * c->x;
float C = c->x * c->x + t * t - 2 * c->y * t + c->y * c->y - c->radius * c->radius;

float delta = B * B - 4 * A * C;

求解 delta为0,正负任意

float x1 = (-B + sqrt(delta)) / (2.0f * A);
float y1 = k*x1 + t;
int x2 = (-B - sqrt(delta)) / (2.0f * A);
int y2 = k*x2 + t;

但是上的上述方法有一个缺陷,就是你必须讨论斜率k为无穷的情况。

向量求解

设圆心坐标为C
令圆形方程为\( \mathtt{(X-C) \ldotp (X-C)=r^2} \),向量点积自己就是求解自身长度的平方,射线方程令为\( \mathtt{R(t) = P + td, t \ge 0} \)。

直接代入\( \mathtt{(P+td-C) \ldotp (P+td-C)=r^2} \), 令\( \mathtt{P-C = m} \)

展开下式

(m+td).(m+td)=r2 \mathtt{(m + td) \ldotp (m + td) = r^2}

等价于二次方程求根

(d.d)t2+2(m.d)t+(m.m)r2=0 \mathtt{(d \ldotp d)t^2 + 2(m \ldotp d)t + (m \ldotp m) - r^2 = 0}

基本b, c, t分量代式

b=m.d \mathtt{b = m \ldotp d}

c=(m.m)r2 \mathtt{c = (m \ldotp m) - r^2}

t=b+b2c \mathtt{t = -b +- \sqrt{b^2 - c}}

这里直接用向量,免去了讨论斜率的情况。交点Q就是\( \mathtt{P + td} \)。