I'm trying to render an grayscale image from a 16-bit array buffer in WebGL2, by applying window leveling in the fragment shader. I'v generated the texture as below:
let typedArray = new Int16Array(data);
gl.texImage2D(
gl.TEXTURE_2D,
0,
gl.R16I,
w, h,
0,
gl.RED_INTEGER,
gl.SHORT,
typedArray);
and tried to use the data from the fragment shader below:
let fragmentShaderSource = `#version 300 es
precision highp float;
precision highp int;
precision highp isampler2D;
// our texture
uniform isampler2D u_image;
uniform highp float u_windowWidth;
uniform highp float u_windowCenter;
in vec2 v_texCoord;
out vec4 outColor;
void main() {
highp float f = float(texture(u_image, v_texCoord).r);
f = (f - (u_windowCenter - 0.5)) / max(u_windowWidth - 1.0, 1.0) + 0.5;
f = min(max(f, 0.0), 1.0);
outColor = vec4(vec3(f), 1.0);
}
`;
but this only renders a black screen. Actually, after some debugging, I found that texture(u_image, v_texCoord)
had zero values in rgb
across all pixels and a
(alpha) field had very large (2^29 ~ 2^30) value. I've tried changing precisions in the shader but results were the same.
In order to narrow down the problem scope, I've tried a different approach by splitting the 16-bit integer into gl.RGBA4
, which contains 4-bits in each RGBA channels:
let typedArray = new Uint16Array(data);
gl.texImage2D(
gl.TEXTURE_2D,
0,
gl.RGBA4,
w, h,
0,
gl.RGBA,
gl.UNSIGNED_SHORT_4_4_4_4,
typedArray);
and combined RGBA values back into 16-bit integer in the fragment shader.
let fragmentShaderSource = `#version 300 es
precision highp float;
precision highp int;
precision highp sampler2D;
// our texture
uniform sampler2D u_image;
uniform highp float u_windowWidth;
uniform highp float u_windowCenter;
in vec2 v_texCoord;
out vec4 outColor;
void main() {
highp vec4 rgba_map = texture(u_image, v_texCoord);
// Combining rgba4 back into int16
highp f = rgba_map.r * 65536.0 + rgba_map.g * 4096.0 + rgba_map.b * 256.0 + rgba_map.a * 16.0;
// signed value
if (f > 32768.0) {
f = 65536.0 - f;
}
f = (f - (u_windowCenter - 0.5)) / max(u_windowWidth - 1.0, 1.0) + 0.5;
f = min(max(f, 0.0), 1.0);
outColor = vec4(vec3(f), 1.0);
}
`;
and this version rendered the expected image quite well, although the result was a bit noisy due to the conversion. I've also tried some other formats, and those with float type were fine and the integer type formats were all not working. So I think the other parts of the program are fine. I wonder what is wrong with my program.