Unity用了noise贴图导出后会fbx模型多贴图打包用贴图部分变白,有些贴图没问题?

《崩坏3》的成功业内有目共睹,这款产品不仅在二次元领域收到诸多玩家的热衷,在手游产品技术上,它也实现了诸多突破,比如在手游的高品质卡通渲染领域,《崩坏3》的确做到了国内顶尖水准。

在去年的Unite开发者大会中,米哈游技术总监贺甲分享了他们在PC端用Unity引擎探索高品质即时卡通渲染的实现方案。而在今年的Unite 2018开发者大会中,贺甲进一步分享了他们移动端的具体实现方案

两者很大的不同在于,PC端对技术的探索更多会追求极致的表现,因此不会过多在意性能消耗方面的情况,而这项技术实际运用到移动端的《崩坏3》之后,需要考虑更多优化、适配,以及某些情况下更加便捷的实现方案。

会后,贺甲也接受了媒体群访。在他看来,国内团队想要涉足卡通渲染领域,并做出一定的成效,首先必须搭建对卡通渲染感兴趣的技术团队,以保证准确抓住玩家的需求点。其次要提升整个项目的管理能力,来保证产品的有效输出,而非停留在Demo实现阶段。

以下演讲及采访内容经游戏葡萄整理:

大家好,欢迎来到Unite2018参加这次演讲,我叫贺甲,目前在miHoYo担任技术总监。我和我的团队主要关注PBR(基于物理的渲染技术)和NPR(非真实渲染技术)方面的实时渲染,以及用于动画CG和游戏过场动画的交互式物理研究。

目前,我们的一部分工作是利用Unity实现高品质的卡通渲染。这次演讲的主题是在Unity上实现高品质卡通渲染的效果,以及这些方法针对各个平台特性进行的优化方案,涵盖了从移动端,到高性能PC等不同等级的平台。

本次演讲涉及到的主要方面:

首先我会介绍一些应用在移动端有关崩坏3的渲染特性。

然后我会谈谈动画风格CG渲染中使用的一些技术,比如插画风格的角色渲染,特殊材质的渲染,特效的渲染及与卡通渲染适配的后期处理等。

最后一部分是关于对今后的展望。

我们来看看在《崩坏3》的场景中使用的一些渲染特性。

从图中我们可以看出,场景中使用了不少特效来提升表现力,比如bloom后处理效果、动态粒子、平面反射、屏幕扭曲特效等,下面我们将会逐一对这些效果进行解析。

首先我们来看一下如何实现高品质的反射效果

在移动端实现高品质的反射,平面反射是一个综合了效果和性能因素较好的办法。通常做法是以地面为对称平面,将摄像机放置在对称位置后渲染场景得到反射结果。

为了能表现出地面的金属质感,首先我们对反射结果应用六边形采样模糊,然后使用金属纹理细节法线贴图来扰动反射结果,除此之外我们还使用了镜面反射贴图和菲涅尔效果来进一步增强反射质感。

在一些远离地面高度或非水平的次要反射表面上,平面反射就不在适用,为此我们使用环境贴图反射作为替代方案。为了尽量减少渲染反射场景所占用的开销,我们将反射分辨率限制在1/3以下,由于反射贴图会经过模糊处理,即使降低了较多的分辨率也并不能明显看出区别,并且我们在渲染反射的过程中还使用简化版的材质,并忽略一些不是很重要的小物体。

接下来让我们看看另一个效果:全屏扭曲特效的应用

我们在《崩坏3》的场景中较多的使用了屏幕扭曲效果,比如刀剑的拖尾特效,时空断裂效果,水流瀑布及其他场景效果。

在渲染扭曲效果的过程中,我们使用3个通道来存储扭曲的渲染结果,两个用于存储uv偏移,另一个用于存储扭曲强度mask,扭曲强度mask用于执行深度剪裁和基于距离的强度控制。

使用单独的pass渲染扭曲结果到帧缓冲纹理对于移动平台来说开销较大,所以我们在最终的后处理中整合应用了扭曲效果,相比前者要快很多。

但这种方法也可能导致靠前面的物体由于没有分层处理而混入后面扭曲材质的问题,不过考虑到移动平台的性能限制,相对于整体效果而言这种妥协是值得的。

让我们再看看bloom的实现

整个场景如果开启HDR会使用fp16格式的render target,然后下采样到原始大小的1/4,以便之后的后处理流程使用。

首先,我们需要指定一个亮度阈值来提取图像中的高亮区域,实现方法也并不复杂,只需从源像素减去阈值,得到的结构就是提取后的高亮度区域,叠加这层内容能使结果看起来更具对比并且色彩鲜艳。

接下来,我们产生4个大小依次递半的render target,并将其内容应用半径逐渐增大的高斯模糊,最后我们将这些模糊后的结果合并起来,以获得最终的bloom效果。

从最终的效果图我们可以看到,bloom效果不仅起到用来表达高亮区域的视觉效果,还对整个图像的色彩中起着明显的润色作用。

当完成了反射渲染,扭曲效果的及bloom的处理后,最终就可以将这些中间结果合成在一起。

我们使用filmic tone mapping与曝光和对比度控制来将fp16 HDR的原图像转换为最终的LDR帧缓冲。由于这些合成操作都是在一个Pass中完成的,所以即使在移动设备上也可以满足性能方面的需求。

下面我们来介绍一下游戏中的天气和云海的实现方案

我们想要创造一个能让玩家感受到纵深,具有各种丰富形态以及动态光照变化的云的渲染系统。而该系统也应该易于调整和使用,方便美术可以创造出不同类型的云层效果。

这对我们来说也是一个有趣的挑战,接下来就让我们来谈谈这些功能:

首先让我们看看渲染云所需要的资源,因为我们想要实现可以24小时动态变化的风格化云的光照效果,如果直接存储画好的贴图数量就会太大而且不方便调整,所以我们使用多层着色来实现这一点。

