2D风吹草吹树shader效果 分享

这是之前的帖子链接:2D 大风吹树效果求思路
以及我正在开坑的关联的单机游戏: Cocos Creator | Game_1
GIF

效果体验 链接:Cocos Creator | NewProject

问题1:要做什么?

   观察树枝受风时的变化,我们看到 1. 树枝弯曲了 2.树枝在摆动

参考示例:CocosCreator Shader学习(四):花草摆动效果_三思而先行的博客-CSDN博客
shader 知识点 Cocos Creator Shader Effect 系列 - 1 - 材质,Effect,Inspector,纹理之间的关系 - 简书

问题2:如何制作?
分3个部分:

   1.shader能使图片弯曲:
     制作能够使图片弯曲的shader ,设置对弯曲程度可变的风力值参数
     将shader设置给材质, 再将材质在树枝节点

   2.树枝js脚本:能够控制节点角度变化
     制作摆动风力函数sin函数, 设置对角度幅度变化的风力值参数

   3.风力管理js

具体步骤:

   1. 制作能够使图片弯曲的shader,设置对弯曲程度可变的风力值参数 

微信截图_20211029105424

//文件:sbranches_shook_Effect.effect

  CCEffect %{
    techniques:
    - passes:
      - vert: vs
        frag: fs
        blendState:
          targets:
          - blend: true
        rasterizerState:
          cullMode: none
        properties:
          texture: { value: white } 
          alphaThreshold: { value: 0.5 }

          # time : {
          #         value: 0.0,
          #         editor: {
          #           tooltip: "时间"
          #         } 
          # } 
          wind_num: { 
                  value: 1.0,
                  editor: {
                    tooltip: "风力值"
                  }
                }
          radian: { 
                  value: 1.0,
                  editor: {
                    tooltip: "旋转值"
                  }
                }
          Flexibility: { value: 1.0,
                  editor: {
                    tooltip: "柔韧度,数值越大越容易弯曲"
                  }
                }
          value_1: {
                  value: 0.5,
                  editor: {
                    tooltip: "参数1"
                  }
          }
          value_2: {
                  value: 4.0,
                  editor: {
                    tooltip: "参数2"
                  }
          }
  }%


  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

    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;

      gl_Position = pos;
    }
  }%


  CCProgram fs %{
    precision highp float;
    
    #include <alpha-test>
  
    in vec4 v_color;
  
    #if USE_TEXTURE
    in vec2 v_uv0;
    uniform sampler2D texture;

    // uniform inputData{
    //   float time;
    // };

    uniform inputData1{
      float wind_num;
    };

    uniform inputData2{
      float radian;
    };

    uniform inputData3{
      float Flexibility;
    };

    uniform inputData4{
      float value_1;
    };

    uniform inputData5{
      float value_2;
    };
  
    #endif
  

    void main () {
      vec4 o = vec4(1, 1, 1, 1);
  
      // 风吹植物变形算法
      // 一.脚本功能
      // 1.风力大小,方向角度
      // 2.材质柔韧性越小的,弯曲幅度越小
      // 二.shader功能
      // 1.表现弯曲方向一致,计算包含自身旋转
      // 2.素材要求完整正方形,防止动画裁切
      // 3.素材要求以底部为不动点,
      

      // 根据自身角度计算 风向量,风力值决定了最大点偏移多少

      float wind_x = -1.0 * wind_num  * cos( radian );
  
      //////////////////////// 弯曲算法: ____________________________

      // 获取v_uv0这个点距离中心点的真实距离
      float height = 1.0 - v_uv0.y;

    
      // 使用pow函数,让距离中心点越长的地方摆动幅度越明显且成抛物线形态(中心点以下部位不参与偏移)

      // x轴偏移量
      float offset_x = value_1 * pow(height, value_2) * wind_x;
      // x新的坐标
      float new_x =  v_uv0.x + offset_x;
      // 通过三角函数,计算出Y轴偏移量
      // y的新坐标
      float offset_y = pow(offset_x, 2.0)  *  2.0;

      float new_y =  v_uv0.y - offset_y;
  
      ////////////////////////风量抖动算法_____________________________




      ////////////////////////

      #if USE_TEXTURE
      // fract函数是GLSL内建函数,取小数部分
      o *= texture(texture, fract(vec2(new_x, new_y)));

        if(new_x <0.0 || new_x>1.0 || new_y<0.0){
        o = vec4(0.0, 0.0, 0.0, 0.0);
        }

        #if CC_USE_ALPHA_ATLAS_TEXTURE
        o.a *= texture2D(texture, v_uv0 + vec2(0, 0.5)).r;
        #endif
      #endif
  
      o *= v_color;
  
      ALPHA_TEST(o);


  
      gl_FragColor = o;
    }
  }%

