【UnityShader入门精要学习笔记】第六章(1)Unity中的基础光照

本系列为作者学习UnityShader入门精要而作的笔记,内容将包括:

  • 书本中句子照抄 + 个人批注
  • 项目源码
  • 一堆新手会犯的错误
  • 潜在的太监断更,有始无终

总之适用于同样开始学习Shader的同学们进行有取舍的参考。


文章目录


光照的原理

一个物体为什么看起来是红色的?从物理上解释是因为这个物体能够反射更多的红色波长而吸收了其他波长。

因此想要实现光照渲染,我们就需要模拟光照环境下的物理现象:

  • 首先,光线要从光源(Light Source)中被发射出来
  • 然后,光线和场景中的一些物体相交:一些光线被物体吸收了,而另一些光线被散射到其他方向
  • 最后,摄像机吸收了一些光,产生了一张图像

光源

光是从光源发射出来的。在光学里,我们量化光的标准是辐照度(irradiance) ,对于平行光而言,辐照度可以通过计算光线方向 l l l(光源照射方向)垂直于单位面积上单位时间穿过的能量来得到。

而在计算光照模型时,若要计算物体表面的辐照度。而物体表面往往和光线方向 l l l是不垂直的,那么我们就会计算光源方向 l l l和表面法线n之间夹角的余弦值来得到。

(通过上图不难知道为什么 c o s θ cos\theta cosθ可以计算辐照度,假设左图单位面积的长度为8d,那么辐照度就是8d/d = 8 = 单位辐照度。如右图所示,若光线与法线入射角为 θ \theta θ,则两条光线间入射点间距则为 d / c o s θ d/cos\theta d/cosθ,则辐照度 = 8 d / ( d / c o s θ ) = 8 c o s θ = 单位辐照度 ∗ c o s θ = 8d / (d/cos\theta)= 8cos\theta = 单位辐照度 * cos\theta =8d/(d/cosθ)=8cosθ=单位辐照度∗cosθ)

因此 c o s θ cos\theta cosθ就可以使用光源向量 l l l和表面法线向量 n n n的点积来计算得到( l ⋅ n ∣ l ∣ ∣ n ∣ \frac{l \cdot n}{|l||n|} ∣l∣∣n∣l⋅n),因此我们可以通过点积来计算辐照度。(点积也可以理解为光线l在法线n向量方向上的投影与法线n的乘积)

吸收和散射

光线由光源发射出来后,就会与一些物体相交,通常相交的结果只有两个:散射(scattering)和吸收(absorption)

散射只能改变光线的方向,但不改变光线的密度和颜色。吸收改变光线密度和颜色但不改变方向。

光线在物体表面产生散射通常有两种方向,如果散射到物体内部,被称为折射(refraction) 。而另一种方向是散射到物体外部,被称为反射(reflection)

为了区分这两种不同的散射方向,我们在光照模型中使用了不同的部分来计算它们:高光反射/镜面反射(specular) 表示物体表面是如何反射光线的,而漫反射(diffuse) 则表示有多少光线会被折射、吸收和散射出表面。根据入射光线的数量和方向,我们也可以计算出出射光线的数量和方向,我们用出射度(exitance) 来描述它。

辐照度和出射度是满足线性关系的,而它们之间的比值就是材质的漫反射和高光反射属性

而且漫反射是没有方向性的,所以我们可以假设它在各个方向上是平均分布的。因此我们只会考虑某一特定方向上的高光反射。

着色

着色(Shading) 指的是,根据材质属性(如漫反射属性等),光源信息(如光源方向,辐照度等),使用一个等式去计算沿某个观察方向的出射度的过程。我们也把这个等式称为光照模型(Lighing Model) 。不同的光照模型由不同的目的,例如一些用于描述粗糙的物体表面,一些用于描述金属表面等等。


BRDF光照模型

BRDF是一种光照模型,通过给定入射光线的方向和辐照度后,BRDF可以给出在某个出射方向上的光照能量分布。


标准光照模型