我们使用4个通道来表示云的光照及阴影:基础照明层,阴影1层,阴影2层,和边缘光层。通过为每个图层设置不同的颜色,我们就可以获得不同时刻的云的色彩方案。我们一共准备了8种形状不同的云的模板,用来构建各种不同的云海景观。

为了构建云海景观,我们使用了很多朝向屏幕发射云朵的粒子发射器,并且使用不同的云的模板以及发射模式来组合出不同的云海景观,我们实现了如各种类型的云海以及暴风雨天气等,这些预设都保存在天气配置中。此外我们还使用关键帧来定义天空背景和云彩的颜色。随着时间的流逝,云的色彩就根据关键帧来变化。

在性能方面主要的开销是overdraw问题,如果我们按照固定控制的pattern来发射云虽然可以以最小的overdraw来获得较好的云海密度,但可能会看起来较为重复,加入产生位置的随机因素可以解决这个问题,但要想获得看起来不那么稀疏的云海效果就需要相比固定pattern更多的粒子数量,我们对于粒子发射配置都有细致的参数可以调整,以便在两者之间可以找到较好的权衡点。

这是一个24小时昼夜变化的云海景观:

这是暴风云闪电的场景:

现在让我们来看看游戏场景中使用的天气系统

我们主要通过全局雾效,Skybox颜色和方向光的设置来改变场景的天气和氛围。对于雾效同样有许多参数可以调整。我们给雾效基于深度划分为远近距离两个区间,远近区间都可以设置不同的颜色和强度值来创造各种各样的气氛。Skybox也可以控制天空颜色渐变,云的受光及阴影颜色等。

综合上述调整选项,我们就可以创建晴天,雨天和大雾,多云和夜间等天气。

另外人物的光照也会受环境的影响,主要的光照颜色由方向光决定,局部区的阴影的变化比如角色走进阴影区域,由一些从关卡编辑器中手工放置的Lighting Volume定义。

让我们再来看看游戏中使用景深的情况

手游中使用景深一般并不常见,因为常见的景深实现对于移动平台来讲还是开销较大,我们主要在人物选择界面和任务简报会话中使用景深效果来突出表现人物。

由于这些场景不需要景深的过度,我们使用一种特殊的方法来提高移动性能。不使用depth buffer做COC混合,而是使用单独的相机直接绘制背景图层。在应用模糊通过后,通过将背景和前景人物组合在一起来获得最终图像。

为了得到更好的视觉效果,我们使用六边形采样模式来获得更好的bokeh形状。除此之外还有bokeh强度调整参数,以使其看起来更清晰,我们使用亮度值作为增量因子,2通常是一个合适的值。

性能方面为了保持性能的稳定,我们模糊背景的分辨率视模糊程度而定,更大的模糊尺寸使用更低的分辨率并且更不容易察觉,我们还使用Unity内置的曲线来描述它们之间的转换关系。

这短视频演示了动态调整模糊大小和焦散强度的结果。

在游戏场景中,我们还实现了一个看起来挺酷的效果

当给最后一个敌人致命一击的时候就会激发子弹时间,这时所有高速运动的物体都会慢下来,在下雨天我们就可以明确的看到雨滴的形状。

为了实现这个效果,我们使用了4个代表雨滴不同速度下形态的关键帧,再根据时间快慢尺度对其进行垂直拉伸。在正常的时间尺度下,雨滴看起来像一条直线,在时间变慢的时候逐渐缩短变成雨滴形状。

在这里我们同样使用了动画曲线来控制拉伸,关键帧选择和时间快慢的关系,调整起来非常灵活方便。

刚才我们谈到的都是一些针对移动端优化的渲染功能,下面我们来介绍一下用于动画风格real-time CG或次世代游戏的渲染方法。

在过去的两年中,我们陆续制作了两个短片音乐视频,其中体现了我们的新渲染风格

我们将它发布在了B站上,3天内获得了B站全站月榜排行第一的位置,至今已有超过300万的点击量。下面我们就来谈谈这些视频中应用到的一些实时渲染CG技术。

首先我们来看看角色的渲染,我们的目标是实现完全动态的光照和阴影,所有材质都对各种光照现象做出正确的反应,包括主光源和区域环境光。这就要求我们不能使用任何在纹理上画死的光照表现。

用于角色渲染的主要特性有:多通道Ramp的材质shading方法,眼睛,头发和其他各向异性材料等特殊材料的处理,以及PCSS角色软阴影和高品质的勾线。

首先我们来看一下多通道Ramp的shading方法。我们希望角色的阴影和颜色的变化可以表现出更细腻的插画风格,所以我们使用2D ramp纹理来表示这些细微的变化,其中RGB通道分辨用于描述于不同阴影层的漫射阴影范围。

每个层都可以制定不同的颜色,这样就能在明暗变化中做到精细的色彩变化控制,对于卡通风格的画面,如果上色只是纯明暗变化,阴影处就会显得比较脏,缺乏表现力,而如果提升暗处的饱和度和色相变化,整体色彩看起来就会比较鲜活。而且通过调整垂直纹理采样坐标,我们可以实现动态的软硬风格转换。

从另一角度来看这种方法还间接表现了皮肤的次表面散射效果。这四幅图展示了多通道逐层上色叠加的效果。

大家可以看到通过一层层的上色叠加,皮肤层次细节会变得更加丰富。

上下两副图分别展示了采样不同位置的ramp texture所对应的渲染效果,不同的ramp可以获得各种不同的上色风格。使用hard ramp比较接近Cel-shading,soft ramp则是类似与插画柔和的阴影层次变化。

由于我们使用了2D的ramp纹理,他们之间的变化是可以动态调整的,我们可以使用ramp mask纹理来选择每像素的ramp软硬以实现插画的手绘风格。这个ramp mask纹理可以由美术直接在模型上进行绘制,我们在unity下有一个3D paint工具,使用起来较为直观。

插画风格渲染的另一个重要因素是使用纹理笔触。

我们可以使用不同的笔触纹理图案以获得不同的着色风格。对于每个笔刷纹理,我们有4个通道可以存储代表不同方向的笔刷图案,混合使用这些笔刷可以获得更丰富的笔刷变化。右边的两张对比图中,使用笔触纹理的有着更多手绘的感觉。

