今天我们来学习unity中的自定义光照
Unity 中的菲涅尔效应
核心原理
菲涅尔效应描述的是:物体表面的反射率随观察角度变化。
- 正对观察(视线与法线夹角小)→ 反射弱,漫反射/折射强
- 掠射观察(视线与法线夹角大,接近平行表面)→ 反射强
典型例子:看一池水,垂直往下看能看到水底;远处水面像镜子一样反射天空。
在 Unity 中的实现方式
| 方式 | 说明 |
|---|---|
| 菲涅尔方程(物理准确) | 基于折射率计算,用于 PBR(基于物理的渲染)材质 |
| Schlick 近似 | 最常用的简化公式:F = F0 + (1 - F0) * (1 - cosθ)^5 |
| 内置 Shader | Standard/URP/HDRP 的金属度/光滑度工作流程已自动包含 |
实际应用场景
- 边缘光(Rim Light):角色轮廓发光
- 玻璃/水面:边缘反射更强
- 全息/护盾效果:视角相关的透明度变化
- 卡通渲染:描边或边缘染色
简而言之就是物体在你观察时变得更易反射的原理
我们有的时候从unity商店下载的资源会显示不出来,这个是因为渲染管不适配导致的,有的材质之前是用Built in渲染管,而我们使用的是URP渲染管
我们只需要选中这个material然后改成URP渲染即可
这样就可以使用我们的材质了
事实上shadergraph已经内置了菲涅尔反射的支持
比如我们将光滑度smoothness改成0,此时的材质就是一张不反光的普通贴图
但是如果我们将其数值调大就可以看到明显的反光
我们可以自己创建一个material
首先像之前那样创建基础色和基础纹理,选择无光照unlit着色器
然后创建菲涅尔节点和浮点类型的Fresnelpower节点控制fresnel的强度
强度默认为1 改为slider滑块,范围0~20
然后用FresnelColor控制颜色,使用HDR
我们改动强度值就可以看到这个材质的反光了
漫反射光
我们可以知道漫反射就是法向量夹角成反比
漫反射的光简化为 n · l
随着角度的增大,随着角度的增大,点积逐渐减少
核心公式
漫反射光照强度 ∝ n · l
其中:
- n = 表面法向量(垂直于表面的单位向量)
- l = 指向光源的单位向量
- · = 点积(dot product)
点积的几何定义是:
n⋅l=∣n∣∣l∣cosθ=cosθ
(因为都是单位向量,长度为1)
| 夹角 θ | cosθ | 漫反射强度 |
|---|---|---|
| 0°(正对光源) | 1.0 | 最强 |
| 30° | 0.87 | 较强 |
| 45° | 0.71 | 中等 |
| 60° | 0.50 | 较弱 |
| 90°(切线方向) | 0 | 无光 |
| >90° | 负值 | 0(背面无光照) |
直观理解
想象一束光照射到地面:
- 正午(太阳在头顶):光线垂直地面,单位面积接收的光最多 → 最亮
- 傍晚(太阳斜射):同样的光束"铺开"在更大的面积上,单位面积能量减少 → 变暗
这就是"与法向量夹角成反比"的本质——夹角越大,有效光照面积越大,单位面积能量越分散,所以看起来越暗。
我们像之前那样创建颜色和纹理节点
实现卡通渲染效果
然后我们实现光源的计算, 这里需要介绍几个节点
Main Light Direction 是 Unity Shader Graph 中的一个内置节点(Shader Graph 13+ / Unity 2022+ 引入),用于获取场景中**主方向光(Main Directional Light)**的方向
| 属性 | 说明 |
|---|---|
| 输出 | Direction (Vector3) — 世界空间中主方向光的归一化方向 |
| 主光源定义 | 投射阴影的方向光;如果没有,则回退到第一个不投射阴影的方向光 |
关键注意点:方向是反的
这是最容易踩坑的地方。Unity 官方讨论中确认:
Main Light Direction节点输出的方向是 从光源指向表面 的向量(即GetMainLight().direction被取反了)。
但在光照计算中,我们需要的是 从表面指向光源 的向量(即 l),所以:
实际光照方向 l = -MainLightDirection
这个节点经典用法就是这样
[Main Light Direction] → [Negate] ───┐
├──→ [Dot Product]
[Normal Vector] (World) ─────────┘
而其他的几个就是
- Main Light Direction 获取光源方向
- Negate 取反,得到从表面指向光源的向量
l - Normal Vector(世界空间)获取表面法线
n - Dot Product 计算
n · l
这里简单说一下
1. [Normal Vector](世界空间)
| 属性 | 说明 |
|---|---|
| 输入 | 无(自动从模型顶点法线获取) |
| 输出 | Vector3 — 世界空间中的表面法线 n |
| 作用 | 告诉你"表面朝哪个方向" |
法线是什么? 想象一个球体,每个点的法线就是从球心指向该点的方向。平面的话,法线就是垂直于平面的向量。
注意:必须选择 World 空间(而非 Object/Tangent),因为光照方向也是在世界空间中定义的,两者要在同一坐标系下才能做点积。
2. [Main Light Direction]
| 属性 | 说明 |
|---|---|
| 输出 | Vector3 — 主方向光的归一化方向 |
| 方向含义 | 从光源指向表面(光传播的方向) |
plain
如果太阳在上方,输出大概是 (0, -1, 0)
↑ 太阳
│
↓ 光往下走
3. [Negate](取反)
| 输入 | 输出 |
|---|---|
(x, y, z) | (-x, -y, -z) |
为什么要取反?
因为光照公式 n · l 中的 l 必须是 从表面指向光源:
plain
Main Light Direction: 光源 ──→ 表面 = (0, -1, 0)
Negate 后: 表面 ──→ 光源 = (0, 1, 0) ← 这才是 l
4. [Dot Product](点积)
这是核心运算。数学上:
n⋅l=∣n∣∣l∣cosθ=cosθ
(因为都是单位向量,长度为1)
它把"角度关系"转换成"亮度数值":
| 夹角 θ | 点积结果 | 含义 |
|---|---|---|
| 0°(正对光源) | 1.0 | 最亮 |
| 45° | 0.707 | 较亮 |
| 60° | 0.5 | 中等 |
| 90°(切线) | 0 | 无光 |
| 120°(背面) | -0.5 | 理论上负值,但光照不能为负 |
为了满足这个n⋅l=∣n∣∣l∣ 我们需要这些节点
main light direction表示从光源到物体的方向,所以用negate节点取反获得从物体表面到光源的方向,接着计算nagate输出的反向向量与normal vector输出的法线向量的点积
以上我们已经完成了光照的计算,有两种实现方式来实现渲染
如图,我们有两个节点,分别为step节点和smoothstep节点,由图像你就可以很清楚的看出二者的区别
Step 节点
功能
硬阈值切换 — 输入大于阈值输出1,小于等于阈值输出0。
plain
Step(Edge, In) = In > Edge ? 1 : 0
| 输入 In | Edge=0.5 | 结果 |
|---|---|---|
| 0.2 | 0.5 | 0 |
| 0.5 | 0.5 | 0(或1,取决于实现,通常是0) |
| 0.8 | 0.5 | 1 |
图形表示
plain
输出
1 │ ┌────────
0 │──────┘
└────┬────┬────→ 输入
0.5(Edge)
完全硬边,没有过渡。
典型用法
- 制作硬边遮罩(如卡通渲染的明暗分界)
- 将连续的灰度图转成纯黑白
Smoothstep 节点
功能
平滑阈值过渡 — 在 Edge1 和 Edge2 之间做平滑的 Hermite 插值。
plain
Smoothstep(Edge1, Edge2, In):
如果 In ≤ Edge1: 输出 0
如果 In ≥ Edge2: 输出 1
如果 Edge1 < In < Edge2: 输出平滑的 0→1 曲线
图形表示
plain
输出
1 │ ┌──────
│ ╱
0 │──────╱
└────┬────┬────→ 输入
Edge1 Edge2
有过渡带,边缘柔和
和 Step 的对比
| Step | Smoothstep | |
|---|---|---|
| 参数 | 1个阈值 (Edge) | 2个阈值 (Edge1, Edge2) |
| 过渡 | 硬切,无过渡 | 平滑曲线过渡 |
| 用途 | 硬边、二值化 | 软边、抗锯齿、柔和遮罩 |
这两个最明显的区别就是step当in输入值小于edge阈值的时候节点输出0,0是黑色,1是白色,我们可以通过控制阈值实现,不过这个明暗过度非常生硬
所以smoothstep可以实现平滑过渡,这个函数具有缓冲区域输出值在此区间内会从0平滑过渡到1,所以这个拥有两个边界值,
当 in输入值< edge1输出为0 ,
当in输入值 > edge2输出为1,
如果in输入值位于 edge1和edge2之间,那么输出将会是介于0~1之间的某个值
我们添加一个vector2的值cutoff thresholds用split分割出x和y来控制两个阈值,分别设置为-0.05和0
不过为了更直观添加一个ambient light strength的浮点节点来控制环境光强度,我们将其设置为(0~1)的slider滑块
Lerp(Linear Interpolation,线性插值)是 Shader Graph 中最常用、最核心的混合节点,它的作用很简单:
在两个值之间,按一个百分比取中间值。
数学公式
Lerp(A,B,T)=A+(B−A)×T=A×(1−T)+B×T
| 参数 | 含义 |
|---|---|
| A | 起始值(T=0 时的结果) |
| B | 目标值(T=1 时的结果) |
| T | 混合因子(0~1),也叫"权重" |
直观理解
想象一条从 A 到 B 的线段,T 就是你走到的位置:
然后将我们smoothstep的输出值放入T槽,将ambient light strength值放入A槽,B槽保持默认的1,这样我们只需要改动A槽就可以了
我们将这个材质添加到物体上,但是你可以看到阴影面黑的离谱,这个只需要调整环境光强度即可
这样就正常多了,这个可以自己调整x y 还有光照强度尝试一下
