标准光照模型是游戏引擎中早期使用的光照模型,原理比较简单,它只关心直接光照。从光源发射出来照射到物体表面的光,经过表面的一次反射直接进入摄像机的光线。

它的基本方法是,把进入到摄像机内部的光线分为4个部分。每个部分使用一种方法来计算它的贡献度:

  • 自发光(emissive) ,在本书中用 C e m i s s i v e C_{emissive} Cemissive来表示。这个部分用于描述当给定一个方向时,一个表面本身会向该方向发射多少辐射度。需要注意的是,如果没有使用全局光照(global illumination)技术,这些自发光的表面并不会真的照亮周围的物体。而是它本身看起来更亮了
  • 高光反射(specular) 部分,本书用 C s p e c u l a r C_{specular} Cspecular来表示,这个部分用于描述当光线从光源照射到模型表面时,该表面会在完全镜面反射方向散射多少辐射量。
  • 漫反射(diffuse) 部分,本书使用 C d i f f u s e C_{diffuse} Cdiffuse来表示,漫反射用于描述,当光线从光源照射到模型表面时,该表面会向每个方向散射多少辐射量。
  • 环境光(ambient) 部分,本书使用 C a m b i e n t C_{ambient} Cambient来表示,用于描述其他所有的间接光照。

自发光

自发光光线会从光源本身直接进入摄像机,无需任何物体表面的反射。自发光的值等于材质本身的自发光颜色值:

C e m i s s i v e = m e m i s s i v e C_{emissive} = m_{emissive} Cemissive=memissive

环境光

虽然标准光照模型通常用于描述直接光照,但是现实中的物体也可以被间接光照所照亮,间接光照指的是,光线通常会在多个物体之间反射,最后进入相机。

例如在红地毯上放置一个灰色的沙发,那么沙发的底部也会反射出由红地毯反射的一部分红光。

我们通过环境光来近似模拟间接光照,环境光就是一个全局变量,场景中的所有物体都使用这个变量:

C a m b i e n t = g a m b i e n t C_{ambient} = g_{ambient} Cambient=gambient

漫反射

漫反射光照的方向是完全随机的,因此我们可以认为在任意反射方向上光照的分布都是一样的,但是入射光线的角度很重要。

漫反射光照符合兰伯特定律 :反射光线的强度与表面法线和光源方向之间的夹角的余弦值成正比,因此,漫反射部分的计算如下:

高光反射

此处的高光反射也是经验模型,并不完全符合现实中的高光反射现象。它可用于计算那些沿着镜面方向被反射的光线,从而让物体看起来有光泽,例如金属材质

计算高光反射需要知道的信息比较多,如表面法线,视角方向,光源方向,反射方向等。

在这四个向量中,我们只需要知道其中的表面法线,视角方向和光源方向即可。反射方向可以通过其他信息计算:

其中, m g l o s s m_{gloss} mgloss是材质的光泽度,也被称为反光度。它用于控制高光区域的大小, m g l o s s m_{gloss} mgloss越大,高光区域呈现的亮点越小。 m s p s c u l a r m_{spscular} mspscular是材质的高光反射颜色,用于控制该材质对于高光反射的强度和颜色。

除了上述的Phong模型,还有一个类似的Blinn模型:

Blinn模型引入了一个归一化矢量h,并使用n和h的夹角进行计算。通常来说,若v和I向量是定值时Blinn模型更快。反之是Phong模型更快。


逐像素还是逐顶点

这些光照模型是在着色器中进行计算的。若在片元着色器中进行计算,就被称为逐像素光照,而在顶点着色器中计算,则被称为逐顶点光照

在逐像素光照中,我们以每个像素为基础,得到它的法线(可以是对顶点法线进行插值得到的,也可以从法线纹理中采样得到)。并进行光照模型的计算。这种在片元着色器中,在面片之间对顶点法线插值的技术被称为Phong着色 ,也被称为Phong插值或者法线插值着色技术。注意,此处的Phong着色不同于我们说的Phong光照模型。

