【cocos creator 3.x】 修改builtin-unlit 加了一个类似流光显示的mask参数

效果见图:

shader 代码修改如下, 主要看 USE_MASK_UVY 关键字部分修改:

bash 复制代码
// Copyright (c) 2017-2020 Xiamen Yaji Software Co., Ltd.
CCEffect %{
  techniques:
  - name: opaque
    passes:
    - vert: unlit-vs:vert
      frag: unlit-fs:frag
      properties: &props
        mainTexture:    { value: grey }
        tilingOffset:   { value: [1, 1, 0, 0] }
        mainColor:      { value: [1, 1, 1, 1], linear: true, editor: { type: color } }
        colorScale:     { value: [1, 1, 1], target: colorScaleAndCutoff.xyz }
        alphaThreshold: { value: 0.5, target: colorScaleAndCutoff.w, editor: { parent: USE_ALPHA_TEST } }
        color:          { target: mainColor, linear: true, editor: { visible: false } } # backward compability
        mask_uvpos:     { value: 0.5, target: mask.x, editor: { parent: USE_MASK_UVY } } # uv 采样中心位置
        mask_width:     { value: 0.1, target: mask.y, editor: { parent: USE_MASK_UVY, range: [0, 1] } } # uv 采样上下宽度范围
        mask_lerpwidth:     { value: 0.05, target: mask.z, editor: { parent: USE_MASK_UVY , range: [0, 1]} } # uv 采样边缘平滑宽度
        mask_alpha_strength:     { value: 1, target: mask.w, editor: { parent: USE_MASK_UVY } } # uv 采样透明度强度

      migrations: &migs
        properties:
          mainColor:    { formerlySerializedAs: color }
    - &planar-shadow
      vert: planar-shadow-vs:vert
      frag: planar-shadow-fs:frag
      phase: planar-shadow
      propertyIndex: 0
      depthStencilState:
        depthTest: true
        depthWrite: false
        stencilTestFront: true
        stencilFuncFront: not_equal
        stencilPassOpFront: replace
        stencilRef: 0x80 # only use the leftmost bit
        stencilReadMask: 0x80
        stencilWriteMask: 0x80
      blendState:
        targets:
        - blend: true
          blendSrc: src_alpha
          blendDst: one_minus_src_alpha
          blendDstAlpha: one_minus_src_alpha
    - &deferred-forward
      vert: unlit-vs:vert
      frag: unlit-fs:frag
      phase: deferred-forward
      propertyIndex: 0
  - name: transparent
    passes:
    - vert: unlit-vs:vert
      frag: unlit-fs:frag
      depthStencilState: &d1
        depthTest: true
        depthWrite: false
      blendState: &b1
        targets:
        - blend: true
          blendSrc: src_alpha
          blendDst: one_minus_src_alpha
          blendDstAlpha: one_minus_src_alpha
      properties: *props
      migrations: *migs
    - *planar-shadow
    - &deferred-forward-transparent
      vert: unlit-vs:vert
      frag: unlit-fs:frag
      phase: deferred-forward
      propertyIndex: 0
      migrations: *migs
      depthStencilState: *d1
      blendState: *b1
  - name: add
    passes:
    - vert: unlit-vs:vert
      frag: unlit-fs:frag
      rasterizerState: &r1 { cullMode: none }
      depthStencilState: *d1
      blendState: &b2
        targets:
        - blend: true
          blendSrc: src_alpha
          blendDst: one
          blendSrcAlpha: src_alpha
          blendDstAlpha: one
      properties: *props
      migrations: *migs
    - &deferred-forward-add
      vert: unlit-vs:vert
      frag: unlit-fs:frag
      phase: deferred-forward
      rasterizerState: *r1
      depthStencilState: *d1
      blendState: *b2
      propertyIndex: 0
      migrations: *migs
  - name: alpha-blend
    passes:
    - vert: unlit-vs:vert
      frag: unlit-fs:frag
      rasterizerState: *r1
      depthStencilState: *d1
      blendState: &b3
        targets:
        - blend: true
          blendSrc: src_alpha
          blendDst: one_minus_src_alpha
          blendSrcAlpha: src_alpha
          blendDstAlpha: one_minus_src_alpha
      properties: *props
      migrations: *migs
    - &deferred-forward-alpha-blend
      vert: unlit-vs:vert
      frag: unlit-fs:frag
      phase: deferred-forward
      rasterizerState: *r1
      depthStencilState: *d1
      blendState: *b3
      propertyIndex: 0
      migrations: *migs
}%

