WebGL:如何正确混合alpha通道png

mod*_*777 7 webgl

我是OpenGL的新手,甚至是WebGL的新手.我正在尝试使用alpha通道绘制纹理四边形.但是我无法正确混合.

这是我正在寻找的结果

这是我正在寻找的结果

这就是WebGL结果的样子

这就是WebGL结果的样子

正如您所看到的,骰子边缘有一种白色轮廓,原始图像中没有.

这就是我在WebGL中进行混合的方法

        gl.clearColor(0.5, 0.5, 0.5, 1);
        gl.disable(gl.DEPTH_TEST);
        gl.enable(gl.BLEND);
        gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
Run Code Online (Sandbox Code Playgroud)

这是我的片段着色器:

precision mediump float;

varying vec2 vUV;

uniform sampler2D texture;

void main(void) {
    vec4 frag = texture2D(texture, vUV);
    gl_FragColor = frag;
}
Run Code Online (Sandbox Code Playgroud)

知道为什么会这样吗?我不会创建mipmap,BTW.

gma*_*man 14

这已在其他地方得到解答,但......

WebGL画布默认需要预乘alpha.WebGL画布在网页上合成(混合到页面上).所以......

您或者您不希望您的WebGL图像与网页混合吗?

如果不是,您不想与网页混合,请执行以下操作之一

如果是,您确实想要与网页混合,然后执行以下操作之一

  • 确保您在画布中写入的值是预乘的alpha值.

  • 告诉浏览器画布中的值不是预乘的

    var gl = someCanvas.getContext("webgl", {premultipliedAlpha: false});
    
    Run Code Online (Sandbox Code Playgroud)

除此之外,默认情况下,加载到WebGL中的图像使用未预乘的alpha, 这意味着您需要

假设你的画布是预乘的,你想要你的混合函数

gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
Run Code Online (Sandbox Code Playgroud)

这是因为你不需要将数据源乘以alpha,因为它已经预乘

这是通过在着色器中乘以alpha来与页面混合的示例.紫色条纹是CSS背景.图像被绘制两次,一次填充画布,一次在1/2尺寸的顶部.你可以看到它都是正确混合的.

var vs = `
attribute vec4 position;
varying vec2 v_texcoord;
uniform mat4 u_matrix;
void main() {
  gl_Position = u_matrix * position;
  v_texcoord = position.xy * .5 + .5;
}
`;

var fs = `
precision mediump float;
varying vec2 v_texcoord;
uniform sampler2D u_tex;
void main() {
  gl_FragColor = texture2D(u_tex, v_texcoord);
  gl_FragColor.rgb *= gl_FragColor.a;
}
`;

var gl = document.querySelector("canvas").getContext("webgl");
var m4 = twgl.m4;
var programInfo = twgl.createProgramInfo(gl, [vs, fs]);
var bufferInfo = twgl.primitives.createXYQuadBufferInfo(gl);

var tex = twgl.createTexture(gl, { 
  src: "https://i.imgur.com/iFom4eT.png",
  crossOrigin: "",
}, render);

function render() {
  gl.enable(gl.BLEND);
  gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
  
  gl.useProgram(programInfo.program);
  twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
  twgl.setUniforms(programInfo, {
    u_tex: tex,
    u_matrix: m4.identity(),
  });
  twgl.drawBufferInfo(gl, bufferInfo);

  twgl.setUniforms(programInfo, {
    u_tex: tex,
    u_matrix: m4.scaling([0.5, 0.5, 1]),
  });
  twgl.drawBufferInfo(gl, bufferInfo);
}
Run Code Online (Sandbox Code Playgroud)
canvas {
  background-color: purple;
  background-image: linear-gradient(45deg, rgba(255, 255, 255, 1) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 1) 50%, rgba(255, 255, 255, 1) 75%, transparent 75%, transparent);
  background-size: 50px 50px;
}
Run Code Online (Sandbox Code Playgroud)
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
<canvas></canvas>
Run Code Online (Sandbox Code Playgroud)

这是一个将画布设置为未预乘的示例.唯一不同的是我传递{premultipliedAlpha: false}给了getContext.我删除了gl_FragColor.rgb *= gl_FragColor.a.并且,我将混合功能更改为gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)

var vs = `
attribute vec4 position;
varying vec2 v_texcoord;
uniform mat4 u_matrix;
void main() {
  gl_Position = u_matrix * position;
  v_texcoord = position.xy * .5 + .5;
}
`;

var fs = `
precision mediump float;
varying vec2 v_texcoord;
uniform sampler2D u_tex;
void main() {
  gl_FragColor = texture2D(u_tex, v_texcoord);
}
`;

var gl = document.querySelector("canvas").getContext("webgl", {
  premultipliedAlpha: false,
});
var m4 = twgl.m4;
var programInfo = twgl.createProgramInfo(gl, [vs, fs]);
var bufferInfo = twgl.primitives.createXYQuadBufferInfo(gl);

var tex = twgl.createTexture(gl, { 
  src: "https://i.imgur.com/iFom4eT.png",
  crossOrigin: "",
}, render);

function render() {
  gl.enable(gl.BLEND);
  gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
  
  gl.useProgram(programInfo.program);
  twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
  twgl.setUniforms(programInfo, {
    u_tex: tex,
    u_matrix: m4.identity(),
  });
  twgl.drawBufferInfo(gl, bufferInfo);

  twgl.setUniforms(programInfo, {
    u_tex: tex,
    u_matrix: m4.scaling([0.5, 0.5, 1]),
  });
  twgl.drawBufferInfo(gl, bufferInfo);
}
Run Code Online (Sandbox Code Playgroud)
canvas {
  background-color: purple;
  background-image: linear-gradient(45deg, rgba(255, 255, 255, 1) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 1) 50%, rgba(255, 255, 255, 1) 75%, transparent 75%, transparent);
  background-size: 50px 50px;
}
Run Code Online (Sandbox Code Playgroud)
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
<canvas></canvas>
Run Code Online (Sandbox Code Playgroud)

  • gl_FragColor.rgb *= gl_FragColor.a 拯救了我一整天,最近的 chromium 100+ 疯狂掉帧,尤其是在带有 webgl2 premultipliedAlpha 的手臂上: false 谢谢 (2认同)