与之相对的是逐顶点光照,被称为高洛德着色(Gouraud shading) 。在逐顶点光照中,我们在每个顶点上计算光照,然后会在渲染图元内部进行线性插值,最后输出成像素颜色。

由于顶点数远远少于像素点数,因此逐顶点光照的计算量少于逐像素光照。但是,由于逐顶点光照依赖于通过顶点的线性插值输出像素颜色,因此若光照模型中有非线性计算的时候(例如计算高光反射时),逐顶点光照就会出现问题。

总结

在上文中我们了解了,光照我们通常用辐照度来描述其强度,并可以用光源方向l和法线向量n的夹角余弦值 c o s θ cos\theta cosθ来描述光的辐照度。

在光线发射过程中会发生吸收和散射两种现象。为了模拟光照,我们通常用光照模型对光线进行计算着色。

在标准光照模型中,通常存在四类光线:

自发光------材质自身的发光值,

环境光------反射光照的间接光照,通常用全局变量来表示,

漫反射------与辐照度类似,反射光线的强度与表面法线和光源方向之间的夹角的余弦值成正比;

高光反射------一个非线性的经验模型,一般有Phong模型和Blinn模型两种。

在对着色器进行光照计算的时候,通常有逐像素和逐顶点两种模式。如果使用片元着色器进行光照渲染,则是逐像素光照,逐像素光照以每个像素为单位进行光照颜色计算,其中每个像素点的法线可以通过顶点进行插值计算获取,或者直接从法线纹理中获取。

若使用顶点着色器进行渲染则为逐顶点光照。逐顶点光照只计算片元顶点上的光照,并直接通过顶点间的线性插值来计算其中每个像素的颜色。

显然逐顶点计算的计算量远小于逐像素计算。但是逐顶点计算的缺陷在于依赖对顶点的线性插值。若光照模型中包含非线性的计算时(例如计算高光反射),逐顶点计算就会出问题。

标准光照模型我们也称为Blinn-Phong光照模型。但这种模型也存在很多局限性,首先很多重要的物理线性无法通过Blinn-Phong模型来表现出来,例如菲涅尔反射

其次,Blinn-Phong模型是各向同性的 ,即当我们旋转物体表面时,光照反射不会发生任何改变。但是有些表面材质是需要各向异性的,例如金属,毛发等。后文中,我们将学习基于物理的光照模型,这些模型将会更加复杂。

相关推荐
道爷我悟了2 分钟前
Vue入门-指令学习-v-on
javascript·vue.js·学习
人工智能技术咨询.32 分钟前
张雪峰谈人工智能技术应用专业的就业前景!
人工智能·学习·计算机视觉·语言模型
s_little_monster34 分钟前
【QT】QT入门
数据库·c++·经验分享·笔记·qt·学习·mfc
alfiy1 小时前
Elasticsearch学习笔记(六)使用集群令牌将新加点加入集群
笔记·学习·elasticsearch
爱学的小涛1 小时前
【NIO基础】基于 NIO 中的组件实现对文件的操作(文件编程),FileChannel 详解
java·开发语言·笔记·后端·nio
爱学的小涛1 小时前
【NIO基础】NIO(非阻塞 I/O)和 IO(传统 I/O)的区别,以及 NIO 的三大组件详解
java·开发语言·笔记·后端·nio
北极无雪1 小时前
Spring源码学习:SpringMVC(4)DispatcherServlet请求入口分析
java·开发语言·后端·学习·spring
望森FPGA2 小时前
HDLBits中文版,标准参考答案 |3.1.1 Basic Gates | 基本门电路
学习·fpga开发
JavaGPT2 小时前
prometheus学习笔记之PromQL
笔记·学习·prometheus
害羞的白菜2 小时前
Nginx基础详解5(nginx集群、四七层的负载均衡、Jmeter工具的使用、实验验证集群的性能与单节点的性能)
linux·运维·笔记·jmeter·nginx·centos·负载均衡