Cocos Shader 基础入门(七):使用噪声图实现不规则溶解效果

本章我们尝试着对自定义的 Effect 做一些改造来实现 贴图溶解效果

为了实现这种效果,需要标记出哪些像素显示、哪些像素消失,比较好的办法是用一张噪声图来给每一个像素做标记,噪声图类似下图。由于噪声图只有黑白灰三种颜色,黑白灰非均匀分布,因此,可以利用黑透、白不透、灰半透的原理实现不规则溶解效果。


溶解效果最简单的制作通常需要两个参数:一个是 噪声图 ,一个是 控制过滤黑/白像素的阈值 。接下来,尝试定义这两个参数。

Cocos Effect

CCEffect

在之前的文章里我们知道, CCEffect 包裹的是用 YAML 格式编辑的渲染流程描述清单,主要内容涉及与编辑器的交互以及与 CCProgram 的数据交互。CCEffect 的结构再次回顾一下,内容大致如下:

CCEffect %{    techniques: # technique 渲染技术代表完成一个最终效果的方案。一个方案可以由一个或者多个 Pass 融合完成。  - passes: # 一个 Pass 就是一次 GPU 绘制,一般包括一次顶点着色器和片元着色器。      - vert: vs:vert      frag: fs:frag}CCProgram vs %{    //...}CCProgram fs %{    //...}

这是一个最最最基础的 shader 声明(例如:绘图组件 Graphics 的 shader),如果要加入一个参数或者贴图,就无法满足。所以我们需要了解 pass 更多的参数。最常用的几个参数如下:

  • pass 参数:

其中,blendState,depthStencilState,rasterizerState 了解即可。

  • properties 参数:

  • defalut values:

更多 pass 和 properties 参数可以参考下方参考文献里的“pass 可选配置参数”。

了解了一些重要的参数后,就可以开始定义参数了,在上一章最终修改后的 shader 上加入一些内容:

CCEffect %{
techniques:
- passes:
- vert: vs:vert
frag: fs:frag
blendState:
targets:
- blend: true
blendSrc: src_alpha
blendDst: one_minus_src_alpha
blendDstAlpha: one_minus_src_alpha
rasterizerState:
cullMode: none
properties:
u_dissolveMap: { value: white, editor: { tooltip: '噪声贴图' } }
dissolveThreshold: { value: 0.5, editor: { range:[0, 1, 0.01], slide: true, tooltip: '溶解阈值' } } # 此处定义的参数都必须指向 CCProgram 处对应声明的 uniform
}%

CCProgram vs %{
precision highp float;
*#inc* *lude <cc-global>*

in vec3 a_position;
in vec2 a_texCoord;
in vec4 a_color;

 out vec4 color;
 out vec2 uv0;

  vec4 vert () {
 vec4 pos = vec4(a_position, 1);
pos = cc_matViewProj * pos;
uv0 = a_texCoord;
color = a_color;

  return pos;
}
}%

CCProgram fs %{
  precision highp float;

in vec4 color;

  uniform Dissolve{
float dissolveThreshold;// 熔岩阀值[0, 1];
};

 *#if*  *USE_TEXTURE*
in vec2 uv0;
  uniform sampler2D u_dissolveMap;// 熔岩形状的纹理;
 *#pragma*  builtin(local)
layout(set = 2, binding = 10) uniform sampler2D cc_spriteTexture;
 *#endif*

 vec4 frag () {
 vec4 o = vec4(1, 1, 1, 1);

*#if*  *USE_TEXTURE*
o *= texture(cc_spriteTexture, uv0);
 *#endif*

o *= color;

return o;
}
}%

接着,回到编辑器,选择材质,就可以看到新增了两个可调整参数:

关联噪声后,根据溶解阈值,处理溶解度:

CCEffect %{
techniques:
- passes:
- vert: vs:vert
frag: fs:frag
blendState:
targets:
- blend: true
blendSrc: src_alpha
blendDst: one_minus_src_alpha
blendDstAlpha: one_minus_src_alpha
rasterizerState:
cullMode: none
properties:
u_dissolveMap: { value: white, editor: { tooltip: '噪声贴图' } }
dissolveThreshold: { value: 0.5, editor: { range:[0, 1, 0.01], slide: true, tooltip: '溶解阈值' } } # 此处定义的参数都必须指向 CCProgram 处对应声明的 uniform
}%

CCProgram vs %{
  precision highp float;
 *#include*   *<cc-global>*

in vec3 a_position;
in vec2 a_texCoord;
in vec4 a_color;

  out vec4 color;
 out vec2 uv0;

  vec4 vert () {
  vec4 pos = vec4(a_position, 1);
pos = cc_matViewProj * pos;
uv0 = a_texCoord;
color = a_color;

return pos;
}
}%

CCProgram fs %{
precision highp float;

in vec4 color;

 uniform Dissolve{
float dissolveThreshold;// 熔岩阀值[0, 1];
};

 *#if*  *USE_TEXTURE*
in vec2 uv0;
 uniform sampler2D u_dissolveMap;// 熔岩形状的纹理;
 *#pragma*   *builtin(local)*
layout(set = 2, binding = 10) uniform sampler2D cc_spriteTexture;
 *#endif*

   vec4 frag () {
  vec4 o = vec4(1, 1, 1, 1);
float value = 1.0;

 *#if*   *USE_TEXTURE*
   vec4 dissolveMap = texture(u_dissolveMap, uv0); // 如果颜色的 r 分量小于阀值,将这个着色操作丢弃;
value *= dissolveMap.r;
 *#endif*

if (value < dissolveThreshold) {
discard; // 将小于阈值的片段丢弃,形成溶解
}

 *#if*   *USE_TEXTURE*
o *= texture(cc_spriteTexture, uv0); // 与原纹理混合;
 *#endif*

o *= color;
if (value < dissolveThreshold + 0.05) {
o = vec4(0.9, 0.6, 0.3, o.a); // 溶解的边缘设置一个边缘过度色
}

return o;
}
}%

最后,我将原图替换上 Cocos logo,将阈值调整为 0.2,画面呈现的效果如下:

如果想要在运行时修改阈值,可以采用如下方法:

const sprite = this.getComponent(Sprite);const mat = sprite.customMaterial;mat.setProperty('dissolveThreshold', 0.5);

到这里为止,我们就完成了一个 shader 的改造,看起来是不是很简单。入门 shader 需要我们不断去尝试,所以大家在学习的时候一定要多去尝试一些 shader 的改造,网上也有很多例子,都可以拿来照猫画虎试上一试。

内容参考:

pass 可选配置参数

要看下一集?戳这里看全系列教程>>>>

1赞

学到了 :grinning:

!!学废了

学到了。。