外观
SPCustomShader
摘要
统一UE4/5和SubstancePainter的表现效果可以辅助提升美术设计师在SP中的绘制效率,达到所见即所得的制作体验。效果统一有多个环节需要处理,本文结合Substance提供的Shader API:Shader API | Substance 3D Painter (adobe.com),梳理自定义shader的流程。
框架
SP的Shader使用GLSL语言,且高度封装,只能编写像素着色器的一部分,类似于Unity的Surfeace Shader,好在提供了一系列的库函数和结构体。其着色入口为shade函数,例如写一个HelloWorld:
void shade(V2F inputs)
{
diffuseShadingOutput(vec3(1.0, 0.0, 1.0));
}
将此段函数复制粘贴到一个**.glsl**后缀的空文件中即编写完一个SP shader,随后将其导入SP并在着色器设置中启用,就能看到“美丽”的紫色了。
路径
先了解一下SP的Shader文件组织结构,所有Substance提供的Shader均存放在如下目录:
Substance Painter\resources\shelf\allegorithmic\shaders
另外还有一个目录:\Substance Painter\resources\shader-doc,存放的不是Shader本体而是着色器说明,也就是离线的Shader API文档。
此外,SP使用框架存储配置文件,导入的Shader也会被存储在当前使用的框架的根目录里,例如:D:\Document\Allegorithmic\Substance Painter\shelf\shaders
导入
SP有多种方式导入Shader文件:
将编写完成的Shader文件放入Shader根目录。
- 这种方式适合项目美术设计师,每次打开SP都会自动加载,无需其他操作。
- 每当有Shader更新都需要手动替换并重启SP。
将Shader文件拖入SP,并导入到当前文件。
- 这种方式适合TA或其他人员编写调试。在编辑器中保存更改之后,右键重载即可实时更新。
- 导入到Self展架或是导入到当前会话均无法直接重载。
- 不对其他文件生效。
结构
以SP自带的pbr-metal-rough.glsl为例,分析各个组成部分:
库函数
首先导入了库文件。为了避免编写大量的着色器代码,Substance提供了一个小巧但实用的函数库。不过目前来说,函数库不支持自定义。
//- Import from libraries.
import lib-sss.glsl
import lib-pbr.glsl
import lib-emissive.glsl
import lib-pom.glsl
import lib-utils.glsl
lib-alpha.glsl : 透明度相关函数
lib-bayer.glsl : contains bayer matrix helpers
lib-defines.glsl : 常用数学常数和渲软模式定义
lib-emissive.glsl : 自发光特性函数
lib-env.glsl : 环境光相关计算
lib-normal.glsl : 法线相关计算(包括混合,生成,解压,转换等)
lib-pbr.glsl : PBR相关计算
lib-pbr-aniso.glsl : 各项异性的PBR计算
lib-pom.glsl : 视差相关函数
lib-random.glsl : 噪声计算函数
lib-sampler.glsl : 包含各种纹理的采样器设置和采样函数
lib-sparse.glsl 包含稀疏纹理的采样和辅助函数(也就是虚拟纹理)
lib-sss.glsl : 次表面散射的相关计算函数
lib-utils.glsl : 包含色彩相关的实用函数(色彩空间转换,色调映射等)
lib-vectors.glsl : 包含当前框架的各种矢量计算函数,以及空间转换函数
Metadata
用于IRay的MDL和自定义UI的QML,使用**//😗* 作为开头标识符,同时约定使用**//-** 作为普通注释开头,例如:
//- Declare the iray mdl material to use with this shader.
//: metadata {
//: "mdl":"mdl::alg::materials::skin_metallic_roughness::skin_metallic_roughness"
//: }
MDL
MDL是nVidia定义的材质语言,参见:Material Definition Language | NVIDIA。SP使用MDL作为IRay的材质定义。
QML
QML是Qt定义的UI语言,参见:Qt QML 5.15.8。SP使用Qt开发界面,因此可以使用QML重写Shader部分的面板。
参数定义
这部分的参数主要提供给SP的Shader面板使用,或是用于绑定纹理。SP使用虚拟纹理显示视口中可见的纹理部分。
Engine Params
SP提供了很多内置的参数,比如纹理、矩阵、摄像机位置以及相机方向等等,参见:All Engine Params - Shader API | Substance 3D Painter (adobe.com)。和Metadata部分类似,这些参数UI部分使用**//😗* 作为开头标识符,然后下一行为参数声明:
// 在lib中定义了SampleSpares的数据结构
import lib-sparse.glsl
//: param auto TEXTURE_TAG
uniform SamplerSparse uniform_tex;
//- 声明长宽比
//: param auto aspect_ratio
uniform float uniform_aspect_ratio;
Custom Params
类似Unity,SP也支持自定义的参数,同时也能定义其在SP面板上的显示行为,只不过语法略微复杂,参见:All Custom Params - Shader API | Substance 3D Painter (adobe.com)。一些常用的UI控件如下:
//- 颜色的声明
//: param custom { "default": 0, "label": "Color RGB", "widget": "color" }
uniform vec3 u_color_float3;
//- SpinBox的声明
//: param custom { "default": 0, "label": "Int spinbox" }
uniform int u_spin_int1;
//- 滑条的声明
//: param custom { "default": 0, "label": "Float4 slider", "min": 0.0, "max": 1.0, "step": 0.02 }
uniform vec4 u_slider_float4_stepped;
//- Bool 变量
//: param custom { "default": false, "label": "Boolean" }
uniform bool u_bool;
//- 自定义采样器
//: param custom { "default": "", "default_color": [1.0, 1.0, 0.0, 1.0], "label": "Texture" }
uniform sampler2D u_sampler1;
//- 枚举的声明
//: param custom {
//: "default": -1,
//: "label": "Combobox",
//: "widget": "combobox",
//: "values": {
//: "Value -1": -1,
//: "Value 0": 0,
//: "Value 10": 10
//: }
//: }
uniform int u_combobox;
渲染设置
这部分可以配置渲染状态参数,参见:All Rendering States Params - Shader API | Substance 3D Painter (adobe.com)。例如背面剔除的控制如下:
//- Cull back faces
//:state cull_face on
//- Draw front and back faces
//: state cull_face off
像素着色
完成了前置的设置之后,可以开始动手写着色部分了。SP的着色入口为:
void shade(V2F inputs);
其输入和输出为:
struct V2F
{
vec3 normal;
vec3 tangent;
vec3 bitangent;
vec3 position;
vec4 color[1]; // 顶点色 0 (color0)
vec2 tex_coord; // UV0
SparseCoord sparse_coord; // 用于虚拟纹理采样的UV
vec2 multi_tex_coord[8]; // uv0-uv7
};
// 像素透明度,默认值: 1.0
void alphaOutput(float);
// 漫反射照明,默认值: vec3(0.0)
void diffuseShadingOutput(vec3);
// 镜面反射照明,默认值: vec3(0.0)
void specularShadingOutput(vec3);
// 像素自发光,默认值: vec3(0.0)
void emissiveColorOutput(vec3);
// 反照率值,默认值: vec3(1.0)
void albedoOutput(vec3);
// 此表面散射值,参看SSS的库函数,默认值: vec4(0.0)
void sssCoefficientsOutput(vec4);
SP中最基本的像素着色方程如下:
emissiveColor + albedo * diffuseShading + specularShading
综合
结合之前的内容,熟悉Unity的TA应该很快就能实现ToonShading了。总体来讲,SP的Shader并没有那么开放,一些特殊功能或许难以实现,但DCC软件和UE的完全一致本身也不太现实,效果接近即可。