学习在 Substance Painter 中添加自定义的Shader

您所在的位置:网站首页 sp加材质 学习在 Substance Painter 中添加自定义的Shader

学习在 Substance Painter 中添加自定义的Shader

2024-06-22 19:09| 来源: 网络整理| 查看: 265

目标

在上一篇中我对SubstancePainter最基本的流程与界面做了学习。我了解到在Texture Set List窗口中罗列了当前所有的“贴图集”,而一个“贴图集”实际上对应了模型的一个部分,而这一个部分对应了一个Shader。

对于Texture Set List所选中的部分(下图是“arm_handle”),会在Shader Settings窗口中显其Shader相关的信息,首要注意的是Shader种类(当前是“pbr-metal-rough”),点击它可以选择其他的Shader种类,他们都算作Shelf中的资源,在安装目录\resources\shelf\allegorithmic\shaders下可以找到对应的文件: 在这里插入图片描述 正如官方文档:Shader API - Substance Painter所说:

Substance Painter uses shaders to render materials in its realtime viewport. It is possible to write custom shaders to implement new behaviors or to simply make the viewport match other renderers.

Substance Painter 在实时视窗中使用shader来渲染材质。你可以写自定义的Shader来实现新的效果,或者使其与其他渲染器效果匹配。

本篇的目标是,结合官方文档来学习以下内容:

创建一个自定义Shader的流程是怎样的。如何与Substance Painter集成?比如怎样从渲染引擎中获取数据,怎样设置数据,或者有哪些与引擎结合的功能。一个稍复杂点的范例。

另外值得一提的是,官方文档也可在软件内直接访问(这样比较快) 在这里插入图片描述

创建一个自定义Shader的流程

流程上是很简单的。

In Substance Painter, you can write your own shaders in GLSL. We allow you to write only a portion of the fragment shader, which is sometimes called a surface shader.

在SubstancePainter中,你可以使用GLSL来写你自定义的Shader。SubstancePainter 让你只写像素着色器中的一部分,这部分有时叫做“表面着色器”。

下面就写一个最简单的吧,我创建了一个yaksue-test.glsl文件,内容简单如下:

void shade(V2F inputs) { diffuseShadingOutput(vec3(0.9, 0.5, 0.7)); }

将其放入安装目录\resources\shelf\allegorithmic\shaders后(导入资源的方式不仅有直接放入目录,还可以在软件内导入,此时有多种选项,详见Adding content via the import window - Substance Painter),就可以在选择Shader种类的时候找到这种Shader了。

使用它,你就会看到一个统一的颜色:粉色(0.9, 0.5, 0.7) 在这里插入图片描述

表面着色器

从上面简单的例子中也能够看出,写一个“表面着色器”是相对简单的,只需要写一个函数:

void shade(V2F inputs);

其中,V2F指“Vertex Shader to Fragment Shader”(顶点着色器到像素着色器),是经过顶点着色器处理过后,在光栅化时进行插值,随后传入像素着色器的数据,具体定义:

