cocos 3.x 溶解

188 阅读4分钟

image.png

  • cocos creator 版本3.8.4

关键点

  1. dissolveThreshold: { value: 0.8, editor: { slide: true, range: [0, 1], step: 0.01, displayName: dissolveThreshold } }定义溶解滑条
  2. uniform Constants { vec4 albedo; vec4 albedoScaleAndCutoff; vec4 pbrParams; float opacity; float dissolveThreshold; }; 定义完成后必须要声明,才能使用
  3. noiseTexture: { value: white, target: noiseMap, visible: true, editor: { displayName: "Noise Map", type: texture } } 这里定义噪声图,并且只有embeddedMacros: { USE_NOISE_MAP: true } # 强制启用宏添加强制使用宏才可以显式在材质里选择对应的噪声图
  4. 所谓噪声图就是一张包含随机灰度值的纹理(通常是 灰度图),每个像素的RGB值相同(R=G=B)。
  5. 这里是核心部分,噪音值小于溶解dissolveThreshold的部分就不展示
#if USE_NOISE_MAP
      float noise = texture(noiseMap, NOISE_UV).r;
    #else
      // 回退到数学噪声
      float noise = randomNoise(gl_FragCoord.xy / 100.0);
    #endif

    if(noise < dissolveThreshold) {
      discard;
    }

    // 边缘过渡(可选)
    float edgeWidth = 0.1;
    float edge = smoothstep(dissolveThreshold, dissolveThreshold + edgeWidth, noise);
    baseColor.a *= (noise < dissolveThreshold + edgeWidth) ? edge : 1.0;

    return baseColor;

6. 完整代码

// Effect Syntax Guide: https://docs.cocos.com/creator/manual/zh/shader/index.html

CCEffect %{
  techniques:
  - name: opaque
    passes:
    - vert: standard-vs
      frag: standard-fs
      embeddedMacros: { USE_NOISE_MAP: true }  # 强制启用宏
      properties: &props
        mainTexture:              { value: grey, target: albedoMap, editor: { displayName: AlbedoMap } }
        mainColor:                { value: [1.0, 1.0, 1.0, 1.0], target: albedo, linear: true, editor: { displayName: Albedo, type: color } }
        opacity:                  { value: 1.0, editor: { slide: true, range: [0, 1], step: 0.01, displayName: Opacity } }
        dissolveThreshold:        { value: 0.8, editor: { slide: true, range: [0, 1], step: 0.01, displayName: dissolveThreshold } }
        noiseTexture:             { 
                                    value: white, 
                                    target: noiseMap,
                                    visible: true,
                                    editor: { 
                                      displayName: "Noise Map", 
                                      type: texture 
                                    } 
        }
        albedoScale:              { value: [1.0, 1.0, 1.0], target: albedoScaleAndCutoff.xyz }
        alphaThreshold:           { value: 0.5, target: albedoScaleAndCutoff.w, editor: { parent: USE_ALPHA_TEST, slide: true, range: [0, 1.0], step: 0.001 } }
        roughness:                { value: 0.8, target: pbrParams.y, editor: { slide: true, range: [0, 1.0], step: 0.001 } }
        metallic:                 { value: 0.6, target: pbrParams.z, editor: { slide: true, range: [0, 1.0], step: 0.001 } }
    - &forward-add
      vert: standard-vs
      frag: standard-fs
      phase: forward-add
      propertyIndex: 0
      embeddedMacros: { CC_FORWARD_ADD: true }
      depthStencilState:
        depthFunc: equal
        depthTest: true
        depthWrite: false
      blendState:
        targets:
        - blend: true
          blendSrc: src_alpha          # 源颜色 = 当前片元Alpha * 当前颜色
          blendDst: one_minus_src_alpha # 目标颜色 = (1 - 当前Alpha) * 原有颜色
          blendSrcAlpha: src_alpha     # 源Alpha = 当前Alpha
          blendDstAlpha: one_minus_src_alpha # 目标Alpha = (1 - 当前Alpha)
    - &shadow-caster
      vert: shadow-caster-vs
      frag: shadow-caster-fs
      phase: shadow-caster
      propertyIndex: 0
      rasterizerState:
        cullMode: front
      properties:
        mainColor:      { value: [1.0, 1.0, 1.0, 1.0], target: albedo, editor: { displayName: Albedo, type: color } }
        albedoScale:    { value: [1.0, 1.0, 1.0], target: albedoScaleAndCutoff.xyz }
        alphaThreshold: { value: 0.5, target: albedoScaleAndCutoff.w, editor: { parent: USE_ALPHA_TEST } }
        mainTexture:    { value: grey, target: albedoMap, editor: { displayName: AlbedoMap } }
  - name: transparent
    passes:
    - vert: standard-vs
      frag: standard-fs
      embeddedMacros: { CC_FORCE_FORWARD_SHADING: true }
      depthStencilState:
        depthTest: true
        depthWrite: false
      blendState:
        targets:
        - blend: true
          blendSrc: src_alpha
          blendDst: one_minus_src_alpha
          blendDstAlpha: one_minus_src_alpha
      properties: *props
    - *forward-add
    - *shadow-caster
}%


