glslshaderspark-ar-studio

Shader looks completely different on Instagram than in SparkAR Studio


I'm trying to create an underwater filter by utilizing shaders in SparkAR. My filter looks like intended in SparkAR, but not at all when tested in Instagram. Here is a comparison, SparkAR on the left, Instagram on the right: SparkAR compared to Instagram

I thought it had something to do with the resolution, so I tried everything there already: upscaling, calculating the UVs by using getModelViewProjectionMatrix() instead of getRenderTargetSize(), etc.

Nothing worked, so I hope someone here has experienced something similar and can help me out!

Here is the shader code used:

#ifdef GL_ES
precision mediump float;
#endif

float length2(vec2 p) { return dot(p, p); }

float noise(vec2 p){
  return fract(sin(fract(sin(p.x) * (4231.13311)) + p.y) * 3131.0011);
}

float worley(vec2 p) {
  float d = 1e30;
  for (int xo = -1; xo <= 1; ++xo) {
    for (int yo = -1; yo <= 1; ++yo) {
      vec2 tp = floor(p) + vec2(xo, yo);
      d = min(d, length2(p - tp - vec2(noise(tp))));
    }
  }
  return 3.0*exp(-4.0*abs(2.0*d - 1.0));
}

float fworley(vec2 p) {
  float time = fragment(std::getTime());
  return sqrt(sqrt(sqrt(
    1.6 * // light
    worley(p*32. + 4.3 + time*.125) *
    sqrt(worley(p * 64. + 5.3 + time * -0.0625)) *
    sqrt(sqrt(worley(p * -100. + 9.3))))));
}

void main(out vec4 Position, out vec4 Color) {
  Position = std::getModelViewProjectionMatrix() * std::getVertexPosition();

  vec2 scaling = vec2(1., 1.);
  float time = fragment(std::getTime());
  vec2 vertCoord =  fragment(std::getVertexTexCoord());
  vec2 resolution = fragment(std::getRenderTargetSize());
  vec2 uv = floor(resolution * vertCoord) / resolution;
    
  vec2 xDifference = vec2(2.0 * (sin(time / 2.0) / 2.0)  - 1.5, 0.8);
  float t = fworley(uv * resolution / (900.0 * scaling)) / 2.;
  t *= exp(-length2(abs(1.0* (uv + xDifference) *  - 1.0)));

  t += fworley(uv * resolution / (450.0 * scaling)) / 2.;
  xDifference = vec2(2.0 * (sin(time / 2.0) / 2.0)  - 0.75, 0.7);
  t *= exp(-length2(abs(1.0* (uv + xDifference) *  - 1.0))) * 0.5;

  t += fworley(uv * resolution / (300.0 * scaling)) / 3.;
  xDifference = vec2(2.0 * (sin(time / 2.0) / 3.0)  - 0.5, 0.6);
  t *= exp(-length2(abs(1.0* (uv + xDifference) *  - 1.0)));
  
  Color = vec4((t+0.05) * vec3(0.3, 1.5*t, 0.3 + pow(t, 1.0-t)), 1.3);
}

I also already checked if I used something that is not supported by GLSL 1.x as that is the basis for SparkSL. But that isn't the case.


Solution

  • You need to read the article : https://sparkar.facebook.com/ar-studio/learn/sparksl/cross-device-shader-sparksl#opengl

    In short, the issue is precision of floats.

    And never use:

    fract(sin(fract(sin(p.x) * (4231.13311)) + p.y) * 3131.0011);