惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Attack and Defense Labs
Attack and Defense Labs
O
OpenAI News
AI
AI
Cloudbric
Cloudbric
Security Archives - TechRepublic
Security Archives - TechRepublic
H
Heimdal Security Blog
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Recent Commits to openclaw:main
Recent Commits to openclaw:main
T
Threat Research - Cisco Blogs
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
腾讯CDC
S
SegmentFault 最新的问题
宝玉的分享
宝玉的分享
Cyberwarzone
Cyberwarzone
博客园 - 【当耐特】
TaoSecurity Blog
TaoSecurity Blog
The Cloudflare Blog
V
Visual Studio Blog
Forbes - Security
Forbes - Security
Apple Machine Learning Research
Apple Machine Learning Research
Spread Privacy
Spread Privacy
L
LINUX DO - 最新话题
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
K
Kaspersky official blog
IT之家
IT之家
大猫的无限游戏
大猫的无限游戏
The Last Watchdog
The Last Watchdog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
博客园_首页
Cisco Talos Blog
Cisco Talos Blog
Security Latest
Security Latest
量子位
W
WeLiveSecurity
V
V2EX
L
Lohrmann on Cybersecurity
S
Security @ Cisco Blogs
小众软件
小众软件
The Hacker News
The Hacker News
阮一峰的网络日志
阮一峰的网络日志
H
Hacker News: Front Page
博客园 - 聂微东
T
Troy Hunt's Blog
S
Schneier on Security
有赞技术团队
有赞技术团队
爱范儿
爱范儿
博客园 - 三生石上(FineUI控件)
Webroot Blog
Webroot Blog
P
Privacy International News Feed
Jina AI
Jina AI
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com

WebGL Fundamentals

WebGL Using 2 or More Textures WebGL Implementing DrawImage WebGL 2D Matrices WebGL Implementing A Matrix Stack WebGL 2D Rotation WebGL 2D Scale WebGL 2D Translation WebGL - Rasterization vs 3D libraries WebGL 3D - Cameras WebGL 3D Geometry - Lathe WebGL 3D - Directional Lighting WebGL 3D - Point Lighting WebGL 3D - Normal Mapping WebGL 3D - Spot Lighting WebGL - Orthographic 3D WebGL 3D Perspective Correct Texture Mapping WebGL 3D Perspective WebGL Textures WebGL and Alpha WebGL - Animation WebGL Anti-Patterns WebGL Attributes WebGL Boilerplate WebGL - Cross Origin Images WebGL Cross Platform Issues WebGL Cubemaps WebGL 3D - Data Textures WebGL - Drawing Multiple Things WebGL Drawing Without Data WebGL Environment Maps (reflections) WebGL Fog WebGL Framebuffers WebGL Fundamentals WebGL GPGPU WebGL How It Works WebGL Image Processing Continued WebGL Image Processing WebGL Indexed Vertices WebGL Optimization - Instanced Drawing WebGL - Less Code, More Fun WebGL Load Obj with Mtl WebGL Load Obj WebGL Matrices vs Math Matrices WebGL Multiple Views, Multiple Canvases WebGL Picking WebGL Planar and Perspective Projection Mapping WebGL Points, Lines, and Triangles WebGL Post Processing WebGL Precision Issues WebGL Pulling Vertices Accessing textures by pixel coordinate in WebGL2 A simple way to show the load on the GPU's vertex and fragment processing? Apply a displacement map and specular map Can anyone explain what this GLSL fragment shader is doing? Can I mute the warning about vertex attrib 0 being disabled? Create image warping effect in WebGL Creating a smudge/liquify effect How to draw Depth Sprites Determine min/max values for the entire image Don't blend a polygon that crosses itself Drawing 2D image with depth map to achieve pseudo-3D effect Drawing a heightmap Drawing layers with different points Drawing Many different models in a single draw call Drawing textured sprites with instanced drawing Efficient particle system in javascript? (WebGL) Emulating palette based graphics in WebGL FPS-like camera movement with basic matrix transformations Get the size of a point for collision checking GLSL shader to support coloring and texturing How can I compute for 500 points which of 1000 line segments is nearest to each point? How can I get all the uniforms and uniformBlocks How can I move the perspective vanishing point from the center of the canvas? How to Achieve Moving Line with Trail Effects How to bind an array of textures to a WebGL shader uniform? How to blend colors across 2 triangles How to combine more text drawing into fewer draw calls How to control the color between vertices How to create a torus How to detect clipped triangles in the framgment shader How to determine the average brightness in a scene? How to draw correctly textured trapezoid polygons How to fade the drawing buffer How to figure out how much GPU work to do without crashing WebGL How to get audio data into a shader How to get code completion for WebGL in Visual Studio Code How to get the 3d coordinates of a mouse click How to get pixelize effect in webgl? How to implement zoom from mouse in 2D WebGL How to import a heightmap in WebGL How to load images in the background with no jank How to make a smudge brush tool How to make WebGL canvas transparent How to optimize rendering a UI How to prevent texture bleeding with a texture atlas How to process particle positions How to read a single component with readPixels How to render large scale images like 32000x32000 How to simulate a 3D texture in WebGL How to support both WebGL and WebGL2
How can I create a 16bit historgram of 16bit data
WebGLFundame · 2025-02-26 · via WebGL Fundamentals

