碧蓝幻想卡通渲染复现
因为非常喜欢Arc System Works的角色渲染,在学习shader一段时间后尝试进行还原。本文还原的效果仅作参考,是学习过程中一些踩坑的总结和经验,如果有写的不对的地方请指出.
贴图分析
还原任何角色渲染效果最重要的一步就是进行贴图分析,因为碧蓝幻想是用UE4引擎开发的游戏,所以我们可以简单的用umodel-/**&……%*&获得一些资源。下面我们来看一下它的贴图。
一共有5张,分别是头发加身体加脸部的basecolor,一张ssscolor(暗一点的basecolor),一张细节描线图,一张用于叠加的deacl以及ILM的四个通道还有几个贴图的alpha通道需要操作,我们后面说:
BaseColor
就是基本色,basecolor的A通道用于区分皮肤区域和头发区域,如下图
ssscolor
颜色深一点的basecolor用于表现阴影部分颜色,命名sss还蛮奇怪的
ILM
R通道:金属光泽度 用于高光强度与高光mask
G通道:和罪恶装备里一样作为阴影倾向权重
B通道:控制高光形状
A通道:内描线细节
4.detail 更多的细节描线
角色shader还原
直接光漫反射
我们先来看一下游戏里的截图
可以看出他的亮部与暗部交界处是一个很硬的边缘,且只有一级阴影。那就很简单的对兰伯特或者半兰伯特光照模型做色阶化处理得到亮部与暗部的mask将basecolor与ssscolor进行一个lerp就完成了。先来看看我们的mask
然后有些区域应该是黑色的,但却是白色的,这时候我们就要去修正这个错误,上面我们说道有些贴图的A通道里面有一些信息,那我们就去找找看。emmmm…好像并没有可以修正这个错误的信息。还有那个地方我们没找呢?是顶点色!我们再去仔细寻找,在顶点色的R通道发现了好像 AO的东西
我觉得它就是,那我们就乘上AO再看看,就会发现这个错误被修正了。利用顶点色的A通道制作AO的可控性很高,完全可以又美术自主定制那些需要,那里深一点,那里浅一点
最后我们进行一个Lerp的混,就完成了我们的直接光漫反射部分。不得不说arc的资源做的真的好,仅仅靠一个漫反射就有这么好的效果
1 | half half_lambert = (NdotL + 1.0) * 0.5; //从-1.0-1.0映射到0.0-1.0 |
直接光镜面反射
我们再来看一下游戏里的金属表现与高光表现
从贴图分析我们知道arc对高光的处理下了一番功夫,不仅画了高光强度,也画了高光大小的mask。从生活中我们知道高光是会随着视角的变化而发生变化,所以我们要使用的光照模型是Phong或者blinnPhong,当然可以。但测试下来我选择用最简单的菲涅尔反射来操作,因为这么好的贴图一定要好好利用上。
先来看看我们的菲涅尔(NdotV),这里已经事先乘过AO并加上阴影权重了
但这个效果不是很好,并且经过仔仔仔仔仔——细观察,感觉高光不是那么纯,像是有一部分漫反射混在里面,并且漫反射的权重还不小。在经过本人不怎么好的眼力与审美观察后。效果较好的表现为反射因子=NdotV(0.1—0.3)+ halflambert(0.7—0.9)之间。下面是0.1NdotV+0.9halflambert的效果
同样的我们也需要对高光进行色阶化的处理,并且利用上贴图
specsize是金属光泽度,这里反向了一下是因为调参数的时候是往负方向调整,与美术直觉不符合。spec_intensity则是高光区域mask与不同的金属度,乘以300是为了提亮并得到硬边缘。
1 | half toon_spec = saturate((spec_term - (1.0 - spec_size * _SpecSize)) * spec_intensity * 300);//色阶化处理得到高光mask |
那我们现在有了高光mask就可以开始上色了,定义一个_SpecColor控制颜色,定义一个_SpecIntensity控制强度
1 | half spec_term = (NdotV + 1.0) * 0.5 * ao + shadow_control; |
直接光漫反射加直接光镜面发射的效果,已经有点味道了
环境光漫反射
并没有什么特别的处理,尝试用了unity自带的球谐光照,对效果也没有特别大的改善,可能需要一个合适的天空盒才会有更好的表现,这里直接将ssscol * 0.1叠加上去了,虽然影响十分微弱
环境光镜面反射
游戏里没做,我也没做+v+,或许可以用vrdirWS采样一张cubemap来做,但目前的效果还挺好,就不做了,诶嘿
描线
先来用贴图来做内描线,detail+ILM的A通道,这里的detail要用UV2去采,因为使用了本村线的做法
什么是本村线呢?
GGX贴图采用独特的uv分布方式(本村式线),其原理在于用垂直的黑线来表示内部黑线,从而防止45度线导致的近视角线段锯齿情况的发生。制作很耗时,后面会贴文章,大家有意可以去看
PS示例
做完了内描线,我们来做外描线。用的是最常规的一套Back-Face的法线外拓方法。还有用顶点色的a通道控制秒描边粗细的常规操作。
顶点色的通道:
B:轮廓线的Z Offset
A:轮廓线的粗细系数,0.5是标准,1是最粗,0的话就没有轮廓线值
B的用法,用背面法膨胀时,对应视点在多大的深度方向(Z方向)上移动(=Offset) 膨胀的系数,这个值设定的很大的话,膨胀的模型就会埋没到邻接的面里,结果就是轮廓线消失了。根据本村氏所说,头发和脸的鼻子下面等,为了防止出现不受欢迎的皱褶一样的轮廓线,而加进的参数
面部修正
修正前:
修正后:
1 | //相机空间法线外扩描边 |
边缘光
有两种思路,都很简单
第一种:万物皆可菲涅尔,菲涅尔边缘光1-NdotV,用_SmoothstepMin和_SmoothstepMax两个值去控制
第二种:自定义边缘光,定义一个四维向量并转换到相机空间与Ndir点积,处理方式与漫反射相似
1 | float3 rimlight_dir = normalize(mul(UNITY_MATRIX_V, _RimLightDir.xyz));//转换到相机空间 |
高清渲染图
参考文章: https://zhuanlan.zhihu.com/p/376094989