接下来让我们看看如何实现高质量的边缘光。

同样是基于菲涅尔方法,我们有参数来控制它,比如边缘宽度和平滑度,除了这些全局控制参数之外,我们也使用笔刷纹理来增加一些局部变化。

我们定义边缘光既可以来自于方向光源也可以来自于环境贴图,使用方向光我们可以按需求定义边缘光,使用环境贴图,我们可以根据环境光照来获得边缘光以显得更真实,两者都比较有用,可以结合使用。为避免边边缘光出现在不需要的区域,我们使用AO纹理和shadowmap来频闭掉遮挡区域。

卡通风格对于面部一般不会有太多阴影层次的变化,如果我们直接套用之前的ramp方法应用在脸部,效果就会像右侧的图看起来一样不自然,为了改善这种情况我们使用顶点色的一个通道作为mask来控制脸部的上色层的强弱,通过压低漫反射表现来达到想要的卡通效果。

接下来我们来说一下高质量角色软阴影的实现

如果我们直接使用unity内置的CSM阴影,在镜头靠近角色的时候阴影品质并不能满足需求,所以我们就为角色单独渲染了一张shadowmap,以确保恒定的阴影品质;为此我们还实现了基于视锥的shadowmap,根据角色的boundingbox和视锥求交集部分,以此作为渲染区域,就可以最大化阴影贴图的使用率,此外还使用了Variance shadow map以及PCSS来减少阴影瑕疵以及获得自然的软阴影效果。

另外,如果要实现正确的透明材质阴影,还需要额外的通道根据材质的透明度来存储阴影强度。我们可以从实例图片中看到半透明的裙子可以投射出自然的阴影。

眼睛的处理我们使用了基于物理的折射计算,普通卡通模型处理眼部的做法通常是把眼白留空,瞳孔凹陷下去,这样在侧面的时候也不会鼓出来显得比较自然,然而如果要做眼部近距离特写,这种做法看上去就不能令人信服。

使用真实折射算法,眼球本身还是按照球面来做,然后根据视线角度算出折射系数去偏移查找贴图对应点。

上述对比图显示了有无折射的实际效果,我们可以看到,如果没有折射效果,眼部侧面看上去较为奇怪。此外我们还加入了光线折射后的焦散光效果,使得眼睛的质感得到进一步增强。

对于非写实风格渲染,物理正确并不是要考虑的因素,由于卡通渲染的特殊情况,我们希望的焦散效果出现在入射光线的另一侧,并且入射角度越平行看起来越明显。

实现方法是通过入射光和眼球前向的夹角算出入射光强度,这里我们使用inverse diffuse来模拟,再辅助fresnel公式做亮度变化,最后乘上eye caustic纹理得到最终效果。通过对比图我们可以看到如果没有焦散效果眼睛就显得暗淡无光缺乏质感。

这段视频展示了眼睛的折射以及头发的各向异性高光效果。

接下来我们就来介绍一下头发的渲染

头发是卡通渲染角色较为重要且独特的部分。我们想要实现根据光源动态变化的高光和阴影渐变,并且这个实现还应具备直观的所见即所得的色彩调节能力。

和皮肤的材质一样,对于头发的漫反射渲染我们同样使用了multi-ramp的方法,而镜面反射高光我们则使用了两层高光做叠加,通过组合高低频的高光成分在一起我们可以得到满意的结果。

此外,我们还使用Glossy Map和AO纹理来进一步增强头发的质感。头发的高光渲染使用了各向异性高光,相比普通的高光使用normal计算光照,各项异性使用tangent作为计算基础,因此可以使高光显示出垂直于发丝方向的形状。

我们在制作头发模型的时候,如果模型拓扑较为复杂,uv展开较难做到全部垂直,我们也可以使用flowmap来梳理高光的形状。我们还使用Jittermap抖动贴图用来增强卡通渲染头发的质感。通过扰动切线方向来达到模拟发丝细节的高光效果。

另外,通过调整jitter map的uv scale还可以做到调整发丝的高光粗细。

这四张图分解展示了各个高光成分对渲染结果的影响。而右下角的则是最终的图像。我们可以看到,结合了低频和高频成分的高光显示,头发看起来更具表现力。

接下来让我们看看另外一种实现cel-shading头发高光的方案

我们的目标同样是使其可以动态化,高光应根据光源和相机位置沿发丝方向移动,形状也应该在移动中有着动态的形态变化。

Cel-shading风格的头发高光较为独特的形态,很难用传统的高光计算方法来描述。同样我们需要使用切线方向而不是法线来进行高光计算,并且需要更为特殊的方法去表现高光形状。

首先,我们要把每缕头发模型在垂直方向进行uv展开,以便高光可以沿着每根发束移动。然后从将每一缕从左侧向右侧填充0到1,用来标识动态生成的高光形状的起始和结束位置,我们使用几个曲线定义的模板来描述头发高光的基本形状,然后使用抖动噪声纹理来调制头发高光的粗细变化。

材质方面有很多参数用来控制生成图案的形状,如位置,偏移,宽度,抖动比例等。通过调整这些参数,我们可以根据需要获得各种不同的形状。

我们来看另一种各向异性材质的例子:丝

这次我们使用了副法线方向来计算了高光反射,并使用三个高光层合成在一起获得最终的渲染效果,我们为每一层分别设置不同的颜色,以便最终材质看起来色彩层次较为丰富。

我们的角色材质中还包括其他特殊的材质,如水晶和纱巾等半透明材质,直接使用alpha混合不能表现出应有的质感,这就需要我们实现折射和模糊效果。这两个效果都依赖于Unity的command buffer。

实现折射效果时,Command buffer在渲染折射前获取已经渲染好的backbuffer作为背景,用于折射采样,rgb通道设置不同折射系数,分别采样三次来模拟色散效果。

对于模糊效果,则是用Command buffer将backbuffer降采样并做模糊,生成4张尺寸依次减半模糊度递增的RenderTexture,然后根据相机距离和FOV以及材质固有的模糊参数,确定模糊程度,选择对应的RenderTexture来完成模糊效果。

