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

相关推荐
/**书香门第*/2 天前
Cocos Creator 3.8箭头小游戏的实现
cocos creator·箭头
玖玥拾5 天前
Unity Shader 基础与图形学(一)
unity·图形渲染·图形学·shader
进哥AI研习社1 个月前
WebGL 与视频背景——首屏视觉层的性能博弈
性能优化·webgl·gpu·canvas·shader·帧率·视频背景
oden1 个月前
一个不会游戏开发的人,用 AI 把一款小游戏做到上线了
ai编程·cocos creator·游戏开发
mxwin3 个月前
Unity Shader exp 函数的算法与渲染应用
算法·unity·游戏引擎·shader
陶锅煮新茄子3 个月前
[cc-2d-kit]CocosCreator2D游戏开发工具包🚀
cocos creator
mxwin3 个月前
Unity Shader URP:法线在空间变换上的特殊性
unity·游戏引擎·shader
mxwin3 个月前
次世代角色 PBR 贴图制作 + Unity URP 接入 极简流程图
unity·流程图·贴图·shader
mxwin3 个月前
Unity URP 法线贴图色彩空间、编码与解码
unity·游戏引擎·贴图·shader
mxwin3 个月前
Unity Shader URP:将法线可视化,便于调试
unity·游戏引擎·shader