struct V2F { vec3 normal; // 法线 vec3 tangent; // 切线 vec3 bitangent; // 副切线 vec3 position; // 位置 vec4 color[1]; // 顶点色 (color0) vec2 tex_coord; // 贴图坐标UV (uv0) SparseCoord sparse_coord; // interpolated sparse texture coordinates used by textureSparse() sampling function vec2 multi_tex_coord[8]; // 多套贴图坐标UV (uv0-uv7) };

(Note: To obtain a SparseCoord for uv1-uv7, you have to explicitly call getSparseCoord(vec2) defined in lib-sparse.glsl)

而shade的“输出”是调用下面的函数来描述这个像素的属性:

// 不透明度,默认值为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); // 次表面散射属性,详见 lib-sss.glsl 默认值: vec4(0.0) void sssCoefficientsOutput(vec4); 与SubstancePainter渲染引擎的集成

作为SubstancePainter中的Shader,不免需要从其渲染引擎获得数据和设置数据。这种“交流”并不是Shader本身的代码。我观察后发现是使用了//:这个符号作为了标记。

获得数据

In Substance Painter, you can access rendering engine parameters (document’s channels, additional textures, camera-related data and the like)

在SubstancePainter中,你可以获得渲染引擎提供的参数,包括:document’s channels,额外的贴图,相机相关的数据等等。

获得纹理数据

SubstancePainter 使用了Sparse Virtual Texture (SVT)系统来在视窗中管理数目庞大的贴图。这个系统对如何编写Shader代码有影响。 不过SubstancePainter提供了辅助功能,详见lib-sparse.glsl。

我个人目前对这个VirtualTexture(虚拟纹理)还并不理解。不过从之后的范例来看,不理解这项技术并不会阻止使用纹理数据。其用法还是相对简单的: 首先,需要包含lib-sparse.glsl:

// Defines the SamplerSparse structure import lib-sparse.glsl

随后,使用//: param auto TEXTURE_TAG的语法,将一个TEXTURE_TAG对应到一个纹理:

//: param auto TEXTURE_TAG uniform SamplerSparse uniform_tex; // 纹理采样器和一些信息

TEXTURE_TAG是下面的标签之一: 在这里插入图片描述

获得其他数据

aspect_ratio : 视窗的 宽度/高度 比例

//: param auto aspect_ratio uniform float uniform_aspect_ratio;

camera_view_matrix : 从世界空间变换到相机空间的矩阵

//: param auto camera_view_matrix uniform mat4 uniform_camera_view_matrix;

camera_view_matrix_it : camera_view_matrix的逆矩阵

//: param auto camera_view_matrix_it uniform mat4 uniform_camera_view_matrix_it;

camera_vp_matrix_inverse : projection * camera_view_matrix的逆矩阵

//: param auto camera_vp_matrix_inverse uniform mat4 uniform_camera_vp_matrix_inverse;

environment_exposure : 环境贴图的曝光量

//: param auto environment_exposure uniform float uniform_environment_exposure;

environment_max_lod : 环境贴图在mip-map金字塔的深度

//: param auto environment_max_lod uniform float uniform_max_lod;

environment_rotation : 代表环境贴图在向上轴上的旋转量,此值范围是[0,1],实际代表了[0,2*pi]。

//: param auto environment_rotation uniform float uniform_environment_rotation;

facing : 一个代表三角形正反面的整数(-1:背面,0:未定义,1:正面)值为0代表你可以安全地依靠GLSL的内建值gl_FrontFacing。

//: param auto facing uniform int uniform_facing;

fovy : 相机在Y轴上的视场(field of view)

//: param auto fovy uniform float uniform_fovy;

is_2d_view : a bool indicating whether the rendering is performed for 2D view or not

//: param auto is_2d_view uniform bool uniform_2d_view;

is_perspective_projection : 投影是“透视”还是“正交”

//: param auto is_perspective_projection uniform bool uniform_perspective_projection;

main_light : 环境中主光的位置

//: param auto main_light uniform vec4 uniform_main_light;

mvp_matrix : 一个矩阵,代表了:模型X视角X投影

//: param auto mvp_matrix uniform mat4 uniform_mvp_matrix;

scene_original_radius : a float representing the radius of the scene’s bounding sphere before its normalization

//: param auto scene_original_radius uniform float uniform_scene_original_radius;

screen_size : 屏幕尺寸数据 (width, height, 1/width, 1/height)

//: param auto screen_size uniform vec4 uniform_screen_size;

world_camera_direction : 世界空间中视线的方向

//: param auto world_camera_direction uniform vec3 uniform_world_camera_direction;

world_eye_position : 世界空间中眼睛的位置

//: param auto world_eye_position uniform vec3 uniform_world_eye_position; 设置渲染状态

In some cases you may want to use a specific rendering configuration (culling, blending, sampling locality, and the like) for an effect. Some rendering states are exposed and can be set in the shader.

在某些情况下,你可能想要设定特定的渲染配置(剔除,混合,采样 等等)来完成一个效果。有些渲染状态是可以在Shader中设置的:

剔除背面:

//: state cull_face on

正反两面都画:

//: state cull_face off

不混合,完全的不透明物体:

//: state blend none

以从后往前的顺序画时的标准混合模式

//: state blend over

以从后往前的顺序画时的标准混合模式,Assume color is pre-multiplied by alpha(?)

//: state blend over_premult

Additive型混合模式

//: state blend add

multiply型混合模式

//: state blend multiply 在界面中显示参数控件

你可以将Shader中的Uniform数据作为参数在界面中实时调整。

以group作为分组。 将visible设为false可以隐藏 设置description值可以添加一个“提示”。

支持的参数类型有:

Color(颜色)Spinboxes (整数)Slider (滑条,浮点数)Bool(布尔)Sampler(纹理)Combobox(下拉菜单)

可以在all-custom-params中找到详细的描述。

这里做个试验: 我将yaksue-test.glsl改为如下:

//: param custom { "default": 0, "label": "YaksueColor", "widget": "color", "group":"Test Group"} uniform vec3 u_color_float3; void shade(V2F inputs) { diffuseShadingOutput(u_color_float3); }

便可以在Shader Settings中看到其控件并可调节。 在这里插入图片描述

内建的库

In order to avoid writing a lot of boilerplate code in all of your shaders, we created a small yet practical library of useful functions.Please note that you can’t edit it nor create your own at the moment.

为了避免每次都需要写大量“模板代码”(boilerplate code ),SubstancePainter创建了一些库。请注意,当前你没法创建或编辑他们。

lib-alpha.glsl : 半透明相关lib-bayer.glsl : bayer矩阵相关lib-defines.glsl : 有用的数学常量lib-emissive.glsl : 自发光属性相关lib-env.glsl : 环境相关lib-normal.glsl : 法线贴图相关 (和高度图生成的法线贴图)lib-pbr.glsl : PBR相关lib-pbr-aniso.glsl : PBR各向异性lib-pom.glsl : 视差遮挡贴图(parallax occlusion mapping)lib-random.glsl : 随机相关的通用函数 (low discrepancy sequences)lib-sampler.glsl : 获得通道相关的辅助lib-sparse.glsl : Sparse Virtual Texture 相关lib-sss.glsl : 次表面散射(subsurface scattering)lib-utils.glsl : 颜色相关的通用函数(sRGB转换,色调映射)lib-vectors.glsl : 常用的向量相关函数

这些库的内容也可以在安装目录\resources\shader-doc\下找到。

(当前并未深入研究,但后续学习)

范例-Toon

来源于官方的范例Toon - Shader API - Substance Painter,对其做了简化

为了可以采样贴图,需要lib-sampler:

import lib-sampler.glsl

硬编码一个全局的光源位置:

const vec3 light_pos = vec3(10.0, 10.0, 10.0);

将world_eye_position(相机位置)绑定到我的camera_pos这个Uniform变量中(即SubstancePainter会帮助我更新这个Uniform变量)

//: param auto world_eye_position uniform vec3 camera_pos;

将channel_basecolor(基础颜色通道)绑定到我的basecolor_tex纹理中

//: param auto channel_basecolor uniform SamplerSparse basecolor_tex;

下面是我们的shade函数,其中的逻辑很简单,就是根据光照方向来离散地对基础颜色进行减弱:

void shade(V2F inputs) { //法线: vec3 N = normalize(inputs.normal); //光源方向 vec3 L = normalize(light_pos - inputs.position); //根据光照方向来离散地对基础颜色进行减弱: float NdL = max(0.0, dot(N, L)); vec3 color = getBaseColor(basecolor_tex, inputs.sparse_coord); if (NdL > 0.75) color = color; else if (NdL > 0.5) color = color * 0.5; else if (NdL > 0.1) color = color * 0.1; else color = vec3(0.0); //输出颜色 diffuseShadingOutput(color); }

效果: 在这里插入图片描述 完整代码:

//为了可以采样贴图,需要lib-sampler: import lib-sampler.glsl //硬编码一个全局的光源位置: const vec3 light_pos = vec3(10.0, 10.0, 10.0); //将world_eye_position(相机位置)绑定到我的camera_pos这个Uniform变量中 //: param auto world_eye_position uniform vec3 camera_pos; //将channel_basecolor(基础颜色通道)绑定到我的basecolor_tex纹理中 //: param auto channel_basecolor uniform SamplerSparse basecolor_tex; void shade(V2F inputs) { //法线: vec3 N = normalize(inputs.normal); //光源方向 vec3 L = normalize(light_pos - inputs.position); //根据光照方向来离散地对基础颜色进行减弱: float NdL = max(0.0, dot(N, L)); vec3 color = getBaseColor(basecolor_tex, inputs.sparse_coord); if (NdL > 0.75) color = color; else if (NdL > 0.5) color = color * 0.5; else if (NdL > 0.1) color = color * 0.1; else color = vec3(0.0); //输出颜色 diffuseShadingOutput(color); }


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3