I'm trying to pass some non-texture values to a pixel shader in a texture and i'm running into a weird problem where sampler2d returns vec4(0.0) when the texture's alpha value is zero, regardless of the value of the other 3 bytes.
this isn't a premultiplied alpha thing, or a blending thing, it doesn't happen when the alpha's byte value is 1 through 255, just zero.
if you run the code below you'll see a 2x2 texture in the small 2d canvas being rendered into the large 3d canvas. all 4 pixels have r,g,b = 255. and all 4 pixels have different a values. the top-left pixel of the texture has an alpha value of zero.
the pixel shader sets gl_FragColor.a = 1.0 always.
the reason i don't believe this is a premultiplied alpha thing is that if it were, then surely all 3 pixels would be different shades of grey?
can anyone tell me why this happens?
const cvs = document.getElementById("cvs"),
{
width: W,
height: H
} = cvs.getBoundingClientRect();
cvs.width = W;
cvs.height = H;
const gl = cvs.getContext("experimental-webgl", {
premultipliedAlpha: false
}),
VERTEX_SHADER = `attribute vec4 a_Position;
attribute vec2 a_TexCoord;
varying vec2 v_TexCoord;
void main() {
gl_Position = a_Position;
v_TexCoord = a_TexCoord;
}`,
FRAGMENT_SHADER = `precision mediump float;
uniform sampler2D u_Sampler;
varying vec2 v_TexCoord;
void main() {
gl_FragColor.rgb = texture2D(u_Sampler, v_TexCoord).rgb;
gl_FragColor.a = 1.0;
}`,
vshader = gl.createShader(gl.VERTEX_SHADER),
fshader = gl.createShader(gl.FRAGMENT_SHADER),
program = gl.createProgram();
gl.shaderSource(vshader, VERTEX_SHADER);
gl.shaderSource(fshader, FRAGMENT_SHADER);
gl.compileShader(vshader);
gl.compileShader(fshader);
gl.attachShader(program, vshader);
gl.attachShader(program, fshader);
gl.linkProgram(program);
gl.useProgram(program);
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
const farr = new Float32Array([-1, 1, 0, 1, -1, -1, 0, 0,
1, 1, 1, 1,
1, -1, 1, 0
]);
const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, farr, gl.STATIC_DRAW);
const a_Position = gl.getAttribLocation(program, "a_Position"),
a_TexCoord = gl.getAttribLocation(program, "a_TexCoord"),
fsize = farr.BYTES_PER_ELEMENT;
gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 4 * fsize, 0);
gl.vertexAttribPointer(a_TexCoord, 2, gl.FLOAT, false, 4 * fsize, 2 * fsize);
gl.enableVertexAttribArray(a_Position);
gl.enableVertexAttribArray(a_TexCoord);
var image = document.getElementById("img"),
context = image.getContext("2d"),
imageData = context.getImageData(0, 0, 2, 2),
pixels = imageData.data;
for (var i = 0; i < pixels.length; i++) {
pixels[i] = 255;
}
pixels[0 * 4 + 3] = 0;
pixels[1 * 4 + 3] = 1;
pixels[2 * 4 + 3] = 128;
context.putImageData(imageData, 0, 0, 0, 0, 2, 2);
const texture = gl.createTexture(),
u_Sampler = gl.getUniformLocation(program, "u_Sampler");
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, texture);
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, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
gl.uniform1i(u_Sampler, 0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
html,
body,
canvas {
padding: 0;
margin: 0;
}
canvas {
border: 1px solid red;
display: block;
margin: 5px;
}
body {
background: black;
display: block;
position: absolute;
width: 100%;
height: 100%;
}
#cvs {
width: 100px;
height: 100px;
}
<canvas id="cvs"></canvas>
<canvas id="img" width="2" height="2"></canvas>