我们还对这两者的实现做了一定的优化,不对直接对backbuffer使用全屏模糊,把物体本身作为proxy mesh,只处理需要画的部分。

接下来让我们来谈谈高品质勾线的方法

对于角色和动态物体我们使用backface勾线方法,并使用顶点色对勾线的宽度进行控制,勾线本身需要连续的顶点法线才能在锐角边不会出现断层,因此我们将平滑过的法线存储在另一套顶点色里,此外,我们也使用顶点色来控制勾线宽度。

比如,发尖处勾线会逐渐变细,我们通过在顶点颜色填充渐变为0的值以使线条宽度逐渐过渡到零,另外,根据相机与物体之间的距离,还应有基于距离修正的勾线宽度。每种材质上也应该有对应的不同勾线颜色,所有这些功能都是高品质的勾线所必需的。

Backface勾线方法虽然可以做到较为细致的勾线还原。但他也有着自身的固有缺陷,那就是不能在非边缘的尖锐折线处产生勾线。而这些折线在硬表面模型上是很常见。

为了解决这个问题,我们添加一个预处理过程来提取这些边缘,并将它们保存到额外的mesh资源中,并使用geometry shader绘制它们。

对于这些折线我们使用了和backface法类似的调整参数,从而使它们看起来完全相同。增加了折线的绘制之后,我们可以看到右侧的图片捕获到了更多的勾线细节。

勾线另一种常见方法就是在图像空间中生成轮廓线。通过检测场景图像中normal和depth的不连续性,我们可以获得细节较为丰富的勾线。无论场景的复杂性如何,这种方法的性能都是恒定的,我们还添加了对勾线颜色的色相,明度,饱和度的调整,使勾线更为自然。

这种方法的缺点则是较难控制勾线的宽度,如果我们想实现距离相关的线宽,我们只能在几个像素的范围内调整它。因此基于图像的方法主要适用于场景轮廓渲染,对于靠近摄像头很近的物体,我们最好使用backface的方法。

最后一种做法是基于笔刷的购线方法,这在离线渲染中使用的比较多,通常分为以下几步:

2.连接轮廓线:根据模型的拓补关系,将相邻的轮廓边连接成尽可能长的轮廓线。

3.轮廓线分段:在步骤2的基础上,根据轮廓线上曲率和可见性的变化,将轮廓线在曲率或可见性的突变处分开:

4.笔触映射:将想要添加的笔触制作成纹理,根据对应的纹理坐标映射到步骤3的轮廓线上。

这种方法可以达到更为风格化,笔触更明显的勾线方式,pencil+ blender里freestyle render基本都是采用类似的方法,性能开销较大,可以用于CG品质渲染,但不适合直接在游戏中使用。

接下来我们来看看其他特殊效果的实现,这些渲染效果在场景刻画中同样起到重要的作用。

这是一段用来展示体积光的场景。

我们可以看到,具有雾效的体积光配合bloom一起使用,场景表现出了较强层次和氛围感。

下面就来看看体积光的实现细节

我们使用unity内置的曲线来体积光的形状,这在运行时也方便调整形状,强度参数变化同样由曲线定义。为了进一步模拟烟雾效果,我们还使用3D noise纹理来模拟动态烟雾流动的效果。noise烟雾本身也有一些参数可调,比如粒度大小,尺寸比例,噪声强度,流动速度等。

此外,配合cookie map还可以自定义体积光投影形状,使用cookie map后同时也引入了高频的变化成分,这就需要对应增加采样数来减少走样,使用抖动算法可以减少采样不足导致的走样,我们实现了两种抖动方式:bayer pattern和blue noise, 通过实验发现blue noise配合Temporal AA可以在较低的采样数下实现较好的体积光效果。

接下来我们来看一下使用Real-time GI的例子。

在这个简单的演示场景中,我们使用enlighten来烘焙Real-time GI的Lightmap,然后使用动态自发光材质和体积光作为光源。我们使用AVpro插件解码视频文件,将其设置在自发光纹理上,并设置强度值为1以上。

我们就可以获得一个动态且明亮的面积光源,同时要记得更新GICache,以便在运行时刻可以动态更新光照环境。当与动态体积光一起使用时,整体的照明效果看起来令人印象深刻。

对于角色上的动态AO实现,我们使用修改过的HBAO,用于指定AO区域中颜色的饱和度和色调调整,以使加入AO后的图像颜色看起来不会变脏,通过对比图我们可以看出,在应用了AO之后,右图比左图层次感更强。

我们还重新实现了适用于卡通渲染的基于图像的眩光效果,用于模拟镜头产生的鬼影和星形散射效果。这里使用与bloom类似的方式提取的高光区域作为输入,然后进行多次不同方向上的卷积并应用色彩调制来获得最终结果。

下面我们来看几张CG视频中的截图和特写。

这是另一组场景截图。我们可以看到在应用了之前提到的这些渲染技术之后,整个场景可以更接近离线渲染的品质。

这幅图描述了上述场景中所应用到的主要渲染特性。从图中我们可以看到这些效果包括:风格化的PBR材质,卡通风格的AO,屏幕空间勾线,屏幕空间反射,以及曲面细分等。

综合应用这些效果对于高品质的动画风格场景渲染起着重要的作用,我们的目标是在PBR的shading基础上加入风格化的调整使其更具有表现力。

场景中的大部分材质都是基于物理的渲染。我们对PBR纹理集进行了一些风格化上的适应调整,比如对于色彩的卡通化调整,以及对于物体材质细节的强调或省略。再结合使用图像空间的勾线来强调物体边缘,整体场景的表现就显得更接近动画风格。

这里是一段演示视频,展示了这些材质在不同光照角度下的光影变化:

这是另一段视频展示了光影的变化:

除了场景渲染之外,我们再来看看其他一些动画渲染所涉及的内容,动画表情。