CCProgram shared-ubos %{
  uniform Constants {
    vec4 albedo;
    vec4 albedoScaleAndCutoff;
    vec4 pbrParams;
    float opacity;
    float dissolveThreshold;
  };
}%

CCProgram macro-remapping %{
  // ui displayed macros
  #pragma define-meta USE_TWOSIDE
  #pragma define-meta USE_VERTEX_COLOR

  #define CC_SURFACES_USE_TWO_SIDED USE_TWOSIDE
  #define CC_SURFACES_USE_VERTEX_COLOR USE_VERTEX_COLOR
}%
CCProgram surface-vertex %{
  #define CC_SURFACES_VERTEX_MODIFY_WORLD_POS
  vec3 SurfacesVertexModifyWorldPos(in SurfacesStandardVertexIntermediate In)
  {
    return In.worldPos;
  }
  
  #define CC_SURFACES_VERTEX_MODIFY_WORLD_NORMAL
  vec3 SurfacesVertexModifyWorldNormal(in SurfacesStandardVertexIntermediate In)
  {
    return In.worldNormal.xyz;
  }
  
  #define CC_SURFACES_VERTEX_MODIFY_UV
  void SurfacesVertexModifyUV(inout SurfacesStandardVertexIntermediate In)
  {
  }
}%


CCProgram surface-fragment %{
  // 声明噪声贴图
  #if USE_NOISE_MAP
    uniform sampler2D noiseMap;
    #pragma define-meta NOISE_UV options([v_uv, v_uv1, v_worldPos.xy])
  #endif

  // 伪随机噪声函数(无需贴图)
  float randomNoise(vec2 uv) {
    return fract(sin(dot(uv, vec2(12.9898, 78.233))) * 43758.5453);
  }

  #if USE_ALBEDO_MAP
    uniform sampler2D albedoMap;
    #pragma define-meta ALBEDO_UV options([v_uv, v_uv1])
  #endif

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

  #define CC_SURFACES_FRAGMENT_MODIFY_BASECOLOR_AND_TRANSPARENCY
  vec4 SurfacesFragmentModifyBaseColorAndTransparency()
  {
    vec4 baseColor = albedo;
    
    #if USE_ALBEDO_MAP
      vec4 texColor = texture(albedoMap, ALBEDO_UV);
      texColor.rgb = SRGBToLinear(texColor.rgb);
      baseColor *= texColor;
    #endif

    #if USE_ALPHA_TEST
      if (baseColor.ALPHA_TEST_CHANNEL < albedoScaleAndCutoff.w) discard;
    #endif

    baseColor.rgb *= albedoScaleAndCutoff.xyz;

    baseColor.a *= opacity;

    vec2 uv = gl_FragCoord.xy / vec2(1024.0, 768.0);
    // float noise = randomNoise(uv * 10.0);
    #if USE_NOISE_MAP
      float noise = texture(noiseMap, NOISE_UV).r;
    #else
      // 回退到数学噪声
      float noise = randomNoise(gl_FragCoord.xy / 100.0);
    #endif

    if(noise < dissolveThreshold) {
      discard;
    }

    // 边缘过渡(可选)
    float edgeWidth = 0.1;
    float edge = smoothstep(dissolveThreshold, dissolveThreshold + edgeWidth, noise);
    baseColor.a *= (noise < dissolveThreshold + edgeWidth) ? edge : 1.0;

    return baseColor;
  }

  #define CC_SURFACES_FRAGMENT_ALPHA_CLIP_ONLY
  void SurfacesFragmentAlphaClipOnly()
  {
    #if USE_ALPHA_TEST
      float alpha = albedo.ALPHA_TEST_CHANNEL;
      #if USE_VERTEX_COLOR
        alpha *= FSInput_vertexColor.a;
      #endif
      #if USE_ALBEDO_MAP
        alpha = texture(albedoMap, ALBEDO_UV).ALPHA_TEST_CHANNEL;
      #endif
  
      if (alpha < albedoScaleAndCutoff.w) discard;
    #endif
  }

  #define CC_SURFACES_FRAGMENT_MODIFY_WORLD_NORMAL
  vec3 SurfacesFragmentModifyWorldNormal()
  {
    return normalize(FSInput_worldNormal);
  }

  #define CC_SURFACES_FRAGMENT_MODIFY_EMISSIVE
  vec3 SurfacesFragmentModifyEmissive()
  {
    return vec3(0.0, 0.0, 0.0);
  }

  #define CC_SURFACES_FRAGMENT_MODIFY_PBRPARAMS
  vec4 SurfacesFragmentModifyPBRParams()
  {
    // ao, roughness, metallic, specularIntensity
    return vec4(1.0, pbrParams.y, pbrParams.z, 0.5);
  }
}%




