游戏架构:核心技术与面试精粹
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

4.2 材质效果

请问常见的材质效果有哪些,并简述如何在Unity 3D中实现对应效果。

问题分析

我们知道,物体的材料会影响人对物体的判断。比如有塑料感的物体就会给人很轻的感觉,而拉丝的反光效果就会给人顺滑的感觉,等等。为了达到不同的表现效果,美术人员在制作过程中会采用各种辅助方式。

从效果的实现原理的角度来看,可以按照是否使用PBR(Physically-Based Rendering)作为标准划分。即使用PBR流程组织美术资源的为一类,其他的为另一类。

对于常规美术流程,即4.1节贴图分类中提到的方式,也是目前绝大多数游戏采用的资源组织方式。它底层基于兰伯特模型(Lambert),通过点乘的方式来估计照度,并通过功能拆分对应的贴图,功能之间互不干扰,给美术更强的控制能力。这既是优点也是缺点。优点是由于这种标准已经在游戏行业中广泛使用,因此并不难找到能够上手的美术人员。缺点是由于美术人员对效果有很强的控制能力,因此整个效果的调整对美术人员的能力要求很高。

另一方面,PBR技术弥补了这一缺陷。它根据能量守恒的原理来计算光强,Unity 3D中默认的StandardShader就是基于这种方式实现的。它的好处是只要按照材质参数表,即可配置出效果正确的材质。图4.4是引自Unity 3D官方文档中提供的参数对照图。

图4.4

在这种流程下,对美术人员的能力要求略低。但由于目前使用这套流程的团队不多,并且美术人员还不太熟悉这种模式,因此反而在制作的过程中造成了困扰。另一方面,这套资源流程对引擎也有些要求。由于材质效果依靠计算,因此美术人员在PBR工具中制作出的效果,与导入引擎后运行的效果会有所不同。不论是Unity 3D还是Unreal,都需要对PBR对应的Shader或材质参数做适当修正,以保障效果的一致性,这对技术层面也提出了更高的要求。因此,目前基于PBR流程研发的游戏数量增长得十分缓慢,相信随着技术的进步会逐渐成为主流。

对于额外的材质效果,不太介意是否基于PBR。虽然乱改贴图会影响PBR的效果,但常规材质效果都已经包含在标准流程中了。如果在PBR流程中需要加入新的特殊效果,则可以在颜色计算好后再叠加。因此下面的这些效果在两种美术流程中都可以使用。

因为需要比较材质效果,所以这里选取了Unity-Chan和Space Robot Kyle的资源作为效果参考。资源的获取方式可参考序言中的相关链接,后面代码片段的完整版本也在资源包中。

边缘光

无论哪种渲染模式,光感的效果都是核心。对于卡通渲染最大的特点就是利落的边缘光或阴影。在Unity-Chan中我们可以明显看到类似的效果,例如,角色袖子上的边缘光效果如图4.5所示。

图4.5

把袖子上的边缘光去掉后,整个衣服的效果就完全不同了,效果如图4.6所示。

图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所示。

图4.7

如果去掉高光,袖子就会显得没有层次,马甲也松松垮垮,如图4.8所示。

图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所示。

图4.9

在这张图的影响下,皮肤的效果如图4.10所示。

图4.10

如果去掉渐变效果,皮肤就缺少了层次感,如图4.11所示。

图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所示设置。

图4.12

接着使用绘图软件,绘制一张用于加强颜色的遮罩贴图,如图4.13所示。

图4.13

最后创建一个新的使用StandardMaterial的材质,将其自发光(Emission)参数更改为如图4.14所示的值。

图4.14

调整摄像机角度,即可看到如图4.15所示的效果。

图4.15

可以看出,使用自发光对画面效果有很大的提升。当然这些提升也是有代价的,最明显的就是资源量变大,每增加一张贴图,就代表增加了美术人员的工作量。另外,由于它的底层原理是后处理(Post-Effect),因此也会增加运行时的内存消耗。在后面的内容中,我们会介绍如何定制自己的辉光效果。

材质捕获贴图

材质捕获贴图(Material Capture),通常被称为MatCap,在很多3D软件中都可以生成。它最大的特点是能真实地表现反射效果,而不需要在场景中提供对应的灯光。从本质上讲,它是将所有的光照信息都存储到了贴图中的。代码实现也不复杂,在运行时,只需将法线从模型空间转到视口空间,再将对应UV映射到贴图上就可以了。

在AssetStore中有名为“Free MatCap Shaders”的插件,它比较直观地展示了这项技术的效果,有兴趣的读者可以自行下载查看。效果如图4.16所示。

图4.16

其中展示的模型依然为kyle,上面的方形贴图即为MatCap贴图。

总结

本节主要介绍了常见的材质效果,并结合代码和实现方式进行了分析。需要注意的是,上面只是说了一些主流的材质效果,真实项目中的材质可能会更多。正是因为美术效果层出不穷,所以我们才能看到各种令人惊叹的游戏。

扩展问题

要应用多种效果势必会增加贴图的数量,有什么办法进行优化吗([:texturepath])?