webgl 中的 alpha 混合无法正常工作

alpha blending in webgl works not correctly

代码:

gl.enable(gl.DEPTH_TEST);
gl.depthFunc(gl.LESS);

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

问题在于绘制了图 "superfluous":
如何纠正?
P.S。 α=0.9

您对 zNear 和 zFar 的看法是什么?有没有可能你把它设置得太近了,你的立方体的背面被剪掉了?请参阅下面的示例,它设置得太近了。这看起来不像是你的问题,但很难判断。

您也在对多边形进行排序吗?当渲染透明的东西时,你通常必须从前到后绘制。对于球体、金字塔或立方体等凸面对象,您可以通过剔除绘制两次,首先使用 gl.cullFace(gl.FRONT) 仅绘制背面三角形,远离相机的三角形,然后再次使用 gl.cullFace(gl.BACK)只绘制前面的三角形,靠近相机的三角形。

还有一个问题是您是否正确地向 canvas 提供了预乘 alpha?大多数着色器都这样做

gl_FragColor = someUnpremultipliedAlphaColor;

但默认情况下您需要提供预乘的 alpha 颜色

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

或者您可以将 canvas 设置为使用未预乘的颜色

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

window.onload = function() {
  // Get A WebGL context
  var canvas = document.getElementById("c");
  var gl = canvas.getContext("webgl");
  if (!gl) {
    return;
  }
  
  var programInfo = webglUtils.createProgramInfo(gl, ["vs", "fs"]);
  var createFlattenedVertices = function(gl, vertices) {
    return webglUtils.createBufferInfoFromArrays(
        gl,
        primitives.makeRandomVertexColors(
            primitives.deindexVertices(vertices),
            {
              vertsPerColor: 6,
              rand: function(ndx, channel) {
                return channel < 3 ? ((128 + Math.random() * 128) | 0) : 255;
              }
            })
      );
  };

  var bufferInfo   = createFlattenedVertices(gl, primitives.createCubeVertices(1));
  
  function degToRad(d) {
    return d * Math.PI / 180;
  }

  var cameraAngleRadians = degToRad(0);
  var fieldOfViewRadians = degToRad(60);
  var uniforms = {
    u_color: [1, 1, 1, 0.8],
    u_matrix: null,
  };
  
  var zClose = false;
  var zNear = 1;
  var zFar  = 3;
  var zElem = document.getElementById("z");
  var bElem = document.getElementById("b");
  bElem.addEventListener('click', toggleZDepth, false);
  toggleZDepth();
  
  function toggleZDepth() {
    zClose = !zClose;
    zFar = zClose ? 3.5 : 4;
    zElem.innerHTML = zFar;    
  }
  
  function drawScene() {
    
    gl.enable(gl.CULL_FACE);
    gl.enable(gl.DEPTH_TEST);
    gl.enable(gl.BLEND);
    gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

    var aspect = canvas.clientWidth / canvas.clientHeight;
    var projectionMatrix =
        makePerspective(fieldOfViewRadians, aspect, zNear, zFar);
    
    var time = Date.now() * 0.0005;
    var radius = 3;

    var cameraPosition = [Math.cos(time) * radius, 1, Math.sin(time) * radius];
    var target = [0, 0, 0];
    var up = [0, 1, 0];
    var cameraMatrix = makeLookAt(cameraPosition, target, up);
    var viewMatrix = makeInverse(cameraMatrix);

    uniforms.u_matrix = matrixMultiply(viewMatrix, projectionMatrix);

    gl.useProgram(programInfo.program);
    webglUtils.setBuffersAndAttributes(gl, programInfo.attribSetters, bufferInfo);
    webglUtils.setUniforms(programInfo.uniformSetters, uniforms);
    
    // draw back facing polygons first
    gl.cullFace(gl.FRONT);
    gl.drawArrays(gl.TRIANGLES, 0, bufferInfo.numElements);
    // now draw front facing polygons
    gl.cullFace(gl.BACK);
    gl.drawArrays(gl.TRIANGLES, 0, bufferInfo.numElements);
    
    requestAnimationFrame(drawScene);
  }
  drawScene();
}
canvas { 
  border: 1px solid black;
}
#overlay {
  position: absolute;
  top: 20px;
  left: 20px;
  z-index: 2;
}
<script src="//webglfundamentals.org/webgl/resources/webgl-utils.js"></script>
<script src="//webglfundamentals.org/webgl/resources/webgl-3d-math.js"></script>
<script src="//webglfundamentals.org/webgl/resources/primitives.js"></script>
<canvas id="c" width="400" height="200"></canvas>  
<div id="overlay">
  <button id="b">toggle z-far</button>
  <div>z-far = <span id="z"></span></div>
</div>
<!-- vertex shader -->
<script id="vs" type="x-shader/x-vertex">
attribute vec4 a_position;
attribute vec4 a_color;

varying vec4 v_color;

uniform mat4 u_matrix;

void main() {
   gl_Position = u_matrix * a_position;
   v_color = a_color;   
}
</script>
<!-- fragment shader -->
<script id="fs" type="x-shader/x-fragment">
precision mediump float;

uniform vec4 u_color;
varying vec4 v_color;

void main() {
   vec4 color = v_color * u_color;
   gl_FragColor = vec4(color.rgb * color.a, color.a);  // premultiply color
}
</script>