【进击的Shader】【入门二】Cocos Shader Effect 实现Sprite 边缘光效果,圆角裁切抗锯齿效果,高斯模糊效果

CCEffect %{
  techniques:
  - name: opaque
    passes:
    - vert: sprite-vs:vert
      frag: sprite-fs:frag4
      depthStencilState:
        depthTest: false
        depthWrite: false
      blendState:
        targets:
        - blend: true
          blendSrc: src_alpha
          blendDst: one_minus_src_alpha
          blendDstAlpha: one_minus_src_alpha
      rasterizerState:
        cullMode: none
      properties: &props   
        colorLight : { value : [1.0,0.0,0.0,1.0] ,  editor: { type: color }}
        outlineSlider : { value : 0.01 , target : outlineW , editor : { slide : true , range : [0.00,0.1], step: 0.01} }
        outRadiusSlider : { value : 0.0 , target : outRadius , editor : { slide : true , range : [0.0,0.3], step: 0.01} } 
        textureSize: { value: [100.0, 100.0], editor: { tooltip: "纹理尺寸 " } }
}%

CCProgram sprite-vs %{
  precision highp float;
  #include <cc-global>

  in vec3 a_position;
  in vec2 a_texCoord;
  in vec4 a_color;
  
  out vec2 v_uv0;
  out vec4 v_color;

  vec4 vert () {
    vec4 pos = vec4(a_position,1.0);
    pos = cc_matProj * cc_matView * pos;

    v_uv0 = a_texCoord;
    v_color = a_color;
    return pos; 
  }
}%