Question:

var gl, utils, pseudoImg, vertices;
var img = null;
document.addEventListener('DOMContentLoaded', () => {
    utils = new WebGLUtils();
    vertices = utils.prepareVec2({x1 : -1.0, y1 : -1.0, x2 : 1.0, y2 : 1.0});
    gl = utils.getGLContext(document.getElementById('canvas'));
    var program = utils.getProgram(gl, 'render-vs', 'render16bit-fs');
    var histogramProgram = utils.getProgram(gl, 'histogram-vs', 'histogram-fs');
    var sortProgram = utils.getProgram(gl, 'sorting-vs', 'sorting-fs');
    var showProgram = utils.getProgram(gl, 'showhistogram-vs', 'showhistogram-fs');
    utils.activateTextureByIndex(gl, showProgram, 'histTex', 3);
    utils.activateTextureByIndex(gl, showProgram, 'maxTex', 4);
    utils.activateTextureByIndex(gl, sortProgram, 'tex3', 2);
    utils.activateTextureByIndex(gl, histogramProgram, 'tex2', 1);
    utils.activateTextureByIndex(gl, program, 'u_texture', 0);

    var vertexBuffer = utils.createAndBindBuffer(gl, vertices);
    var imageTexture;
    computeHistogram = (AR, myFB) => {
        gl.useProgram(histogramProgram);
        var width = AR.width;
        var height = AR.height;
        var numOfPixels = width * height;
        var pixelIds = new Float32Array(numOfPixels);
        for (var i = 0; i < numOfPixels; i++) {
            pixelIds[i] = i;
        }
        var histogramFbObj = utils.createTextureAndFramebuffer(gl, {
            format : gl.RED,
            internalFormat : gl.R32F,
            filter : gl.NEAREST,
            dataType : gl.FLOAT,
            mipMapST : gl.CLAMP_TO_EDGE,
            width : 256,
            height : 256
        });
        gl.bindFramebuffer(gl.FRAMEBUFFER, histogramFbObj.fb);
        gl.viewport(0, 0, 256, 256);
        var pixelBuffer = utils.createAndBindBuffer(gl, pixelIds, true);
        gl.blendFunc(gl.ONE, gl.ONE);
        gl.enable(gl.BLEND);
        utils.linkAndSendDataToGPU(gl, histogramProgram, 'pixelIds', pixelBuffer, 1);
        gl.uniform2fv(gl.getUniformLocation(histogramProgram, 'imageDimensions'), [width, height]);
        utils.sendTextureToGPU(gl, myFB.tex, 1);
        gl.drawArrays(gl.POINTS, 0, numOfPixels);

        gl.blendFunc(gl.ONE, gl.ZERO);
        gl.disable(gl.BLEND);
        return histogramFbObj;
    };

    sortHistogram = (histogramFbObj) => {
        gl.useProgram(sortProgram);
        utils.linkAndSendDataToGPU(gl, sortProgram, 'vertices', vertexBuffer, 2);
        var sortFbObj = utils.createTextureAndFramebuffer(gl, {
            format : gl.RED,
            internalFormat : gl.R32F,
            filter : gl.NEAREST,
            dataType : gl.FLOAT,
            mipMapST : gl.CLAMP_TO_EDGE,
            width : 1,
            height : 1
        });
        gl.bindFramebuffer(gl.FRAMEBUFFER, sortFbObj.fb);
        gl.viewport(0, 0, 1, 1);
        utils.sendTextureToGPU(gl, histogramFbObj.tex, 2);
        gl.drawArrays(gl.TRIANGLES, 0, 6);
        return sortFbObj;
    };

    showHistogram = (histFb, sortFb) => {
        gl.useProgram(showProgram);
        utils.linkAndSendDataToGPU(gl, showProgram, 'vertices', vertexBuffer, 2);
        utils.sendTextureToGPU(gl, histFb.tex, 3);
        utils.sendTextureToGPU(gl, sortFb.tex, 4);
        gl.uniform2fv(gl.getUniformLocation(showProgram, 'imageDimensions'), [gl.canvas.width, gl.canvas.height]);
        gl.drawArrays(gl.TRIANGLES, 0, 6);
    };

    showTexture = (AR) => {
        imageTexture = utils.createAndBindTexture(gl, {
            filter : gl.NEAREST,
            mipMapST : gl.CLAMP_TO_EDGE,
            dataType : gl.UNSIGNED_SHORT,
            format : gl.RGBA_INTEGER,
            internalFormat : gl.RGBA16UI,
            img : AR.img,
            width : AR.width,
            height : AR.height
        });

        gl.useProgram(program);
        var myFB = utils.createTextureAndFramebuffer(gl, {
            filter : gl.NEAREST,
            mipMapST : gl.CLAMP_TO_EDGE,
            dataType : gl.UNSIGNED_BYTE,
            format : gl.RGBA,
            internalFormat : gl.RGBA,
            width : AR.width,
            height : AR.height,
        });
        gl.bindFramebuffer(gl.FRAMEBUFFER, myFB.fb);
        gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
        utils.linkAndSendDataToGPU(gl, program, 'vertices', vertexBuffer, 2);
        gl.uniform1f(gl.getUniformLocation(program, 'flipY'), 1.0);
        utils.sendTextureToGPU(gl, imageTexture, 0);
        gl.drawArrays(gl.TRIANGLES, 0, 6);

        var fb1 = computeHistogram(AR, myFB);
        var fb2 = sortHistogram(fb1);
        gl.bindFramebuffer(gl.FRAMEBUFFER, null);
        gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
        showHistogram(fb1, fb2);
    };

    var w = 128;
    var h = 128;
    var size = w * h * 4;
    var img = new Uint16Array(size); // need Uint16Array
    for (var i = 0; i < img.length; i += 4) {
        img[i + 0] = 65535; // r
        img[i + 1] = i/64 * 256; // g
        img[i + 2] = 0; // b
        img[i + 3] = 65535; // a
    }
    showTexture({
        img : img,
        width : w,
        height : h
    });
});
<script id="render16bit-fs" type="not-js">
            #version 300 es
            precision highp float; 
            uniform highp usampler2D tex;
            in vec2 texcoord; // receive pixel position from vertex shader
            out vec4 fooColor;
            void main() {
                uvec4 unsignedIntValues = texture(tex, texcoord);
                vec4 floatValues0To65535 = vec4(unsignedIntValues);
                vec4 colorValues0To1 = floatValues0To65535;
                fooColor = colorValues0To1;
            }          
        </script>

        <script type="not-js" id="render-vs">
            #version 300 es
            in vec2 vertices;
            out vec2 texcoord;
            uniform float flipY;
            void main() {
                texcoord = vertices.xy * 0.5 + 0.5;
                gl_Position = vec4(vertices.x, vertices.y * flipY, 0.0, 1.0);
            }
        </script>

        <script type="not-js" id="histogram-vs">
            #version 300 es
            in float pixelIds; //0,1,2,3,4,.......width*height
            uniform sampler2D tex2;
            uniform vec2 imageDimensions;
            void main () {
                vec2 pixel = vec2(mod(pixelIds, imageDimensions.x), floor(pixelIds / imageDimensions.x)); 
                vec2 xy = pixel/imageDimensions;
                float pixelValue = texture(tex2, xy).r;//Pick Pixel value from GPU texture ranges from 0-65535
                float xDim = mod(pixelValue, 255.0)/256.0;
                float yDim = floor(pixelValue / 255.0)/256.0;
                float xVertex = (xDim*2.0) - 1.0;//convert 0.0 to 1.0 -> -1.0 -> 1.0, it will increment because we have used gl.blendFunc
                float yVertex = 1.0 - (yDim*2.0);
                gl_Position = vec4(xVertex, yVertex, 0.0, 1.0);
                gl_PointSize = 1.0;
            }
        </script>
        <script type="not-js" id="histogram-fs">
            #version 300 es
            precision mediump float;
            out vec4 fcolor;
            void main() {
                fcolor = vec4(1.0, 1.0, 1.0, 1.0);
            }
        </script>

        <script type="not-js" id="sorting-vs">
            #version 300 es
            in vec2 vertices;
            void main () {
                gl_Position = vec4(vertices, 0.0, 1.0);
            }
        </script>
        <script type="not-js" id="sorting-fs">
            #version 300 es
            precision mediump float;
            out vec4 fcolor;
            uniform sampler2D tex3;
            const int MAX_WIDTH = 65536;
            void main() {
                vec4 maxColor = vec4(0.0);
                for (int i = 0; i < MAX_WIDTH; i++) {
                    float xDim = mod(float(i), 256.0)/256.0;
                    float yDim = floor(float(i) / 256.0)/256.0;
                    vec2 xy = vec2(xDim, yDim);
                    vec4 currPixel = texture(tex3, xy).rrra;
                    maxColor = max(maxColor, currPixel);
                }
                fcolor = vec4(maxColor);
            }
        </script>

        <script type="not-js" id="showhistogram-vs">
            #version 300 es
            in vec2 vertices;
            void main () {
                gl_Position = vec4(vertices, 0.0, 1.0);
            }
        </script>
        <script type="not-js" id="showhistogram-fs">
            #version 300 es
            precision mediump float;
            uniform sampler2D histTex, maxTex;
            uniform vec2 imageDimensions;
            out vec4 fcolor;
            void main () {
                // get the max color constants
                vec4 maxColor = texture(maxTex, vec2(0));
                // compute our current UV position
                vec2 uv = gl_FragCoord.xy / imageDimensions;
                vec2 uv2 = gl_FragCoord.xy / vec2(256.0, 256.0);
                // Get the history for this color
                vec4 hist = texture(histTex, uv2);
                // scale by maxColor so scaled goes from 0 to 1 with 1 = maxColor
                vec4 scaled = hist / maxColor;
                // 1 > maxColor, 0 otherwise
                vec4 color = step(uv2.yyyy, scaled);
                fcolor = vec4(color.rgb, 1);
            }
        </script>

        <canvas id="canvas"></canvas>
        <script type="text/javascript">
        class WebGLUtils {
    getGLContext = (canvas, version) => {
        canvas.width = window.innerWidth * 0.99;
        canvas.height = window.innerHeight * 0.85;
        var gl = canvas.getContext(version ? 'webgl' : 'webgl2');
        const ext = gl.getExtension("EXT_color_buffer_float");
        if (!ext) {
            console.log("sorry, can't render to floating point textures");
        }
        gl.clearColor(0, 0, 0, 1.0);
        gl.clear(gl.COLOR_BUFFER_BIT|gl.DEPTH_BUFFER_BIT);
        gl.lineWidth(0.5);
        return gl;
    };

    clear = (gl) => {
        gl.clear(gl.COLOR_BUFFER_BIT|gl.DEPTH_BUFFER_BIT);
    };

    getShader = (gl, type, shaderText) => {
        var vfs = gl.createShader(type);
        gl.shaderSource(vfs, shaderText);
        gl.compileShader(vfs);
        if (!gl.getShaderParameter(vfs, gl.COMPILE_STATUS)) {
            console.error(gl.getShaderInfoLog(vfs));
        }
        return vfs;
    };

    getProgram = (gl, vertexShader, fragmentShader) => {
        var program = gl.createProgram();
        gl.attachShader(program, this.getShader(gl, gl.VERTEX_SHADER, document.getElementById(vertexShader).text.trim()));
        gl.attachShader(program, this.getShader(gl, gl.FRAGMENT_SHADER, document.getElementById(fragmentShader).text.trim()));
        gl.linkProgram(program);
        if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
            console.error(gl.getProgramInfoLog(program));
        }
        return program;
    };

    createAndBindBuffer = (gl, relatedVertices, isNotJSArray) => {
        var buffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
        gl.bufferData(gl.ARRAY_BUFFER, isNotJSArray ? relatedVertices : new Float32Array(relatedVertices), gl.STATIC_DRAW);
        gl.bindBuffer(gl.ARRAY_BUFFER, null);
        return buffer;
    };

    createAndBindTexture = (gl, _) => {
        var texBuffer = gl.createTexture();
        gl.bindTexture(gl.TEXTURE_2D, texBuffer);
        if (_.img.width) {
            gl.texImage2D(gl.TEXTURE_2D, 0, _.internalFormat, _.format, _.dataType, _.img);
        } else {
            gl.texImage2D(gl.TEXTURE_2D, 0, _.internalFormat, _.width, _.height, 0, _.format, _.dataType, _.img);
        }
        // set the filtering so we don't need mips
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, _.filter);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, _.filter);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, _.mipMapST);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, _.mipMapST);
        gl.bindTexture(gl.TEXTURE_2D, null);
        return texBuffer;
    };

    createTextureAndFramebuffer = (gl, _) => {
        const tex = gl.createTexture();
        gl.bindTexture(gl.TEXTURE_2D, tex);
        gl.texImage2D(gl.TEXTURE_2D, 0, _.internalFormat, _.width, _.height, 0, _.format, _.dataType, null);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, _.filter);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, _.filter);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, _.mipMapST);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, _.mipMapST);
        const fb = gl.createFramebuffer();
        gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
        gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);
        const status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
        console.log(`can ${status === gl.FRAMEBUFFER_COMPLETE ? "" : "NOT "}render to R32`);
        return {tex: tex, fb: fb};
    };

    linkAndSendDataToGPU = (gl, program, linkedVariable, buffer, dimensions) => {
        var vertices = gl.getAttribLocation(program, linkedVariable);
        gl.enableVertexAttribArray(vertices);
        gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
        gl.vertexAttribPointer(vertices, dimensions, gl.FLOAT, gl.FALSE, 0, 0);
        return vertices;
    };

    sendDataToGPU = (gl, buffer, vertices, dimensions) => {
        gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
        gl.vertexAttribPointer(vertices, dimensions, gl.FLOAT, gl.FALSE, 0, 0);
    };

    sendTextureToGPU = (gl, tex, index) => {
        gl.activeTexture(gl.TEXTURE0 + index);
        gl.bindTexture(gl.TEXTURE_2D, tex);
    };

    calculateAspectRatio = (img, gl) => {
        var cols = img.width;
        var rows = img.height; 
        var imageAspectRatio = cols / rows;
        var ele = gl.canvas;
        var windowWidth = ele.width;
        var windowHeight = ele.height;
        var canvasAspectRatio = windowWidth / windowHeight;
        var renderableHeight, renderableWidth;
        var xStart, yStart;
        /// If image's aspect ratio is less than canvas's we fit on height
        /// and place the image centrally along width
        if(imageAspectRatio < canvasAspectRatio) {
            renderableHeight = windowHeight;
            renderableWidth = cols * (renderableHeight / rows);
            xStart = (windowWidth - renderableWidth) / 2;
            yStart = 0;
        }

        /// If image's aspect ratio is greater than canvas's we fit on width
        /// and place the image centrally along height
        else if(imageAspectRatio > canvasAspectRatio) {
            renderableWidth = windowWidth;
            renderableHeight = rows * (renderableWidth / cols);
            xStart = 0;
            yStart = ( windowHeight  - renderableHeight) / 2;
        }

        ///keep aspect ratio
        else {
            renderableHeight =  windowHeight ;
            renderableWidth = windowWidth;
            xStart = 0;
            yStart = 0;
        }
        return {
            y2 : yStart + renderableHeight,
            x2 : xStart + renderableWidth,
            x1 : xStart,
            y1 : yStart
        };
    };

    convertCanvasCoordsToGPUCoords = (canvas, AR) => {
        //GPU -> -1, -1, 1, 1
        //convert to 0 -> 1
        var _0To1 = {
            y2 : AR.y2/canvas.height,
            x2 : AR.x2/canvas.width,
            x1 : AR.x1/canvas.width,
            y1 : AR.y1/canvas.height
        };
        //Convert -1 -> 1
        return {
            y2 : -1 + _0To1.y2 * 2.0,
            x2 : -1 + _0To1.x2 * 2.0,
            x1 : -1 + _0To1.x1 * 2.0,
            y1 : -1 + _0To1.y1 * 2.0
        };
    };

    //convert -1->+1 to 0.0->1.0
    convertVertexToTexCoords = (x1, y1, x2, y2) => {
        return {
            y2 : (y2 + 1.0)/2.0,
            x2 : (x2 + 1.0)/2.0,
            x1 : (x1 + 1.0)/2.0,
            y1 : (y1 + 1.0)/2.0
        };
    };

    activateTextureByIndex = (gl, program, gpuRef, gpuTextureIndex) => {
        gl.useProgram(program);
        gl.uniform1i(gl.getUniformLocation(program, gpuRef), gpuTextureIndex);
    };

    prepareVec4 = (_) => {
        return [_.x1, _.y1, 0.0, 1.0,
            _.x2, _.y1, 0.0, 1.0,
            _.x1, _.y2, 0.0, 1.0,
            _.x2, _.y1, 0.0, 1.0,
            _.x1, _.y2, 0.0, 1.0,
            _.x2, _.y2, 0.0, 1.0];
    };

    prepareVec2 = (_) => {
        return [_.x1, _.y1,
            _.x2, _.y1, 
            _.x1, _.y2, 
            _.x2, _.y1,
            _.x1, _.y2,
            _.x2, _.y2];
    };
};
        </script>