我们使用blendshape来制作面部表情。眼睛,嘴巴和眉毛的表情独立为不同的部件单独制作,然后通过我们的自定义面部表情插件,来实现表情动画的及语音嘴型的自动映射。此外,我们还可以通过预定义不同的表情集合来在交互应用中驱动面部表情。

在Unity中使用humanoid作为动画导入方式的时候,如果关节处旋转角度较大,按照动画品质的要求关节处的形状就不能令人满意。

为此,我们通过在建模软件中建立了每关节修正的blendshape导入到Unity当中来防止关节变形。我们使用一个自动控制脚本根据关节旋转角度来差值混合形状。为了确保更好的结果,我们为每个关节分别制作了两个blendshaoe,一个用于90度,另一个用于140度以补正关节变形。

另外一种方法还可以使用额外的骨骼进行关节修正,这种方法更容易制作,但是对于结构细节的表现不如使用blendshape。

为了可以表现更复杂的场景动态,比如流体和破碎的场景,我们可以使用alembic格式,或者用EXR纹理作为载体从Houdini或其他DCC工具导入顶点动画资源。

Houdini对EXR纹理格式导出顶点动画提供了很好的转换支持,对于real-time的应用而言,顶点动画纹理在因为是在GPU上运行,运行效率及加载速度要快于alembic格式。

最后,我们来谈谈实时卡通渲染在今后可以继续改进和完善的地方。

第一点是实现所有类型材质完全可定制的风格化渲染,目前我们初步在人物皮肤和服装渲染中的应用了笔刷以获得笔触效果,下一步我们希望将其扩展到整个场景的渲染,比如新海诚式的场景风格,以呈现有着独特且统一的风格化动画风格渲染。

另外一点,是要进一步提高模型的渲染精度,我们希望可以实时呈现CG级的模型精度。可以尝试使用geometry shader或预烘培displacement map进行动态自适应的曲面细分,相比直接导入原始高模,它可以极大减少资源导入的开销和提升运行效率。最后是优化整套流程解决方案,使之更易于实时调整和编辑,进一步提升运行效率以适合在游戏中使用。

好的,以上就是我们今天有关于卡通渲染要分享的主要内容,谢谢大家。

你认为卡通渲染的要点是什么?

贺甲:做卡通渲染的话,在原画阶段把想要的效果画出来,然后从原画提供设计概念阶段,进入下一步从技术角度实现这些,我们会有不同的尝试。因为毕竟作为原画角度,可以比较随意的达到所要的效果,从3D角度还原有诸多限制,有些并且不能纯从技术解决角度。我们主要从表现出发,无论用什么样的方式,尽可能逼近手绘的感觉,来完成卡通渲染的效果。

卡通渲染主要特性:第一,角色。色彩相对于写实方面一些风格化的调整。另外,对于角色渲染阴影的形状,也是有比较细致的考究还原;

第二,对于角色的造型,也相对与写实二次元的加工,比如说头发,写实的话就是比较碎,不太讲究曲线造型感。但是卡通渲染对头发、身材比例、形态都是有非常考究的追求。所以,我们在建模的时候,也会相当注意这点。

第三,渲染的时候,因为突出了一些东西,简化了一些元素,突出表现的这些东西,要重点极致的把这些以手绘的风格还原出来。这也是我们卡通渲染重点追求的部分。

在游戏中实际运用需要注意哪些方面?

贺甲:做渲染MV,或者渲染卡通CG的话,基本上需要关注的点是如何把画面做到极致,可以不惜一切代价,把画面做到最好。如果做游戏的话,要权衡各方面的因素。特别是在移动平台,跑的足够快,要考虑到续航等其他因素,所以游戏方面肯定挑战最大,要在画面与性能之间作出比较好的平衡。

如果国内团队希望学习卡通渲染的技术,你会给出什么建议?

贺甲:首先要做卡通渲染,团队要对卡通渲染、二次元方面比较感兴趣,只要有兴趣,才能把握住玩家所需要的点,而且才有兴趣做好。

其次,除了这方面,要在技术做到比较好的实现,要大量查阅国内国外比较主流的实现,按照自己的需求都能实现出来。但是这只是完成预演与项目Demo阶段,真正产品化做出来之后,更多需要整体的控制项目管理能力,如果忽视了这一点的话,可能只能停留在Demo阶段,作为一个完整的项目做出来的话,其他方面综合都是非常重要。

马上注册,加入CGJOY,让你轻松玩转CGJOY。

您需要 才可以下载或查看,没有帐号?




之前在【GPU精粹与Shader编程】系列中写过一篇,这篇文章则是它的番外篇,主要关注于真实感水体渲染技术。

本文将对游戏开发以及电影业界的真实感水体渲染技术从发展史、知识体系、波形模拟技术以及着色技术等多个方面进行较为系统的总结,文末也对业界优秀的水体实时渲染开源库进行了盘点。

真实感水体的渲染和模拟,一直是计算机图形学和游戏开发领域的核心难点之一。而在水体渲染中,最核心的部分为波形的渲染技术,即如何模拟出逼真的水面波浪的流动变化。按时间分布,近50年水体波形渲染的主流技术发展可以总结列举如下:

需要注意的是,上面列出的时间点,可能并不是严格意义上的该技术提出的时间点,而是该技术在论文或会议上被提出,被大众熟知,被引入到水体渲染技术中的时间点。

接下来,先看一些近年游戏中的真实感水体渲染画面,然后对这里列出的水体主流渲染技术中的主要方法,按流派和内容分别进行总结。

首先是《神秘海域4》中清澈的海岛浅滩:

然后是《盗贼之海》中波涛汹涌的海洋:

接着是《孤岛惊魂5》中阴天的池塘:

还有《战神4》中深邃的海面:

以及《刺客信条:奥德赛》中平静的海滩:

这边也放一个继承了《刺客信条》系列水体渲染技术的《怒海战记(Skull & Bones)》的gameplay视频:

要实现如上3A游戏级别的水体渲染,其实是有章可循的,对应的核心方法在本文以及下面的这张思维导图中都有进行总结。

本文配套的水体渲染的知识体系思维导图如下:

按照流派进行分类,可将上文总结的水体渲染波形模拟的二十三种方法分为如下几类:

下面将对其中比较常见的方案进行盘点。

4.1 线性波形叠加方法

线性波形叠加方法的主要思路是累加不同的线性波形函数以构造波浪表面。可以将其理解为波动现象在深水中引起水颗粒运动的一种解析解。

图 水颗粒运动的图示。波浪中的任何点都沿圆形轨迹移动,靠近表面的半径较大,而在水中更深的半径呈指数减小。突出显示了两个橙色点,可以发现他们的运动轨迹都是圆形。(图片来自)

作为比较早期的水面波形模拟方案,正弦波(Sinusoids Wave)的特点是平滑,圆润,适合表达如池塘一样平静的水面。

1981年,Max[Max 1981]首先提出了采用高低振幅的正弦波曲线的序列组合来模拟水面起伏的想法。将水体表面采用高度进行建模,则基于正弦波(Sinusoids Wave)的方法在时间t的每个点(x,z)上计算的高度y = h(x,z,t)的通用公式为:

正弦波(Sinusoids Wave)目前在水体渲染领域已经很少直接使用,业界往往青睐于使用它的进化版Gerstner波。

作为正弦波的进化版,Gerstner 波(Gerstner Wave)的特点是波峰尖锐,波谷宽阔,适合模拟海洋等较粗犷的水面。

选择一组波矢量ki,振幅Ai,频率ωi和相位φi,对于,Gerstner Waves的通用公式为:

Gerstner Waves由于计算量可控,性价比高,在游戏水体渲染领域的应用较为广泛。不少3A游戏了采用Gerstner Wave作为水体渲染的基础实现。如下文Wave Particles部分也会提到的《神秘海域3》,即是采用了Gerstner Wave + Wave Particles的水体渲染方案组合。

作为目前电影业界广泛采用的海洋表面渲染解决方案,基于快速傅立叶变换(Fast Fourier Transform , FFT)的水体渲染方法的特点是真实感出色,全局可控,细节丰富,但计算量相对较大。

图 Unity下实现的基于FFT的水体

transform,DFT)的高效、快速计算方法集的统称。最初的快速傅里叶变换方法早在1805年就已由高斯推导出来,并于1965年由Cooley和Tukey重新提出,并渐渐被大众所熟知。从此,对快速傅里叶变换(FFT)算法的研究便不断深入,数字信号处理这门新兴学科也随FFT的出现和发展而迅速发展。根据对序列分解与选取方法的不同而产生了FFT的多种算法。

FFT的基本思想是把原始的N点序列,依次分解成一系列的短序列。充分利用DFT计算式中指数因子 所具有的对称性质和周期性质,进而求出这些短序列相应的DFT并进行适当组合,达到删除重复计算,减少乘法运算和简化结构的目的。

关于FFT的算法细节这里就不展开讲了,放两张经典的总结图: 

基于FFT的水体渲染方法,也常被各类文献称为基于频谱(spectrum-based)的方法,其核心思想是基于FFT构造出水体的表面高度。具体而言,该方法使用从理论或测量统计数据获得的海浪频谱(最常见的频谱为[Tessendorf 2001]使用的Phillips频谱)来描述海洋表面,结合大量的正弦波的叠加在频域中生成波型的分布,然后执行逆FFT,将数据转到空间域,经过运算生成位移贴图(displacement map)。最终,由位移贴图导出表面法线贴图,以及其他相关数据,如代表白沫区域的Folding Map。

采用FFT的水体渲染方法从90年代开始广泛用于电影制作(离线渲染),从2000年代开始广泛用于游戏(实时渲染)。离线渲染和实时渲染的选择,主要在于当时硬件计算能力可以承受多少分辨率的高度图的实时运算。早期的游戏,如Crysis,由于硬件计算量的限制,采用了64 x 64的高度图分辨率。而由于硬件的发展,目前512 x 512的分辨率的计算量已经在实时渲染中较为普遍。而电影工业中采用FFT生成的高度图,由于可以采用离线渲染,以及品质的要求,分辨率一般较大,如早在1997年的《泰坦尼克号》的海洋渲染的渲染,就已经采用了2048 x 2048分辨率的高度图。

图 著名电影《泰坦尼克号》中,基于FFT方法离线渲染的海洋,采用2048 x 2048分辨率的高度图

波动粒子(Wave Particle)方法最初由Yuksel于2007年[Yuksel 2007]提出,该方法的核心思想是采用粒子代表每一个水波,并允许波反射以及与动态对象的相互作用。这种方法将动态模拟三维水波的复杂度降维到模拟在平面上运动的粒子系统的级别。

波动粒子(Wave Particle)方法结合了线性叠加方法的灵活性和基于FFT方法的稳定性和视觉细节,其可控制性和性能,以及出色的交互表现,是模拟实时水体交互的不错方案。

需要注意的是,波动粒子(Wave particles)的作用不只是代表波浪的位置。它们还可以带有描述其形状和行为的其他属性,例如振幅(amplitude)和半径(radius)。

当相邻波动粒子之间的距离大于半径的一半时,该方法会将一个波动粒子转换为三个新的波动粒子。新的波动粒子直接从现有波动粒子中吸收能量(即振幅)。从而减小了现有波动粒子的振幅,而整体波峰的总振幅保持不变。三个子粒子的振幅和扩散角度变为父粒子的三分之一,而新粒子的半径与父波动粒子保持相同。如下图所示。

图 (a)和(b)分别是波动粒子的初始位置和它们形成的波峰(c)和(d)是波粒经过一定距离后的位置和波动粒子形状(图片来自[Yuksel 2010])

因为在波动粒子系统中,假设每个波动粒子在两侧都具有两个相同的相邻粒子,所以当一个波动粒子细分时,其会在两侧产生两个新的波动粒子,如下图所示。

图 具有相同扩散角度的两个相邻波动粒子之间的距离(图片来自[Yuksel 2010])

另外,Wave Particles方法还可以与现有各种方案进行结合和改进。

2007年Yuksel提出的原版Wave Particles的波动粒子的生成源来自点状的粒子波源。对此,《神秘海域3》对其进行了改进方案。在《神秘海域3》中,并没有使用点状粒子波源,而是在环形区域中放置随机分布的粒子源,以近似开放水域的混沌运动,从而产生一个可平铺的向量位移场(vector displacement field)。

图 《神秘海域3》中基于随机分布wave particles粒子源的波浪模拟方法

《神秘海域4》中则采用了多分辨率Wave Particles方案,从另一个角度对Wave Particles方法进行了改进。

packets )方法。该方法继承了基于频谱的方法的优点,如数值稳定性和理论上准确的波速。同时,他们通过将全局余弦波分解成一系列更短的波分量,从而避免了基于频谱的方法的复杂性。

Wavelets)基于欧拉方法,自由度与空间区域有关,与波动本身无关。因此,该方法可以和GPU更好的结合,因为计算复杂度是恒定的,因为不随粒子的数量而变化。不过该方法由于提出时间较新,性能也没有太大优势,所以目前还没有听说有实际的实时渲染项目在使用。

基于物理的水体模拟方法一般比较昂贵,由于可以离线渲染,所以在电影工业中具有很好的运用。由于现阶段很难用于实时渲染,这边仅进行一个综述性的总结。

基于物理模型的水体模拟方法的核心是对Navier-Stokes方程(Navier-Stokes Equations,NS方程)进行求解。Navier-Stokes方程是一组描述液体和空气之类的流体物质的方程,描述作用于液体任意给定区域的力的动态平衡。除了水体模拟之外,其还可以用于模拟天气,水流,气流,恒星的运动。

  • 欧拉方法(Eularian Method)是一种基于网格的方法。它从研究流体所占据的空间中各个固定点处的运动着手,分析被运动流体所充满的空间中每一个固定点上流体的速度、压强、密度等参数随时间的变化,以及由某一空间点转到另一空间点时这些参数的变化。

  • 拉格朗日方法(Lagrangian Method)是一种基于粒子的方法。它从分析流体各个微粒的运动着手,即研究流体中某一指定微粒的速度、压强、密度等参数随时间的变化,以及研究由一个流体微粒转到其他流体微粒时参数的变化,以此来研究整个流体的运动。最常用的拉格朗日方法是光滑粒子流体力学(Smoothed Particle Hydrodynamics,SPH)方法,其核心渲染思想为流体模拟产生粒子,然后多边形化粒子以产生波。

图 基于SPH方法的水体渲染表现

除了独立的两种方法之外,还有结合两者的欧拉-拉格朗日混合方法(Eularian-Lagrangian Hybrid approaches),其主要思想是使用欧拉方法来模拟流体的主体,并使用拉格朗日方法来模拟诸如泡沫,喷雾或气泡之类的细小细节。

FX Guide上有一篇关于电影业界使用流体模拟方法的不错文章,感兴趣的朋友可以了解一下:

另外,也可以采用bake to flipbook方法,将离线的流体模拟,烘焙成flipbook帧动画,用于实时渲染。

Flow Map除了用于水体的渲染以外,任何和流动相关的效果都可以采用Flow Map,如沙流,以及云的运动等效果。

Flow Map的核心思想是预烘焙2D方向信息到纹理,以在运行时基于UV采样,对流动感进行模拟。

Flow Map的典型使用代码如下所示:

离线FFT烘焙(Offline FFT Texture)方法最初由《刺客信条3》团队开始采用[Torres 2012]而进入大众视野,思路为基于离线FFT预渲染出一系列高度图,烘焙得出一系列法线贴图或矢量位移贴图(vector displacement maps),并在运行时进行采样。FFT的周期性质可以让烘焙得出的贴图非常适合做tiling。

图 基于离线FFT烘焙的《刺客信条3》的水面表现

图 基于离线FFT烘焙的《刺客信条3》的水面表现

除了上述5大类方法之外,还有一些其他的常见水体渲染方法,可以总结如下:

其中,凹凸纹理贴图(Bump Mapping)比较早期的水体模拟方案,主要思想是扰动参与光照计算的法向量,并通过凹凸纹理的连续移动来模拟海浪的随机运动。目前凹凸纹理贴图几乎是实时水体渲染的必备贴图之一。

而分形噪声(Fractal Noise)方法核心思想是基于不同频率Perlin噪声的叠加,混合出分形噪声,以构建海面高度场。

矢量位移贴图(Vector Displacement Map)的核心思想则是使用空间中的向量的颜色通道在方向与大小上置换对应几何体的顶点。

其他的方案相对而言比较小众,都有对应paper,篇幅原因这里就不展开总结了。

关于水体渲染的Shading部分,首先要提到的是,目前游戏业界的主流方案都不是基于物理的。

到达水面的光线除了在水体表面发生反射之外,还有部分光线进入水体内部,经过吸收和散射后再次从水体表面射出,即水体的次表面散射现象(Sub-Surface Scattering, SSS)。基于物理的渲染中,求解次表面散射最标准的方法是求解BSSRDF(Bidirectional Surface Scattering Reflectance Distribution Function,双向表面散射反射分布函数)。 

但在光栅图形学中,求解BSSRDF需要很大的计算量,所以实时渲染业界大多数的水体渲染,依旧是非基于物理的经验型渲染方法。

《神秘海域3》在2012年SIGGRAPH上的技术分享中有一张分析水体渲染技术非常经典的图,如下。

对此,我们可以将水体渲染的要点总结为:

其中,漫反射,镜面反射,法线贴图,折射等都是比较常见的技术,而流动表现(Flow)上文已有涉及,这里都不再赘述。

下文将对水体渲染的难点,通透感(Translucency),白沫(Foam/WhiteCap)渲染分别进行总结。

关于水体通透感(Translucency)的表现方案,可以将业界主流方案总结为如下三个流派:

  • 混合型方案。 即同时将LUT与次表面散射近似两种方案结合使用的方法。典型的例子如《刺客信条3》

Depth Based-LUT方法的思路是,计算视线方向的水体像素深度,然后基于此深度值采样吸收/散射LUT(Absorb/Scatter LUT)纹理,以控制不同深度水体的上色,得到通透的水体质感表现。

