Cocos Creator - 2D扭曲Shader

前言

昨天刚办完离职手续,今天闲来无事,就分享一篇关于cocos shader中的扭曲(水波纹)特效的实现吧,话不多说,直接步入正题。

在这里打个广告,本人刚离职,坐标深圳,有没有游戏公司正在招聘U3D的(cocos 3D手游的也可以),麻烦帮忙推荐一下呗,感谢。(ps:我U3D项目经验较少,但是我非常热爱U3D游戏开发,平时也自己花时间去研究,不嫌弃的可以帮忙推荐一下呗,谢谢!可以留言或者私信我,wx: CharlieLi_Wechat)

CocosCreator版本:2.4.2

效果

这个效果原理非常简单,就是对 texture 随机采样,当然,这个随机会有一定的约束,不能太随机,在当前uv坐标附近随机即可。也就是说对uv进行随机偏移。

在shader中没有内置的随机函数,要么自己写一个随机函数,要么通过采样噪声图拿到随机值。这里我们就采用第二种方法,简单而且性能也好。(在shader中严格说来应该叫噪声,有兴趣的可以自己去查阅相关的资料)

首先我们需要一张的噪声图:


在shader中添加noisetex 属性,用来接收噪声纹理,并在拖拽图片到属性面板:

有了噪声图,我们就可以轻松的得到所谓的随机值了,代码如下:

vec4 noise = vec4(1);
CCTexture(noisetex, v_uv0.xy, noise);

此时我们得到了噪声值,然后我们对 uv坐标进行偏移,最后在采样,代码如下:

vec2 uv_temp = v_uv0;
uv_temp += noise.xy;

vec4 o = vec4(1);
CCTexture(texture, uv_temp, o);

此时效果大致如下:
在这里插入图片描述

现在是一个静态的,然后我们怎么让它动起来呢?很简单,在采样噪声图的时候加上一个时间变量就可以了。如下:

CCTexture(noisetex, v_uv0.xy + v_time.x * speedFactor , noise);

v_time 是从顶点着色器 传递到 片元着色器的,内置变量为:cc_time,随着游戏运行不断增长。
此时我们就得到了一个动态的噪声值。
==注意:纹理 Wrap Mode 需要设置为平铺模式 Repeat==

在这里插入图片描述
此时运行游戏,我们就能看到一个动态扭曲的特效了。

至此完毕,最后附上完整shader源码

// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.  
/**
 扭曲 特效
 author: lichanglong
 create time:2020.8.11
 **/
CCEffect %{
  techniques:
  - passes:
    - vert: vs
      frag: fs
      blendState:
        targets:
        - blend: true
      rasterizerState:
        cullMode: none
      properties:
        texture: { value: white }
        alphaThreshold: { value: 0.5 }
        # 噪声纹理
        noisetex: { value: white }
        speedFactor: {
          value: 0.1,
          editor: {
            tooltip: "速度",
            range: [0.0, 1.0],
          }
        }
        strengthFactor: {
          value: 0.1,
          editor: {
            tooltip: "强度",
            range: [-0.5, 0.5],
          }
        }
        isHorizontal: {
            value: 0,
            editor: {
              tooltip: "横向扭曲",
              range: [0.0, 1.0],
            }
        }
        isVertical: {
            value: 0,
            editor: {
              tooltip: "纵向扭曲",
              range: [0.0, 1.0],
            }
        }
}%


CCProgram vs %{
  precision highp float;

  #include <cc-global>
  #include <cc-local>

  in vec3 a_position;
  in vec4 a_color;
  out vec4 v_color;

  #if USE_TEXTURE
  in vec2 a_uv0;
  out vec2 v_uv0;
  #endif

  out vec4 v_time;

  void main () {
    vec4 pos = vec4(a_position, 1);

    #if CC_USE_MODEL
    pos = cc_matViewProj * cc_matWorld * pos;
    #else
    pos = cc_matViewProj * pos;
    #endif

    #if USE_TEXTURE
    v_uv0 = a_uv0;
    #endif
    v_color = a_color;

    v_time = cc_time;
    gl_Position = pos;
  }
}%


CCProgram fs %{
  precision highp float;
  
  #include <alpha-test>
  #include <texture>

  in vec4 v_color;

  #if USE_TEXTURE
  in vec2 v_uv0;
  uniform sampler2D texture;
  #endif

  #if USE_NOISETEX
  uniform sampler2D noisetex;
  #endif

  uniform Factor {
      float speedFactor;
      float strengthFactor;
      float isHorizontal;
      float isVertical;
  };

  in vec4 v_time;

  void main () {
    vec4 o = vec4(1);
    vec4 noise = vec4(1);

    vec2 uv_temp = v_uv0;

    // 采样噪声纹理
    #if USE_NOISETEX
      CCTexture(noisetex, v_uv0.xy + v_time.x * speedFactor , noise);
    #endif
      // 偏移uv
      // uv_temp += noise.xy * strengthFactor;
      float isH = step(0.1, isHorizontal);
      float isV = step(0.1, isVertical);

      uv_temp.x += noise.x * strengthFactor * isH;
      uv_temp.y += noise.x * strengthFactor * isV;

    #if USE_TEXTURE
      CCTexture(texture, uv_temp, o);
    #endif

    o *= v_color;

    ALPHA_TEST(o);

    gl_FragColor = o;
  }
}%

最后

以上可能需要稍微懂点shader的同学才能理解,项目源码在我的 GitHub 能找到,不只是cocos中shader,还有关于Unity 和 WebGL相关的工程,喜欢的可以给个star,谢谢!

更多关于Shader 特效的可以来我的博客逛逛,喜欢的可以素质三连,嘿嘿

17赞

#Nice!

fs片元里直接 #include cc-global 可以不用传递,也可以用cc_time.x

咦,是吗? 我试试

謝謝分享,對小白如我很有幫助

马克。留名有空看

cocos3d里用不了