iOS only, flickering edges with a RawShaderMaterial

Edges flicker in iOS, work on other browsers

JSFiddle :

Expected result, here on Chromium Linux:
Expected result, here on Chromium Linux

Flickering edges on Safari iO (flickering is visible and edge artifacts change on a per frame render basis):
Flickering edges on Safari iOS


Our custom shader composites arrays of textures with standard compositing operation (over, add, mult…), the same way Photoshop / After Effects / Nuke would composite layers. The fragment gets a procedural base color, assign it to gl_FragColor, then for each layer:

  1. the matching texture gets composited with gl_FragColor: gl_FragColor = merge(gl_FragColor, texelColor, MERGE_OPERATION). The type of merge (over, add, mult…) is defined with MERGE_OPERATION
  2. based on a switch, alpha can be kept or reset to 1.0 for make the texture fully opaque: gl_FragColor.a = transparent ? gl_FragColor.a : 1.0;

The layers are defined by arrays of attributes, TEXTURES_ARRAY_SIZE being the number of layers:

uniform sampler2D layersTexture[TEXTURES_ARRAY_SIZE];
uniform int layersMergeOp[TEXTURES_ARRAY_SIZE];
uniform bool layersTransparent[TEXTURES_ARRAY_SIZE];
for (int layerIndex = 0 ; i < TEXTURES_ARRAY_SIZE ; ++i) {
    // gl_FragColor = compositeLayer(gl_FragColor, layerIndex);

In the jsfiddle sample the shaders have been simplified to composite only two procedurally defined colors (the base color and the first and only layer): we don’t pass actual textures, so layersTexture does not exist. However:

  • layersMergeOp is [0], 0 being the mergeOver operation code
  • layersTransparent is [true], so we keep all transparency
Issue on iOS

This shader works fine on evey platform we’ve tried so far, Windows, macOS, Linux, Android on a range of browsers, but on iOS the edges are flickering. The problems seems to be related to alpha and antialiasing : after turning antialiasing off the edges are not flickering anymore.

Here are several options we are exploring that have an impact on the iOS edges flickering:

  • FIX 1: hardcoding the merge operation code or the transparent layer property lookup
// int mergeOp = layersMergeOp[i];
int mergeOp = 0;


// bool transparent = layersTransparent[i];
int transparent = true;
  • FIX 2: forcing the merge operation type prevents the operation type switch in merge, bypassing the layersMergeOp[i] lookup
// gl_FragColor = merge(gl_FragColor, color2, mergeOp);
gl_FragColor = mergeOver(gl_FragColor, color2);
  • FIX 3: boundary checking the merge operation code to ensure that it matches an operation in the merge switch and forcing a static color for the fragment:
if (mergeOp < 0 || mergeOp > 2) {
    gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);

None of thoses fix make sense to me : it is as if looking values in the uniform arrays would return invalid values for the fragments computed for antialiasing purpose along the edges…

Is there something obvious I’m missing here ? An iOS limitation that I’m not yet aware off ?

Many thanks !

Three.js version
  • r86
  • All of them
  • Chrome
  • Firefox
  • Internet Explorer
  • Safari
  • All of them
  • Windows
  • macOS
  • Linux
  • Android
  • iOS
Hardware Requirements (graphics card, VR Device, …)
  • iPad Air 2 iOS 10.3.2
  • Recent iPhone

Author: Fantashit

1 thought on “iOS only, flickering edges with a RawShaderMaterial

  1. Even if my suggested approach is not feasible for your use case, it would be good to know if it solves the issue you’re seeing.

Comments are closed.