CCProgram unlit-vs %{
  precision highp float;
  #include <legacy/input>
  #include <builtin/uniforms/cc-global>
  #include <legacy/decode-base>
  #include <legacy/local-batch>
  #include <legacy/input>
  #include <legacy/fog-vs>

  #if USE_VERTEX_COLOR
    in lowp vec4 a_color;
    out lowp vec4 v_color;
  #endif

  #if USE_TEXTURE
    out vec2 v_uv;
    uniform TexCoords {
      vec4 tilingOffset;
    };
  #endif

  vec4 vert () {
    vec4 position;
    CCVertInput(position);

    mat4 matWorld;
    CCGetWorldMatrix(matWorld);

    #if USE_TEXTURE
      v_uv = a_texCoord * tilingOffset.xy + tilingOffset.zw;
      #if SAMPLE_FROM_RT
        CC_HANDLE_RT_SAMPLE_FLIP(v_uv);
      #endif
    #endif

    #if USE_VERTEX_COLOR
      v_color = a_color;
    #endif

    CC_TRANSFER_FOG(matWorld * position);
    return cc_matProj * (cc_matView * matWorld) * position;
  }
}%

CCProgram unlit-fs %{
  precision highp float;
  #include <legacy/output-standard>
  #include <legacy/fog-fs>

  #if USE_ALPHA_TEST
    #pragma define-meta ALPHA_TEST_CHANNEL options([a, r, g, b])
  #endif

  #if USE_TEXTURE
    in vec2 v_uv;
    uniform sampler2D mainTexture;
  #endif

  uniform Constant {
    vec4 mainColor;
    vec4 colorScaleAndCutoff;
    vec4 mask;  // USE_MASK_UVY
  };

  #if USE_VERTEX_COLOR
    in lowp vec4 v_color;
  #endif

  #if USE_MASK_UVY
  // float LerpMask(float uv_y, vec4 mask) {
  //   float d = abs(uv_y - mask.x);  // uv y 与中心点的距离
  //   float a = mask.w;
  //   float d2 = d - mask.y;        // 距离小于 mask.y(mask宽度范围) 则显示全值
  //   if(d2 > 0.0) {
  //     if(d2 <= mask.z && mask.z > 0.0) {
  //       a *= (1.0 - (d2 /mask.z)); // 距离大于 mask.y 且 小于 mask.z(mask边缘平滑宽度) 则开始衰减
  //     } else {
  //       a = 0.0;
  //     }
  //   }
  //   return a;
  // }
  float LinearStep(float t1, float t2, float x)
  {
      x = clamp((x-t1)/(t2-t1),0.0,1.0);
      // return x*x*(3-2*x);  // smoothstep
      return x;
  }
  #endif

  vec4 frag () {
    vec4 o = mainColor;
    o.rgb *= colorScaleAndCutoff.xyz;

    #if USE_VERTEX_COLOR
      o.rgb *= SRGBToLinear(v_color.rgb);//use linear
      o.a *= v_color.a;
    #endif


    #if USE_TEXTURE
      vec4 texColor = texture(mainTexture, v_uv);
      texColor.rgb = SRGBToLinear(texColor.rgb);
      o *= texColor;
    #endif

  #if USE_MASK_UVY
    // o.a *= LerpMask(v_uv.y, mask);
    o.a *= LinearStep(mask.z, 0.0, abs(v_uv.y - mask.x) - mask.y) * mask.w;
  #endif

    #if USE_ALPHA_TEST
      if (o.ALPHA_TEST_CHANNEL < colorScaleAndCutoff.w) discard;
    #endif

    CC_APPLY_FOG(o);
    return CCFragOutput(o);
  }
}%

