Shader新发: 无缝滚动背景材质特效.

游戏中比较常用的一个效果就是背景无缝持续滚动, 以前材质系统不完善的时候,想要实现此效果, 只能是通过移动背景节点的坐标进行移动,同时还要处理好拼接的时机.
现在完全可以用Shader 进行重构实现了.
话不多说, 直接放代码:

  1. 材质代码:()

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 }
        speed: {value: 1.0 }   // time 和speed 共同决定采样的偏移量.
}%


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;
  #endif

  uniform Param {
    float time;
    float speed;
  };

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

    float offset = fract( time* speed + v_uv0.x);

    o *= texture(texture, vec2(offset, v_uv0.y));
    
    o *= v_color;

    ALPHA_TEST(o);

    gl_FragColor = o;
  }
}%

  1. 通用材质球文件:(省略)

  2. 材质属性操控组件:


const { ccclass, property } = cc._decorator;

@ccclass("shareParam")
export class ShaderParameter {

    @property()
    public key: string = "";

    @property()
    public value: string = "";
}


@ccclass
export default class ShaderParamComponent extends cc.Component {

    private sprite: cc.Sprite = null;

    private _material: cc.Material = null;

    private _start = 0;

    @property({ type: [ShaderParameter], displayName: "参数列表", tooltip: "向材质传递自定义参数,参数类型会进行json转换." })
    private params: ShaderParameter[] = [];

    @property({ displayName: "更新时间", tooltip: "是否传递时间变化" })
    private timeUpdate: boolean = true;

    onLoad() {
        this.sprite = this.getComponent(cc.Sprite);
        if (this.sprite) {
            this._material = this.sprite.getMaterial(0);
        }
        this.initParams()
    }

    public updateParam(key: string, value: any) {

        if (!key || key.length <= 0 || typeof value === 'undefined') {
            cc.warn("设置材质参数为空:", key, value)
            return;
        }
        // 防止中途有材质变更.
        if (this.sprite) {
            this._material = this.sprite.getMaterial(0);
        }

        if (this.sprite && this._material) {
            if (this._material.getProperty(key, 0) != undefined) {
                this._material.setProperty(key, JSON.parse(value))
            }
        }
    }
    private initParams() {
        if (this.sprite && this._material && this.params) {

            for (let p of this.params) {

                let key = p.key;
                let value = p.value;

                if (!key || key.length <= 0 || typeof value === 'undefined') {
                    cc.warn("设置材质参数为空:", key, value)
                    return;
                }
                if (this._material.getProperty(key, 0) != undefined) {
                    this._material.setProperty(key, JSON.parse(value))
                }
            }
        }
    }

    protected update(dt) {

        if (this.sprite) {
            this._material = this.sprite.getMaterial(0);
        }
        if (this.node.active && this._material) {
            if (this._material.getProperty("time", 0) != undefined) {
                this._setShaderTime(dt);
            }
        }
    }

    private _setShaderTime(dt) {
        this._material.setProperty('time', this._start);
        this._start += dt;
    }
}

使用方法:

在要移动的背景节点上选择此材质, 并挂载操作组件.
参数设置如下:

其中 参数speed 用于设置背景的移动速度. 可通过代码动态修改参数值.

不同的背景节点 设置不同的speed 参数, 即可实现背景视觉差 式的移动效果. 完全不需要再控制背景节点进行坐标移动.

9赞

mark…

->mark<-

mar了个k

2.2.2测试可用,厉害了我的哥!

修正一下:

  1. timeUpdate 忘了写代码了, 尴尬, 就是控制是否在update中持续设置时间更新.
  2. 另外 for 循环中 不应该 return, 应该是continue;

mar了个k

mark。。。。

mark 0.0

大家不要再mark了. 点击最下面的书签收藏就好了.

厉害了。。。mark:grin:

感觉很厉害,不知道效果怎么样,有空试试

2.4.4好像就用不了了