4. 光线追迹基础:斯涅尔定律的向量形式、光线与自由曲面求交算法(牛顿迭代法)、光线微分方程
光线追迹,说白了就是模拟光线怎么走。做自由曲面设计,这步要是搞不清楚,后面全是空中楼阁。我刚开始接触自由曲面那会儿,总觉得光线追迹是现成工具的事,自己写代码纯属浪费时间。直到有一次,一个非序列系统怎么调都追不准,我才老老实实把底层逻辑啃了一遍。
嗯,今天咱们就聊聊光线追迹的三个核心:斯涅尔定律怎么用向量算、光线和自由曲面怎么求交、以及光线微分方程到底在说什么。
4.1 斯涅尔定律的向量形式
传统教材里,斯涅尔定律长这样:n₁ sin θ₁ = n₂ sin θ₂。但在自由曲面里,我们面对的是任意方向的入射光和任意朝向的曲面法线。这时候,向量形式才是王道。
我个人习惯用这个形式:
n₁ (I × N) = n₂ (T × N)
其中 I 是入射光方向单位向量,T 是折射光方向单位向量,N 是法线单位向量。叉积代表什么?代表光线和法线构成的平面。说白了,折射光、入射光和法线必须在同一个平面内。
但实际计算时,我们更常用的是这个形式:
T = (n₁/n₂) I + [ - (n₁/n₂) (I·N) + sqrt(1 - (n₁/n₂)² (1 - (I·N)²)) ] N
看着复杂,其实逻辑很简单:折射光 = 入射光在切向的分量 + 法向分量的修正。我在项目中遇到过一个问题——当根号里面是负数时,说明发生了全反射。这时候光线就出不去了。
反射的向量形式更简单:
R = I - 2 (I·N) N
你想想看,反射其实就是把入射光在法线方向的分量反向,切向分量不变。这个公式我闭着眼睛都能写出来,因为太常用了。
4.2 光线与自由曲面求交算法
自由曲面没有解析表达式,没法像球面那样直接解二次方程。怎么办?牛顿迭代法。
基本思路是这样的:
- 给一个初始猜测点 P₀
- 计算 P₀ 到曲面的有符号距离 f(P₀)
- 如果 |f(P₀)| 小于阈值,认为找到了交点
- 否则,沿梯度方向更新:P₁ = P₀ - f(P₀) / (∇f(P₀) · D)
其中 D 是光线方向,∇f 是曲面的梯度(也就是法线方向)。
我曾经踩过一个坑:初始点选得太远,牛顿迭代直接发散。后来我学乖了,先用包围盒做粗筛,再用牛顿迭代精修。
代码实现大概是这样的:
def ray_surface_intersection(ray_origin, ray_dir, surface_func, grad_func, tol=1e-8, max_iter=20):
# 初始猜测:沿光线方向走一步
t = 0.1
for i in range(max_iter):
P = ray_origin + t * ray_dir
f = surface_func(P)
if abs(f) < tol:
return P, t
grad = grad_func(P)
# 沿梯度方向修正
dt = f / (np.dot(grad, ray_dir) + 1e-12)
t = t - dt
if abs(dt) < tol:
return P, t
# 迭代不收敛
return None, None
这里有个细节:分母加了个小量 1e-12,防止除零。光线和曲面相切的时候,梯度方向和光线方向垂直,点积为零。这种情况虽然少见,但遇到了就是大麻烦。
4.3 光线微分方程
光线微分方程描述的是光线在非均匀介质中的传播路径。说白了,就是光线在折射率连续变化的空间里怎么走。
方程长这样:
d/ds (n dr/ds) = ∇n
其中 s 是光程,r 是位置向量,n 是折射率。这个方程的意思是:光线会朝折射率增大的方向弯曲。你想想看,海市蜃楼就是这个原理——空气温度不同导致折射率变化,光线就弯了。
在自由曲面设计中,我们通常假设介质是均匀的(空气或玻璃),所以 ∇n = 0。这时候方程退化为:
d²r/ds² = 0
说白了就是直线传播。但如果你做渐变折射率透镜(GRIN lens),这个方程就派上用场了。
我记得有一次做自由曲面导光板设计,需要模拟光线在微结构中的传播。一开始我用直线近似,结果和实验对不上。后来老老实实解光线微分方程,才把问题搞定。
- 斯涅尔定律向量形式:记住 T = (n₁/n₂) I + [...] N 这个公式
- 牛顿迭代求交:初始点选好,迭代就稳
- 光线微分方程:均匀介质中退化为直线,非均匀介质中需要数值求解
4.4 知识体系总览
下面这张图把本章的核心逻辑串起来了。从光线出发,经过曲面求交,再通过斯涅尔定律计算折射/反射,最后更新光线状态。循环往复,就是完整的光线追迹。
这张图里,我把整个流程分成了四个阶段。你从「光线出发」开始,经过「曲面求交」找到交点,再用「斯涅尔定律」算出新方向,最后「更新光线状态」。如果光线还没出射,就继续循环。
我个人觉得,初学者最容易卡在「曲面求交」这一步。因为自由曲面没有标准方程,每次都要自己写求交函数。我的建议是:先把球面和平面的求交写熟,再扩展到自由曲面。一步一步来,别想一口吃成胖子。
好了,这一章的内容就到这儿。光线追迹是自由曲面设计的基石,后面的优化、公差分析都建立在这之上。把这些基础打牢,后面会轻松很多。