第 13 课:Oriented Line Circle Intersection
我的解:目标:用“方向对准”来判断线是否可能与圆相交。
我的解
uniform float iTime;
uniform vec2 iResolution;
void main() {
vec2 uv = gl_FragCoord.xy / iResolution.xy;
uv *= 2.0;
uv -= 1.0;
uv.x *= iResolution.x / iResolution.y;
vec2 a = vec2(1.0, 0.0);
vec2 b = a + vec2(cos(iTime), sin(iTime));
vec2 a2b = b - a;
vec2 n = normalize(vec2(a2b.y, -a2b.x));
float d = -dot(n, a);
float line = 1.0 - smoothstep(0.04, 0.05, abs(dot(uv, n) + d));
vec2 circleCenter = vec2(-1.0, 0.0);
float circleRadius = 0.5;
float circle = 1.0 - smoothstep(0.49, circleRadius, distance(circleCenter, uv));
float centerDist = length(a - circleCenter);
vec2 leftVec = vec2(-1.0, 0.0);
float cosAngle = abs(dot(leftVec, normalize(a2b)));
float tangentEdge = sqrt(pow(centerDist,2.0)-pow(circleRadius,2.0));
float tangentCos = tangentEdge/centerDist;
float intersect = step(tangentCos,cosAngle);
vec3 shapeColor = mix(vec3(0.38, 0.12, 0.93), vec3(1.0, 0.3, 0.3), intersect);
vec3 result = mix(vec3(0.12), shapeColor, clamp(line + circle, 0.0, 1.0));
gl_FragColor = vec4(result, 1.0);
}
复盘笔记
- 目标:用“方向对准”来判断线是否可能与圆相交。
- 核心计算:
-
- 线段方向 \hat{d}=\mathrm{normalize}(b-a)
-
- 与基向量 ((-1,0)) 的夹角余弦 \cos\phi=|\hat{d}\cdot(-1,0)|
-
- 由外切几何得到阈值 \cos\theta_t=\sqrt{1-(r/d)^2},\quad d=|a-\mathrm{circleCenter}|
-
- 若 \cos\phi\ge\cos\theta_t 判为可能相交。
- 直觉:比较“线的朝向”与“圆的切线角”;只要线的方向足够偏向圆,即认为会碰到。
- 优缺点:实现直观,适合可视化;但未计算真实距离,对数值边界需保护(如 (d\le r) 时根号无定义)。
- 目标:直接用几何距离判断相交。
- 核心计算:
-
- 直线由 \vec{n}\cdot\vec{x}+d=0,\quad d=-\vec{n}\cdot a 定义。
-
- 圆心到直线距离 |\vec{n}\cdot\mathrm{circleCenter}+d|
-
- 到圆边的签名距离 s = |\vec{n}\cdot\mathrm{circleCenter}+d| - r
-
- 若 s\le0线与圆相交或相切。
- 直觉:先求点到线的垂直距离,再减去半径;若结果为负,说明线进入圆内部。
- 优缺点:几何严格、可推广、数值稳定;需保证 \vec{n}已归一化。
- | 方法 | 判定依据 | 关键量 | 精度 | 应用场景 |
- | ----- | --------- | ----------------------------- | --- | ------------ |
- | 角度阈值法 | 朝向是否足够对准圆 | \cos\phi \ vs\ \cos\theta_t | 近似 | 启发式或视觉判断 |
- | 距离场法 | 圆心到线的最近距离 | \vec{n}\cdot p+d-r | 精确 | SDF、抗锯齿、几何计算 |
-
两者都先建立法线式直线 n\cdot x+d=0,
-
角度法比较“方向”,距离场法比较“距离”;
-
若追求通用与稳定,应选 SDF 法。