仿宋代水墨山水画风格 3D 渲染的 Unity 实现

作者:sacshadow
2023-02-07
47 41 8

一. 项目起因

2019 年,我正在为自己的功夫题材游戏寻找到一个合适的美术风格。当时在知乎看到了一个仿吴冠中绘画风格的 Unity 3D 场景实现(搜了下没找到,有知道的朋友可以联系我,我来补上连接),于是开始对中国传统绘画风格感兴趣,进行了一些研究和尝试。 之后,又受到知乎作者“无聊”发布的文章 《Unity-一个简单的水墨渲染方法》 的启发,有了现在这个美术风格。 同时还要感谢中国独立游戏的先行者之一老彭(彭必涛)的帮助。 老彭在十多年前就在研究 3D 国画场景的相关实现,在艺术上给了我很多建议。

目前项目的实现效果 :

游戏《无极道人》实机截图

游戏《无极道人》实机截图

二. 山水画简介

《富春山居图》(局部)-[元]黄公望/图片:网络

山水画是中国传统绘画的一个分支。很多人只知道国画、水墨, 但和西方绘画一样,中国传统绘画有许多不同的分类方式, 比如,按技法可以分为工笔、写意、水墨、白描等, 按内容可以分为花鸟、山水、人物、宫室等。每种画和画法都有自己的特点和习惯。

山水画从隋唐开始出现,此后逐渐演变成一个单独的题材,至宋代开始盛行,技法也趋于完善。它主要以描绘山川自然景色为主, 可以分为青绿山水、水墨山水、浅绛山水、小青绿山水和没骨山水等流派。常用技法有勾、皴、擦、染、点五法。

在研究了众多中国传统绘画风格后, 我选择以宋代水墨山水画作为基础,进行风格上的模拟仿制,因为这是一个相对写实的风格,比较有规律,在计算机上模拟起来比较容易。

三. 宋代水墨山水画简介

宋代水墨山水画在国画中属于比较写实的一个派别,跟素描的绘画技法有些相似。

国画讲究线为骨。绘画技法在表现结构时要有“骨力”,重视线条的运用,并将书法笔画的技巧融入其中,很多国画大家也是书法大家。类似于素描线条一样,不同的轻重快慢可以画出不同感觉的线条。

《十八描》,一本关于传统国画线条技法的书/图片:网络

颜色以墨色为主,讲究墨分五色焦、浓、重、淡、清, 配合干湿一共有十种主要变化。物体的远近和遮挡关系,质地坚硬还是柔软,视觉重点还是点缀,都要靠墨色的变化来实现。

图片:网络

如前一节所述,技法为勾、皴、擦、染、点。

勾又称勾勒,为轮廓沟边;皴是画出主要结构;擦和染负责明暗关系和质感;点又称点苔, 画出附着在山石上的植物。绘画时通常先用墨线勾出山石的轮廓,再用各种皴法画出山石明暗向背,然后用淡墨渲染,进一步加强山石的立体感,最后用浓墨或鲜明的颜色点出石上青苔或远山的树木。

图片:网络

在塑造立体感方面,讲究石分三面:受光面、侧光面、背光面一起构成物体的立体感。在某些印象中,国画不怎么讲究光影和立体关系,比较平面,实际上并非如此。

图片:网络


内容和构图

宋代山水画倾于自然,侧重“真”和“实”,虽提倡山水画的写实风格,但不拘泥于物体本身的真实性,而重在其背后的主观真实,即“山川使我为山川言”等,借物抒情,以物喻人。这有些类似于后印象派和当代美术理念,绘画内容是自我表达,抒发艺术家的自我感受和主观感情,而非对景物的客观还原。

在本项目中,主要参考了各种古代名画和《芥子园画谱》等书。

《溪山清远图》(局部)- [南宋]夏圭,本项目的主要美术参考风格/图片:网络

《芥子园画谱》-[清] /图片:网络

四. 在 Unity 引擎 中进行实现

 1. 渲染使用的相关技术说明

这里给出相关技术的中英文名称和简介方便查找。 有些技术名词会有多个不同的中文翻译。


Non-Photorealistic Rendering(NPR), 非真实感绘制

本项目的美术风格属于 NPR 的一种。

非真实感绘制(NPR)是计算机图形学的一类,主要模拟艺术式的绘制风格,也用于发展新的绘制风格。和传统的追求真实感的计算机图形学不同,NPR 受到油画、素描、技术图纸和动画卡通的影响。

—— Wikipedia

《无主之地》(Borderlands),一款非常出名的 NPR 美术风格游戏/图片:网络


Vertex Extrusion Outlines,顶点外扩描边

顶点外扩描边为游戏渲染中常用的几种实现描边(Outlines)的方法之一。这里主要是沿法线方向对顶点进行外扩。想要得到比较好的效果,模型的顶点数量最好不要太低,同时整个模型需要全部软边(Maya 里称为软边, 3ds max 里称为同一光滑组,在不同软件内可能有不同叫法)。 如果描边效果不好,可以尝试增加边缘的顶点数量并检查是否都是软边。如果遇到一定要硬边的情况,则可以使用沿顶点色方向扩张,即将顶点扩张的方向记录在顶点色里。这可能需要额外的制作流程关系和相关工具。

立方体的布线模式分别为硬边、软边、加辅助线和倒角


Rim Light,边缘光

边缘光是一个常见的游戏渲染效果,根据摄像机视角方向和物体法线的夹角来计算一个值,以进行照亮、描边等后续操作。


MatCap (Material Capture)

MatCap 是 Material Capture 的缩写,是一种用作图像纹理的图像,可以在 3D 应用程序中伪造包括照明和反射在内的整个材质。允许通过简单预渲染一个 3D 球体对象的 2D 图片来创建表面材质和照明环境,然后在 Shader 中将原始 3D 球形法线映射到渲染表面的法线,从而将预渲染的球形图像的光影和材质应用于目标表面,并使其看起来像其原始渲染环境中希望表面出现的样子。

2D MatCap 素材纹理


Lambert,兰伯特光照模型

兰伯特是渲染中常见的一个光照模型。在这个项目中主要是用来和其他技术一起组合出纹理的渲染区域。


Tri-planar projection,三方向纹理投影

Tri-planar projection 是将多个平面纹理组合在一起并混合以覆盖整个 3D 网格的纹理投影,可以创建无缝的噪音和纹理贴图。通常使用模型的法线方向作为投影和混合依据。可以是世界坐标也可以是局部坐标。


Tilemap,四方连续贴图

四方连续贴图也称瓦片贴图,特点是相邻贴图上下边和左右边的纹理是连续的,没有接缝。通常用来绘制大片相同区域。

图片:网络


Noise map,噪音纹理

Noise map,一种用于在计算机生成的表面上产生有自然外观的纹理的技术,用于游戏电影等视觉效果。常用的有 Perlin Noise 等生成算法。Noise map 可以让计算机图形渲染时能够更好地表现视觉效果中自然现象的复杂性。


3D Noise map 3D,噪音纹理

3D Noise map 为三维空间下的噪音纹理, 通常使用模型的顶点作为 3D uv 使用,不受模型本身 uv 的影响。


2 山石渲染实现

具体代码请在 Github 下载项目示例查看。链接在文末也有单独附列。


 2.1 勾

在 CIPR_0_Gou_step_0 中通过外层、中层和内层三个 Pass 的控制完成勾线的笔触效果模拟。

毛笔的勾线笔触效果, 笔刷中间白色的部分称为飞白。

为了模拟毛笔勾线的勾边效果,一共使用了两个 Vertex Extrusion 的 pass 和一个基础的着色 pass。前文提到的“无聊”发布的知乎文章中,使用了两个 Vertex Extrustion pass, 一个提供基础描边,一个提供外轮廓的笔触效果。在此基础上,可以使用 rimlight + matcap 或 rimlight + noise 的方式再额外对内轮廓的笔触效果进行模拟。当然,也可以增加第三个 Vertex Extrusion pass 向内收缩或通过 offset 改变渲染顺序来模拟内轮廓,但是会额外增加不少三角形的渲染数量。综合性能考虑,还是在着色 pass 中进行模拟比较好。但若想追求更好效果,也不是不能再增加一个 pass,通过一张 __OutlineNoiseFB 贴图的控制来模拟笔触中飞白的效果,利用公式将 2D Noise map 计算成伪 3D Noise map。 这里可以根据实际需要选择用 3D Noise 还是 2D Noise, 是 world space 还是 local space。

第一个顶点外扩 Pass 基础勾边和飞白效果

第二个顶点外扩 Pass 外层飞白效果

rimLight 实现内层勾边和飞白效果

在上图中:

  • RimColor 用来 Debug 显示 RimLight 的范围;
  • RimRate 调整 RimLight 的范围;
  • Inline Ctrl 调整内勾边的范围,显示区间, Noise 纹理大小和擦除强度;
  • ON Ctrl(Outline Noise Control)调整主要勾边和外层勾边的 Noise 纹理大小和擦除强度。


在 CIPR_0_Gou_step_1 中,引进根据距离控制笔触效果的参数,增加 _DistanceCtrl 距离控制来处理不同距离物体的渲染效果。根据距离,修改勾边的粗细和颜色。 这个值包括最大距离,描边粗细衰减,近距离物体边缘光和远距离物体边缘光。增加一个 _ColorRemap 材质来映射不同距离下的墨色使用。 边缘光根据距离变化公式 pow(clamp(dist/_DistanceCtrl.x,0,1), 0.05) 里, 这个 0.05 次方是项目中实验下来比较好的值,实际应用时,可根据自己项目场景大小自行调整。

在上图中:

  • Color Remap,根据模型距离重定向渲染颜色;
  • Distance,距离控制:最远计算距离, 描边粗细衰减,近距离 RimLight 强度,远距离 RimLight 强度。


在 CIPR_0_Gou_step_2 中,引进随机函数来模拟笔触的粗细和浓淡变化。这里简单的利用顶点位置作为随机种子,简单的用正弦函数来计算随机粗细变化。使用一张 Noise 贴图配合顶点相对位置作为做种子来模拟浓淡。实际可以根据项目的具体需求选择不同的随机方式。

在上图中:

  • Outline Ctrl 描边控制主描边粗细,外描边粗细,随机函数周期,随机大小百分比;
  • OC Rand 描边颜色随机 Noise 贴图大小,随机范围。


 2.2 皴、擦

这里我们主要用笔触的 Tilemap 贴图配合 Noise 来模拟皴擦的笔触效果。通过一些 shader 基础对需要绘制的位置进行定位。

首先加入一张 _Stroke 笔触贴图 和 _Noise 笔触噪音贴图。利用伪 3D Noise 技术将这两张图变为 3D 纹理,利用 rimLight 和 Lambert 光照来控制笔触贴图的投影范围。 这里对笔触贴图进行两次采样,一个作为皴的笔触效果, 一个作为擦的笔触效果。在 _Stroke 贴图中我们可以在不同通道储存不同的笔触纹理。之后跟 Noise 纹理混合来消除重复感。

在上图中:

  • Lambert <=> RimLight 调整控制区域受灯光还是边缘光照影响;
  • 增加了 Stroke 笔触贴图 和 Noise 噪音贴图;
  • Size 贴图大小;
  • Area Begin 根据 RimLight 或光照强度决定渲染开始的区域;
  • Area End 根据 RimLight 或光照强度决定渲染开始过度的位置;
  • Dark 加强纹理的颜色深度。


想要更好的纹理效果可以用 Tri-planar 代替伪 3D Noise, 但是会增加纹理采样数。 取决于项目需求是否采用。

如果希望更精确地控制皴擦的显示区域, 可以用 MatCap 贴图和 uv 贴图绘制控制区域来代替或混合 rimLight 和 Lambert 光照的控制区域效果。 一样会增加纹理采样次数,取决于项目需求和美术效果是否要采用。

这里加入了一个 MatCap 贴图来控制笔触的渲染位置。


 2.3 染和其他

一般来讲,直接用 rimLight + Lambert 光照控制或 MatCap 控制都可以。 如果需要,则再叠加一层 Noise 噪音来消除重复感。

另外,也可以直接用 MatCap 或绘制到模型的 Diffuse 纹理贴图上。

MatCap

Diffuse

对于整个场景,可以考虑像烘 UV 一样,直接绘制到 lightmap 上。 本项目由于比较简单,就直接使用 projector 投影绘制了一个。 用编辑器指令 CaptureScreenShot 在投影位置拍摄场景, 然后到 PS 里绘制笔触,最后再用投影投回去。项目中可以在编辑器顶部的插件 SDTK -> Common 里找到这个指令。

投影前

投影后

PS 里绘制的投影贴图

对于宣纸等底层纹理, 实现方法也很多。本项目考虑到减少透视关系,采用的是从摄像机观察相似角度,用投影仪把一张宣纸纹理投影到游戏会用到的区域。

屋顶瓦片则使用法线求出朝向后,以世界坐标进行贴图平铺和 Noise 混合,消除重复感。

五. 其他注意事项

本文讨论的主要是制作思路,不用完全按照这篇文章的步骤制作。

部分渲染技术消耗资源比较大,比如两次勾边等,在远处的物体上并不明显。 所以推荐做 LOD 的时候 shader 可以用得简单一点,只勾一次边,减少皴擦的贴图采样次数。

本项目代码主要用来说明各种制作过程,如果使用,需要自行优化。 比如几个控制函数的控制公式是可以直接一起计算的,但是为了方便说明被分开来写了。控制贴图和笔触贴图都是黑白的,可以合并到一张图的不同通道里。 这里为了展示也没有合并。

如果想要做出不错的美术场景,还是需要对中国传统绘画进行深入的研究和了解。比如此前我一直觉得水墨画应该是高饱和、高对比的,冲击力很强。 后来分析了很多国画的直方图之类的素材后发现,传统国画一般都是中低饱和,整体颜色对比并不强烈,过渡平缓,而对比感来自于技巧的合理运用和构图画面安排。

六. 示例项目下载地址

https://github.com/sacshadow/3D_ChineseInkPaintingStyleShader

本文为用户投稿,不代表 indienova 观点。

近期点赞的会员

 分享这篇文章

sacshadow 

目标是世界一流的游戏开发者 

您可能还会对这些文章感兴趣

参与此文章的讨论

  1. 朔锋 2023-02-08

    我膝盖呢?

  2. sdjdasha 2023-02-08

    太厉害了

  3. mnikn 2023-02-08

    学不会系列,进我收藏夹吃灰吧!

  4. zfplay 2023-02-08

    进来膜拜大佬

  5. Minato。 2023-02-14

    强的一

  6. 今个儿赛太阳 2023-02-17 微信会员

    新蜜蜂

  7. Beta-Zero 2023-03-14 微信会员

    你好,这个风格做得很出色,我可以在这个shader的基础上制作游戏并参加比赛吗?

    • sacshadow 2023-03-15

      @Beta-Zero:可以的 随便用没限制

您需要登录或者注册后才能发表评论

登录/注册