javascript - webgl 中的 alpha 混合工作不正常

标签 javascript webgl alpha alphablending

代码:

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

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

在图形上绘制“多余”的问题:enter image description here
如何纠正?
附:阿尔法=0.9

最佳答案

您的视角 zNear 和 zFar 设置为多少?有没有可能你把它设置得太近,立方体的背面被剪掉了?请参阅下面的示例,其中设置得太近。这看起来不像你的问题,但很难说。

您还在对多边形进行排序吗?渲染透明物体时,通常必须从前到后绘制。对于像球体、金字塔或立方体这样的凸面物体,您可以在剔除的情况下绘制两次,首先使用 gl.cullFace(gl.FRONT) 仅绘制背面的三 Angular 形,即距离相机较远的三 Angular 形,然后再次使用 gl.cullFace(gl.BACK) 仅绘制正面的三 Angular 形,即靠近相机的三 Angular 形。

另一个问题是您是否正确地向 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>

关于javascript - webgl 中的 alpha 混合工作不正常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29217189/

相关文章:

javascript - WinJS 数据绑定(bind) : Classes and Event Binding

2d - 为什么透明像素在 WebGL 中不能正确混合

javascript - 如何在javascript中的图像上添加可拖动的文本

javascript - 使用 Javascript、WebGL 和 HTML 绘制正方形

javascript - BabylonJS 画线

c# - PorterDuff.Mode.Multiply 没有按预期工作?黑色背景而不是透明

opengl-es - 使用 alpha 渲染到纹理问题

ios - 在我的纹理上绘制形状时,OpenGL 使我的纹理半透明

javascript - 每次在同一行内选中复选框时获取具有特定id的td文本

javascript - $interval 的 invokeApply 参数不会改变任何东西