《Unity Shader入门精要》读书笔记05

铁名_IronName Lv2

第 5 章 Unity 中的基础光照

物理;一些定义

  • 光源(light source):一个没有体积的点
  • 辐照度(irradiance):在垂直于 ll 的单位面积上单位时间内穿过的能量;和照射到物体表面时光线之间的距离 d/cosθd/\cos\theta 成反比,cosθ\cos\theta 可以用光源方向 ll 和表面法线 nn 计算。
  • 散射(scattering) 只改变光线的方向,但不改变光线的密度和颜色。吸收(absorption) 只改变光线的密度和颜色 ,但不改变光线的方向。
  • 折射(refracion)/ 透射(transmission)散射到物体的内部。
  • 反射(reflection)散射到物体外部。
  • 高光反射(specular),在光照模型中表示物体表面是如何反射光线的。
  • 漫反射(diffuse),在光照模型中表示有多少光线会被折射、吸收和散射出表面。
  • 出射度(shading)描述出射光线的数量和方向。辐照度和出射度之间是满足线性关系的,它们之间的比值是材质的漫反射和高光反射属性。
  • 着色(shading) 指的是根据材质属性,使用一个等式去计算沿某个观察方向的出射度的过程。这个等式被称为光照模型(Lighting Model)。
  • BRDF(Bidirectional Reflectance Distribution Function)光照模型,本章涉及的 BRDF 都是经验模型。

    计算机图形学的第一定律:如果它看起来是对的,那么它就是对的。

标准光照模型

在BRDF理论提出前就被广泛使用了。基本理念由裴祥风(Bui Tuong Phong)提出。标准光照模型只关心直接光照(direct light),即直接从光源发射出来照射到物体表面后,经过物体表面的一次反射直接进入摄像机的光线。
标准光照模型将进入摄像机内的光线分为 4 个部分。

  • 自发光(emissive)cemissivec_{emissive} 。这个部分用于描述当给定一个方向时,一个表面本身会向该方向发射多少辐射量。在没有使用全局光照(global illumination)的情况下,这些自发光的表面并不会真的照亮周围。只是本身看起来更亮。
  • 漫反射(diffuse)cdiffusec_{diffuse} 。这个部分用于描述。当光线从光源照射到模型表面时,该表面会向每个方向散射多少辐射量。
  • 高光反射(specular)cspecularc_{specular} 。这个部分用于描述,当光线从光源照射到模型表面时,该表面会在完全镜面反射方向散射多少辐射量。
  • 环境光(ambient)cambientc_{ambient} 。用于描述其他所有的间接光照。

自发光

直接使用该材质的自发光颜色:

cemissive=memissivec_{emissive}=m_{emissive}

漫反射

Lambert 光照模型。漫反射光照符合兰伯特定律(Lambert‘s law):反射光线的强度与表面法线和光源方向之间的夹角的余弦值成正比。

cdiffuse=(clightmdiffuse)max(0,nI)c_{diffuse}=(c_{light}\cdot m_{diffuse})max(0, \textbf{n} \cdot \textbf{I}) nn 是表面法线,II 是指向光源的单位矢量,mdiffusem_{diffuse}是材质的漫反射颜色,clightc_{light}是光源颜色。max(0,nI)max(0, n \cdot I) 可以防止物体被从后面来的光源照亮。

高光反射

经验模型,并不完全符合真实世界中的高光反射现象。
nn表示表面法线,II表示指向光源的单位矢量,vv表示指向相机的单位矢量。可以计算反射方向:

r=2(n^I)n^I\textbf{r}=2(\hat{\textbf{n}}\cdot\textbf{I})\hat{\textbf{n}}-\textbf{I}

用 Phong 模型计算高光部分:

cspecular=(clightmspecular)max(0,v^r)mglossc_{specular}=(c_{light}\cdot m_{specular})max(0, \hat{\textbf{v}}\cdot\textbf{r})^{m_{gloss}} mglossm_{gloss}是材质的光泽度(gloss)/ 反光度(shininess),mglossm_{gloss} 越大,亮点越小。mspecularm_{specular} 是材质的高光反射颜色,用于控制该材质对于高光反射的强度和颜色。clightc_{light} 则是光源的颜色和强度。这里也用max()防止 v^r^\hat{\textbf{v}}\cdot\hat{\textbf{r}} 为负数。

Blinn 模型避免计算反射方向 r^\hat{\textbf{r}},引入新的矢量 h^\hat{\textbf{h}}