CCProgram standard-vs %{
  precision highp float;

  // 1. surface internal macros, for technique usage or remapping some user (material) macros to surface internal macros
  #include <macro-remapping>
  #include <surfaces/effect-macros/common-macros>

  // 2. common include with corresponding shader stage, include before surface functions
  #include <surfaces/includes/common-vs>

  // 3. user surface functions that can use user (effect) parameters (ubo Constants)
  //    see surfaces/default-functions/xxx.chunk
  #include <shared-ubos>
  #include <surface-vertex>

  // 4. surface include with corresponding shader stage and shading-model (optional)
  #include <surfaces/includes/standard-vs>

  // 5. shader entry with corresponding shader stage and technique usage/type
  #include <shading-entries/main-functions/render-to-scene/vs>
}%


CCProgram shadow-caster-vs %{
  precision highp float;
  #include <surfaces/effect-macros/render-to-shadowmap>
  #include <surfaces/includes/common-vs>
  #include <shared-ubos>
  #include <surface-vertex>
  #include <shading-entries/main-functions/render-to-shadowmap/vs>
}%



CCProgram standard-fs %{
  // shading-model : standard
  // lighting-model : standard (isotropy / anisotropy pbr)
  // shader stage : fs
  // technique usage/type : render-to-scene

  precision highp float;
  // 1. surface internal macros, for technique usage or remapping some user (material) macros to surface internal macros
  #include <macro-remapping>
  #include <surfaces/effect-macros/common-macros>

  // 2. common include with corresponding shader stage, include before surface functions
  #include <surfaces/includes/common-fs>

  // 3. user surface functions that can use user (effect) parameters (ubo Constants)
  //    see surfaces/default-functions/xxx.chunk
  #include <shared-ubos>
  #include <surface-fragment>

  // 4. lighting-model (optional)
  #include <lighting-models/includes/standard>

  // 5. surface include with corresponding shader stage and shading-model (optional)
  #include <surfaces/includes/standard-fs>

  // 6. shader entry with corresponding shader stage and technique usage/type
  #include <shading-entries/main-functions/render-to-scene/fs>
}%

CCProgram shadow-caster-fs %{
  precision highp float;
  #include <surfaces/effect-macros/render-to-shadowmap>
  #include <surfaces/includes/common-fs>
  #include <shared-ubos>
  #include <surface-fragment>
  #include <shading-entries/main-functions/render-to-shadowmap/fs>
}%