![游戏架构:核心技术与面试精粹](https://wfqqreader-1252317822.image.myqcloud.com/cover/460/23914460/b_23914460.jpg)
4.2 材质效果
请问常见的材质效果有哪些,并简述如何在Unity 3D中实现对应效果。
问题分析
我们知道,物体的材料会影响人对物体的判断。比如有塑料感的物体就会给人很轻的感觉,而拉丝的反光效果就会给人顺滑的感觉,等等。为了达到不同的表现效果,美术人员在制作过程中会采用各种辅助方式。
从效果的实现原理的角度来看,可以按照是否使用PBR(Physically-Based Rendering)作为标准划分。即使用PBR流程组织美术资源的为一类,其他的为另一类。
对于常规美术流程,即4.1节贴图分类中提到的方式,也是目前绝大多数游戏采用的资源组织方式。它底层基于兰伯特模型(Lambert),通过点乘的方式来估计照度,并通过功能拆分对应的贴图,功能之间互不干扰,给美术更强的控制能力。这既是优点也是缺点。优点是由于这种标准已经在游戏行业中广泛使用,因此并不难找到能够上手的美术人员。缺点是由于美术人员对效果有很强的控制能力,因此整个效果的调整对美术人员的能力要求很高。
另一方面,PBR技术弥补了这一缺陷。它根据能量守恒的原理来计算光强,Unity 3D中默认的StandardShader就是基于这种方式实现的。它的好处是只要按照材质参数表,即可配置出效果正确的材质。图4.4是引自Unity 3D官方文档中提供的参数对照图。
![](https://epubservercos.yuewen.com/3EAF16/12741015804673506/epubprivate/OEBPS/Images/figure_0066_0001.jpg?sign=1739297140-lKm5fMmhnKzG9DhGwkR817DmRtXLuFG7-0-1dfff3e8cbf0e2e9a4a3644848633b79)
图4.4
在这种流程下,对美术人员的能力要求略低。但由于目前使用这套流程的团队不多,并且美术人员还不太熟悉这种模式,因此反而在制作的过程中造成了困扰。另一方面,这套资源流程对引擎也有些要求。由于材质效果依靠计算,因此美术人员在PBR工具中制作出的效果,与导入引擎后运行的效果会有所不同。不论是Unity 3D还是Unreal,都需要对PBR对应的Shader或材质参数做适当修正,以保障效果的一致性,这对技术层面也提出了更高的要求。因此,目前基于PBR流程研发的游戏数量增长得十分缓慢,相信随着技术的进步会逐渐成为主流。
对于额外的材质效果,不太介意是否基于PBR。虽然乱改贴图会影响PBR的效果,但常规材质效果都已经包含在标准流程中了。如果在PBR流程中需要加入新的特殊效果,则可以在颜色计算好后再叠加。因此下面的这些效果在两种美术流程中都可以使用。
因为需要比较材质效果,所以这里选取了Unity-Chan和Space Robot Kyle的资源作为效果参考。资源的获取方式可参考序言中的相关链接,后面代码片段的完整版本也在资源包中。
边缘光
无论哪种渲染模式,光感的效果都是核心。对于卡通渲染最大的特点就是利落的边缘光或阴影。在Unity-Chan中我们可以明显看到类似的效果,例如,角色袖子上的边缘光效果如图4.5所示。
![](https://epubservercos.yuewen.com/3EAF16/12741015804673506/epubprivate/OEBPS/Images/figure_0067_0001.jpg?sign=1739297140-MiY7AY7JohNQwKV6EdggOoMKWRfpBvGl-0-4fc4ef0dff3b196e82576fbd12679aac)
图4.5
把袖子上的边缘光去掉后,整个衣服的效果就完全不同了,效果如图4.6所示。
![](https://epubservercos.yuewen.com/3EAF16/12741015804673506/epubprivate/OEBPS/Images/figure_0067_0002.jpg?sign=1739297140-sOZUTHxN8gAlczPSkVWMtLyzbJd6tDrb-0-1ca3a853ee1697419d50d40cd6584a06)
图4.6
边缘光的计算并不复杂,核心是使用一张渐变图做控制,然后根据照度在图上做强度的采样,相关代码如下:
float_t rimlightDot=saturate( 0.5 * ( dot( normalVec, i.lightDir ) + 1.0 ) ); falloffU=saturate( rimlightDot * falloffU ); falloffU=tex2D( _RimLightSampler, float2( falloffU, 0.25f ) ).r; float3_t lightColor=diffSamplerColor.rgb; // * 2.0; combinedColor +=falloffU * lightColor;
高光效果
另一个比较重要的光效是高光,物体的质感几乎完全取决于高光的效果。我们可以看到在UnityChan的袖口、胸、马甲的兜附近都有明显的高光,效果如图4.7所示。
![](https://epubservercos.yuewen.com/3EAF16/12741015804673506/epubprivate/OEBPS/Images/figure_0068_0001.jpg?sign=1739297140-McyrcRiyiOIoZzuP59ZnayDuv4pRIOfv-0-0d8914465186ee5a1549e77da57b6e86)
图4.7
如果去掉高光,袖子就会显得没有层次,马甲也松松垮垮,如图4.8所示。
![](https://epubservercos.yuewen.com/3EAF16/12741015804673506/epubprivate/OEBPS/Images/figure_0068_0002.jpg?sign=1739297140-O3FWQwAtFbLjT2CiMm0kOrF2xgDn2Wmw-0-1dca02aabc7bdb8382fa9e74d615e217)
图4.8
具体代码逻辑是通过一张高光图记录反光的倍率与色值,然后再与标准高光计算出的结果相乘。核心内容如下:
float4_t reflectionMaskColor=tex2D( _SpecularReflectionSampler, i.uv.xy ); float_t specularDot=dot( normalVec, i.eyeDir.xyz ); float4_t lighting=lit( normalDotEye, specularDot, _SpecularPower ); float3_t specularColor=saturate( lighting.z ) * reflectionMaskColor.rgb * diffSamplerColor.rgb; combinedColor +=specularColor;
渐变贴图
渐变贴图(Ramp)或者叫衰减贴图(FallOff),与前面的应用范围不太一样,它更多是以一种加强色彩控制的形式出现。例如前面提到的采样用贴图也是渐变贴图的一种,这里拿出来单独说,是因为有时候它不太明显,效果会与固有色贴图混在一起,让人以为是画在固有色中的效果。最明显的例子就是角色的皮肤。在Unity的皮肤效果中,使用了一张长方形的渐变图,如图4.9所示。
![](https://epubservercos.yuewen.com/3EAF16/12741015804673506/epubprivate/OEBPS/Images/figure_0069_0001.jpg?sign=1739297140-UgirQVYC4UfRssKepx2WaGOGs3EvCT2L-0-d2a3bcc460c7ab556d0bbb086e82ceec)
图4.9
在这张图的影响下,皮肤的效果如图4.10所示。
![](https://epubservercos.yuewen.com/3EAF16/12741015804673506/epubprivate/OEBPS/Images/figure_0069_0002.jpg?sign=1739297140-OKcotzipe78q8nuwFgz0DdFZDWV3U6Tq-0-e2eec6367144da28db332930f1cdafd8)
图4.10
如果去掉渐变效果,皮肤就缺少了层次感,如图4.11所示。
![](https://epubservercos.yuewen.com/3EAF16/12741015804673506/epubprivate/OEBPS/Images/figure_0070_0001.jpg?sign=1739297140-6222NCkRK1StFvrh0yUPFIhxwN1FYXP2-0-df9f7c0be6062d34512676cb60f90eb2)
图4.11
实现方面,使用视线与平面法线点乘的值作为标准,在渐变图中采样。最终,通过渐变图的透明通道作为插值标准,与固有色进行混合。核心代码如下:
float_t normalDotEye=dot( i.normal, i.eyeDir ); float_t falloffU=clamp( 1- abs( normalDotEye ), 0.02, 0.98 ); float4_t falloffSamplerColor=FALLOFF_POWER * tex2D( _FalloffSampler, float2( falloffU, 0.25f ) ); float3_t combinedColor=lerp( diffSamplerColor.rgb, falloffSamplerColor.rgb * diffSamplerColor.rgb, falloffSamplerColor.a ); combinedColor=diffSamplerColor;
自发光
自发光效果(Glow)其实算是后处理效果的一种,并不属于材质层。不过它的贴图和参数配置都可以放在材质上,因此也算与材质有关,因而把它放在这里一起说。
这种效果最大的优势是,可以使画面看起来有更多的光源,这在很多特效中都会用到,当然用在角色身上的例子也比比皆是。这里使用Kyle做了一个简单的例子,来说明效果。
首先引入Unity 3D的Effect资源包,接着新建一个场景,在摄像机上挂载Bloom脚本,并做如图4.12所示设置。
![](https://epubservercos.yuewen.com/3EAF16/12741015804673506/epubprivate/OEBPS/Images/figure_0071_0001.jpg?sign=1739297140-imjMXs8GaHwYr8otgIzkJzDI1FhTHCOX-0-b23f32fbd2b4707809779fc25523af67)
图4.12
接着使用绘图软件,绘制一张用于加强颜色的遮罩贴图,如图4.13所示。
![](https://epubservercos.yuewen.com/3EAF16/12741015804673506/epubprivate/OEBPS/Images/figure_0071_0002.jpg?sign=1739297140-LrqkFqqqkhiqCDJtSl4AZ1N0xmOmNPpc-0-fbab73d790c0514fca272a331687fa7e)
图4.13
最后创建一个新的使用StandardMaterial的材质,将其自发光(Emission)参数更改为如图4.14所示的值。
![](https://epubservercos.yuewen.com/3EAF16/12741015804673506/epubprivate/OEBPS/Images/figure_0072_0001.jpg?sign=1739297140-05bD1G1nOLW1phGOd1sLmlXcNCHtD66d-0-04189aeba87ce84d9d2496d7d842fbac)
图4.14
调整摄像机角度,即可看到如图4.15所示的效果。
![](https://epubservercos.yuewen.com/3EAF16/12741015804673506/epubprivate/OEBPS/Images/figure_0072_0002.jpg?sign=1739297140-OOSvwpLDzOXJsz1GpiEKQb4TNDsgiikV-0-3de8e221eef5b085bd52c6d0593723f5)
图4.15
可以看出,使用自发光对画面效果有很大的提升。当然这些提升也是有代价的,最明显的就是资源量变大,每增加一张贴图,就代表增加了美术人员的工作量。另外,由于它的底层原理是后处理(Post-Effect),因此也会增加运行时的内存消耗。在后面的内容中,我们会介绍如何定制自己的辉光效果。
材质捕获贴图
材质捕获贴图(Material Capture),通常被称为MatCap,在很多3D软件中都可以生成。它最大的特点是能真实地表现反射效果,而不需要在场景中提供对应的灯光。从本质上讲,它是将所有的光照信息都存储到了贴图中的。代码实现也不复杂,在运行时,只需将法线从模型空间转到视口空间,再将对应UV映射到贴图上就可以了。
在AssetStore中有名为“Free MatCap Shaders”的插件,它比较直观地展示了这项技术的效果,有兴趣的读者可以自行下载查看。效果如图4.16所示。
![](https://epubservercos.yuewen.com/3EAF16/12741015804673506/epubprivate/OEBPS/Images/figure_0073_0001.jpg?sign=1739297140-pp7aN7bDbAKSFLmYiC9YWm7U4uHwTsOd-0-be25a9b7fdea3dee56419eec4c154616)
图4.16
其中展示的模型依然为kyle,上面的方形贴图即为MatCap贴图。
总结
本节主要介绍了常见的材质效果,并结合代码和实现方式进行了分析。需要注意的是,上面只是说了一些主流的材质效果,真实项目中的材质可能会更多。正是因为美术效果层出不穷,所以我们才能看到各种令人惊叹的游戏。
扩展问题
要应用多种效果势必会增加贴图的数量,有什么办法进行优化吗([:texturepath])?