I am able to render a 8 bit histogram in both WebGL1 and WebGL2 using this code. But I need to generate a 16 bit histogram using 16 bit texture.

Here's how am sending the texture to GPU:

var tex = gl.createTexture(); // create empty texture gl.bindTexture(gl.TEXTURE_2D, tex); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); gl.texImage2D( gl.TEXTURE_2D, // target 0, // mip level gl.RGBA16UI, // internal format -> gl.RGBA16UI w, h, // width and height 0, // border gl.RGBA_INTEGER, //format -> gl.RGBA_INTEGER gl.UNSIGNED_SHORT, // type -> gl.UNSIGNED_SHORT img // texture data );

So, take the working example in mind, I am stuck with few things :

1) How to create a 65536 X 1 framebuffer/texture to keep the 16 bit histogram as WebGL clearly says : WebGL: INVALID_VALUE: texImage2D: width or height out of range. Can we try a 256 x 256 framebuffer? I tried but stuck in point no. 2 below.

2) How to read through the pixels inside the vertex shader in case of 16 bit, below code is for 8-bit data, will it work for 16 bit as well? As I can't debug, so can't say whether it works or not:

Answer:

If you just want answers to your 2 questions then

1) How to create a 65536 X 1 framebuffer/texture to keep the 16 bit histogram as WebGL clearly says : WebGL: INVALID_VALUE: texImage2D: width or height out of range. Can we try a 256 x 256 framebuffer?