CCProgram planar-shadow-vs %{
  precision highp float;
  #include <legacy/input>
  #include <builtin/uniforms/cc-global>
  #include <legacy/decode-base>
  #include <legacy/local-batch>
  #include <builtin/uniforms/cc-shadow>
  #include <common/lighting/functions>

  out float v_dist;

  vec4 vert () {
    vec4 position;
    CCVertInput(position);
    // World Space
    mat4 matWorld, matWorldIT;
    CCGetWorldMatrixFull(matWorld, matWorldIT);
    vec3 worldPos = (matWorld * position).xyz;
    vec4 shadowPos = CalculatePlanarShadowPos(worldPos, cc_cameraPos.xyz, cc_mainLitDir.xyz, cc_planarNDInfo);
    position = CalculatePlanarShadowClipPos(shadowPos, cc_cameraPos.xyz, cc_matView, cc_matProj, cc_nearFar, cc_shadowWHPBInfo.w);
    v_dist = shadowPos.w;
    return position;
  }
}%

CCProgram planar-shadow-fs %{
  precision highp float;
  #include <builtin/uniforms/cc-shadow>
  #include <legacy/output>

  in float v_dist;

  vec4 frag () {
    if(v_dist < 0.0)
      discard;
    return CCFragOutput(cc_shadowColor);
  }
}%

即加了4个参数:

bash 复制代码
        mask_uvpos:     { value: 0.5, target: mask.x, editor: { parent: USE_MASK_UVY } } # uv 采样中心位置
        mask_width:     { value: 0.1, target: mask.y, editor: { parent: USE_MASK_UVY, range: [0, 1] } } # uv 采样上下宽度范围
        mask_lerpwidth:     { value: 0.05, target: mask.z, editor: { parent: USE_MASK_UVY , range: [0, 1]} } # uv 采样边缘平滑宽度
        mask_alpha_strength:     { value: 1, target: mask.w, editor: { parent: USE_MASK_UVY } } # uv 采样透明度强度

核心算法就一句:

o.a *= smoothstep(mask.z, 0.0, abs(v_uv.y - mask.x) - mask.y) * mask.w;

感觉平滑过渡反而不好,所以自己实现了一个函数 LinearStep:

o.a *= LinearStep(mask.z, 0.0, abs(v_uv.y - mask.x) - mask.y) * mask.w;

注释掉的 LerpMask 是等价这个算法的,只不过用了 if else来实现的。

算法思路如下: 靠近 pos width内的 全部显示, 接着lerpwidth内的渐变显示, 超过这个距离的不显示:

相关推荐
VaJoy14 天前
Cocos Creator Shader 入门 ⑺ —— 图层混合样式的实现与 Render Texture
cocos creator
VaJoy16 天前
Cocos Creator Shader 入门 ⑹ —— 灰阶、反色等滤镜的实现
cocos creator
VaJoy18 天前
Cocos Creator Shader 入门 ⑸ —— 代码复用与绿幕抠图技术
cocos creator
龚子亦19 天前
【Shader学习】完整光照效果
unity·技术美术·shader
VaJoy19 天前
Cocos Creator Shader 入门 ⑷ —— 纹理采样与受击闪白的实现
cocos creator
VaJoy21 天前
Cocos Creator Shader 入门 ⑶ —— 给节点设置透明度
cocos creator
VaJoy23 天前
Cocos Creator Shader 入门 (2) —— 给节点染色
cocos creator
heeheeai23 天前
kotlin kmp 副作用函数 effect
kotlin·effect·kmp·副作用函数
VaJoy24 天前
Cocos Creator Shader —— 附录
cocos creator
成长ing1213824 天前
多层背景视差滚动Parallax Scrolling
cocos creator