开篇提示
从这篇文章起,之后的所以shader编写将会转为HLSL语言,CG已经有点过时了。
高光反射(镜面反射)
镜面反射是指若反射面比较光滑,当平行入射的光线射到这个反射面时,仍会平行地向一个方向反射出来,这种反射就属于镜面反射。
高光可以表示出一个物体表面的光滑程度,越光滑表面高光越强。可以想象一个球,有一个手电筒直接打在球上,球的表面越光滑,高光点越小越集中,越出超漫反射就越严重,高光点就越大。
其中关于高光反射的经验方程是
- : 材质的高光反射系数。
- : 入射光强度。
- : 从顶点指向摄像机的单位向量(View Vector)。
- : 光线在表面的单位反射向量(Reflection Vector)。
- : 高光指数(Shininess),控制高光的“紧凑”程度。 越大,高光点越小、越锐利。
Tis:高光指数可以表现未一个材质的光滑度(gloss)。
反射向量 的计算公式:
(其中 为表面法线, 为指向光源的单位向量)
接下来我将演示如何推导出R(反射向量),在Unity中关照方向是从光照点指向光源

反射向量 的计算公式疑点讲解:
为什么想到用投影向量?根据镜面反射的定理,反射光向量和光线向量的模长一定,根据公式反推使R向量加上L向量就可以得到一个未知的向量L1,观察形式可知是投影向量。
高光反射的经验方程理解
经验公式描述了这么一个经验现象,把光想成一条条的向量,经过反射之后只有和v重合的可以被看到,经验公式通过计算V和L的夹角(通过点积cos)当夹角为0是点积的结果为1,那么不是一的呢?任何小于一的数都会被指数函数无限缩小就表现为光线迅速减弱,不要忘记还有n。
下面给一个示意图

效果分析
那么就想上面说的高光反射的效果会让物体有一个高光点,来看一下shader编写中的公式形式
我们需要物体颜色,光照颜色,观察方向的向量,反射向量,和一个Gloss(通常是自己定)
Shader编写
和漫反射一样,高光的光照模型也有逐顶点和逐像素两种方式,具体差别和漫反射一样,可以翻看一下漫反射那节
1 | Shader "Unlit/Blinn-Phong_URP" |
半角向量优化(Bilnn-Phone)
先看公式吧
其中H的计算公式为
下面我们来讲解这个公式的由来
先看这个特殊情况光正好可以被看到你就会发现这时候L向量和V向量相加得出的新向量与N向量重合(微面元理论),这时候这个新向量就代表了V和L向量的角平分线所在的线段,所以叫半角向量。

这样计算的优点是Phong 模型在计算 时,如果观察角度大于 90 度,点积会迅速变为负数,导致高光在边缘处戛然而止。
而在 Blinn-Phong 中,因为 是平分线, 的夹角增加速度比 慢(大约是一半)。这使得高光带的衰减更加柔和,能更真实地模拟金属或塑料在边缘处的漫射高光。
对比Phong性能优势
| 步骤 | Phong 模型 (反射向量 R) | Blinn-Phong (半角向量 H) |
|---|---|---|
| 几何逻辑 | 计算 关于 的对称向量 | 计算 和 的角平分线 |
| 计算开销 | (包含较多乘法) | (加法为主) |
| 性能优势 | 必须针对每个顶点/像素重新计算 | 若光源和相机无限远, 是常数 |
| 在代码实现上其实很明了了 |
1 | half3 relfect = 2*(dot(normal, lightDir))*normal - lightDir; |
疑点解析
为何还有混合Lambert光照的效果?单单从代码上理解没有这一部分,物体将只有高光点,就像是被聚光灯照到了一样不符合平行光照的效果。
从模拟现实的方面添加混合是为了更加贴近现实中的物体受光感
当光线照射到非金属(电介质)表面时,会发生两种物理现象:
- 折射与散射(Lambert 部分):光线进入物体表面内部,经过多次碰撞后随机散射出来。这部分光失去了方向性,形成了我们看到的“底色”(Diffuse)。
- 表面反射(高光部分):光线直接从表面弹射走。这部分光保留了光源的颜色和方向感,形成了“亮点”(Specular)。
如果没有 Lambert,物体看起来就像一个透明的玻璃球或纯黑的金属壳;如果没有高光,物体看起来就像粗糙的石灰粉末。混合两者,才能让物体看起来像“有涂层的实体”。
说些什么吧!