为什么我的 webgl 着色器不能正确改变像素片段?

Why is my webgl shader not changing pixel fragments correctly?

我正在尝试获取片段的位置并更改位置处的颜色,但是当我尝试这样做时,我得到了一个奇怪的效果,它们不想完全改变。

注意有青色,但那部分应该是透明的。似乎发生了一些奇怪的舍入,我不确定如何解决它。这里发生了什么?

        void main() {
        vec4 c0 = vec4(0,1,0,1);
        c0.a *= step(132.0,gl_FragCoord.x);
        gl_FragColor = c0;
        }

您需要显示更多代码。你启用混合了吗?你选择了什么混合函数和混合方程。你的 canvas 有 alpha 吗? canvas 的背景是什么颜色?

这是一个使用您的示例的小程序

"use strict";
var gl = twgl.getWebGLContext(document.getElementById("c"));
var programInfo = twgl.createProgramInfo(gl, ["vs", "fs"]);

var arrays = {
  position: [-1, -1, 0, 1, -1, 0, -1, 1, 0, -1, 1, 0, 1, -1, 0, 1, 1, 0],
};
var bufferInfo = twgl.createBufferInfoFromArrays(gl, arrays);

var uniforms = { };

gl.useProgram(programInfo.program);
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
twgl.setUniforms(programInfo, uniforms);
twgl.drawBufferInfo(gl, bufferInfo);
html, body {
  background: red;
}
<canvas id="c"></canvas>
<script id="vs" type="notjs">
attribute vec4 position;

void main() {
  gl_Position = position;
}
</script>
<script id="fs" type="notjs">
precision mediump float;
void main() {
  vec4 c0 = vec4(0,1,0,1);
  c0.a *= step(132.0,gl_FragCoord.x);
  gl_FragColor = c0;
}
</script>
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>

WebGL 将 canvas 与 HTML 合成。在这种情况下,它使用 预乘 alphared 页面

上绘制 canvas

您的着色器在 gl_FragCoord.x 小于 132 时输出 0,1,0,0,这是无效的颜色

我敢肯定这听起来毫无意义,但它无效,因为浏览器需要预乘颜色。由于 alpha 为 0,这意味着 R、G 和 B 不能为零以外的任何值,因为任何 * 0 = 0。这是另一种说法,浏览器在这种情况下显示的内容是未定义的,因为它是无效的颜色 结果每个浏览器可能不同。

几个选项

  1. 预乘 alpha

    将其放在着色器的末尾

    gl_FragColor.rgb *= gl.FragColor.a;
    
  2. 告诉 WebGL 您正在使用未预乘的 alpha

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

    在那种情况下 0,1,0,0 是有效的颜色

  3. 如果不需要 alpha,请将其关闭

    gl = someCanvas.getContext("webgl", { alpha: false });
    

另一个想法是,如果您的 canvas 与显示的大小不同,那么浏览器将绘制 canvas 过滤后的内容。这些过滤后的像素既不是 0,1,0,0 也不是 0,1,0,1,而是两者之间的双线性插值。

例如,让我们制作一个只有 10 个像素但显示 300 个像素的 canvas。我们会将您的更改更改为 3 而不是 132。

"use strict";
var gl = twgl.getWebGLContext(document.getElementById("c"));
var programInfo = twgl.createProgramInfo(gl, ["vs", "fs"]);

var arrays = {
  position: [-1, -1, 0, 1, -1, 0, -1, 1, 0, -1, 1, 0, 1, -1, 0, 1, 1, 0],
};
var bufferInfo = twgl.createBufferInfoFromArrays(gl, arrays);

var uniforms = {};

gl.useProgram(programInfo.program);
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
twgl.setUniforms(programInfo, uniforms);
twgl.drawBufferInfo(gl, bufferInfo);
html, body {
  background: red;
}
<canvas id="c" width="10" style="width: 300px; height: 150px;"></canvas>
<script id="vs" type="notjs">
attribute vec4 position;

void main() {
  gl_Position = position;
}
</script>
<script id="fs" type="notjs">
precision mediump float;
void main() {
  vec4 c0 = vec4(0,1,0,1);
  c0.a *= step(3.0,gl_FragCoord.x);
  gl_FragColor = c0;
}
</script>
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>