【问题标题】:WebGL shader z position not used in depth calculationsWebGL 着色器 z 位置未用于深度计算
【发布时间】:2017-04-08 10:03:48
【问题描述】:

我一直在尝试一些 WebGL,但有一个错误我似乎无法找到解决方法。

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

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

我尝试了什么?

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 值高于较大的三角形(近距离)。

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

【问题讨论】:

  • 为什么不能在 z=10 的三角形上绘制 z=1 的三角形? 1 IS 小于或等于 10.
  • 我希望更高的 Z 值位于顶部,那么实际上应该是 gl.GEQUAL,这很好。深度测试仍然无法在我更新的gl_Position 上运行。
  • 请在问题中发布一个有效的 sn-p。 SO 要求:“寻求调试帮助的问题(“为什么这段代码不起作用?”)必须包括所需的行为、特定问题或错误以及重现它所需的最短代码在问题本身中.

标签: webgl depth-buffer zbuffer


【解决方案1】:

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

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

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>

【讨论】:

  • 我测试了不同的组合,发现 depthFunc GEQUAL 和 clearDepth of 1 仍然有效,这意味着每个三角形的 z 值为 1。但是问题是我所有的三角形都被绘制了在单个 drawArrays 函数中,它们的 Z 在顶点着色器中定义。我怎样才能让它工作?目前使用您的解决方案,顺序仍然不正确。
  • 在我的示例中,顺序正是我所期望的。我用 z = 0.1 -> 1.0 使用 LESS 绘制红色,其中 0.1 小而 1.0 大,我看到大的被绘制在小后面,这意味着深度缓冲区按预期工作。绿色是 z = 1.0 到 0.1,其中 1.0 小,0.1 大。这次我使用GEQUAL。再次因为我最后绘制 0.1 并且它是最大的,这表明它按预期工作。它不会覆盖 z = 1.0 处的小东西,因为深度缓冲区正在工作并被清除为 0。
  • 最后一个(蓝色)显示如果深度缓冲区被清除为 1,那么只有 1.0 的东西起作用(第一个小矩形)。所有其他都不起作用,因为它们小于 1.0 并且测试是GEQUAL。在您的示例中,您至少需要清除为 0 而不是 1,否则除了 z = 1 之外什么都不能绘制。
  • 我现在了解 z 值如何影响深度测试,我尝试了所有不同的组合,但似乎没有任何改变它们的绘制顺序。 .drawArrays() 只是在下一个三角形上绘制每个三角形,这可能是因为我有 1 个绘制调用,其中包含不同的三角形,而不是你有 3 个不同的一次?
  • 不,我更新了示例以一次绘制所有矩形。我得到相同的结果。您应该发布更多代码,尽管您仍然没有承认您当前的代码无法工作,因为它清除深度为 1,因此 GEQUAL 到 1 的唯一值是 1。除此之外的任何内容都不会因为它被剪裁了。因此,如果您的所有对象都位于 Z=1 处,那么它们都是 GEQUAL,因此它们都将按绘制顺序绘制。否则,您是直接绘制到画布上还是绘制到帧缓冲区?如果是帧缓冲区,您是否创建了深度附件?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-04-27
  • 1970-01-01
  • 2016-11-27
  • 1970-01-01
  • 2014-02-18
  • 2014-05-30
  • 1970-01-01
相关资源
最近更新 更多