CCProgram sprite-fs %{
  precision highp float;
  #define PI 3.14159265359
  // 定义无理数
  #define e 2.718281828459045 
  #define stDev 5.0

  in vec2 v_uv0;
  in vec4 v_color;

  uniform Constant {
    vec4 colorLight;
    float outlineW;
    float outRadius;
    vec2 textureSize; 
  };

  #pragma builtin(local)
  layout(set = 2, binding = 11) uniform sampler2D cc_spriteTexture; 

  //边缘光方法1
  bool checkIsMakeOutline(vec2 pos){
    //alpha检测值
    float alpha = 0.1;
    vec4 color = texture(cc_spriteTexture, pos);
    if(color.a <= alpha || outlineW == 0.0)return false;

    // if(color.a >= 0.8 )return false; 
 
    //检测当前点周围的8个点的alpha值
    color = texture(cc_spriteTexture, pos + vec2(0, outlineW));
    if(color.a <= alpha)return true;
    color = texture(cc_spriteTexture, pos + vec2(outlineW, outlineW));
    if(color.a <= alpha)return true;
    color = texture(cc_spriteTexture, pos + vec2(outlineW, 0));
    if(color.a <= alpha)return true;
    color = texture(cc_spriteTexture, pos + vec2(outlineW, -outlineW));
    if(color.a <= alpha)return true;
    color = texture(cc_spriteTexture, pos + vec2(0, -outlineW));
    if(color.a <= alpha)return true;
    color = texture(cc_spriteTexture, pos + vec2(-outlineW, -outlineW));
    if(color.a <= alpha)return true;
    color = texture(cc_spriteTexture, pos + vec2(-outlineW, 0));
    if(color.a <= alpha)return true;
    color = texture(cc_spriteTexture, pos + vec2(-outlineW, outlineW));
    if(color.a <= alpha)return true;
    
    //当前点已是纹理边缘
    if(pos.x <= outlineW || pos.x >= 1.0 - outlineW)return true;
    if(pos.y <= outlineW || pos.y >= 1.0 - outlineW)return true;
 
    return false;
  } 

  
  float getBackArea()
  {
    vec4 color_up;
    vec4 color_down;
    vec4 color_left; 
    vec4 color_right; 
    // vec4 color_up_left; 
    // vec4 color_up_right; 
    // vec4 color_down_left; 
    // vec4 color_down_right; 
    float total = 0.0 ; 

    color_up = texture(cc_spriteTexture, v_uv0 + vec2(0.0, outlineW)); 
    color_down = texture(cc_spriteTexture, v_uv0 - vec2(0.0, outlineW)); 
    color_left = texture(cc_spriteTexture, v_uv0 - vec2(outlineW, 0.0)); 
    color_right = texture(cc_spriteTexture, v_uv0 + vec2(outlineW, 0.0)); 
    // color_up_left = texture(cc_spriteTexture, v_uv0 + vec2(outlineW, -outlineW)); 
    // color_up_right = texture(cc_spriteTexture, v_uv0 + vec2(outlineW, outlineW)); 
    // color_down_left = texture(cc_spriteTexture, v_uv0 + vec2(-outlineW, -outlineW)); 
    // color_down_right = texture(cc_spriteTexture, v_uv0 + vec2(-outlineW, outlineW)); 
    // total = color_right.a + color_left.a + color_down.a + color_up.a + color_up_left.a + color_up_right.a + color_down_left.a + color_down_right.a; 
    total = color_right.a + color_left.a + color_down.a + color_up.a; 
    return clamp(total, 0.0, 1.0);
  }

  //边缘光方法 1 
  vec4 frag0 () {
    vec4 o = vec4(1, 1, 1, 1);
    o *= texture(cc_spriteTexture,v_uv0);  
    o*= v_color; 
    if(checkIsMakeOutline(v_uv0)){ 
    //   //检查到v_uv0点需要描边,直接改变颜色值
      o = vec4(1, 0, 0,  o.a); 
      // o*=o; 
    } 
    return o;
  }

  // 边缘光方法 2 
  vec4 frag1 () {
    vec4 fragColor = v_color * texture(cc_spriteTexture, v_uv0); 
    float isBack = getBackArea(); 

    // 正常的rgb + 正常的透明区域 * 背面颜色 * 描边颜色
    vec4 o = vec4(fragColor.rgb + (1.0 - fragColor.a)* colorLight.rgb * isBack, isBack); 
    return o;
  }

  //圆角裁切
  vec4 frag2 () {
    float radius = outRadius;
    vec2 o1 = v_uv0; 
    vec4 o  = vec4(0,0,0,0);   
    if((o1.x > radius && o1.x < 1.0-radius) || (o1.y > radius && o1.y < 1.0-radius) ){
      o  = texture(cc_spriteTexture,o1);   
    }else{
      float tx = 0.5 + abs(o1.x - 0.5);
      float ty = 0.5 - abs(o1.y - 0.5);
      float len = distance(vec2(tx,ty), vec2(1.0-radius, radius));  

      float smo = radius * 0.01;//抗锯齿
      if( len <= radius ){  
        o = texture(cc_spriteTexture,o1); 
      }else if(len <= radius + smo){
        float cur = radius + smo-len; 
        o = texture(cc_spriteTexture,o1); 
        o.a = smoothstep(0.0, smo, cur);  
      }; 

    }; 
    return o;
  } 

  //高斯模糊1 只取一圈的8个正点位,均值模糊,模糊基础原理实现
  vec4 frag3 () { 
    vec4 finalColor = vec4(0.0, 0.0, 0.0, 0.0); 
    float onePxWidth = 1.0 / textureSize.x;
    float onePxHeight = 1.0 / textureSize.y;
    float dif = 4.0;//取第4层
    finalColor += texture(cc_spriteTexture, v_uv0) * (1.0/9.0); 
    finalColor += texture(cc_spriteTexture, v_uv0 + vec2(0.0, onePxHeight * dif)) * (1.0/9.0);
    finalColor += texture(cc_spriteTexture, v_uv0 + vec2(0.0, -onePxHeight * dif)) * (1.0/9.0);
    finalColor += texture(cc_spriteTexture, v_uv0 + vec2(onePxWidth * dif, 0.0)) * (1.0/9.0);
    finalColor += texture(cc_spriteTexture, v_uv0 + vec2(-onePxWidth * dif, 0.0)) * (1.0/9.0); 
    finalColor += texture(cc_spriteTexture, v_uv0 + vec2(onePxWidth * dif, onePxHeight * dif)) * (1.0/9.0);
    finalColor += texture(cc_spriteTexture, v_uv0 + vec2(onePxWidth * dif, -onePxHeight * dif)) * (1.0/9.0);
    finalColor += texture(cc_spriteTexture, v_uv0 + vec2(-onePxWidth * dif, -onePxHeight * dif)) * (1.0/9.0);
    finalColor += texture(cc_spriteTexture, v_uv0 + vec2(-onePxWidth * dif, onePxHeight * dif)) * (1.0/9.0); 

    return finalColor;  
  }

  //高斯模糊2  取相邻若干层 进行均值模糊  未使用高斯模糊算法
  vec4 frag4 () { 
    vec4 finalColor = vec4(0.0, 0.0, 0.0, 0.0); 

    const float size = floor( 5.0 * 2.0 + 1.0);//取5层
    const float halfSize = floor(size / 2.0);

    float onePxWidth = 1.0 / textureSize.x;
    float onePxHeight = 1.0 / textureSize.y;
    for(float x = -halfSize; x<= halfSize; x++) {
      for (float y = -halfSize; y<= halfSize; y++) {
        finalColor += texture(cc_spriteTexture, v_uv0 + vec2(onePxWidth * x, onePxHeight * y)) * (1.0/ pow(size,2.0));
      }
    }   
    return finalColor;
  } 
  
  float getWeight(float x, float y) { 
    return (1.0 / (2.0 * PI * pow(stDev, 2.0))) * pow(1.0 / e, (pow(x, 2.0) + pow(y, 2.0)) / (2.0 * pow(stDev, 2.0)));
  }

  //高斯模糊3  使用高斯模糊算法
  vec4 frag5 () {   
    // 根据高斯分布(也叫正态分布),在3个标准差范围内的分布比例占到99%的权重,因此我们只需要计算矩阵范围 [6 * stDev + 1, 6 * stDev +1] 上的权重
    const float size = floor(stDev * 6.0 + 1.0);
    const float halfSize = floor(size / 2.0);

    // 步骤一:计算高斯矩阵上所有权重的和 
    // 原点
    float totalWeight = getWeight(0.0, 0.0);

    // X轴正方向上的权重 * 2.0 就是整个X轴上的权重
    for(float x = 1.0; x <= halfSize; x++) {
        totalWeight += getWeight(x, 0.0) * 2.0; 
    } 
    // Y轴正方向上的权重 * 2.0 就是整个Y轴上的权重
    for(float y = 1.0; y <= halfSize; y++) {
        totalWeight += getWeight(0.0, y) * 2.0;
    } 
    // 第一象限的权重 * 4.0 就是4个象限的权重
    for(float x = 1.0; x <= halfSize; x++) {
      for (float y = 1.0; y<= halfSize; y++) {
        totalWeight += getWeight(x, y) * 4.0;
      }
    } 

    // 步骤二:采样周边像素并应用加权平均值,得出最终像素值
    vec4 finalColor = vec4(0.0, 0.0, 0.0, 0.0); 
    float onePxWidth = 1.0 / textureSize.x;
    float onePxHeight = 1.0 / textureSize.y;
    for(float x = -halfSize; x<= halfSize; x++) {
      for (float y = -halfSize; y<= halfSize; y++) {
        // 求出对应坐标的真正权重(对应权重矩阵)
        float weight = getWeight(x, y) / totalWeight;

        // 求出对应坐标像素颜色值的加权值 
        finalColor += texture(cc_spriteTexture, v_uv0 + vec2(onePxWidth * x, onePxHeight * y)) * weight;
      }
    } 
    return finalColor;  
  }
}%
 

