Histogram in WebGL

by Subhasish2015

HTML

<script id="new-vs" type="not-js">
    #version 300 es
    in vec4 position;
    out vec2 texcoord;
    uniform float flipY;
    void main() {
      gl_Position = position;
      texcoord = position.xy * .5 + .5;
    }
    </script>

    <script id="new-fs" type="not-js">
    #version 300 es
    precision highp float;
    in vec2 texcoord;
    uniform sampler2D u_texture;
    out vec4 fcolor;
    void main() {
        fcolor = vec4(texture(u_texture, texcoord).rgb, 1.0);
    }
    </script>

    
    <script id="hist-vs" type="not-js">
    #version 300 es
    in float pixelId;
    uniform vec2 u_resolution;
    uniform sampler2D u_texture;
    void main() {
        vec2 pixel = vec2(mod(pixelId, u_resolution.x), floor(pixelId / u_resolution.x));
        vec2 uv = (pixel + 0.5) / u_resolution;
        vec4 color = texture(u_texture, uv);
        float colorSum = (color.r + color.g + color.b) / 3.0 ; 
        float verticesXPos = (colorSum * 255.0 + 0.5) / 256.0 * 2.0 - 1.0;
        gl_Position = vec4(verticesXPos, 0.5, 0, 1);
        gl_PointSize = 1.0;
    }
    </script>
    <script id="hist-fs" type="not-js">
    #version 300 es
    precision highp float;
    out vec4 fcolor;
    void main() {
        fcolor = vec4(1.0, 1.0, 1.0, 1.0);
    }
    </script>
    <script id="max-fs" type="not-js">
    #version 300 es
    precision highp float;
    uniform sampler2D u_texture;
    out vec4 fcolor;
    void main() {
        vec4 maxColor = vec4(0);
        for (int i = 0; i < 255; i++) {
            vec2 uv = vec2((float(i)) / 255.0, 0.5);
            vec4 currentPixelValue = vec4(texture(u_texture, uv).rgb, 1.0);
            maxColor = max(maxColor, currentPixelValue);  
        }
        fcolor = maxColor;
    }
    </script>
    <script id="show-vs" type="not-js">
    #version 300 es
    in vec4 position;
    void main() {
        gl_Position = position;
    }
    </script>
    <script id="show-fs" type="not-js">
    #version 300 es
    precision highp float;    
...

CSS

img, canvas { border: 1px solid black; margin: 5px; }

JavaScript

"use strict";

var canvas = document.createElement("canvas");
canvas.width = 256;
canvas.height = 120;
var m4 = twgl.m4;
var gl = canvas.getContext("webgl2");
const ext = gl.getExtension("EXT_color_buffer_float");
if (!ext) {
  console.log("sorry, can't render to floating point textures");
}
twgl.createTexture(gl, {
  //src: "https://i.imgur.com/9Y3sd8S.png",
  src: "https://farm1.staticflickr.com/293/18414763798_cb8ebded43_m_d.jpg",
  // required link: https://www.flickr.com/photos/greggman/18414763798/in/album-72157653822314919/
  min: gl.NEAREST,
  mag: gl.NEAREST,
  wrap: gl.CLAMP_TO_EDGE,
  crossOrigin: "",
}, function(err, tex, img) {
  log("img");
  document.body.appendChild(img);
  log("histogram");
  document.body.appendChild(canvas);

  var quadBufferInfo = twgl.primitives.createXYQuadBufferInfo(gl);
  var histProgramInfo = twgl.createProgramInfo(gl, ["hist-vs", "hist-fs"]);
  var pixelIds = [];
  var numIds = img.width * img.height;

  // Just fill a buffer with an incrementing count. If we wanted to make this
  // generic we'd re-use this buffer and just make it bigger if we were
  // processing a bigger image
  for (var i = 0; i < numIds; ++i) {
    pixelIds.push(i);
  }
  var pixelIdBufferInfo = twgl.createBufferInfoFromArrays(gl, {
    pixelId: { size: 1, data: new Float32Array(pixelIds), },
  });

  // make a 256x1 RGBA floating point texture and attach to a framebuffer
  var sumFbi = twgl.createFramebufferInfo(gl, [
    { type: gl.FLOAT,
      min: gl.NEAREST,
      mag: gl.NEAREST,
      wrap: gl.CLAMP_TO_EDGE,
    },
  ], 256, 1);
  if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) !== gl.FRAMEBUFFER_COMPLETE) {
    alert("can't render to floating point texture");
  }

  // Render sum of each color

  // we're going to render a gl.POINT for each pixel in the source image
  // That point will be positioned based on the color of the source image
  // we're just going to render vec4(1,1,1,1). This blend function will
  // mean each time we render to a...