yes, you'd make 256x256 texture if you want to know the totals for each of the 65536 possible values

2) How to read through the pixels inside the vertex shader in case of 16 bit, below code is for 8-bit data, will it work for 16 bit as well? As I can't debug, so can't say whether it works or not:

Of course you can debug. You try it and see if the results are correct. If they aren't you look at your code and or the error messages and try to figure out why. That's called debugging. Make a 1x1 texture, call your function, check if the histogram has the correct count of 1 for that 1x1 pixel input by calling gl.readPixels. Then try 2x1 or 2x2.

In any case you can't read gl.RGBA16UI textures with GLSL 1.0 es. You have to use version 300 es so if you actually want to create a separate bucket for all 65536 values then

Here's some a WebGL2 GLSL 3.00 ES shader that will fill out the totals for values from 0 to 65535 in a 256x256 texture

#version 300 es

uniform usampler2D u_texture;
uniform uvec4 u_colorMult;

void main() {
  const int mipLevel = 0;

  ivec2 size = textureSize(u_texture, mipLevel);

  // based on an id (0, 1, 2, 3 ...) compute the pixel x, y for the source image
  vec2 pixel = vec2(
     gl_VertexID % size.x,
     gl_VertexID / size.x);

  // get the pixels but 0 out channels we don't want
  uvec4 color = texelFetch(u_texture, pixel, mipLevel) * u_colorMult;

  // add up all the channels. Since 3 are zeroed out we'll get just one channel
  uint colorSum = color.r + color.g + color.b + color.a;

  vec2 outputPixel = vec2(
     colorSum % 256u,
     colorSum / 256u);

  // set the position to be over a single pixel in the 256x256 destination texture
  gl_Position = vec4((outputPixel + 0.5) / 256.0 * 2.0 - 1.0, 0, 1);

  gl_PointSize = 1.0;
}

Example

Notes:

  • In WebGL2 you don't need pixelID, you can use gl_VertexID so no need to setup any buffers or attributes. Just call

      const numPixels = img.width * img.height;
      gl.drawArrays(gl.POINTS, 0, numPixels);
    
  • You can use textureSize to get the size of a texture so no need to pass it in.

  • You can use texelFetch to get a single texel(pixel) from a texture. It takes integer pixel coordinates.

  • To read an unsigned integer texture format like RGBA16UI you have to use a usampler2D otherwise you'll get an error at draw time drawing to use an RGBA16UI texture on a sampler2D (this is how I know you weren't actually using a RGBA16UI texture because you would have gotten an error in the JavaScript console telling you and leading you to change your shader.

  • You still need to use a floating point texture as the target because the technique used requires blending but blending doesn' work with integer textures (just in case you got the idea to try to use an integer based texture in the framebuffer)

The question and quoted portions thereof are CC BY-SA 4.0 by graphics123 from here