内含 边缘光2种, 圆角裁切1种,高斯模糊3种

入门学习记录,原理之后再加

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实现搓牌效果可以使用Cocos Creator的js shader来完成。首先,我们需要创建一个自定义的shader,将其应用到牌的渲染组件上。可以通过编辑顶点和片段着色器来实现搓牌的效果。 首先,定义一个变量来控制搓牌的进度。可以通过在脚本中设置一个初始值,然后在每一帧更新该值,以模拟手指滑动搓牌的效果。 然后,在顶点着色器中,对牌的每个顶点进行偏移操作。根据搓牌的进度值,调整顶点的位置,使之呈现出搓牌的形态。可以使用简单的插值方法(如线性插值),计算出每个顶点新的位置。 接下来,在片段着色器中,根据顶点的位置信息,设置每个像素的颜色值。可以使用纹理坐标来采样牌的纹理图片,根据搓牌的进度值,调整采样的坐标,以实现搓牌的效果。 最后,在每一帧更新搓牌的进度值,并将其传递给shader,更新牌的渲染效果。可以通过设置shader的uniform变量,将进度值传递给shader。 总结起来,使用Cocos Creator的js shader实现搓牌效果的步骤如下: 1. 创建自定义的shader,定义搓牌的进度变量。 2. 在顶点着色器中根据进度值调整顶点位置。 3. 在片段着色器中根据进度值调整纹理采样坐标。 4. 在每一帧更新进度值,并将其传递给shader。 5. 应用shader到牌的渲染组件上,实现搓牌效果。 希望这个简单的解答对你有帮助!如果你还有其他问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值