其中,视线方向的水体像素深度值计算思路如下图中的蓝色箭头所示的橘褐色区间:

图 蓝色箭头所示的橘褐色区间为视线方向的水体像素深度

可用于水体通透感表现的次表面散射(Sub-Surface Scattering,SSS)的近似方案有很多种,这边推荐两种:

图 有无次表面散射的水体表现对比

  • 假设光更有可能在波浪的一侧被水散射与透射。

  • 基于FFT模拟产生的顶点偏移,为波的侧面生成波峰mask

  • 根据视角,光源方向和波峰mask的组合,将深水颜色和次表面散射水体颜色之间进行混合,得到次表面散射颜色。

  • 将位移值(Displacement)除以波长,并用此缩放后的新的位移值计算得出次表面散射项强度。

对应的核心实现代码如下:

其中,sssIndensity,即散射强度,由采样位移值计算得出。

图 《盗贼之海(Sea of Thieves)》中基于次表面散射近似的水体表现

图 《盗贼之海(Sea of Thieves)》中基于次表面散射近似的水体表现

具体方案和代码如下所示:

5.2 白沫的渲染方案

白沫(Foam),在有些文献中也被称为Whitecap,White Water,是一种复杂的现象。即使白沫下方的材质具有其他颜色,白沫也通常看起来是白色的。出现这种现象的原因是因为白沫是由包含空气的流体薄膜组成的。随着每单位体积薄膜的数量增加,所有入射光都被反射而没有任何光穿透到其下方。这种光学现象使泡沫看起来比材质本身更亮,以至于看起来几乎是白色的。

对于白沫的渲染而言,白沫可被视为水面上的纹理,其可直接由对象交互作用,浪花的飞溅,或气泡与水表面碰撞而产生。

白沫的渲染方案,按大的渲染思路而言,可以分为两类:

按照类型,可以将白沫分为三种:

而按照渲染方法,可将白沫渲染的主流方案总结如下:

这边对其中比较典型的几种进行说明。

《战争雷霆(War Thunder)》团队在CGDC 2015上对此的改进方案为,取雅克比矩阵小于M的区域作为求解白沫的区域,其中M~0.3...05。

另外,《盗贼之海(Sea of Thieves)》团队在SIGGRPAPH 2018上提出,可以对雅可比矩阵进行偏移,以获得更多白沫。且可以采用渐进模糊(Progressive Blur)来解决噪点(noisy)问题以及提供风格化的白沫表现。

图 《盗贼之海》基于雅可比矩阵偏移 + 渐进模糊(Progressive Blur)的风格化白沫表现

《GPU Gems 2》中提出的白沫渲染方案,思路是将一个预先创建的泡沫纹理在高于某一高度H0的顶点上进行混合。泡沫纹理的透明度根据以下公式进行计算:

  • 其中,H_max是泡沫最大时的高度,H_0是基准高度,H是当前高度。

  • 泡沫纹理可以做成序列帧来表示泡沫的产生和消失的演变过程。这个动画序列帧既可以由美术师进行制作,也可以由程序生成。

  • 将上述结果和噪声图进行合理的结合,可以得到更真实的泡沫表现。

《刺客信条3》中的岸边白沫的渲染方案可以总结为:

  • 以规则的间距对地形结构进行离线采样,标记出白沫出现的区域。

  • 采用高斯模糊和Perlin噪声来丰富泡沫的表现形式,以模拟海岸上泡沫的褪色现象。

  • 由于白沫是白色的,因此在R,G和B通道中的每个通道中都放置三张灰度图,然后颜色ramp图将定义三者之间的混合比率,来实现稠密、中等、稀疏三个级别的白沫。要修改白沫表现,美术师只需对ramp图进行颜色校正即可。如下图所示:

5.2.4 交互白沫:[SIGGRAPH 2018]《盗贼之海》基于场景深度的交互白沫渲染

  • 盗贼之海中,得到相对深度后,还会对白沫mask做渐进模糊(progressively blur),以得到风格化的白沫表现。

5.2.5 浪尖白沫&岸边白沫:[GDC 2018]《孤岛惊魂5》基于有向距离场的方法

GDC 2018上《孤岛惊魂5》团队分享的白沫渲染技术也不失为一种优秀的方案,主要思路是基于单张Noise贴图控制白沫颜色,结合两个offset采样Flow Map控制白沫的流动,并基于有向距离场(Signed Distance Field,SDF)控制岩石和海岸线处白沫的出现,然后根据位移对白沫进行混合。

时间来到2019年,已有不少3A级别的水体渲染技术以免费&开源的方式涌现了出来,这里将进行一个盘点。

如果要实现一个高品质的水体实时渲染解决方案,以下的这六个开源库会让你事半功倍。

之前在【GPU精粹】系列文章中也提到过,CryEngine作为比较老牌的引擎,其内置的水体渲染表现在各大游戏引擎的内置水体中,可谓是顶尖级别的。CryEngine现在也已经开源。

Dynamic Water Project 是Unreal引擎下一款不错的开源水面交互解决方案,对于可交互水体而言是不错的参考。

Ceto也是Unity引擎下的另一个不错的水体渲染开源库。

BoatAttack是Unity在2018年5月13日开源的基于LWRP的项目,经历了几个版本的开发周期,具有令人印象深刻的水体表现,可谓是Unity引擎下非常优质的水体渲染参考。

本文对游戏以及电影业界的真实感水体渲染技术从发展史、知识体系等多个方面进行了较为系统的总结,文末也对业界优秀的水体实时渲染开源库进行了盘点。

不妨用配套的思路导图作为本文的收尾:

可以将这篇文章理解为【GPU精粹与Shader编程】系列的番外篇,所以它和【GPU精粹与Shader编程】系列文章一样,也收录在了这个GitHub Repo中。

本文的GitHub版本传送门:

[28] 题图来自《盗贼之海》

我要回帖

更多关于 fbx模型多贴图打包 的文章

 

随机推荐