在 webgl 中生成文本纹理:Alpha 是不透明的

generating text texture in webgl: Alpha is opaque

我正在从包含文本的 canvas 生成纹理,问题是当我渲染纹理时,文本的透明部分被完全忽略。

当我渲染纹理时它看起来像顶部文本,当它应该看起来像底部文本时。

这是我生成纹理的方式:

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);

这就是我绘制纹理的方式:

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);

这是片段着色器经过的代码:

vec4 tex = texture2D(sampler2DUniform, vTextureCoord);
gl_FragColor = vec4(tex.rgb, tex.a);

有什么想法吗?

您必须将 UNPACK_PREMULTIPLY_ALPHA_WEBGL 参数设置为 true (pixelStorei)。这将导致颜色通道乘以 alpha 通道,初始值为 false:

gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);

WebGL Fundamentals - textures:

This tells WebGL to supply premultiplied alpha values to gl.texImage2D and gl.texSubImage2D. If the data passed to gl.texImage2D is already premultiplied as it is for Canvas 2D data then WebGL can just pass it through.

参见 Khronos 规范 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.


此外,您使用 NEAREST:

设置纹理参数 TEXTURE_MAG_FILTER
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER,gl.NEAREST);

参见 Sampler Object 的 Khronos OpenGL 参考:

The magnification filter is controlled by the GL_TEXTURE_MAG_FILTER texture parameter. This value can be GL_LINEAR or GL_NEAREST. If GL_NEAREST is used, then the implementation will select the texel nearest the texture coordinate; this is commonly called "point sampling". If GL_LINEAR is used, the implementation will perform a weighted linear blend between the nearest adjacent samples.

这意味着,如果你使用NEAREST,那么根据纹理坐标从纹理中读取最近的纹素。这会导致硬 angular 外观。
如果将纹理参数 TEXTURE_MAG_FILTER 设置为 LINEAR,将对纹素进行插值,并计算给定坐标周围 4 个像素的加权平均值。结果是外观更平滑:

gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER,gl.LINEAR);


另见:

首先,要在 WebGL 中使用 alpha 作为透明度,您必须使用正确的混合方程启用混合。典型的是:

gl.enable(gl.BLEND);
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);

我在你的代码中没有看到任何与混合相关的内容,你是否在其他地方设置了它,你使用什么混合方程?