cocos / cocos-engine

Cocos simplifies game creation and distribution with Cocos Creator, a free, open-source, cross-platform game engine. Empowering millions of developers to create high-performance, engaging 2D/3D games and instant web entertainment.
https://www.cocos.com/en/creator
Other
8.23k stars 1.94k forks source link

If the 3D particle's animation texture uses a PVRTC 4bits RGB Separate A compressed texture, it may render incorrectly on iOS devices #16543

Open zhefengzhang opened 11 months ago

zhefengzhang commented 11 months ago

Cocos Creator version

2.4.12 & 3.8.1

System information

MacOS & iOS

Issue description

If the 3D particle's animation texture uses a PVRTC 4bits RGB Separate A compressed texture, it may render incorrectly on iOS devices

8c20363d4a535c299675504828769c9

Relevant error log output

-

Steps to reproduce

Download the project file below and open it in CocosCreator. Build the web-mobile project and run it. Run the web-mobile project on a macOS or iOS device and observe if there are any display issues. The image resource with the issue is named T_TD_thunder_A.png.

Minimal reproduction project

TestPVR.zip

zhefengzhang commented 11 months ago

Solution: Modify the built-in 3D particle material shader of the engine, specifically adding the CCSampleWithAlphaSeparated function as follows:

CCEffect %{
  temporaries:
    b1: &b1
      targets:
      - blend: true
        blendSrc: src_alpha
        blendDst: one
        blendSrcAlpha: src_alpha
        blendDstAlpha: one
    b2: &b2
      targets:
      - blend: true
        blendSrc: src_alpha
        blendDst: one_minus_src_alpha
        blendSrcAlpha: src_alpha
        blendDstAlpha: one_minus_src_alpha
    d1: &d1 { depthTest: true, depthWrite: false }
    r1: &r1 { cullMode: none }
    p1: &p1
      mainTexture:            { value: grey }
      mainTiling_Offset:      { value: [1, 1, 0, 0]  }
    p2: &p2
      <<: *p1
      tintColor:              { value: [0.5, 0.5, 0.5, 0.5], inspector: { type: color } }

  techniques:
  - name: opaque-add
    passes:
    - stage: opaque 
      vert: particle-vs-legacy:lpvs_main
      frag: tinted-fs:add
      rasterizerState: *r1
      depthStencilState: *d1
      blendState: *b1
      properties: *p2
  - name: opaque-alpha-blend
    passes:
    - stage: opaque
      vert: particle-vs-legacy:lpvs_main
      frag: tinted-fs:add
      rasterizerState: *r1
      depthStencilState: *d1
      blendState: *b2
      properties: *p2
  - name: opaque-add-multiply
    passes:
    - stage: opaque 
      vert: particle-vs-legacy:lpvs_main
      frag: tinted-fs:multiply
      rasterizerState: *r1
      depthStencilState: *d1
      blendState: *b2
      properties: *p2
  - name: opaque-add-smooth
    passes:
    - stage: opaque 
      vert: particle-vs-legacy:lpvs_main
      frag: no-tint-fs:addSmooth
      rasterizerState: *r1
      depthStencilState: *d1
      blendState: *b2
      properties: *p1
  - name: opaque-premultiply-blend
    passes:
    - stage: opaque
      vert: particle-vs-legacy:lpvs_main
      frag: no-tint-fs:premultiplied
      rasterizerState: *r1
      depthStencilState: *d1
      blendState: *b2
      properties: *p1
  - name: transparent-add
    passes:
    - stage: transparent 
      vert: particle-vs-legacy:lpvs_main
      frag: tinted-fs:add
      rasterizerState: *r1
      depthStencilState: *d1
      blendState: *b1
      properties: *p2
  - name: transparent-alpha-blend
    passes:
    - stage: transparent
      vert: particle-vs-legacy:lpvs_main
      frag: tinted-fs:add
      rasterizerState: *r1
      depthStencilState: *d1
      blendState: *b2
      properties: *p2
  - name: transparent-add-multiply
    passes:
    - stage: transparent 
      vert: particle-vs-legacy:lpvs_main
      frag: tinted-fs:multiply
      rasterizerState: *r1
      depthStencilState: *d1
      blendState: *b2
      properties: *p2
  - name: transparent-add-smooth
    passes:
    - stage: transparent 
      vert: particle-vs-legacy:lpvs_main
      frag: no-tint-fs:addSmooth
      rasterizerState: *r1
      depthStencilState: *d1
      blendState: *b2
      properties: *p1
  - name: transparent-premultiply-blend
    passes:
    - stage: transparent
      vert: particle-vs-legacy:lpvs_main
      frag: no-tint-fs:premultiplied
      rasterizerState: *r1
      depthStencilState: *d1
      blendState: *b2
      properties: *p1
}%

// TODO: soft particle

CCProgram tinted-fs %{
  precision highp float;
  #include <output>

  in vec2 uv;
  in vec4 color;

  uniform sampler2D mainTexture;
  uniform FragConstants {
    vec4 tintColor;
  };

  vec4 CCSampleWithAlphaSeparated(sampler2D tex, vec2 uv) {
    #if USE_EMBEDDED_ALPHA
      return vec4(texture(tex, uv).rgb, texture(tex, uv + vec2(0.0, 0.5)).r);
    #else
      return texture(tex, uv);
    #endif
  }

  vec4 add () {
    vec4 col = 2.0 * color * tintColor * CCSampleWithAlphaSeparated(mainTexture, uv);
    return CCFragOutput(col);
  }

  vec4 multiply () {
    vec4 col;
    vec4 texColor = CCSampleWithAlphaSeparated(mainTexture, uv);
    col.rgb = tintColor.rgb * texColor.rgb * color.rgb * vec3(2.0);
    col.a = (1.0 - texColor.a) * (tintColor.a * color.a * 2.0);
    return CCFragOutput(col);
  }
}%

CCProgram no-tint-fs %{
  precision highp float;
  #include <output>

  in vec2 uv;
  in vec4 color;

  uniform sampler2D mainTexture;

  vec4 addSmooth () {
    vec4 col = color * CCSampleWithAlphaSeparated(mainTexture, uv);
    col.rgb *= col.a;
    return CCFragOutput(col);
  }

  vec4 premultiplied () {
    vec4 col = color * CCSampleWithAlphaSeparated(mainTexture, uv) * color.a;
    return CCFragOutput(col);
  }
}%

Then, execute the following code during the 2.4.x project's runtime: 80077ea1e7ca77536b9c3aa3401b3b6

For version 3.8.1, execute the following code: f44285f938b4d8dc7d757d6233dc71f1