h^=v^+Iv^+I\hat{\textbf{h}}=\frac{\hat{\textbf{v}}+\textbf{I}}{|\hat{\textbf{v}}+\textbf{I}|}

Blinn 模型:

cspecular=(clightmspecular)max(0,n^h^)mglossc_{specular}=(c_{light}\cdot m_{specular})max(0, \hat{\textbf{n}}\cdot\hat{\textbf{h}})^{m_{gloss}}

在硬件实现时,如果摄像机和光源距离模型足够远的话,Blinn 模型比 Phong 模型快, 以为此时可以认为 v^\hat{\textbf{v}}I^\hat{\textbf{I}} 是定值,h^\hat{\textbf{h}} 同样;反之,Phong 模型可能更快。两者都是经验模型。

环境光

在真实的世界中,物体也可以被间接光照(indirect light) 照亮。我们用环境光来近似模拟间接光照。

cambient=gambientc_{ambient}=g_{ambient}

逐像素or逐顶点

在片元着色器中计算光照模型,称为逐像素光照(per-pixel lighting)。Phong 着色(Phong shading)在面片之间对顶点法线进行插值,也被称为 Phong 插值或者法线插值着色技术。
在顶点着色器中计算光照模型,称为逐顶点光照(per-vertex lighting)。高洛德着色(Gouraud shading)在每个顶点上计算光照,然后在渲染图元内部线性插值。在某些情况下会产生明显的棱角现象。

总结

标准光照模型——Phong 光照模型;Blinn-Phong 光照模型。因为 Blinn 模型计算高光反射的方式和 Phong 模型不同,除了性能外,还有其他差异。

  • 局限性:无法表现菲涅耳反射(Fresnel reflection);Blinn-Phong 模型是各向同性(istropic),然而现实中拉丝金属、毛发等表面是各向异性(anisotropic)反射性质的。

在 Unity 中实践

实践

在 Unity 中实现以下光照模型。

逐顶点的漫反射光照

1
2
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'
  • 将法线变换到世界空间,可以使用顶点变换矩阵的逆转置矩阵,
  • 因此我们首先得到模型空间到世界空间的变换矩阵的逆矩阵_World2Object,然后通过调换它在mul函数中的位置,得到和转置矩阵相同的矩阵乘法。
  • 由于法线是一个三维矢量,因此我们只需要截取_World2Obiect的前三行前三列即可。
  • saturate函数是CG提供的一种函数,它的作用是可以把参数截取到[0,1]的范围内。

    对于细分程度较高的模型,逐顶点光照可以得到较好的光照效果。但是对于细分程度较低的模型,逐顶点光照就会出现一些问题

逐像素的漫反射光照

  • 顶点着色器不需要计算光照模型,只需要把世界空间下的法线传递给片元着色器即可;
  • 片元着色器需要计算漫反射光照模型。

半兰伯特模型(Half Lambert)

兰伯特模型改善了“漫反射光照下,背光面没有明暗变化,导致细节缺失”的问题。由Valve公司在开发《半条命》时提出。
广义的半兰伯特光照模型公式:

cdiffuse=(clightmdiffuse)(α(n^I)+β)c_{diffuse}=(c_{light}\cdot m_{diffuse})(\alpha(\hat{\textbf{n}}\cdot\textbf{I})+\beta)

通过这样的方式,我们可以把n^I\hat{\textbf{n}}\cdot\textbf{I}的结果范围从[-1, 1]映射到[0, 1]范围内。这样,背光面也可以用明暗变化。

需要注意的是,半兰伯特是没有任何物理依据的,它仅仅是一个个视觉加强技术。

逐顶点的高光反射

逐像素的高光反射

至此,实现了一个完整的 Phong 光照模型。

Blinn-Phong 光照模型

Blinn-Phong 光照模型的高光反射部分看起来更大、更亮一些。(和 Phong 模型相比)
实际渲染中绝大多数情况选择 Blinn-Phong 光照模型。

Unity 内置函数

  • 这些函数都没有保证得到的方向矢量是单位矢量。所以使用前记得归一化。
  • 部分函数只能在前向渲染中使用,如WorldSpaceLightDir、UnityWorldSpaceLightDir和ObjSpaceLightDir。

实践

使用内置函数来改写 Blinn-Phong 光照模型.shader

  • 标题: 《Unity Shader入门精要》读书笔记05
  • 作者: 铁名_IronName
  • 创建于 : 2026-01-15 15:25:27
  • 更新于 : 2026-01-17 13:44:29
  • 链接: https://blog.ironname.top/2026/01/15/《Unity-Shader入门精要》读书笔记05/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论