Unity Shader入门精要 第6章 Unity中的基本光照 读书笔记

第6章 Unity中的基本光照

注意:图片的来源基本来自作者冯乐乐的GitHub,感谢作者分享

https://github.com/candycat1992/Unity_Shaders_Book

 

渲染的两大部分:

1、决定一个像素的可见性

2、光照模型:决定这个像素上的光照计算

 

如果一个物体在看来是黑色的,实际上是因为这个物体吸收了绝大部分的波长。

 

模拟真实光照环境生成一张图像,需要考虑3种物理现象:

1、光线从光源中被发射出来

2、光线和场景中的一些物体相交:一些光线被物体吸收了,而另一些光线被散射到其他方向

3、摄像机吸收了这些被散射出来的光,产生了一张图像

 

光源:光由光源发射出来。

光源是没有体积的点,用 l 表示光源的方向

辐照度:光源发射出的光的多少

平行光 的 辐照度:计算在垂直于 l 的单位面积上单位时间内穿过的能量

计算光照模型的时候如何计算表面的辐照度:物体表面往往和 l 不垂直

光源方向 l 和 表面法线 n 之间的夹角的余弦值(这里的方向矢量的模为1)

 

为什么使用点积计算辐照度

1、如果光是垂直照射到物体表面,那么光线之间的垂直距离 d 保持不变

