• 在 Substance Painter中实现Unity Standard Shader


    由于有需要在Substance Painter中显示什么样的效果,在Unity就要显示什么样的效果的需求,最近研究了几天,总算在Substance Painter中实现Unity standard的材质的渲染效果。具体效果如下:
    在Unity中:
    在这里插入图片描述

    Substance Painter中:
    在这里插入图片描述
    相识度能够达到百分之八九十吧。主要是Unity的项目使用的是Gamma颜色空间,还是有很大的出入,而且还不好修改。

    这一篇不再讲基础的如何在Substance Painter中自定义Shader了,不了解的可以翻一翻我之前写的。

    版本相关

    Unity 2019.4.40 内置渲染管线 Gamma颜色空间
    Substance Painter 9

    痛点

    1. 阴影问题,在sp里面,阴影是取环境光里面最亮的点作为主光源位置,这个我的解决方案就是自己调,设置主光源朝向配置项,可以同步unity和sp里面的主光源朝向,那么自动生成的shadow也是一个方向的。
    2. 间接光源的镜面反射,其它文章里面也说这个问题了,大都没有很好的解决方案,我这里的解决方案是通过shader去实现动态Mipmap实现,作为调试最终效果时使用。

    接下来梳理一下实现过程

    模型朝向同步

    两个软件使用的坐标系不同,unity是左手坐标系,而sp是右手坐标系,解决方案是,在unity里面在y轴旋转180度。
    在这里插入图片描述

    保证天空球的位置正确

    在unity里面,我专门搭建了一个测试环境,环境反射,直接设置了一张环境反射Cubemap
    在这里插入图片描述
    在sp里面,需要打开显示设置,然后设置背景贴图,背景曝光设置0,背景旋转设置为270,这样设置完,两个场景去采样环境全景图时,采样的位置是一致的。
    在这里插入图片描述
    贴图直接用的sp里面的,位置在项目文件夹下面
    在这里插入图片描述

    相机同步

    在unity里面使用默认的透视相机,Field of View 为60
    在这里插入图片描述
    在sp里面,视角设置60度,与unity相同,记得把后期特效关闭
    在这里插入图片描述

    主光源同步

    主光源同步我的思路是,在SP里面设置主光源参数,主光源参数需要一个旋转参数,主光源颜色,以及强度,主光源默认是方向光。
    在这里插入图片描述
    在SP里面,我们需要先在shader里面定义参数
    在这里插入图片描述
    显示效果
    在这里插入图片描述
    接下来比较重要的就是,在SP里面将主光源的旋转,修改为朝向,实现函数这里要感谢文心一言,它总算干了一件正事
    在这里插入图片描述
    由此获得主光源朝向。

    定义一些Unity常量

    要同步shader,需要将一些常量设置
    在这里插入图片描述
    SP是线性空间的,所以Standard里面一些Gamma相关的代码自动摒弃。
    贴图直接使用内置的方法去获取
    在这里插入图片描述
    还有一些和Standard对应的参数
    在这里插入图片描述
    间接光漫反射的球谐光照参数,是直接写死在shader里面的
    在这里插入图片描述
    还有像在unity里面常用的一些函数,比如saturate和lerp,都直接定义出来
    在这里插入图片描述

    从SP导出贴图设置

    我的设置是导出四张贴图,以后需要再加,分别是Albedo贴图,Normal,Emissive,MRA
    在这里插入图片描述
    MRA贴图由三张贴图拼接而成,三个通道分别是Metallic,Roughness,AO

    在unity里面,也重写了FragmentSetup函数,修改了里面一些逻辑
    在这里插入图片描述
    本来standard比较笨重,所以,我们可以将一些没必要的设置改掉,比如工作流我确定使用金属工作里,那就不需要判断了,直接使用金属工作流
    在这里插入图片描述
    在SP里面,直接使用内置库函数去获取贴图,思路直接按照standard的思路来即可。
    在这里插入图片描述

    实现直接光照

    直接光照在standard里面有多种方式,为了保证效果,我这里直接使用了效果最好,渲染最昂贵的双向表面分布函数实现,代码渲染逻辑没动,还是standard的哪一套
    在这里插入图片描述
    在SP里面,直接复制过来即可,除了一些没用的代码删除掉了,缺少什么函数,在unity复制过来改改就能用,glsl和cg区别不大。
    在这里插入图片描述
    最后,输出时,我只使用了内置diffuseShadingOutput函数输出渲染。
    在这里插入图片描述
    同样参数下,两个模型的渲染效果
    在这里插入图片描述
    在这里插入图片描述

    实现间接光漫反射

    间接光漫反射都是直接使用SH球谐光照,我在SP里面是直接写死的参数,参数是在unityframedebug里面抄的
    在这里插入图片描述
    直接将它抄给SP
    在这里插入图片描述
    实现很简单,直接用standard的函数实现即可
    在这里插入图片描述
    在这里插入图片描述

    在这里插入图片描述

    实现间接光镜面反射

    间接光镜面反射是这里面最难实现的,主要还是mipmap的问题,如果粗糙度为0,也就是最光滑的平面的时候,可以看到,获取到的镜面反射的效果是一致的。
    Unity Roughness=0
    在这里插入图片描述
    Substance Painter Roughness=0
    在这里插入图片描述
    如果Roughness加大,mipmap层级上去以后,区别就很明显了。
    Unity Roughness=0.5
    在这里插入图片描述
    Substance Painter Roughness=0.5
    在这里插入图片描述
    造成这样的结果的原因是两个引擎内部的对Cubemap的mipmap采样造成的,看一下Roughness=1的结果,更加明显。
    Unity Roughness= 1
    在这里插入图片描述
    Substance Painter Roughness=1
    在这里插入图片描述
    在这里,我还是先列一下实现方式,两个引擎都是通过采样环境反射球来实现的环境光的镜面反射。unity里面是通过Unity_GlossyEnvironment函数实现,支持两个Cubemap采样结果混合。
    在这里插入图片描述
    在Substance Painter里面,则是直接使用的SP内置的函数库 lib-env.glsl,里面有个方法envSample,传入方向和mipmap即可实现
    在这里插入图片描述
    在这里插入图片描述
    粗糙度转Mipmap和Unity的也有所不同,这个代码抄至 nagnae blog

    #define UNITY_SPECCUBE_LOD_STEPS_CUSTOM 6
    real PerceptualRoughnessToMipmapLevel(real perceptualRoughness)
    {
        half mip = perceptualRoughness * (1.7 - 0.7 * perceptualRoughness);
    	//mip = pow( mip, 0.53 );
    	mip = pow( mip, 0.4 );
    	//mip = pow( mip, 0.3 );
    	mip *= 0.97;
    	
    	//float unity_environment_lod_count = float(unity_specularprobe_lod_count);
    
    	#if 0
    		 float mipmap_end = environment_max_lod - environment_mipmap_bias;
    		 float mipmap_start = mipmap_end - UNITY_SPECCUBE_LOD_STEPS_CUSTOM;
    	#elif 0	
    		 float mipmap_start = max( 0, environment_max_lod - unity_environment_lod_count );
    		 float mipmap_end = min( unity_environment_lod_count, mipmap_start + UNITY_SPECCUBE_LOD_STEPS_CUSTOM );
    	#elif 0
    		 float mipmap_start = 0;
    		 float mipmap_scale = environment_max_lod / unity_environment_lod_count;
    		 float mipmap_tail = ( unity_environment_lod_count - UNITY_SPECCUBE_LOD_STEPS_CUSTOM ) * mipmap_scale - 1;
    		 float mipmap_end = min( environment_max_lod, environment_max_lod - mipmap_tail*1.2 );
    	#elif 1
    		 float mipmap_start = 0;
    		 float mipmap_end = environment_max_lod - 1.5;
    	#endif
    
    	return mip * ( mipmap_end - mipmap_start ) + mipmap_start;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    如果按照Substance Painter 默认的效果,结果是不理想的,环境反射越强烈,效果区别越明显,所以,我的解决方案,就是在shader里面进行一次mipmap,这是我在learnopengl学习的结果,地址:https://learnopengl.com/PBR/IBL/Specular-IBL,我实现的原理也是粗暴的进行多重采样
    在这里插入图片描述
    每个片元要进行1024次采样,这样性能很低,所以,我增加了一个配置项,可以进行一次采样,如果开启配置,实现多重采样,实现Unity内的那种顺滑的mipmap
    在这里插入图片描述
    在Roughness=0时,效果还是一致,这里不再展示。
    Unity Roughness= 1
    在这里插入图片描述
    Substance Painter Roughness=1
    在这里插入图片描述
    可以看的出来,在Roughness为1时,颜色基本上相近了,只有高光范围还是有一些不同,那先这样,这也算一种解决方案。如果有更好的解决方案,欢迎小伙伴们告诉我。
    Unity Roughness=0.5
    在这里插入图片描述

    Substance Painter Roughness=0.5
    在这里插入图片描述
    最终,实现了所有的直接光漫反射,直接光镜面反射 和间接光漫反射 间接光镜面反射,我们最后按照Unity的standard将颜色合并到一起,就实现了对应的效果。
    在这里插入图片描述
    Substance Painter Combie Roughness = 0.5 Metallic = 1
    在这里插入图片描述

  • 相关阅读:
    [学习笔记]python绘制图中图(绘制站点分布图)
    专利申请流程,申请专利去哪
    Prometheus与Grafana监控SpringBoot应用
    超市火灾烟气蔓延及人员疏散的matlab仿真模拟
    Python魔法:20个让你编程事半功倍的奇淫技巧(建议收藏)
    【JavaEE进阶系列 | 从小白到工程师】JavaEE中的迭代器,并发修改异常与增强for循环,一文上手使用
    JVM学习(宋红康)之运行时数据区之方法区
    大学生简单环保环境静态HTML网页设计作品 DIV布局环境介绍网页模板代码 DW学生环境网站制作成品下载 HTML5期末大作业
    三数之和(python)
    【Qt】一文总结Qt5.15的在线安装
  • 原文地址:https://blog.csdn.net/qq_30100043/article/details/133143970