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

相关推荐
mxwin4 天前
unity shader中 ddx ddy是什么
unity·游戏引擎·shader
mxwin5 天前
Unity SetPassCall和DrawCall的区别是什么
unity·游戏引擎·shader
mxwin8 天前
在unity shader中,通过pass产生阴影,通过主pass的光照 接收阴影!那么问题来了,是先产生阴影吗?还是先接收阴影,执行顺序是啥呢
数码相机·unity·游戏引擎·shader
小贺儿开发8 天前
《唐朝诡事录之长安》——盛世马球
人工智能·unity·ai·shader·绘画·影视·互动
mxwin15 天前
Unity Shader 半透明物体为什么不能写入深度缓冲?
unity·游戏引擎·shader
mxwin15 天前
Unity Shader 手写基于 PBR 的 URP Lit Shader 核心光照计算
unity·游戏引擎·shader
mxwin15 天前
Unity GPU Shader 性能优化指南
unity·游戏引擎·shader
mxwin17 天前
Unity Custom Interpolators与半透明阴影的原理与实战
unity·游戏引擎·shader
小贺儿开发20 天前
【MediaPipe】Unity3D 虚拟面具互动演示
unity·人机交互·shader·摄像头·面具·互动·脸部捕捉
mxwin20 天前
Unity Shader 屏幕空间反射 (SSR) 原理解析
jvm·unity·游戏引擎·shader