理解光照模型
第三章 理解光照模型 在前面的那些章节中,我们介绍了表面着色器并且还理解了如何修改一些物理属性(比如Albedo和Specular)来模拟不同的材质。这些到底是如何工作的呢?每个表面着色器中最重要的部分一一光照模型lighting model。它的功能就是接受这些参数然后计算每一个像素点的最终着色。Unity通常会对开发者隐藏这部分,因为如果想要编写一个光照模型的话,你就必须要去理解光在物体表面是如何反射和折射的。这个章节中我们会毫无保留的向你展示光照模型是如何工作的,并且给你介绍一些你自己创建光照模型所需要的一些基础知识。 这一章中,我们会学习下面所列的知识点: 创建一个自定义的漫反射光照模型 创建一个Toon风格的着色器 创建一个Phong类型类型的高光反射着色器 创建 BlinnPhong 类型的高光反射着色器 创建各向异性类型的高光反射着色器 介绍 想要模拟光的工作方式是一项非常具有挑战性的工作,同时也非常消耗计算资源。在之前的很早一段时间内,游戏中使用的都是一些非常简单的光照模型,效果看起来差到难以置信。尽管现在的3D游戏引擎已经使用了基于物理原理的渲染器,但是有些更简单的光照模型技术还是值得我们去探索的。但有时,我们不得不面对资源紧张的现实,没有办法在这些资源有限的设备上完整实现光照模型,比如我们的移动设备。所以你想在这上面实现自己的光照模型,那么你就很有必要了解这些简单的光照模型。 创建一个自定义的漫反射光照模型 如果你对Unity4很了解的话,你应该知道Unity提供的默认的着色器是基于一个叫Lambertian reflectance的光照模型。我们会在这个知识点向你展示如何创建一个自定义的光照模型,并且解释它后面的数学原理和实现方式。下面的两张图分别展示了标准着色器Standard Shader (右)和diffuse Lambert着色器对同一个几何体进行渲染后,不同的显示效果: 基于Lambertian reflectance光照模型的着色器是典型的非真实渲染着色器;我们现实生活中没有物体会看起来像那样。然而Lambert 着色器依然能在一些低多边形风格的游戏中经常看到,因为跟一些复杂的几何体比起来,它们的三角面数量对比非常明显。用于计算Lambertian反射的光照模型非常高效,这特别适合移动端的游戏。 Unity其实已经提供了光照函数给我们,好让我们能在着色器中使用。它就是Lambertian光照模型。它是光反射模拟的一种更基础更有效率的形式,你能在当今的很多游戏中看到它的存在。 因为它们已经内建在了Unity的表面着色器语言中,所以我从这个开始和基于它开始构建也不失为一个好的选择。你也可以在Unity用户手册中找到一个例子,但我们还是会更深入学习,从而向你解释这些数据是从哪里来的以及为什么它是那样工作的。这些可以为设置光照模型打下一个很好的基础,这些知识将来也能在后面的章节中对我们有帮助。 始前准备 让我们从实现下面几个步骤开始: 创建一个新的着色器并且给它命名好。 创建一个新的材质球,命名好,并且把上一步新建的着色器应用于该材质。 接下来,创建一个球形对象,并且把它大致放在场景中间的位置。 最后,我们创建一个方向光源,让光找到游戏对象上。 当你在Unity中设置好这些资源后, 你就会有一个类似于下图的场景: 操作步骤 Lambertian反射可以在着色器中修改下面的代码实现: 首先在着色器的属性Properties块中添加下面的属性: _MainTex("Texture", 2D) = "white" 修改着色器的**#pragma指示符,从而让着色器使用我们自定义的光照模型,而不是标准Standard**: #pragma surface surf SimpleLambert 使用一个非常简单的表面函数surface function,这个函数仅仅通过它的UV数据对纹理进行采样: void surf (Input IN, inout SurfaceOutput o) { o.Albedo = tex2D(_MainTex,IN.uv_MainTex).rgb; } 添加一个叫做LightingSimpleLambert()的函数,这个函数包含了下面实现Lambertian反射的代码: half4 LightingSimpleLambert(SurfaceOutput s,half3 lightDir,half atten) { half NdotL = dot(s.Normal,lightDir); half4 c; c....