0
votes

I am using WebGL to generate points on top of a leaflet map. Depending on an attribute of the data three colors are plotted: red, orange and green. (Colors are float i.e. 0.0 -> 1.0) Which are pushed onto an array:

points.push(point.x, point.y, 1, 0, 0, 0); //for red
points.push(point.x, point.y, 1, 0.67, 0, 0); //for orange
points.push(point.x, point.y, 0, 1, 0, 0); // green

This array is passed to my webgl drawing function the critical part of the code that sets vertices and the colors for the shader, is as follows:

let vertArray = new Float32Array(verts);
let fsize = vertArray.BYTES_PER_ELEMENT;
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, vertBuffer);
this.gl.bufferData(this.gl.ARRAY_BUFFER, vertArray, this.gl.STATIC_DRAW);
this.gl.vertexAttribPointer(vertLoc, 2, this.gl.FLOAT, false, fsize*6, 0); //2 vertices & 4 colors
this.gl.enableVertexAttribArray(vertLoc);
      // -- offset for color buffer
this.gl.vertexAttribPointer(colorLoc, 4, this.gl.FLOAT, false, fsize*6, fsize*2); //offset ignore 2 vertices
this.gl.enableVertexAttribArray(colorLoc);

clearColor and clear buffer are called before rendering

gl.clearColor(0, 0, 0, 0);
gl.clear(this.gl.COLOR_BUFFER_BIT);

The points are all drawn in correct location and correct colors. The end goal is to record which point the user clicked. When the user clicks a point this code is called.

if (mouseclick !== null) {
    let pixel = new Uint8Array(4);
    this.gl.readPixels(mouseclick.layerX, this.canvas.height - mouseclick.layerY, 1, 1, this.gl.RGBA, 
    this.gl.UNSIGNED_BYTE, pixel);
}

This is where the problem is, for example, if I click a red point I get the output:

Uint8Array(4) [229, 0, 0, 207]

Orange:

Uint8Array(4) [229, 154, 0, 207]

Green:

Uint8Array(4) [0, 229, 0, 207]

These are roughly the correct values but I set alpha (channel 4) to 0 and red should be 255, 0, 0, 0 orange 255, 165, 0, 0 and green 0, 255, 0, 0. I have tried to return a Float32Array from readPixels but get INVALID_ENUM: readPixels: invalid type for a gl.FLOAT. Also is I click where there are no points I get [0, 0, 0, 0] which is black which is correct. Does someone know why this is happening? And potentially a solution. Thanks :)

edit: shader code:

<script id="vshader" type="x-shader/x-vertex">
  uniform mat4 u_matrix;
  attribute vec4 a_vertex;
  attribute float a_pointSize;
  attribute vec4 a_color;
  varying vec4 v_color;

  void main() {
      gl_PointSize =  a_pointSize;
      gl_Position = u_matrix * a_vertex;
      v_color = a_color;
  }
</script>
<script id="fshader" type="x-shader/x-fragment">
    precision mediump float;
    varying vec4 v_color;

    void main() {

        float border = 0.05;
        float radius = 0.5;
        vec4 color0 = vec4(0.0, 0.0, 0.0, 0.0);
        vec4 color1 = vec4(v_color[0], v_color[1], v_color[2], 0.9);

        vec2 m = gl_PointCoord.xy - vec2(0.5, 0.5);
        float dist = radius - sqrt(m.x * m.x + m.y * m.y);

       float t = 0.0;
       if (dist > border)
       t = 1.0;
       else if (dist > 0.0)
       t = dist / border;
       gl_FragColor = mix(color0, color1, t);
    }
  </script>
1
can you post a repo in a snippet? Just draw 1 point and then call readPixels on it. And/Or add your shaders to the question. - gman
@gman - Shader code added. Yes I think the fragment shader is the problem. That will teach me for blindly copying code without understanding it first. - ozzyzig
@gman if you post an answer I will mark as accepted. - ozzyzig

1 Answers

1
votes

It's clear the fragment shader is generating different colors. It's drawing circles and it's blending between (r, g, b, 0.9) and (0, 0, 0, 0)

If you want to get colors you put in change it to

precision mediump float;
varying vec4 v_color;
void main() {
   gl_FragColor = v_color;
}

or change it to have no blending

precision mediump float;
varying vec4 v_color;

void main() {
    float radius = 0.5;

    vec2 m = gl_PointCoord.xy - vec2(0.5, 0.5);
    float dist = radius - sqrt(m.x * m.x + m.y * m.y);

    gl_FragColor = dist < 0.0 ? vec4(0) : v_color;
}