Cocos Creator Shader实现镂空遮罩

Cocos Creator Shader实现镂空遮罩

前言

想不到距离上一遍博客更新已经有13个月之久了,之前定下的一个月至少更新一遍早已不知什么时候抛之脑后。今天开个头,希望以后输出更多的学习总结。

该文起源是同事的一个需求,实现一个简单的镂空遮罩引导,具体效果如下

实现思路

看到这个第一个感觉应该是使用cocos shader,在指定区域做一个镂空处理,需要变化的参数就是指定位置position,镂空尺寸。黑幕渐变的效果就是宽高递减,在ts上根据指定速度递减。

编写shader

下面我们先来实现shader,话不多说,直接上代码



CCEffect %{
  techniques:
  - passes:
    - vert: vs
      frag: fs
      blendState:
        targets:
        - blend: true
      rasterizerState:
        cullMode: none
      properties:
        size: { value: [1920.0, 1080.0], editor: { tooltip: '节点尺寸' } }
        center: { value: [0.5, 0.5], editor: { tooltip: '中心点 (左上角为原点)' } }
        width: { value: 0.5, editor: { tooltip: '宽 (目标宽度 / 节点宽度)' } }
        height: { value: 0.5, editor: { tooltip: '高 (目标高度 / 节点宽度)' } }
}%


CCProgram vs %{
  precision highp float;

  #include 

  in vec3 a_position;
  in vec2 a_uv0;
  in vec4 a_color;

  out vec2 v_uv0;
  out vec4 v_color;

  void main () {
    gl_Position = cc_matViewProj * vec4(a_position, 1);
    v_uv0 = a_uv0;
    v_color = a_color;
  }
}%


CCProgram fs %{
  precision highp float;

  in vec2 v_uv0;
  in vec4 v_color;

  uniform sampler2D texture;

  uniform Properties {
    vec2 center;
    vec2 size;
    float width;
    float height;
  };

  void main () {
    vec4 color = v_color;
    color *= texture(texture, v_uv0);
    // 边缘
    float ratio = size.x / size.y;
    float minX = center.x - (width / 2.0);
    float maxX = center.x + (width / 2.0);
    float minY = center.y - (height * ratio / 2.0);
    float maxY = center.y + (height * ratio / 2.0);
    if (v_uv0.x >= minX && v_uv0.x <= maxX && v_uv0.y >= minY && v_uv0.y <= maxY) {
     // 下面判断4个边,和中间位置
      vec2 vertex;
      if (v_uv0.x <= minX) {
        vertex=vec2(minX,v_uv0.y/ratio);
      } else if (v_uv0.x >= maxX) {
        vertex=vec2(maxX,v_uv0.y/ratio);
      } else if (v_uv0.y <= minY) {
        vertex = vec2(v_uv0.x, minY/ ratio); // 上
      } else if (v_uv0.y >= maxY) {
        vertex = vec2(v_uv0.x,maxY/ ratio); // 下
      } else {
        discard; // 中间discard表示直接丢弃,不渲染
      }
      float dis = distance(vec2(v_uv0.x, v_uv0.y / ratio), vertex);
    }
    
    color.a *= v_color.a;
    gl_FragColor = color;
  }
}%

代码很少,就几行,如果不理解的可以翻看我之前几遍shader的文章应该可以懂得。

编写ts更改相应参数

核心shader完成,接下来要做的就是通过获取到这个shader然后通过改变其参数来移动定位到具体镂空位置。这里我这里一个范例,可以直接拿来用。



const {ccclass, property} = cc._decorator;

/**
 * 
 * 把这个类挂在一个遮罩的Sprite里,这个Sprite节点一般是一个黑色的图,透明度直接在color上设置就好
 */
@ccclass
export default class GuideShader extends cc.Component {
    /** 这里实现点击某个节点,获取鼠标位置,定位到这里 */
    @property(cc.Node)
    clickTarget:cc.Node=null;

    /** 黑幕遮罩移动的速度 */
    @property
    public wSpeed:number=90;
    @property
    public hSpeed:number=70;

    private shader:cc.MaterialVariant=null;
    /** 镂空的宽高 */
    private btnWh:cc.Vec2=cc.v2(160,80);
    private isUpdate:boolean=false;
    /** 这里一般为屏幕尺寸 */
    private widthDiff=1920;
    private heightDiff=1080;

    onLoad () {
        this.node.width=cc.winSize.width;
        this.node.height=cc.winSize.height;
    }

    start () {
        this.shader=this.node.getComponent(cc.Sprite).getMaterials()[0];
        this.clickTarget && this.clickTarget.on(cc.Node.EventType.TOUCH_END,this.clickHandle,this);
    }

    private clickHandle(e:cc.Event.EventTouch){

        this.setLocation(e.getLocation(),this.btnWh);
    }

    public setLocation(location:cc.Vec2,focusWH:cc.Vec2)
    {
        /** 设置相应的shader属性 */
        this.shader.setProperty('center',cc.v2(location.x/cc.winSize.width,1-location.y/cc.winSize.height));
        this.widthDiff=cc.winSize.width;
        this.heightDiff=cc.winSize.height;
        this.btnWh=focusWH;
        this.isUpdate=true;
    }
   
    update (dt) {
        if(this.isUpdate)
        {
            
            if(this.widthDiff>this.btnWh.x) this.shader.setProperty('width',this.widthDiff/cc.winSize.width);
            else  this.shader.setProperty('width',this.btnWh.x/cc.winSize.height);
            if(this.heightDiff>this.btnWh.y) this.shader.setProperty('height',this.heightDiff/cc.winSize.height);
            else this.shader.setProperty('height',this.btnWh.y/cc.winSize.height);
            this.widthDiff-=this.wSpeed;
            this.heightDiff-=this.hSpeed;
        }
        
    }
}


这样就能实现上面gif的效果了。

你可能感兴趣的:(CocosCreator,游戏开发,cocos,creator,shader,shader,cocos-creator)