【问题标题】:Loading the PNG Image by webgl is not perfect通过 webgl 加载 PNG 图像并不完美
【发布时间】:2019-11-20 13:53:22
【问题描述】:

当使用canvas.getContext('2d')加载具有透明部分的png文件时,它看起来与png文件本身完全相同。但是当通过canvas.getContext('webgl')加载时,它会在透明部分显示为白色。然后如果你在着色器中添加discard,它会更好,但仍然不如png文件完美。如何解决这个问题?


gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this.img);

void main() {
      vec4 color = texture2D(u_image, v_texCoord);
      if(color.a < 0.5) {
         discard;
      }
      gl_FragColor = color;
    }

【问题讨论】:

    标签: javascript canvas webgl


    【解决方案1】:

    听起来您可能需要激活混合。

    gl.enable(gl.BLEND);
    

    然后将混合函数设置为使用预乘 alpha(默认)

    gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
    

    【讨论】:

    • 谢谢 Nathan,是的,我现在启用混合。但我选择 gl.SRC_ALPHA 作为第一个参数,因为 gl.ONE 会将透明像素更改为白色。
    【解决方案2】:

    透明度实际上有点复杂

    #1 画布本身需要什么

    默认画布需要预乘 alpha。换句话说,它希望您提供 RGBA 值,其中 RGB 已乘以 A。

    您可以设置画布,使其在创建 webgl 上下文时不需要预乘 alpha,方法是传入 premultipledAlpha: false,如下所示

    const gl = someCanvas.getContext('webgl', {premultipliedAlpha: false});
    

    注意:IIRC 这不适用于 iOS。

    #2 加载图片的格式

    在 WebGL 中加载图像的默认值是未预乘的 alpha。换句话说,如果图像的像素是

    255, 128, 64, 128   RGBA
    

    它将完全像那样加载(*)

    您可以通过设置告诉 WebGL 在加载图像时为您预乘

    gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
    

    在致电gl.texImage2D之前。

    现在上面的同一个像素最终会变成

    128, 64, 16, 128    RGBA
    

    每个 RGB 都乘以 A(上面的 A 是 128,其中 128 代表 128/255 或 0.5019607843137255)

    #3 你在着色器中写出的内容

    如果您加载了未预乘的数据,您可能会选择在着色器中进行预乘

    gl_FragColor = vec4(someColor.rgb * someColor.a, someColor.a);
    

    #4 你如何混合

    如果要将正在绘制的内容混合到已经绘制的内容中,则需要打开混合

    gl.enable(gl.BLEND);
    

    但您还需要设置混合的方式。有多种功能会影响混合。最常用的是gl.blendFunc,它设置src 像素(由着色器生成的像素)和dst 像素(在画布顶部绘制的像素)在组合之前受到的影响。两种最常见的设置是

    gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);  // unpremultiplied alpha
    

    gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);  // premultiplied alpha
    

    第一个参数是如何乘以 src 像素。上面我们要么乘以 src 的 alpha (SRC_ALPHA),要么乘以 1 (ONE)。第二个参数是如何乘以 dst 像素。 ONE_MINUS_SRC_ALPHA 正是它所说的(1 - alpha)

    如何将所有这些放在一起取决于您。

    This articleThis one 在某种程度上涵盖了这些问题

    (*) 图片可能有color conversion applied

    【讨论】:

    • 非常感谢!我已经尝试了上面列出的所有 4 个建议。 #4 混合功能在第一个常见设置下按预期工作。但是与canvas2d相比,webgl渲染的PNG文件在细节上不如canvas2d渲染的那么流畅。是否有任何其他设置可用于使其与 canvas2d 执行完全相同?
    • 仅供参考,标准画布的第一个设置是错误的。请参阅 #1 在任何情况下您都需要发布我认为的代码(在新问题中更好)。
    猜你喜欢
    • 1970-01-01
    • 2023-03-27
    • 2014-05-23
    • 1970-01-01
    • 2015-01-30
    • 1970-01-01
    • 1970-01-01
    • 2021-04-24
    • 1970-01-01
    相关资源
    最近更新 更多