IntroductionPRB 材质改变了人们对于引擎实时渲染画面的理解,让玩家在游戏中,也能够体验到锈蚀的金属,厚重的皮革,精细的纹理,感受更加真实的世界。在正式发布的 Cocos Creator 3D 中,真实感渲染和强大的材质系统成为开发者关注的一大重点。为了给 Web 和小游戏平台带来更好的 3D 游戏表现,Cocos Creator 3D 首次真正将基于物理渲染全面带到了小游戏中,不仅支持 PBR 材质,还将光源系统和渲染统一升级为基于物理的度量衡和算法。

 

在 9 月份深圳技术分享会上,Cocos 3D 引擎开发工程师武云潇,为与会开发者带来了 Cocos Creator 3D 材质系统的分享,内容由浅及深,实机演示 3D 材质系统的工作流,并准备了具体的案例学习环节。Creator 3D 实现小姐姐高光发丝,这帮引擎大佬真的是服了!_数据讲师,Cocos 武云潇以下内容是演讲干货整理:Definition要了解材质系统,首先需要知道什么是材质。要知道什么是材质,首先需要明确什么不是材质。下面我以头盔场景作为案例,为大家展示讲解。Creator 3D 实现小姐姐高光发丝,这帮引擎大佬真的是服了!_小游戏_02

 

对于这个头盔而言,材质系统到底在其中发挥了什么作用呢?为了更直观地说明,我们不妨把所有材质系统的贡献全部剔除,看看还会剩下什么。Creator 3D 实现小姐姐高光发丝,这帮引擎大佬真的是服了!_空间数据_03可以观察到,除了头盔的形状,所有的表面细节、对光照的反馈、颜色质感等信息都消失了。这些信息决定着一个几何体的材质,也是材质系统控制和提供定制化的最重要的内容。而几何体的形状本身,是由模型数据决定的,如果我们把这部分最原始的数据可视化出来,可以看到,这一个个分散的三角形,才是游戏世界中所有模型的本来面貌。如果把渲染看做画画,材质系统最重要也是最基础的功能,就是在已有线稿的基础上,控制如何给这里的每个三角形上色。(当然更进阶的,也可以控制线稿本身的一些细节,甚至处理更为复杂的计算任务,如骨骼动画的蒙皮等)

 

Presentation现在我们对课题有了基本的定义,就让我们来利用引擎内置的材质系统,一层层把颜色上回去,以熟悉一些基本的工作流。头盔模型使用的是标准材质,背后是目前业界普遍使用的基于物理的渲染模型(PBR),是一套很好地权衡了高效和美观的算法。 Creator 3D 实现小姐姐高光发丝,这帮引擎大佬真的是服了!_空间数据_04

 

当算法框架足够合理时,视觉上的“美观”很大程度上就取决于“信息量”了,这个模型本身是专门为展示 PBR 各个层级特性而制作的,可以看到,随着每一层贴图信息的加入,它们共同融合成了一套统一和谐的效果。

 

当然材质系统的任务是提供方便的定制化,所以并不和某套渲染模型挂钩,在同样的系统下,我们可以很方便地提供比如卡通渲染的支持。

 

Creator 3D 实现小姐姐高光发丝,这帮引擎大佬真的是服了!_数据_05(致谢:卡渲框架设计受 UTS2 启发)Deconstruction这里要提一下,材质系统是 Cocos 针对 Creator 3D 架构设计的,但目前 Creator 2D 从 2.1.1 版本开始同步引入了材质系统,已在使用其中大部分的前端设计,并针对渲染后端做了适配和优化,所以今天分享的内容对两款产品均适用。

 

首先既然定位是小而精,那么需要明确,我们希望做到的,和我们没有打算做到的(至少现阶段而言)我们希望做到:
  • 对 TA:全自动处理书写 shader 过程中琐碎易错细节的趁手有力的工具

  • 对 TA:任何内容与算法都应不受阻碍地完成

  • 对美术:以最便利、符合直觉的方法接收 TA 的产出,无缝连接下一步的创作

 

现阶段不打算做到:
  • 工业级别的 shader 语言转译/优化器

  • 使零程序基础的美术也能加入 shader 创作流程

 

我们希望在 TA 和美术各司其职,各自发挥优势的过程中,引擎和编辑器能够首先成为双方合作的坚实基础和便利桥梁。最终设计也是这点的直接映射,一个非常小巧高效的系统,各自有着明确的目标和能力:Creator 3D 实现小姐姐高光发丝,这帮引擎大佬真的是服了!_小游戏_06
  • EffectAsset 是由 TA 或图形程序设计制作,提供定制化的着色机制和数据接口

  • Material 是由美术创建,会被大量用在实际游戏场景中的资源实例,负责提供所有实际使用的数据

  • 所有 EffectAsset 层提供出的接口都会以最自然便利的方式在 Material 面板上呈现

 

这里举两个小细节,更多信息及接口文档参考 [3]
  • Shader 中所有 uniform 变量声明都会在资源导入时解析依赖宏,并直接映射到编辑器的材质 Inspector 上

 

Creator 3D 实现小姐姐高光发丝,这帮引擎大佬真的是服了!_空间数据_07

 

TA 只需要按照标准 GLSL 语法完成目标逻辑,大部分繁琐易错的胶水代码可以全部通过固定解析流程自动对接。
  • 对于需要自定义这个过程的需求,有完善的 uniform 重定向,及类似 ccclass 的定制系统 [5]

 

Creator 3D 实现小姐姐高光发丝,这帮引擎大佬真的是服了!_数据_08比如这里红框内的四个属性,在 Shader 中其实是同一个 vec4 的不同分量(参考 [4] 关于 UBO 成员布局的考虑,为了达到最佳性能确实会出现类似需求),但为了使用起来更符合直觉和便于调整,在 Effect 中为每个分量单独增加了新的属性,使得它们可以被独立编辑,无论是在 Inspector 还是代码中直接调用。

 

现在我们清楚了材质使用层面的设计,让我们继续深入底层,来看看在 Effect 层面我们有哪些实用的设计。这是一份标准的 Cocos Effect 文件示例(也是引擎内置天空盒使用的 Effect):Creator 3D 实现小姐姐高光发丝,这帮引擎大佬真的是服了!_数据_09

 

在声明式语法的大框架下,已经可以看出一些有趣且实用的选择,它的主要特性有:
  • 统一的 Shader 语法(GLSL 300 ES)

  • 多 Technique 多 Pass 支持

  • 标准头文件库、Include 机制

  • 常规语法自动 Fallback GLSL 100

  • 进阶语法通过 __VERSION__ 宏手动 Fallback

  • 大量引擎、渲染管线、运行平台相关的类型检查

  • 定制化 Inspector 对接集成

 

这背后是一直在不断完善的 Cocos Effect 语法和编译器,从设计之初理念就忠于 C 语言设计哲学,我们致力于提供一套明确清晰的 Shader 书写工具集,使得每一个细节的控制都是透明可见/可推导的。更多 Effect 相关具体特性这里不再详细解析,可移步参考官方文档 [4]。

 

Demonstration恭喜大家坚持到了现在,我们终于要进入今天的案例环节了。今天的案例是头发高光的计算。无论在现实生活还是各类动漫游戏作品中,头发高光都是头发不可或缺的一项标志特性,也非常讨人喜爱。Creator 3D 实现小姐姐高光发丝,这帮引擎大佬真的是服了!_空间数据_10素材来源于《Blue Reflection》,仅作学习交流使用

 

那么如何在游戏项目中实时计算这样的高光呢?

 

我们先来尝试简化问题,这里是一个使用标准卡通渲染的球体(下图),它的高光是按标准 Blinn-Phong 模型计算的,可以看到只在光源的理想反射方向可见,就是一个圆点。

 

Creator 3D 实现小姐姐高光发丝,这帮引擎大佬真的是服了!_3d_11但如果我们把这个球体近似地看成角色头发的话(如上图右下角示意),其中最显著的特征是,我们希望这个高光不是一个圆点,而是……一个圈。我们今天案例解析的重点,就是如何从物理上理解,并实时近似计算这个高光圈。

 

参考学界的一些相关论文,这个问题的基本思路是把每根发丝近似地看成是一个个很小的半透明圆柱体,而可以证明 [1],在理想圆柱体上,对平行光而言,它的所有出射光线都在一个和理想反射方向倾角相同的圆锥上(如下图中间示意)

 

Creator 3D 实现小姐姐高光发丝,这帮引擎大佬真的是服了!_空间数据_12

 

我们看到的头发上连成一圈的高光,就是因为这个特性而产生的。(联系下现实生活的话,其实是发质越好发丝越接近圆柱体,所以高光越明显)所以有了基本的模型,我们来扩展一下基本的 Blinn-Phong 高光计算,让它从单一方向变成到整个圆锥,就应该能在这个球体上看到变化。

 

可以很快发现,这个圆锥中轴与发丝方向平行,圆锥大小只是由一个与发丝方向的夹角决定的,那如何取这个夹角呢?

 

这样的需求,一般会使用模型的切空间数据来辅助计算,我们先来看一下这个球体的切空间数据。Creator 3D 实现小姐姐高光发丝,这帮引擎大佬真的是服了!_数据_13

 

这里做了切空间数据的可视化,图中球体上黄色线段就是每个顶点的副切线,可以看出也是我们需要的“发丝方向”。当然对于更一般的头发模型来说,这个方法会对模型的 uv 展开方式有要求,要求头发部分的 uv 纵轴应当与发丝方向基本一致;不过好在这种展开方式相对普遍,制作美术资源时也经常这样做,所以适用性还是较为普遍的。

 

Creator 3D 实现小姐姐高光发丝,这帮引擎大佬真的是服了!_数据_14

 

我们在 shader 中可以很方便地把每个片段计算 BRDF 常用的向量(R、V、N、H、L)和副切线 (T) 取到,根据论文 [2] 中的思路,这里我们也直接用一个 gaussian 来做近似,那么可以基于 Phong 着色模型,写一个最符合直觉、易于理解的版本:Creator 3D 实现小姐姐高光发丝,这帮引擎大佬真的是服了!_3d_15其中 mr 就是通过 gaussian 算出的连续的高光亮度,通过一个 step 函数切出卡渲效果的硬边。在此基础上可以进一步尝试优化为 Blinn-Phong,写出来要比想象中更高效一些:

 

Creator 3D 实现小姐姐高光发丝,这帮引擎大佬真的是服了!_空间数据_16这里 3 和 6 其实都是用户可调参数,为了对接原有卡渲参数这里调整合适后硬编码进来,最后运行效果是这样:

 

Creator 3D 实现小姐姐高光发丝,这帮引擎大佬真的是服了!_3d_17这样我们就有了一个适用于发丝的卡渲 shader 了,调整一下还可以控制高光宽度和位移(想一想位移参数应该怎么加)。如果从背光面观察可以看到还是有一部分不太真实的反射,这是因为我们没有考虑方位角维度上的反射强度差异。并且像图中所示那样,我们其实只非常粗略地计算了完整发丝高光模型的主高光,即反射部分,还有更多的散射项没有考虑。这里不再深入介绍,感兴趣的同学,推荐阅读下面两篇参考论文 [1]、[2] 深入了解,并尝试自己实现更真实完整高光的效果。