// 然后新建一个材质,设置材质的effect,为上面的文件
image

// 新建树枝图片节点 //注意::(被使用的图片需要 去掉图片素材packable ,否则有概率自动合图合图将错误计算uv)
微信截图_20211029105227

// 将材质放到树枝

//树枝脚本:branches_shook.js

cc.Class({
    extends: cc.Component,

    properties: {
        material: {
            default: null,
            type: cc.Material
        },


        time: {
            default: 0
        },


        wind_num: {
            default: 1,
            tooltip: "风力值"
        },

        radian: {
            default: 0,
            tooltip: "旋转角度转弧度值"
        },

        Flexibility: {
            default: 1,
            tooltip: "柔韧度" // 柔韧度影响弯曲度
        }
    },

    // LIFE-CYCLE CALLBACKS:

    onLoad() {

        this.set_raotaion();

    },


    start() {
        this.material = this.node.getComponent(cc.Sprite).getMaterial(0);
    },

    update(dt) {
        this.time += dt;
        if (globalThis.WeatherManager) {

            this.wind_num = globalThis.WeatherManager.wind_num;

        }

        if (this.node.active && this.material != null) {

            this.radian = (this.node.angle) * Math.PI / 180;


            // this.material.setProperty("time", this.time);
            this.material.setProperty("wind_num", this.wind_num);
            this.material.setProperty("radian", this.radian);
            this.material.setProperty("Flexibility", this.Flexibility);

        }

        this.update_wind(dt);

    },





    // 树枝对风力值感受

    // 1.树枝角度变形
    set_raotaion: function () {
        // 记录树枝的角度
        this.angle = this.node.angle;
        if (this.angle < 0) {
            this.angle += 360;
        }

        this.time = Math.random() * 2;
    },

    // 2.根据风大小方向,动态抖动树叶角度,抖动树叶弯曲值1
    update_wind: function (dt) {

        this.time += dt;

        // 根据时间值,计算出sin规律
        var _num1 = Math.sin(this.time * (this.wind_num / 2));

        // 计算出偏移角度

        // if (this.wind_num > 0) {
        if (this.angle > 90 && this.angle < 270) {
            this.node.angle = this.angle + (this.wind_num * (_num1 + 1));
        } else {
            this.node.angle = this.angle - (this.wind_num * (_num1 + 1));
        }

        // }



        // if (this.wind_num < 0) {
        //     if (this.angle > 90 && this.angle < 270) {
        //         this.node.angle = this.angle + (this.wind_num * (_num1 + 1) * 2);
        //     } else {
        //         this.node.angle = this.angle - (this.wind_num * (_num1 + 1) * 2);
        //     }

        // }

        // 计算出偏移抖动值1
        this.material.setProperty("value_1", Math.abs(this.wind_num) * (_num1 + 1) * 0.02 + 0.1);


    }
});

wind_manager.js

cc.Class({
extends: cc.Component,

properties: {
    wind_num: 1,

    wind_label: {
        default: null,
        type: cc.Label,
        tooltip: "风力描述label"
    }
},

// LIFE-CYCLE CALLBACKS:

onLoad() {

    globalThis.WeatherManager = this;


},

start() {

},

update(dt) {

    this.wind_label.string = "风力: " + this.wind_num;


},


on_change_wind: function (slider, customEventData) {

    this.wind_num = slider.progress * 10 - 5;

}

});

设置一个滑动器,将风回调函数绑定到上面
最终效果:
为什么没有第一张图好看…emmmm, 那是…天气昼夜系统的效果

GIF

附上demo: NewProject.zip (1.3 MB)

15赞

非常感谢分享. MARK.

mark了。
厉害呢。

非常感谢分享.
先回贴,再啃



为啥我搬到项目里面后,这个材质一用上叶子就不见了

bilinear 图片模式下,
被使用的图片需要 去掉图片素材packable ,否则合图将错误计算图片的uv

1赞

学一波!!

大佬牛逼,学习了

mark 针不戳

有高斯模糊的shader吗?
陈皮皮的性能堪忧,高斯模糊 Shader
那个 wheatup的版本升级到2.4.0又只能黑屏。【技术分享】Cocos Creator 2.1.1 实现背景高斯模糊效果
blur_2.zip (1.8 KB) 我手动升级的文件在这,2.4.0用上后会黑屏。
难搞


掉水里没淹死 但是健康度从85到100了 哈哈

试试这个看看 浣熊大佬的高斯模糊

mark 大佬 :ox::beer:

类卷积算法的高斯模糊性能肯定不太行的