禁用混合时 WebGL return 像素颜色如何?

how WebGL return pixel color when blending is disabled?

在没有混合的情况下,fragment color 和 clearColor 给出颜色像素的函数是什么?

const canvas = document.querySelector("#normal");
const gl = canvas.getContext('webgl',  {premultipliedAlpha: false});

gl.clearColor(0 , 0.5 , 0.7 , 0.65);
gl.clear(gl.COLOR_BUFFER_BIT); 
html, body {
  height: 100%;
  background: repeating-linear-gradient(
    45deg,
    lime, /*  lime=( 0.0 , 1.0 , 0.0 , 1.0 ) */
    lime 10px,
    orange 10px,  /* orange=( 1.0 , 0.64705.. , 0.0 , 1.0) */
    orange 20px
  );
}
canvas {
  border: 1px solid black;
}
<canvas width="128" height="128" id="normal"></canvas>

正文 1.0 , 0.647 , 0.0 , 1.0
canvas 0.0 , 0.5 , 0.7 , 0.65
(1)canvas x α 0.0 , 0.325 , 0.455 , 0.4225
(2)正文 x (1-alpha) 0.35 , 0.2264 , 0.0 , 0.35
(1)+(2)= 0.35 , 0.5514 , 0.455 , 0.7725

因此,结果如下:

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

但我没有写那个代码...

16/07/2021 : Merci peabrainiac !

结果与以下相同: gl.blendFuncSeparate(gl.SRC_AlPHA,gl.ONE_MINUS_SRC_ALPHA,gl.ONE,gl.ONE_MINUS_SRC_ALPHA)

颜色(RGB) = sourceColor * As + destinationColor * (1-As)

颜色(A) = sourceAlpha + destinationAlpha * ( 1-As)

颜色(RGB) = (0.0, 0.5, 0.7) * 0.65 + (1.0, 0.647.., 0.0) * 0.35

颜色(A) = 0.65 + 1.0 * 0.35

颜色(RGB) = (0.35, 0.55147.., 0.455)

颜色(A) = 1.0

测试:

test('#normal');
test3('#blendfunc');

function test(selector) {
  const canvas = document.querySelector(selector);
  const gl = canvas.getContext('webgl');
  
  var r = 0;
  var g = 0.5;
  var b = 0.7;
  var a = 0.65;
  
  gl.clearColor(r * a, g * a, b * a, a);
  gl.clear(gl.COLOR_BUFFER_BIT); 
}

function test3(selector) {
  const canvas = document.querySelector(selector);
  const gl = canvas.getContext('webgl');
  
  const vs=`
    void main() {
      gl_Position=vec4(0,0,0,1);
      gl_PointSize = 128.;
    }
  `;
  const fs=`
    precision highp float;
    
    void main() {
    float r=0.0;
    float g=0.5;
    float b=0.7;
    float a=0.65;

      gl_FragColor=vec4(r*a,g*a,b*a,a);
      
      // it works with gl_FragColor = vec4 (r, g, b, a)
      //However I am not in {premultipliedAlpha: false}
      //gl_FragColor=vec4(r,g,b,a);

    }
  `;
  
  const vertexShader = gl.createShader(gl.VERTEX_SHADER);
  gl.shaderSource(vertexShader, vs);
  gl.compileShader(vertexShader);
  
  const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
  gl.shaderSource(fragmentShader, fs);
  gl.compileShader(fragmentShader);
  
  const program = gl.createProgram();
  gl.attachShader(program, vertexShader);
  gl.attachShader(program, fragmentShader);
  gl.linkProgram(program);
  
  gl.useProgram(program);
  
  gl.clearColor(0, 0, 0, 0);
    gl.clear(gl.COLOR_BUFFER_BIT);
  
  gl.enable(gl.BLEND);
  //gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
  gl.blendFuncSeparate(gl.SRC_ALPHA,gl.ONE_MINUS_SRC_ALPHA,gl.ONE,gl.ONE_MINUS_SRC_ALPHA);
  
  gl.viewport(0,0,canvas.width,canvas.height);

  gl.drawArrays(gl.POINTS,0,1);
  
  
}
html, body {
  height: 100%;
  background: repeating-linear-gradient(
    45deg,
    lime,
    lime 10px,
    orange 10px, /* 1,0.647,1,0 */
    orange 20px
  );
}
canvas {
  border: 1px solid black;
}
<canvas width="128" height="128" id="normal"></canvas>
<canvas width="128" height="128" id="blendfunc"></canvas>

...天哪,它不起作用!

test('#normal');
test3('#blendfunc');

function test(selector) {
  const canvas = document.querySelector(selector);
  const gl = canvas.getContext('webgl');
  
  var r = 0;
  var g = 0.5;
  var b = 0.7;
  var a = 0.65;
  
  gl.clearColor(r * a, g * a, b * a, a);
  gl.clear(gl.COLOR_BUFFER_BIT); 
}

function test3(selector) {
  const canvas = document.querySelector(selector);
  const gl = canvas.getContext('webgl');
  
  const vs=`
    void main() {
      gl_Position=vec4(0,0,0,1);
      gl_PointSize = 128.;
    }
  `;
  const fs=`
    precision highp float;
    
    void main() {
    float r=0.0;
    float g=0.5;
    float b=0.7;
    float a=0.65;
    
    gl_FragColor=vec4(r,g,b,a);

    }
  `;
  
  const vertexShader = gl.createShader(gl.VERTEX_SHADER);
  gl.shaderSource(vertexShader, vs);
  gl.compileShader(vertexShader);
  
  const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
  gl.shaderSource(fragmentShader, fs);
  gl.compileShader(fragmentShader);
  
  const program = gl.createProgram();
  gl.attachShader(program, vertexShader);
  gl.attachShader(program, fragmentShader);
  gl.linkProgram(program);
  
  gl.useProgram(program);
  
  gl.clearColor(0, 0, 0, 0);
  gl.clear(gl.COLOR_BUFFER_BIT);
  
  gl.enable(gl.BLEND);
  
  gl.blendFuncSeparate(gl.SRC_ALPHA,gl.ONE_MINUS_SRC_ALPHA,gl.ONE,gl.ONE_MINUS_SRC_ALPHA);
  
  gl.viewport(0,0,canvas.width,canvas.height);

  gl.drawArrays(gl.POINTS,0,1);
  
  
}
html, body {
  height: 100%;
  background: repeating-linear-gradient(
    45deg,
    lime,
    lime 10px,
    orange 10px, /* 1,0.647,1,0 */
    orange 20px
  );
}
canvas {
  border: 1px solid black;
}
<canvas width="128" height="128" id="normal"></canvas>
<canvas width="128" height="128" id="blendfunc"></canvas>

在这种情况下,混合不是发生在 WebGL 内部,而是发生在浏览器内部,就像任何其他颜色为 0 , 0.5 , 0.7 , 0.65 的图像一样。

在 WebGL 中混合只是改变了从片段着色器发出的值与该缓冲区中已有的值混合的方式。当禁用混合时,默认情况下,它们只是 overwrite the old values without any sort of blending. Similarly, glClear always just overwrites the old values even if blending is enabled.

因此,在您的情况下,主缓冲区 / canvas 确实完全充满了 rgba 值 0, 0.5, 0.7, 0.65,没有以任何方式与其他任何东西混合;然而,与任何部分透明的元素一样,这将 blended linearly 带有浏览器的背景。