找回密码
 立即注册
查看: 346|回复: 3

3DS MAX、Substance Painter和Unity3D的渲染效果同步

[复制链接]
发表于 2022-9-1 15:56 | 显示全部楼层 |阅读模式
迁移自本人同名新浪博客,原文发表于2019年。
  游戏的美术效果都是以引擎为最终目标,这里以unity3d为例,但是一些美术资源制作步骤却是在第三方软件完成的,比如绘制某些辅助贴图、编辑顶点法线、展分UV等等,而且在很多情况下进行这些步骤的同时必须要看到引擎里的最终效果才能知道具体该怎么做,因此需要把unity3d里的渲染效果同步到第三方软件,使之在这些软件中的每一步调整都能得到一个对最终效果影响的实时反馈信息,以方便资源制作。这里的第三方软件以资源制作流程中常用的Substance Painter和3DS Max举例。SP的shader是用glsl写的,而Max的shader是用hlsl写的,而这两种语言从语法上跟unity3d的cg极为相似,也为此功能的实现提供了不少方便。这里就从PBR和CelShading方面入手说明如何在Substance Painter和3DS Max里实现和unity3d里一模一样的渲染效果。
一.Substance Painter

  首先说一下SP,最基本的用途就是配合unity的standard shader制作metallic、roughness、ao等贴图,但SP默认的pbr-metal-rough shader的效果和standard 的效果却不一致,如下图:


  如果一方按照SP的默认效果出图,而另一方在unity里验收,中间的差距只能靠二次出图了——把图片在photoshop里人肉矫正,这个流程问题是很大的。因为两者默认shader的设计思路根本不是一回事,所以这次差距小但是下次的差距就可能会很明显;这次对某些图片这样重新调了一下,下次调的方式或调哪张图片就可能不一样了,这中间是不存在转换规律的。一种正确的解决办法是在SP里实现跟unity的standard相同的效果。这种技术在上海某些较有名的美术外包公司其实很早很早就已经比较完备了,现在在一些游戏大厂流程上也会强制要求SP里美术画的每一笔必须和最终引擎里呈现的效果一模一样。当然是否真的需要严格意义上完全一致这个还需要考虑可行性,因为首先技术上存在个别地方同步有困难,比如投影等方面;再者有些技术从理论上能实现完全同步但是对美术操作上或其它方面有额外要求,这时候其实可以去考虑用一种近似方式但是副作用很小会不会更加实用些。
  根据简化版的渲染方程:


可以看出要用正确运用公式计算PBR必须用离线渲染的raytracing。在实时渲染里,unity里模拟思路是把其中的光源人为的划分为主光源,一般是一盏DirectionalLight,和其它光源,统称为环境光源,一般用IBL处理。并依据反射光线的方向特点又细分为漫反射和镜面反射。即:
光照=主光源光照+环境光源光照=主光源漫反射+主光源镜面反射+环境光源漫反射+环境光源镜面反射
  其这样划分的一个好处就是可以在主光源的光照部分应用较为复杂的光照模型,而IBL部分就相对简单些(通过IBL的卷积一篇可知unity的IBL实际是用的Lambert和Phong的光照模型)。
  Unity主光源的BRDF在standard里采用的是:
fr =kd fdisney + ks fcooktorrance\\
其中cook-torrance里对高光形状起主要作用的D项用的是流行的GGX,下面是自己顺便做的一组GGX(黄)、BlinnPhong(红)、Beckmann(蓝)函数曲线及效果对比:


  由图可见,GGX最明显的特点就是由长长的拖尾效果。另外还可以发现这里所有的函数曲线和论文里的不太一样,这也是在roughness方面把unity的镜面反射算法写到SP的shader时需要注意的地方,解释一下:漫反射disney算法需要一个roughness输入,镜面反射cook-torrance算法也需要一个roughness输入,而这两个roughness的含义是不太一致的,但它们之间是可以换算的而且关系很简单——平方关系,所以也就不需要做两张roughness贴图。那SP按谁输出的roughness呢?SP输出的是disney算法需要的输入,即disney原则的roughness。因此unity里计算镜面反射时需要把SP输出的这个roughness进行一次平方转换,函数PerceptualRoughnessToRoughness就是干的这个事情。因为通常游戏项目里roughness的来源都是SP的输出,所以上图我做的镜面反射D项的曲线反映的是跟disney原则的roughness的关系。SP就没有主光源这个概念,所有的光照全部来源于那张环境图,其中SP里镜面反射的复杂度还不是个定值,而是O(n),n是SP里用户的SHADER PARAMETERS->Common Parameters->Quality设置,即这个数值会导致镜面反射计算量成其倍数增长。投影和AO贴图的作用在SP里也是一样的,两者的乘积代表AO,但是SP里镜面反射和漫反射用的不是同一个AO——金属度越高,粗糙度越低,会导致镜面反射的AO会越小,即SP认为极为光滑的纯金属是不受OA影响的。基于上述,对于一个纯非金属,AO贴图画成纯黑的地方最后的颜色也一定是纯黑的(这里不考虑除了反射以外的现象),如果不是纯黑的说明SP设置里SHADER PARAMETERS->Common Parameters->AO Intensity没有给成1。而在unity里给一张纯黑AO贴图会发现依然有光照,这是因为为了能自圆其说,unity设定实时阴影只能遮挡主光源光照、AO只能遮挡环境光照。Unity这种强制划分主光源和环境光源的做法可能会导致一些渲染现象跟现实中有出入,但综合下来这种处理思路是一种性能比较廉价的能较好表现质感的处理方案,也是各游戏引擎常用的做法。在金属度方面,unity和SP都是纯金属没有漫反射,但纯非金属都还会有一点镜面反射,区别之一就是SP还可以用一张specularlevel贴图控制不是纯金属的高光颜色(纯金属的高光颜色就是albedo)。至于SP里shader的具体书写主要就是一个不同着色器语言的翻译过程,这里我做了一个案例:
  这是unity默认的standard shader的分解效果:


  这是在SP里做过和unity渲染效果同步之后的分解效果:


  可见每个光照部分基本都实现了渲染效果同步。
  两个软件的最终效果对比:


  以上介绍就是在PBR方面,如何在SP里实现跟unity的standard shader一样的效果。当然这是一个普适的PBR shader,目的是能准确的在SP里制作unity需要的metallic、roughness、ao贴图,除此之外引擎里其它自定义的PBR shader也都可以在SP里实现,比如下面是在SP里实现的具有SSS效果的皮肤shader,跟unity效果同步后就可以在SP里制作thickness、specularlevel、glossness等当前shader在unity需要的贴图。


  当然,除了PBR以外,CelShading项目的shader也可以把unity的渲染效果同步到SP里以便于相关辅助贴图的绘制,CelShading方面在 结合SubstancePainter制作《GuiltyGear》角色流程已经实现过,这里就不重复了。
  二.3DS Max

  首先谈谈PBR方面。在Max里实现unity standard的效果可以倒是可以,但是实践意义并不太大。明确一下我们在Max里同步unity渲染效果目的是服务于那些在Max中对最终效果有直接影响但具体影响的结果又不太好想象的操作。比如头发的各向异性高光的处理,如果头发出于美术风格等原因用模型体块做的话(非透贴插片),高光的效果是跟UV有关的,所以我们要在Max里实现和unity里一模一样的头发各向异性高光效果,使之在Max的UV编辑框里每移动一个点都能实时看到这步操作对高光的影响,以此来便于在Max里编辑头发UV(当然也可以走SP那套流程用flowmap处理,选择上需要具体情况具体分析)。下面是在Max里的实现《守望先锋》半藏的头发高光:


  在CelShading方面,避免不了要在Max调整模型顶点法线,因为在没有normalmap的情况下,顶点法线对CelShading中的非常重要明暗交界线的效果起到了关键作用。我们希望在Max里编辑顶点法线的同时,也能同时看到这根法线转了这下之后到底起到了什么影响。当然这还需要在Max里新建一盏target light,用其方向在shader里模拟unity里directional light的方向,以便于调整顶点法线后时常转一下target light来观察法线改变后的明暗交界线的变化。如果不做效果同步的话,盲转法线是很难很难想象这根法线究竟应该旋转到一个什么方向才算合适。下面就是在Max里实现了unity里看到的《崩坏3rd》的光照效果:


  效果同步后,就可以在Max里有目的的调整模型的顶点法线了:


  关于CelShading模型顶点法线的调整除了手动单根旋转之外还得用封套转写的方式,即另做一个简模并把其法线转写到目标模型上。能实现这种功能的3D软件有很多,比如在前文提到的SoftImage(不过在《Guilty Gear Xrd-SIGN》面世2年后就已经停更了,现在基本算是过气软件了),其它的像Modo之类的也可以实现,我个人习惯是用Blender。然而这个流程在实际应用中好景不长,因为第三方软件的法线转写多是以模型为单位的,而实际中几乎没有哪个模型需要把整个模型的所有顶点的法线全部转写。相反,角色的身体装备结构都是像一块块积木堆起来的那样理解,每个积木都是些简单的几何体,比如这里理解成个球、那里理解成个圆柱等等,积木之间还有些不好概括的形状需要单调。因此我们在Max里如果要借助第三方软件以模型为单位完成的话流程就是这样子:Detach->从Max导出并导入第三方软件完成后在再从其中导出并导入Max->Attach->Weld,频繁的Detach+Attach操作降低了这个流程可行性。所以最好的解决方案还是要在Max里用maxscript写个插件完成这个功能,即模型中哪一小块需要顶点法线转写就针对这个局部做个简模,用插件自动计算完成法线朝向的修改,如下图以琪亚娜的辫子示意一下:


  当然理论上是通过选择法线进行这种局部操作的,但是我在maxscript的函数里没找到怎么根据所选择的法线逆推出这根法线所在的是哪个顶点(直觉上我觉得这个问题肯定是有解决办法的只是我没有找到,欢迎指点),所以最后写的插件是让用户在Edit Poly里选择顶点,然后改变所选择的顶点的法线。
  此外,做了unity效果的同步后,在Max里也可以边看着最终的渲染效果边刷顶点色了。当然流程上也可以在unity里通过写刷模型顶点色的插件完成,特别是当顶点色是用来控制CelShading描边效果时,因为第三方软件的shader一般都是只留出PS的部分供用户自定义。不过引擎里的这个流程会牵扯到编辑完之后的数据保存及模型修改后的数据复用问题。选择上也是需要具体情况具体分析了。
  本文更加侧重的是提出一种改进美术资源制作流程的思想,至于具体的技术是会随着时间发生变化的,比如这里举例用的Max、SP,实际中有可能需要同步的是Maya或者是一些其它软件都很难说,引擎可能也不是unity,而是UE4,或者将来CE出4了也都说不准,至于shader那更是因项目而异了,碰到个非常另类风格化项目都有可能。总之要想好什么时候才需要和引擎做效果同步(从这个效果的应用范围、对应的美术操作等方面分析),以及做好同一个shader多个翻译版本的维护工作。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
发表于 2022-9-1 16:05 | 显示全部楼层
请问sp里间接光高光怎么和unity对齐的啊?unity是直接采样一个离线积分后的cubemap,sp默认是暴力算一张背景图。这两个算法不一致啊。[捂脸]
发表于 2022-9-1 16:10 | 显示全部楼层
Unity的cubemap资源肯定是不能直接导入SP的,这很正常因为现在市面上就没有所谓的通用的3D图片格式。cubemap需要卷积完后并把结果从cubic space转换到spherical space,即通用的2D图片,就可以用于SP了。
发表于 2022-9-1 16:14 | 显示全部楼层
为什么非要坚持“一方按照SP的默认效果出图,而另一方在unity里验收”这种明显会造成问题的流程方案?要求出图方按照unity默认管线效果出图不就好了么……
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-9-22 01:34 , Processed in 0.095337 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表