0

我一直在尝试一些 WebGL,但有一个错误我似乎无法找到如何修复。

目前我有以下设置:我有大约 100 个三角形,它们都有一个位置并且由一个gl.drawArrays函数绘制。为了让它们以我使用的正确顺序绘制,gl.enable(gl.DEPTH_TEST);这给出了正确的结果。

我现在遇到的问题是,如果我更新gl_Position顶点着色器中的三角形,则更新的 Z 值不会用于深度测试。结果是gl_Position.z可以在 a 为 10 的三角形之上绘制一个 a 为 1 的三角形gl_Position.z,这并不是我想要的。

我尝试了什么?

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

gl.clear(gl.DEPTH_BUFFER_BIT);
gl.clearDepth(0);
gl.drawArrays(gl.TRIANGLES, 0, verticesCount);

在渲染函数中。

以下代码用于创建缓冲区:

gl.bindBuffer(gl.ARRAY_BUFFER, dataBuffer);
gl.bufferData(gl.ARRAY_BUFFER, positionBufferData, gl.STATIC_DRAW);
const positionLocation = gl.getAttribLocation(program, 'position');
gl.enableVertexAttribArray(positionLocation);
gl.vertexAttribPointer(positionLocation, 3, gl.FLOAT, false, false, 0, 0);

z 值较高的三角形尺寸要大得多(由于透视),但小三角形仍然出现在其上(由于渲染顺序)。

在片段着色器中,我用来gl_fragCoord.z查看这是否正确,较小的三角形(更远)接收到的 alpha 比较大的三角形(近距离)更高。

奇怪的绘图行为可能是什么原因?

4

1 回答 1

1

剪辑空间中的深度从 -1 变为 1。写入深度缓冲区的深度从 0 变为 1。您正在清除为 1。没有深度值 > 1,因此您应该看到的唯一内容是在gl_Position.z = 1. 任何小于 1 的都将通过测试gl.depthFunc(gl.GEQUAL);。任何大于 1 的东西都将被剪裁。只有 1 既在深度范围内又大于等于 1

下面的示例使用不同的 z 值绘制从小到大的矩形。红色是标准gl.depthFunc(gl.LESS)的,深度清除为 1。绿色是gl.depthFunc(gl.GEQUAL)深度清除为 0。蓝色是gl.depthFunc(gl.GEQUAL)深度清除为 1。请注意蓝色仅绘制单个矩形,gl_Position.z = 1因为所有其他矩形均未通过测试,因为它们位于 Z < 1 .

const m4 = twgl.m4;
const gl = document.querySelector("canvas").getContext("webgl");
const vs = `
attribute vec4 position;
varying vec4 v_position;
uniform mat4 matrix;
void main() {
   gl_Position = matrix * position;
   v_position = abs(position);
}
`;
const fs = `
precision mediump float;
varying vec4 v_position;
uniform vec4 color;
void main() {
  gl_FragColor = vec4(1. - v_position.xxx, 1) * color;
}
`;
// compiles shaders, links program, looks up attributes
const programInfo = twgl.createProgramInfo(gl, [vs, fs]);
// calls gl.createBuffer, gl.bindBindbuffer, gl.bufferData for each array
const z0To1BufferInfo = twgl.createBufferInfoFromArrays(gl, {
  position: [ 
     ...makeQuad( .2, 0.00),
     ...makeQuad( .4,  .25),
     ...makeQuad( .6,  .50),
     ...makeQuad( .8,  .75),
     ...makeQuad(1.0, 1.00),
  ],
});
const z1To0BufferInfo = twgl.createBufferInfoFromArrays(gl, {
  position: [ 
     ...makeQuad(.2, 1.00),
     ...makeQuad(.4,  .75),
     ...makeQuad(.6,  .50),
     ...makeQuad(.8,  .25),
     ...makeQuad(1., 0.00),
  ],
});

function makeQuad(xy, z) {
  return [
     -xy, -xy, z,
      xy, -xy, z,
     -xy,  xy, z,
     -xy,  xy, z,
      xy, -xy, z,
      xy,  xy, z,
  ];
}

gl.useProgram(programInfo.program);

gl.enable(gl.DEPTH_TEST);

gl.clearDepth(1);
gl.clear(gl.DEPTH_BUFFER_BIT);
gl.depthFunc(gl.LESS);
drawRects(-0.66, z0To1BufferInfo, [1, 0, 0, 1]);

gl.clearDepth(0);
gl.clear(gl.DEPTH_BUFFER_BIT);
gl.depthFunc(gl.GEQUAL);
drawRects(0, z1To0BufferInfo, [0, 1, 0, 1]);

gl.clearDepth(1);
gl.clear(gl.DEPTH_BUFFER_BIT);
gl.depthFunc(gl.GEQUAL);
drawRects(0.66, z1To0BufferInfo, [0, 0, 1, 1]);


function drawRects(xoffset, bufferInfo, color) {
  // calls gl.bindBuffer, gl.enableVertexAttribArray, gl.vertexAttribPointer
  twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
  
  let mat = m4.translation([xoffset, 0, 0]);
  mat = m4.scale(mat, [.3, .5, 1]);

  // calls gl.uniformXXX
  twgl.setUniforms(programInfo, {
    color: color,
    matrix: mat,
  });

  // calls gl.drawArrays or gl.drawElements
  twgl.drawBufferInfo(gl, bufferInfo);
}
<script src="https://twgljs.org/dist/3.x/twgl-full.min.js"></script>
<canvas></canvas>
<pre>
red  : depthFunc: LESS,   clearDepth: 1
green: depthFunc: GEQUAL, clearDepth: 0
blue : depthFunc: GEQUAL, clearDepth: 1
</pre>

于 2017-04-09T02:58:51.897 回答