0

It seems GLSL ES 3.0 does not execute properly my code.

I wrote twice the same code, first in an unrolled manner ; and second with a for loop :


    // Unrolled version:

    float minDistance = 1000000.0;

    vec3 finalColor1 = vec3(0.0);
    int index1 = 0;

    float distance = colorDifferenceCIE94FromRGB(pixel, colors[0]);
    if(distance < minDistance) {
        finalColor1 = colors[0];
        minDistance = distance;
        index1 = 0;
    }
    distance = colorDifferenceCIE94FromRGB(pixel,  colors[1]);
    if(distance < minDistance) {
        finalColor1 = colors[1];
        minDistance = distance;
        index1 = 1;
    }
    distance = colorDifferenceCIE94FromRGB(pixel, colors[2]);
    if(distance < minDistance) {
        finalColor1 = colors[2];
        minDistance = distance;
        index1 = 2;
    }
    distance = colorDifferenceCIE94FromRGB(pixel, colors[3]);
    if(distance < minDistance) {
        finalColor1 = colors[3];
        minDistance = distance;
        index1 = 3;
    }
    distance = colorDifferenceCIE94FromRGB(pixel, colors[4]);
    if(distance < minDistance) {
        finalColor1 = colors[4];
        minDistance = distance;
        index1 = 4;
    }
    distance = colorDifferenceCIE94FromRGB(pixel,  colors[5]);
    if(distance < minDistance) {
        finalColor1 = colors[5];
        minDistance = distance;
        index1 = 5;
    }
    distance = colorDifferenceCIE94FromRGB(pixel,  colors[6]);
    if(distance < minDistance) {
        finalColor1 = colors[6];
        minDistance = distance;
        index1 = 6;
    }
    distance = colorDifferenceCIE94FromRGB(pixel,  colors[7]);
    if(distance < minDistance) {
        finalColor1 = colors[7];
        minDistance = distance;
        index1 = 7;
    }
    distance = colorDifferenceCIE94FromRGB(pixel,  colors[8]);
    if(distance < minDistance) {
        finalColor1 = colors[8];
        minDistance = distance;
        index1 = 8;
    }

    // For Loop version:

    int index2 = 0;

    vec3 finalColor2 = pixel;

    minDistance = 100000.0;
    for(int i=0 ; i<9 ; i++) {
        distance = colorDifferenceCIE94FromRGB(pixel, colors[i]);
        if(distance < minDistance) {
            finalColor2 = colors[i];
            minDistance = distance;
            index2 = i;
        }
    }

    gl_FragColor = vec4((uv.x < 0.5 ? finalColor1 : finalColor2), 1.0);


At the left of the screen should be exactly the same as the right of the screen, but it is not (at least on my Macbook Pro Unibody 2012 OS X 10.14.4). Why?

I made a snippet available at the bottom of the question (and a demo project) to show the bug.

Code explanation

The code uses Paper.js to draw a red circle on a canvas, then gives this canvas to a Three.js CanvasTexture, which is applied to a fullscreen quad (a plane mesh).

The fragment shader computes the distance between the pixel colors (of the given texture) and a set of colors ; then render the closest color. This operation is performed twice, once in an unrolled version / sequencially, and once with a for loop. The result of the first version is displayed on the left of the screen, the second version on the right.

The result should be exactly the same but strangely it is not. Why?

You can see that by uncommenting line 157:

colors[8] = vec3(0.8, 0.4, 0.1);

(or lines 148 to 152) both codes execute similarly.

Here is what I get on my computer:

Left Right are different

The white square on the left is the paper.js canvas, the black square at the right is the three.js scene ; the second circle should be entirely red as well.

Code snippet

