I'm generating a texture from a canvas that contains text, the problem is that the transparent part of the text is completely ignored when I render the texture.
When I render the texture it looks like the top text, when it should look like the bottom text.
This is how I generate the texture:
canvas.width = textRendBuffC.measureText(text).width*2;
canvas.height = parseInt(fontStyle, 10)*1.5;
c.clearRect(0, 0, canvas.width, canvas.height);
c.font = fontStyle;
c.fillStyle = colorStyle;
c.fillText(text, 0, parseInt(fontStyle, 10));
var canvasTexture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, canvasTexture);
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL,true);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, canvas);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER,gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER,gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.bindTexture(gl.TEXTURE_2D,null);
And this is how I draw the texture:
gl.bindBuffer(gl.ARRAY_BUFFER, spritePlan.vertBuffer);
gl.vertexAttribPointer(currentShader.sh.vertexAttribLocation, spritePlan.vertBuffer.itemSize, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, spritePlan.texCoordBuffer);
gl.vertexAttribPointer(currentShader.sh.textureCoordAttribute, spritePlan.texCoordBuffer.itemSize, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, spritePlan.colorBuffer);
gl.vertexAttribPointer(currentShader.sh.colorAttribLocation, spritePlan.colorBuffer.itemSize, gl.FLOAT, false, 0, 0);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.uniform1i(currentShader.sh.sampler2DUniform, 0);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, spritePlan.indexBuffer);
setMatrixUniforms();
gl.drawElements(gl.TRIANGLES, spritePlan.indexBuffer.numItems, gl.UNSIGNED_SHORT, 0);
gl.bindTexture(gl.TEXTURE_2D, null);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
And this is the code the fragment shader goes through:
vec4 tex = texture2D(sampler2DUniform, vTextureCoord);
gl_FragColor = vec4(tex.rgb, tex.a);
Any ideas?
You have to set the UNPACK_PREMULTIPLY_ALPHA_WEBGL
paramter to true
(pixelStorei
). This will cause the the color channels to be multiplied by the alpha channel, The initial value is false
:
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
See WebGL Fundamentals - textures:
This tells WebGL to supply premultiplied alpha values to
gl.texImage2D
andgl.texSubImage2D
. If the data passed togl.texImage2D
is already premultiplied as it is for Canvas 2D data then WebGL can just pass it through.
See Khronos specification Premultiplied Alpha, Canvas APIs and texImage2D:
When passing a WebGL-rendered Canvas to the texImage2D API, then depending on the setting of the premultipliedAlpha context creation parameter of the passed canvas and the
UNPACK_PREMULTIPLY_ALPHA_WEBGL
pixel store parameter of the destination WebGL context, the pixel data may need to be changed to or from premultiplied form.
Further, you set up the texture paramter TEXTURE_MAG_FILTER
with NEAREST
:
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER,gl.NEAREST);
See the Khronos OpenGL reference for Sampler Object:
The magnification filter is controlled by the
GL_TEXTURE_MAG_FILTER
texture parameter. This value can beGL_LINEAR
orGL_NEAREST
. IfGL_NEAREST
is used, then the implementation will select the texel nearest the texture coordinate; this is commonly called "point sampling". IfGL_LINEAR
is used, the implementation will perform a weighted linear blend between the nearest adjacent samples.
This means, if you use NEAREST
, then the the nearest texel is read from the texture, according to the texture coordinates. This causes a hard and angular appearance.
If you set the texture parameter TEXTURE_MAG_FILTER
to LINEAR
, the texels will be interpolated and the weighted average of the 4 pixels surrounding the given coordinate is calculated. The result is a smoother appearance:
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER,gl.LINEAR);
See also: