学习目标
能解释 Generic Refraction Simulation 如何把入射方向、表面法线和介质 IOR 变成折射方向,并区分方向计算与颜色查询
能实现厚度或后表面深度近似、屏幕空间颜色采样和 total internal reflection fallback,说明每种近似的失效边界
能调节 RefractionLab 的介质方向、入射角、IOR 与厚度,定位法线错误、偏移过大和临界角闪烁
先把“透明”拆成方向、距离和颜色
透明材质最容易被一张扭曲的环境图伪装:画面看起来像玻璃,但折射角、物体厚度和背面颜色之间没有可解释的关系。GPU Gems 2 第 19 章的 Generic Refraction Simulation 关注的是一条可实时近似的路径:先根据入射方向和法线计算光线进入介质后的方向,再用厚度、后表面或屏幕空间信息决定它应该看到什么颜色。
先打开实验,固定 IOR,分别切换 air → glass 与 glass → air。增大入射角时,预测折射方向是更靠近法线还是更贴近界面;再切到厚度调试,确认厚度只改变颜色查询偏移,而不会替代正确的方向计算。最后用 TIR 调试观察临界角附近为何不能继续采样透射颜色。
Generic refraction 实验
改变介质方向、入射角、IOR 与厚度,分辨折射方向、颜色偏移和全内反射。
refract:方向随 IOR 改变 air · n≈1 glass · n=IOR N θᵢ 34° θₜ 21.888° 查询记录 IOR 1.50 transmitted 21.9° thickness 0.60 lookup offset 0.24 sin θₜ ≤ 1 sample refracted color 角度接近临界值时,先看 TIR 证据,再决定 screen-space lookup 如何退化
先写清楚光线和法线方向
调试前统一 incident vector 是“指向表面”还是“离开表面”,normal
是否朝向当前介质,并记录 n₁、n₂
的顺序。折射公式本身没有替你修正坐标约定,方向错一位就会表现成整块材质反向扭曲。
把 screen-space 偏移当成折射定律
现象 → 颜色纹理确实发生偏移,但换 IOR 或视角后折射弯曲几乎不变。原因 →
只用法线乘一个经验 scale,没有先计算介质边界上的折射方向。修法 → 先用
Snell/refract 得到方向,再用厚度、后表面或深度信息把方向投影为颜色查询;把
scale 当作材质参数而不是物理替代。
refraction vector ↡ 描述光线穿过介质界面后方向变化的向量;它由入射方向、法线和两个介质的折射率共同决定。
index of refraction ↡ 介质中光速与真空光速的比值;渲染中用两个介质的 IOR 比值控制折射角。
Generic Refraction Simulation:方向计算与颜色查询分层 表面输入 I · N · IOR front position depth / thickness 方向阶段 Snell / refract T · exit point TIR fallback 颜色阶段 screen lookup environment / backface blend · Fresnel 折射向量决定“看向哪里”,厚度与深度决定“穿过多少介质”
折射模拟至少有两个可以独立验证的输出:第一是 T 的方向,第二是沿 T 查询到的颜色。即使方向正确,厚度或屏幕空间投影错误也会让背景拉伸;即使颜色查询看起来平滑,方向错误也会让 IOR 和视角失去意义。把它们分开显示,才能知道问题在几何、向量还是纹理坐标。
1. 用 Snell 定律计算折射方向
Snell’s law ↡ 光线从一个介质进入另一个介质时,入射角和折射角满足的关系;它是计算折射方向与临界角的基础。
设入射介质折射率为 n 1 n_1 n 1 ,出射介质折射率为 n 2 n_2 n 2 ,法线方向为 N N N 。折射角满足:
n 1 sin ( θ i ) = n 2 sin ( θ t ) . n_1\sin(\theta_i)=n_2\sin(\theta_t). n 1 sin ( θ i ) = n 2 sin ( θ t ) .
GPU shader 通常直接使用 refract(I, N, eta) 形式的向量函数,其中 e t a = n 1 / n 2 eta=n_1/n_2 e t a = n 1 / n 2 。实现时要先把 I I I 、N N N 归一化,并保证它们位于同一坐标空间。若法线来自法线贴图,需要先从切线空间变到世界或视图空间,再参与折射计算。
Snell:折射只改变法线方向上的分量 medium 1 · n₁ medium 2 · n₂ normal N θᵢ θₜ n₁ sin(θᵢ) = n₂ sin(θₜ);如果 sin(θₜ) 超过 1,就不能继续传播
当 e t a sin ( θ i ) > 1 eta\sin(\theta_i)>1 e t a sin ( θ i ) > 1 时,θ t \theta_t θ t 不存在,光线不会离开当前介质,这就是 total internal reflection。不能把无效的平方根或 NaN 继续送进颜色采样;应检测判别式,使用反射向量作为 fallback,并在材质边缘保持连续。
total internal reflection ↡ 从高折射率介质射向低折射率介质时,入射角超过临界角后不再产生透射光、而全部返回原介质的现象。
忽略 n₁、n₂ 顺序与全内反射
现象 → 玻璃到空气时角度越大,shader 输出黑色、NaN 或闪烁的折射颜色。原因 → IOR
比值方向写反,或没有检查 e t a sin ( θ i ) eta\sin(\theta_i) e t a sin ( θ i ) 是否超过 1。修法 →
根据光线所在介质选择 n₁/n₂,先检查判别式;发生 TIR 时使用 reflect
方向或稳定的边界颜色,不读取无效 UV。
2. 用厚度与后表面补回“穿过多少介质”
只知道 front surface 的位置和法线时,折射光线可以告诉我们“朝哪个方向看”,但不知道它在物体内部走了多远。薄片、球体和厚玻璃在相同 front normal 下会产生不同的颜色偏移,因此通用方案常用一个厚度代理:厚度纹理、backface depth、双层位置或预计算的 object-space thickness。
thickness proxy ↡ 描述折射光线在介质内部传播距离的近似量;它可以来自厚度纹理、前后表面深度差或规则物体的解析估计。
front → inside → back:厚度决定颜色偏移 front surface back surface inside distance / thickness offset = T · thickness → lookup UV 只有 front normal 的近似会失去后表面信息;厚度纹理或 backface depth 能补回一部分证据
一种可解释的近似是先在 front surface 计算 T T T ,再用厚度 d d d 沿 T T T 推进到估计的 exit point:p e x i t ≈ p f r o n t + d T p_{exit}\approx p_{front}+dT p e x i t ≈ p f r o n t + d T 。随后把 exit point 投影到环境、后表面或屏幕空间,取得透过物体后的颜色。这个模型不等同于完整的光线与真实背面相交,但它把厚度参数和颜色偏移联系起来,便于按材质调节。
如果使用 backface depth,需要确认前后深度位于相同投影和线性化空间;直接相减非线性 depth 值会让远处厚度严重失真。screen-space 方案还需要处理射线走出屏幕、穿过别的物体或投影到透明物体自身之外的情况。遇到查询失败时,宁可使用环境颜色或反射 fallback,也不要把越界坐标 clamp 成一条明显的拉伸带。
3. 把方向投影成可查询的颜色
screen-space lookup ↡ 用折射方向、厚度或 exit point 推导纹理坐标,并从屏幕颜色、环境图或后表面缓存取回透射颜色的采样策略。
颜色来源有三类:环境图适合没有可见背景的封闭场景,屏幕颜色适合把场景背景折射进透明物体,后表面缓存适合需要近似穿透顺序的物体。三者都不是免费的真实光传输:环境图缺乏局部遮挡,屏幕颜色缺少屏幕外信息,后表面缓存需要额外的渲染目标和深度管理。
generic refraction 的误差来自哪里? normal 方向偏差 → 高光/折射抖动 IOR 介质参数错 → 弯折角错误 thickness 深度近似错 → 偏移过大 screen lookup 投影出界 → 拉伸/黑洞 先建立可解释的近似,再把误差限制在材质、视角和屏幕 footprint 能接受的范围
折射颜色常与 Fresnel 权重混合:正视角更多看到透射,掠射角更多看到反射。混合时要让反射与透射的颜色、曝光和 alpha 处在一致的能量约定中。若直接把两个未预乘颜色相加,边缘会过亮;若透明排序和深度写入不一致,正确的折射方向也会被错误遮挡。
用 clamp 隐藏 screen-space lookup 越界
现象 → 画面没有黑边,但物体边缘出现背景颜色被拉成长条。原因 → 折射 UV
超出屏幕后被 clamp 到最后一个像素,越界状态被伪装成有效样本。修法 → 返回
lookup validity,越界时切换环境或反射
fallback,并对镜头移动、物体靠近屏幕边缘和大厚度做回归。
三步实验:从向量到透射颜色
每一步只改变一个变量,记录入射角、IOR、折射角、TIR 状态和颜色查询偏移。不要用最终颜色单独判断方向正确性;先观察向量和命中点,再恢复材质混合。
⚡ 分步1 / 3
1 2 3 重置
第一步:验证 refraction vector 选择 air → glass,固定厚度,只改变 incident angle 与 IOR。预测 θₜ 如何变化,再用 Snell 图核对 n₁、n₂ 顺序、法线方向和归一化状态。
Snell:折射只改变法线方向上的分量 medium 1 · n₁ medium 2 · n₂ normal N θᵢ θₜ n₁ sin(θᵢ) = n₂ sin(θₜ);如果 sin(θₜ) 超过 1,就不能继续传播 上一步 播放 下一步
常见误区
把厚度乘到法线偏移上而不是折射方向上
现象 → 改变物体厚度会让边缘颜色变化,但视角和 IOR 对弯折角几乎没有影响。原因 →
厚度被当成了 normal map 的 UV scale,方向阶段没有真正使用 refract。修法 →
先计算单位 refraction vector,再沿它估计 exit
point;把厚度只用于传播距离和颜色查询位置。
把前后 depth 的非线性值直接相减
现象 → 近处厚度看起来正常,远处物体的折射偏移突然爆炸或消失。原因 →
perspective depth 不是线性距离,前后 buffer 的数值差不等于介质内部距离。修法 →
先还原到线性 view-space 或 object-space,再求差并限制有效范围。
只用折射颜色替代反射和透明排序
现象 → 玻璃边缘发灰发黑、相互重叠的透明物体顺序错误,开发者继续调 IOR。原因 →
Fresnel、alpha、深度写入和透明排序是独立的管线状态。修法 →
先单独验证反射、透射、validity 和 alpha,再按材质规则混合,并为 TIR
与查询失败保留 fallback。
本章小结
Generic Refraction Simulation 先计算 refraction vector,再决定用环境、后表面或 screen-space lookup 得到透射颜色;方向和颜色来源必须分开验证。
Snell's law 由 n₁、n₂、法线和入射方向决定折射角;IOR 顺序错误或未检测 total internal reflection 会产生 NaN、黑洞和闪烁。
thickness proxy 让通用近似获得“穿过多少介质”的信息,但厚度应在 exit point/颜色查询阶段使用,不能替代方向公式。
屏幕空间查询需要 validity 和边界 fallback;不能用 clamp 把越界样本伪装成有效背景。
发布前应分别回归正视角、掠射角、玻璃到空气、厚度变化、屏幕边缘和透明排序,再决定近似是否满足材质预算。
练习 问题 1|计算折射角。 光线从空气进入 IOR 为 1.5 的玻璃,入射角为 30°。请写出折射角的计算关系,并说明 shader 需要先做什么。
查看答案使用 n 1 sin ( θ i ) = n 2 sin ( θ t ) n_1\sin(\theta_i)=n_2\sin(\theta_t) n 1 sin ( θ i ) = n 2 sin ( θ t ) ,所以
sin ( θ t ) = 1 ⋅ sin ( 30 ° ) / 1.5 = 1 / 3 \sin(\theta_t)=1\cdot\sin(30°)/1.5=1/3 sin ( θ t ) = 1 ⋅ sin ( 30° ) /1.5 = 1/3 ,折射角约为 19.5°。shader
应先归一化入射方向和法线,确定 n₁/n₂
的方向,再检查判别式并把向量送到同一坐标空间的颜色查询。
问题 2|诊断黑洞。 玻璃到空气的折射在掠射角突然变黑。你会检查哪些证据?
查看答案先记录 n₁/n₂ 顺序、e t a sin ( θ i ) eta\sin(\theta_i) e t a sin ( θ i ) 和折射函数的判别式;若它超过 1,应是
total internal reflection,而不是继续采样透射颜色。随后检查 TIR 是否使用反射
fallback、法线是否朝向当前介质、screen-space lookup
是否越界,以及越界时是否错误 clamp。
问题 3|选择厚度方案。 一个凸透镜需要近景可见的背景变形,但屏幕外信息不可避免。你会如何组合厚度、后表面和环境 fallback?
查看答案用 front surface 的法线和 IOR 计算 refraction vector,再用 backface depth
或厚度纹理估计 exit point;把 exit point 投影到屏幕颜色做透射查询,并返回
validity。屏幕外、查询失败或 TIR 时切换环境/反射
fallback;用线性空间求前后深度差,并对镜头边缘、厚度极值和移动画面做回归。
名词解释 本章出现的专业名词,用大白话再讲一遍。
refraction vector
index of refraction
Snell’s law
total internal reflection
thickness proxy
screen-space lookup
资料与写作方式声明
本章以GPU Gems 2 · Chapter 19. Generic Refraction Simulation 的权威目录界定学习范围,并结合正文列出的技术资料独立重写;不宣称复现原书正文,也不沿用原作表述。
原作版权归作者与出版社所有;本站原创教学结构与表述仅供学习交流。