欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Cocos Creator - 2D扭曲Shader

程序员文章站 2022-07-14 11:42:22
...

前言

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

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

CocosCreator版本:2.4.2

效果

Cocos Creator - 2D扭曲Shader

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

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

首先我们需要一张的噪声图:
Cocos Creator - 2D扭曲Shader
在shader中添加noisetex 属性,用来接收噪声纹理,并在拖拽图片到属性面板:

Cocos Creator - 2D扭曲Shader

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

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);

此时效果大致如下:
Cocos Creator - 2D扭曲Shader

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

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

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

Cocos Creator - 2D扭曲Shader
此时运行游戏,我们就能看到一个动态扭曲的特效了。

至此完毕,最后附上完整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,谢谢!