来点新花样!使用噪声图实现不规则溶解效果

共 3626字,需浏览 8分钟

 ·

2021-10-27 23:36

上一章里,我们成功地利用了自定义 Effect 和材质,替换了 Sprite 组件内置的材质。本章我们尝试着对自定义的 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;
  #include 

  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 

  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 可选配置参数:

https://docs.cocos.com/creator/3.2/manual/zh/material-system/pass-parameter-list.html




Cocos Shader 基础入门系列


(一)WebGL & GLSL 基础

(二)顶点着色器与片元着色器

(三)绘制多个三角形并给顶点换颜色

(四)纹理映射

(五)在 Creator 中画一个矩形

(六)Sprite Shader

···更新中···


该系列教程视频版

已更新至 EP07

欢迎点击【阅读原文】

前往 B 站观看交流 ↓

B 站关注「Cocos 引擎官方」

https://www.bilibili.com/video/BV1Cq4y1d726


往期精彩

浏览 83
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报