上一篇介绍了一下场景的渲染,这一篇准备分享一下角色的渲染.
项目一开始的时候,考虑到我们是多人同屏的游戏,沿用了以前项目最简单的角色制作标准,一张512贴图,1500面,随着手机硬件的发展和各种牛逼重度手游的出现,角色就需要新的shader来提升效果了.对于大量同屏的怪物,我们采用传统光照模型,对于重要的NPC和玩家,可以使用PBR.除了这些基本的,角色渲染还需要各种效果,比如流光,残影,X-Ray透视,溶解,受击闪光等等.
传统光照模型的角色渲染,大部分和场景的差不多,也有一些技巧,会让效果更好,比如用边缘光来模拟背光.
// back light diffuse
nl = dot(fixedNormal, _GlobalBackLightDir.xyz);
finalColor.rgb += mainColor.rgb * _GlobalBackLightColor.rgb * saturate(nl);
// back light rim
half fresnel = 1 - saturate(dot(viewDir, fixedNormal));
nl = nl * 0.5 + 0.5; // [0, 1]
half rim = saturate(step(_RimSharp, fresnel) * fresnel - _RimSharp); // fixed rim = pow(fresnel, _RimSharp);
fixed3 rimColor = _GlobalBackLightColor.rgb * nl * _RimIntensity;
finalColor.rgb += rimColor * rim;
只有背光的diffuse:
加上边缘光后:
对边缘光做过滤,只留下背光方向的边缘光:
然后背光的光照效果就特别明显了.
接下来主要介绍下PBR.Unity5支持PBR技术,所以我们也直接跟进了,由于我们的角色有很多其他效果,所以只能把PBR技术整合进自己的shader中.
PBR(Physically Based Rendering)翻译过来就是指基于物理的渲染,为什么叫物理的渲染,其实就是他用的光照模型的理论和物理原理更加符合,效果也更加真实.由于它与物理性质非常接近,因此我们(尤其是美术师们)可以直接以物理参数为依据来编写表面材质,而不必依靠粗劣的修改与调整来让光照效果看上去正常。使用基于物理参数的方法来编写材质还有一个更大的好处,就是不论光照条件如何,这些材质看上去都会是正确的,而在非PBR的渲染管线当中有些东西就不会那么真实了。
PBR物理原理的近似,体现在三个方面:微表面;能量守恒;基于物理的BRDF。
微表面:简单说,就是在微观尺度下,没有任何平面是完全光滑的,这个光滑或者粗糙的程度,我们用粗糙度贴图来表示.
能量守恒:出射光线的能量永远不能超过入射光线的能量(发光面除外)。当一束光线碰撞到一个表面的时候,它就会分离成一个折射部分和一个反射部分。反射部分就是会直接反射开来而不会进入平面的那部分光线,这就是我们所说的镜面光照(高光)。而折射部分就是余下的会进入表面并被吸收的那部分光线,这也就是我们所说的漫反射光照。能量守恒公式:漫反射+镜面反射= 1
BRDF:Cook-Torrance BRDF光照模型兼有漫反射和镜面反射两个部分:
漫反射用Lambert,镜面反射比较复杂,包含3个函数,
1.D(法线分布函数)
用统计学来估算在受到表面粗糙度的影响下,微观法线方向与宏观法线一致的微平面的数量。对于美术来说,主要受粗糙贴图的影响,它决定了高光的大小强度和形状。
2.V(自阴影遮挡函数)
描述了微平面自成阴影的属性。当一个平面相对比较粗糙的时候,平面表面上的微平面有可能挡住其他的微平面从而减少表面所反射的光线。如果没有遮挡函数,就可能造成能量不守恒。
3.F(菲涅尔方程)
菲涅尔方程描述的是在不同的表面角下表面所反射的光线所占的比率。
以上三项,每一项都会有一些变种算法,比如法线分布函数,常见的是BlinnPhong和GGX,由于移动平台的性能限制,我们的PBR采用的算法是:
D: BlinnPhong
V: Modified Kelemen and Szirmay-Kalos
F: Schlick Fresnel
CharacterStandard_PBR.shader:
Shader "Luoyinan/Character/CharacterStandard_PBR"
{
Properties
{
_MainTex("Main Texture", 2D) = "white" {}
_Color ("Main Color", Color) = (1, 1, 1, 1)
_NormalTex("Normal Texture", 2D) = "bump" {}
_GlossTex ("Gloss Texture (R:gloss) (G:roughness) B(:flowlight)", 2D) = "white" {}
_SpecularColor ("Specular Color", Color) =