2、如果光是斜着照射到物体表面,那么在物体表面光线之间的距离是 d/cosθ,因此单位面积上接收到的光线数目要少于垂直照射的光线数目(辐照度 和 照射到物体表面时光线之间的距离 d/cosθ 成反比,即 辐照度 和 cosθ 成正比,而 cosθ 可以使用光源方向 l 和 表面法线 n 的点积得到

Unity Shader入门精要 第6章 Unity中的基本光照 读书笔记_第1张图片

吸收 和 散射:

光线由光源发射出来后会与一些物体相交,相交后有两个结果:散射 和 吸收

1、散射:改变光线方向,但是不改变光线的密度和颜色

2、吸收:改变光线的密度和颜色,但是不改变光线方向

 

散射的两个结果(两个不同的散射方向):

1、折射(透射):散射 到 物体内部

2、反射:散射 到 物体外部

光照模型:

                漫反射(diffuse)表示有多少光线会被折射、吸收 和 散射出表面

                高光反射(specular)表示物体表面是如何反射光线的

在光照模型中,出射度:计算 射光线的数量 和 方向。

辐照度 和 出射度 之间是满足 线性关系的

辐照度 和 出射度 之间的比值 就是 材质的漫反射 和 材质的高光反射 属性

不透明的物体,折射进入物体内部的光线会继续与内部的颗粒进行相交,其中一些光线最后会重新发射出物体表面,而另一些则被物体吸收。

从物体表面重新发射出的光线将会具有和射入光线不同的方向分部和颜色:

Unity Shader入门精要 第6章 Unity中的基本光照 读书笔记_第2张图片

着色(shading):

根据材质属性(如 漫反射属性 等)、光源信息(如 光源方向、辐照度 等),使用 光照模型(Lighting Model 即 一个计算等式) 去计算沿着某个观察方向的出射度的过程。例如,一些用于描述粗糙的物体表面,一些用于描述金属表面等

经验模型:对真实场景进行理想化和简化,不能真实地反映物体和光线之间的交互.

 

1、BRDF 光照模型:

解决 一个表面是如何与光照进行交互的(有多少光线被反射,反射的方向有哪些)

当给定模型表面上的一个点时,BRDF用数学公式表示,包含了对该点外观的完整的描述,也提供了一些参数来调整材质属性。

即:当给定 入射光线 的方向和辐照度后,BRDF 可以给出在某个出射方向上的光照能量分布

 

2、基于物理的 BRDF 模型:更加真实地模拟光和物体的交互

 

标准光照模型:

早期游戏引擎的光照模型。BRDF理论被提出之前就存在并广泛使用。

只关心直接光照(direct Light),也就是直接从光源发射出来照射到物体表面后,经过物体表面的一次反射直接进入摄像机的光线。

把进入摄像机的光线分为4个部分(每个部分各自使用一种方法计算光线的贡献度)

(自发光e+高光反射s+漫反射d+环境光a)

 

 

1、自发光(emissive):

当给定一个方向时,一个表面本身会向该方向发射多少辐射量

注意:如果没有使用 全局光照(Globa lillumination)技术,这些自发光的表面并不会真的照亮周围的物体,只是它本身看起来更加亮了而已

直接光源发射进入摄像机,而不需要经过任何物体的反射。

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

注意:通常在实时渲染中,自发光不会照亮周围的表面,带有自发光的物体并不会被当成光源(如果是 全局光照系统 就可以模拟自发光物体对周围物体的影响)。

 

2、高光反射(specular):

当光线从光源照射到模型表面时,该表面会在完全镜面反射方向散射多少辐射量

经验模型,并不完全符合真实世界中的高光反射现象,让物体看起来有光泽(金属材质)

(1)Phong 模型:

Unity Shader入门精要 第6章 Unity中的基本光照 读书笔记_第3张图片

Unity Shader入门精要 第6章 Unity中的基本光照 读书笔记_第4张图片

(2)Blinn 模型:

避免计算反射方向 r ,引入新的矢量 h,h 是通过对 v 和 I 的取平均后再归一化得到的:

使用 矢量n和矢量h 之间的夹角进行计算,而不是 Phong模型的 矢量v 和 矢量r 之间的夹角:

Unity Shader入门精要 第6章 Unity中的基本光照 读书笔记_第5张图片

因此如果摄像机和光源距离足够远的话,因为此时可以认为 矢量v 和矢量I 都是定值,所以 矢量h 将会是一个常量,即此时 Blinn模型 会快于 Phong模型。

但是假如当 矢量v 和 矢量I 不是定值时,Phong 模型反而更快一些。

很多重要的物理现象无法使用 Blinn-Phong模型 表现出来,例如 菲涅尔反射(Fresnel reflection)

Blinn-Phong 模型 具有 各向同性(isotropic)反射性质:当固定视角 和 光源方向 旋转表面时,反射不会发生任何改变。无法表现出 各向异性(anisotropic)反射性质:拉丝金属、毛发等,这些需要基于物理的光照模型更加真实地反映光和物体的交互。

3、漫反射(diffuse):

当光线从光源照射到模型表面时,该表面会向每个方向散射多少辐射量

在漫反射中,视角的位置不重要,反射是完全随机的(任何反射方向上的分布是一样的),但是入射光线的角度很重要

兰伯特定律(Lambert's Law):反射光线的强度 与 表面法线 和 光源方向 之间夹角的余弦值成正比

注意:需要防止法线和光源方向点乘的结果为负值,因此需要取最大值的函数来截取至0,这样就可以防止物体被后面来的光源照亮。

 

 

4、环境光(ambient):

近似模拟其他所有间接光照

间接光照(indirect Light):光线在多个物体之间反射最后进入摄像机,在光线进入摄像机之前经过不止一次的物体反射。

全局变量:

 

基本光照模型的使用:

1、在 顶点着色器 中计算光照模型:逐顶点光照(per-vertex lighting)

高洛德着色(Gouraud shading):在每个顶点上计算光照,然后在渲染图元内部进行线性插值,最后输出成像素颜色。由于顶点数目往往小于像素数目,因此逐顶点光照的计算量往往要小于逐像素光照

缺点:因为逐顶点光照依赖于线性插值得到像素光照,因此当光照模型中有非线性的计算(例如计算高光反射时),逐顶点光照就会出问题。而且会由于逐顶点光照在渲染图元内部对顶点颜色进行插值,会导致渲染图元内部的颜色总是暗于顶点处的最高颜色值,这在某些情况下会产生明显的棱角现象

 

2、在 片元着色器 中计算光照模型:逐像素光照(per-pixel lighting)

Phong着色(Phong shading):在面片之间对顶点法线进行插值的技术,也称为 Phong插值 或者 法线插值着色技术。以每个像素为基础,得到法线,这个法线值可以是对顶点法线插值得到的也可以是从法线纹理中采样得到的,然后进行光照模型的计算。注意,这个不同于前面的 Phong光照模型

 

Unity中的 环境光 和 自发光:

在标准光照模型中,环境光和自发光的计算最简单

1、场景中的环境光:Window -> Lighting -> Ambient Source/Ambient Color/Ambient Intensity

Unity Shader入门精要 第6章 Unity中的基本光照 读书笔记_第6张图片

2、在Shader中,通过 Unity 内置变量 UNITY_LIGHTMODEL_AMBIENT 得到环境光的颜色和强度信息

注意:大多数物体没有自发光特性。如果要计算自发光就需要在片元着色器输出最后的颜色之前,把材质的自发光颜色添加到输出颜色上即可

 

在Unity Shader 中实现漫反射光照模型:

CG函数:saturate

 

兰伯特光照模型:逐顶点的漫反射光照 和 逐像素的漫反射光照

兰伯特定律:在平面某点漫反射光的光强与该反射点的法向量和入射光角度的余弦值成正比。

 

半兰伯特定律:改善兰伯特的缺点

没有任何的物理依据,仅仅是视觉加强技术

Unity Shader入门精要 第6章 Unity中的基本光照 读书笔记_第7张图片

在半兰伯特模型中,背光面也可以有明暗变化,不同的点积结果会映射到不同的值上。

fixed4 frag(v2f i) : SV_Target {

      // Get ambient term

      fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;

                

      // Get the normal in world space

      fixed3 worldNormal = normalize(i.worldNormal);

      // Get the light direction in world space

      fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);

                

      // Compute diffuse term

      fixed halfLambert = dot(worldNormal, worldLightDir) * 0.5 + 0.5;

      fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * halfLambert;

                

      fixed3 color = ambient + diffuse;

                

      return fixed4(color, 1.0);

}

 

 逐顶点漫反射光照、逐像素漫反射光照、半兰伯特光照的对比效果 

Unity Shader入门精要 第6章 Unity中的基本光照 读书笔记_第8张图片

在Unity Shader 中实现 高光反射光照模型:

CG 函数:reflect(i,n) 计算反射方向

Unity Shader入门精要 第6章 Unity中的基本光照 读书笔记_第9张图片

Unity Shader入门精要 第6章 Unity中的基本光照 读书笔记_第10张图片

 

逐顶点的高光反射光照:(逐顶点高光模型 & 逐像素高光反射Phong & 逐像素高光反射Blinn)

逐顶点的高光反射光照、逐像素的高光反射光照(Phong光照模型)和Blinn-Phong高光反射光照的对比结果:

Unity Shader入门精要 第6章 Unity中的基本光照 读书笔记_第11张图片

使用 Unity(UnityCG.cginc) 内置的函数

 

(平行光)光源方向的计算:

normalize(_WorldSpaceLightPos0.xyz)

注意:在不使用Unity内置函数前提下,这个方法不能用于计算电光源和聚光灯的情况下,需要先判断光源类型才能再计算它的光源信息

视角方向 的计算:

normalie(_WorldSpaceCameraPos.xyz - i.worldPosition.xyz)

 

 

注意:

1、这些帮助函数使得开发者不需要跟各种变换矩阵、内置变量打交道,也不需要考虑各种不同的情况

2、这些函数在使用前需要将方向矢量进行归一化(normalize)变成单位矢量。

 

使用Unity内置函数:

o.worldNormal = mul(v.normal, (float3x3)unity_WorldToObject);

=> o.worldNormal = UnityObjectToWorldNormal(v.normal);

 

fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);

=> fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));

 

fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);

=> fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(读书笔记,-,Unity,Shader,入门精要,读书笔记)