<!DOCTYPE html>
<html>
  <head>
    <title>Dynamic array glsl test</title>
    <meta charset="UTF-8" />

    <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/103/three.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/paper.js/0.12.0/paper-full.min.js"></script>

    <style>
      #three,
      #paper {
        width: 100px;
        height: 100px;
      }
      #three {
        /*display: none;*/
      }
      #paper {
        /*display: none;*/
      }
    </style>
  </head>

  <body>
    <canvas id="paper"></canvas>
    <canvas id="three"></canvas>
    <script type="application/glsl" id="fragmentShader2">
      varying vec2 vUV;

      uniform sampler2D textureSampler;
      uniform vec2 screenResolution;
      uniform vec2 textureResolution;

      void main(void) {

          vec2 uv = gl_FragCoord.xy / screenResolution.xy - 0.5;                    // [-0.5, 0.5]

          float screenRatio = screenResolution.x / screenResolution.y;
          float textureRatio = textureResolution.x / textureResolution.y;

          vec2 textureUV = textureRatio > screenRatio ? vec2(uv.x, uv.y * textureRatio / screenRatio) : vec2(uv.x / textureRatio * screenRatio, uv.y);

          gl_FragColor = texture2D(textureSampler, textureUV + 0.5);
          // gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
      }
    </script>

    <script type="application/glsl" id="fragmentShader">
      precision highp float;

      varying vec2 vUV;

      uniform sampler2D textureSampler;
      uniform vec2 screenResolution;
      uniform vec2 textureResolution;
      uniform float hueRotation;

      vec3 colors[9];

      #define PI 3.1415926535897932384626433832795


      vec3 hsv2rgb(vec3 c) {
          vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
          vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
          return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
      }

      vec4 hsv2rgb(vec4 c) {
          return vec4(hsv2rgb(c.xyz), c.w);
      }

      vec3 rgb2hsv(vec3 c) {
          vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
          vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
          vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));

          float d = q.x - min(q.w, q.y);
          float e = 1.0e-10;
          return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
      }

      vec4 rgb2hsv(vec4 c) {
          return vec4(rgb2hsv(c.xyz), c.w);
      }

      vec4 rotateHue(vec4 c, float angle) {
          vec4 chsv = rgb2hsv(c);
          chsv.x = mod(chsv.x + angle, 1.0);
          return hsv2rgb(chsv);
      }

      vec3 mixColors(vec3 c1, vec3 c2) {
          return sqrt(0.5 * c1 * c1 + 0.5 * c2 * c2);
      }

      vec3 mixColors(vec3 c1, vec3 c2, vec3 c3) {
          return sqrt( (c1 * c1 / 3.0) + (c2 * c2 / 3.0) + (c3 * c3 / 3.0));
      }

      vec3 rgb2xyz(vec3 rgb) {
          rgb.r = rgb.r > 0.04045 ? pow( ( rgb.r + 0.055 ) / 1.055, 2.4) : rgb.r / 12.92;
          rgb.g = rgb.g > 0.04045 ? pow( ( rgb.g + 0.055 ) / 1.055, 2.4) : rgb.g / 12.92;
          rgb.b = rgb.b > 0.04045 ? pow( ( rgb.b + 0.055 ) / 1.055, 2.4) : rgb.b / 12.92;

          rgb *= 100.0;

          return vec3(rgb.r * 0.4124 + rgb.g * 0.3576 + rgb.b * 0.1805,
                      rgb.r * 0.2126 + rgb.g * 0.7152 + rgb.b * 0.0722,
                      rgb.r * 0.0193 + rgb.g * 0.1192 + rgb.b * 0.9505);
      }


      vec3 xyz2lab(vec3 xyz) {
          xyz = xyz / vec3(94.811, 100.000, 107.304);

          xyz = vec3( xyz.r > 0.008856 ? pow( xyz.r, 1.0/3.0) : (7.787 * xyz.r) + (16.0 / 116.0),
                      xyz.g > 0.008856 ? pow( xyz.g, 1.0/3.0) : (7.787 * xyz.g) + (16.0 / 116.0),
                      xyz.b > 0.008856 ? pow( xyz.b, 1.0/3.0) : (7.787 * xyz.b) + (16.0 / 116.0));

          return vec3( (116.0 * xyz.y) - 16.0, 500.0 * (xyz.x - xyz.y), 200.0 * (xyz.y - xyz.z) );
      }

      vec3 rgb2lab(in vec3 rgb) {
          vec3 xyz = rgb2xyz(rgb);
          vec3 lab = xyz2lab(xyz);
          return(lab);
      }

      float colorDifferenceCIE94FromLab(vec3 cieLab1, vec3 cieLab2) {

          // Just to make it more readable
          float cL1 = cieLab1.r;
          float ca1 = cieLab1.g;
          float cb1 = cieLab1.b;

          float cL2 = cieLab2.r;
          float ca2 = cieLab2.g;
          float cb2 = cieLab2.b;

          float c1 = sqrt(ca1 * ca1 + cb1 * cb1);
          float c2 = sqrt(ca2 * ca2 + cb2 * cb2);

          float dL = cL2 - cL1;

          float dC = c2 - c1;

          float dE = sqrt( (cL1 - cL2) * (cL1 - cL2) + (ca1 - ca2) * (ca1 - ca2) + (cb1 - cb2) * (cb1 - cb2) );

          float dH = (dE * dE) - (dL * dL) - (dC * dC);

          dH = dH > 0.0 ? sqrt(dH) : 0.0;

          float kL = 1.0;
          float kC = 1.0;
          float kH = 1.0;
          float k1 = 0.045;
          float k2 = 0.015;

          float sL = 1.0;
          float sC = 1.0 + ( k1 * c1 ); // sX
          float sH = 1.0 + ( k2 * c1 ); // sH

          float dLw = dL / (kL * sL);
          float dCw = dC / (kC * sC);
          float dHw = dH / (kH * sH);

          float deltaE94 = sqrt(dLw * dLw + dCw * dCw + dHw * dHw);

          return deltaE94;
      }

      float colorDifferenceCIE94FromRGB(vec3 rgb1, vec3 rgb2) {
          vec3 lab1 = rgb2lab(rgb1);
          vec3 lab2 = rgb2lab(rgb2);
          return colorDifferenceCIE94FromLab(lab1, lab2);
      }

      // float colorDifferenceCIE94FromRGB(vec3 rgb1, vec3 rgb2) {
      //     return abs(rgb2.g - rgb1.g);
      // }

      void main()
      {
          vec2 uv = gl_FragCoord.xy / screenResolution.xy;

          vec3 pixel = texture2D(textureSampler, uv).xyz;


          vec3 white = vec3(1.0);
          vec3 black = vec3(0.0);
          vec3 c1 = rotateHue(vec4(1.0, 0.0, 0.0, 1.0), hueRotation).xyz;
          vec3 c2 = rotateHue(vec4(0.0, 1.0, 0.0, 1.0), hueRotation).xyz;
          vec3 c3 = rotateHue(vec4(0.0, 0.0, 1.0, 1.0), hueRotation).xyz;

      /*
          vec3 c1 = vec3(1.0, 0.0, 0.0);
          vec3 c2 = vec3(0.0, 1.0, 0.0);
          vec3 c3 = vec3(0.0, 0.0, 1.0);
      */
          vec3 c12 = mixColors(c1, c2);
          vec3 c13 = mixColors(c1, c3);
          vec3 c23 = mixColors(c2, c3);
          vec3 c123 = mixColors(c1, c2, c3);

          colors[0] = white;
          colors[1] = black;
          colors[2] = c1;
          colors[3] = c2;
          colors[4] = c3;
          colors[5] = c12;
          colors[6] = c13;
          colors[7] = c23;
          colors[8] = c123;
          // colors[8] = vec3(0.8, 0.4, 0.1);

          /*
          colors[0] = white;
          colors[1] = black;
          colors[2] = vec3(1.0, 0.0, 0.8);
          colors[3] = vec3(0.0, 0.7, 0.4);
          colors[4] = vec3(0.0, 0.8, 0.9);
          colors[5] = vec3(0.8, 0.4, 0.1);
          colors[6] = vec3(0.4, 0.9, 0.0);
          colors[7] = vec3(0.1, 0.2, 7.0);
          colors[8] = vec3(0.9, 0.1, 0.0);
          */
          float minDistance = 1000000.0;

          vec3 finalColor1 = vec3(0.0);
          int index1 = 0;

          float distance = colorDifferenceCIE94FromRGB(pixel, colors[0]);
          if(distance < minDistance) {
              finalColor1 = colors[0];
              minDistance = distance;
              index1 = 0;
          }
          distance = colorDifferenceCIE94FromRGB(pixel,  colors[1]);
          if(distance < minDistance) {
              finalColor1 = colors[1];
              minDistance = distance;
              index1 = 1;
          }
          distance = colorDifferenceCIE94FromRGB(pixel, colors[2]);
          if(distance < minDistance) {
              finalColor1 = colors[2];
              minDistance = distance;
              index1 = 2;
          }
          distance = colorDifferenceCIE94FromRGB(pixel, colors[3]);
          if(distance < minDistance) {
              finalColor1 = colors[3];
              minDistance = distance;
              index1 = 3;
          }
          distance = colorDifferenceCIE94FromRGB(pixel, colors[4]);
          if(distance < minDistance) {
              finalColor1 = colors[4];
              minDistance = distance;
              index1 = 4;
          }
          distance = colorDifferenceCIE94FromRGB(pixel,  colors[5]);
          if(distance < minDistance) {
              finalColor1 = colors[5];
              minDistance = distance;
              index1 = 5;
          }
          distance = colorDifferenceCIE94FromRGB(pixel,  colors[6]);
          if(distance < minDistance) {
              finalColor1 = colors[6];
              minDistance = distance;
              index1 = 6;
          }
          distance = colorDifferenceCIE94FromRGB(pixel,  colors[7]);
          if(distance < minDistance) {
              finalColor1 = colors[7];
              minDistance = distance;
              index1 = 7;
          }
          distance = colorDifferenceCIE94FromRGB(pixel,  colors[8]);
          if(distance < minDistance) {
              finalColor1 = colors[8];
              minDistance = distance;
              index1 = 8;
          }

          int index2 = 0;

          vec3 finalColor2 = pixel;

          minDistance = 100000.0;
          for(int i=0 ; i<9 ; i++) {
              distance = colorDifferenceCIE94FromRGB(pixel, colors[i]);

              if(distance < minDistance) {
                  finalColor2 = colors[i];
                  minDistance = distance;
                  index2 = i;
              }
          }

          vec3 green = vec3(0.0, 1.0, 0.0);
          vec3 red = vec3(1.0, 0.0, 0.0);

          /*
          // Display colors:
          if(uv.x < 0.1) {
              float y = uv.y;
              finalColor1 = colors[int(floor(y * 8.9))];
          }
          */


          // gl_FragColor = vec4(index1 == index2 ? green : red,1.0);
          gl_FragColor = vec4((uv.x < 0.5 ? finalColor1 : finalColor2), 1.0);
      }
    </script>
    <script type="application/glsl"  id="vertexShader">
      varying vec2 vUv;

      void main() {
          vUv = uv;
       gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0 );
      }
    </script>

    <!--  <script src="src/index.js"></script> -->

    <script type="application/javascript">
      //import * as vertexShader from "./vertex-shader";
      //import * as fragmentShader from "./fragment-shader";

      let fragmentShader = document.getElementById("fragmentShader").textContent;
      let vertexShader = document.getElementById("vertexShader").textContent;



      let screenWidth = window.innerWidth;
      let screenHeight = window.innerHeight;
      // let screenWidth = document.body.clientWidth;
      // let screenHeight = document.body.clientHeight;
      let uniforms = {};
      let scene = null;

      let parameters = {
        hueRotation: 0
      };
      let renderer, camera, texture, raster;

      var paperCanvas = document.getElementById("paper");
      paper.setup(paperCanvas);

      function initialize() {
        let canvas = $("#three").get(0);
        let context = canvas.getContext("webgl2");
        renderer = new THREE.WebGLRenderer({
          context: context,
          canvas: canvas,
          antialias: true,
          preserveDrawingBuffer: true
        });

        renderer.setSize(screenWidth, screenHeight);

        scene = new THREE.Scene();

        camera = new THREE.OrthographicCamera(
          screenWidth / -2,
          screenWidth / 2,
          screenHeight / 2,
          screenHeight / -2,
          1,
          1000
        );

        texture = new THREE.CanvasTexture(paper.view.element, THREE.UVMapping);
        texture.needsUpdate = true;


        window.texture = texture;

        uniforms = {
          screenResolution: {
            type: "v2",
            value: new THREE.Vector2(screenWidth, screenHeight)
          },
          textureSampler: { value: texture },
          textureResolution: new THREE.Uniform(
            new THREE.Vector2(
              canvas ? canvas.height / 2 : 0,
              canvas ? canvas.width / 2 : 0
            )
          ),
          hueRotation: { type: "f", value: parameters.hueRotation }
        };

        let material = new THREE.ShaderMaterial({
          uniforms: uniforms,
          // extensions: { derivatives: true },
          vertexShader: vertexShader.trim(),
          fragmentShader: fragmentShader.trim(),
          side: THREE.DoubleSide
        });

        let mesh = new THREE.Mesh(
          new THREE.PlaneGeometry(screenWidth, screenHeight),
          material
        );
        // mesh = new THREE.Mesh(geometry, material);

        mesh.position.z = -1;
        window.mesh = mesh;
        scene.add(mesh);

        //raster = new paper.Raster("./Velo.jpg");
        //raster.onLoad = rasterLoaded;

        let circle = new paper.Path.Circle(paper.view.bounds.center, 25);
        circle.fillColor = "red";
        
        setTimeout(() => { texture.needsUpdate = true }, 100);
      }
      $(document).ready(()=> {
        let paperCanvas = $("#paper").get(0);
        screenWidth = paperCanvas.clientWidth;
        screenHeight = paperCanvas.clientHeight;
        initialize();
      })
      
      //document.addEventListener("DOMContentLoaded", initialize);

      function rasterLoaded() {
        console.log("raster loaded");
        // raster.fitBounds(paper.view.bounds);

        console.log("texture:", texture);
        if (texture) {
          console.log("texture.needsUpdate");
          texture.needsUpdate = true;
        }
        setTimeout(() => updateUniforms(parameters), 100);
      }

      function updateUniforms(parameters) {
        if (uniforms == null) {
          return;
        }

        uniforms.hueRotation.value = parameters.hueRotation;
        texture.needsUpdate = true;
      }

      function animate() {
        requestAnimationFrame(animate);
        if (renderer) {
          renderer.render(scene, camera);
        }
      }

      animate();
    </script>
  </body>
</html>
arthur.sw
  • 11,052
  • 9
  • 47
  • 104
  • Can you put working code in a [snippet](https://stackoverflow.blog/2014/09/16/introducing-runnable-javascript-css-and-html-code-snippets/)? Question asking for debugging help require an [mcve](https://meta.stackoverflow.com/a/349790/128511) in the question itself, not a link to some offsite example. An mcve in the question itself then people be happy to take a look but going to your link doesn't repo the issue and asking us to download your code and try it for you is asking a little much. You shouldn't need the paper library to repo this issue. Nor even an image (use a canvas or something) – gman Apr 10 '19 at 06:07
  • 1
    and add an image of the output you're getting since on my platform I see a red circle wiith no difference between left and right, considering your hardware you might very well run into driver issues. – LJᛃ Apr 10 '19 at 18:01
  • Have you tried multiple browsers? FWIW I get a full red circle on my MacBook Air mid-2013 on macOS Mojave 10.14.4 in Safari. – Andrea May 19 '19 at 20:58

0 Answers0