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

效果见图:

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

// 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个参数:


        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内的渐变显示, 超过这个距离的不显示:

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-06-13 22:36:03       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-06-13 22:36:03       106 阅读
  3. 在Django里面运行非项目文件

    2024-06-13 22:36:03       87 阅读
  4. Python语言-面向对象

    2024-06-13 22:36:03       96 阅读

热门阅读

  1. Android Unable to determine activity name

    2024-06-13 22:36:03       30 阅读
  2. APP怎么上架到应用商店

    2024-06-13 22:36:03       31 阅读
  3. 你认为这个项目的难点和亮点是什么?

    2024-06-13 22:36:03       33 阅读
  4. 事务并发问题 与 事务隔离级别

    2024-06-13 22:36:03       36 阅读
  5. pytorch中,load_state_dict和torch.load的区别?

    2024-06-13 22:36:03       28 阅读
  6. springMVC简介

    2024-06-13 22:36:03       25 阅读