1

我想调整我的窗口大小并让我的画布和其中的所有内容随着窗口的扩展/收缩而伸展以填充。

这有点棘手,因为在我的 webgl 代码中,我在帧缓冲区菊花链和片段着色器之间创建了一个反馈循环。在一个顶点着色器中发生了一个小的转换,以保持反馈循环继续进行。如果我在调整大小事件上调用以下内容,它会进行我不想要的额外转换,并使反馈循环失控。但是,它确实会拉伸纹理以适应窗口。

gl.viewport(0,0,canvas.clientWidth, canvas.clientHeight);

我也尝试过做一个事件监听器来调整画布的大小,但纹理不会随之调整大小。相反,它们只是锁定在我窗口的左下角。检查画布元素显示画布确实改变了大小,但纹理没有。

window.addEventListener( 'resize', resizeCanvas );

function resizeCanvas(){
var width = canvas.clientWidth;
var height = canvas.clientHeight;
if(canvas.width != width ||
 canvas.height != height){
 canvas.width = width;
 canvas.height = height;
 //gl.viewport(0,0,width, height);
 }
}

我想这样做而不必重新分配我的 fbo。出于某种原因,我认为我只能拉伸我的画布和其中的所有东西,但我似乎无法让它工作。

这是包含我的完整 webgl 代码的页面的链接。为了简单起见,这个没有任何反馈循环,但如果对查看有帮助,我可以发布一个。在此先感谢您的帮助!

4

1 回答 1

4

我不确定我是否理解这个问题,但看看你的代码,如果你的帧缓冲区附件(在这种情况下是纹理)的大小与你gl.viewport每次更改当前帧缓冲区时需要调用的画布不同。

换句话说,在伪代码中

function(render) {
  resizeCanvas();

  gl.bindFramebuffer(gl.FRAMEBUFFER, someFramebuffer);
  gl.viewport(0, 0, widthOfSomeFramebuffer, heightOfSomeFramebuffer);
  drawStuffToFramebuffer();

  gl.bindFramebuffer(gl.FRAMEBUFFER, someOtherFramebuffer);
  gl.viewport(0, 0, widthOfSomeOtherFramebuffer, heightOtherOfSomeFramebuffer);
  drawStuffToOtherFramebuffer();

  gl.bindFramebuffer(gl.FRAMEBUFFER, null);
  gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
  drawStuffToCanvas();

  requestAnimationFrame(render);
}
render();

在大多数情况下,当绘制到画布时,视口应始终设置为画布的大小(widthheight不是clientWidthand clientHeight)。使用clientWidthandclientHeight来调整大小和/或计算投影的纵横比,无论该投影是 2d 还是 3d。事实上,使用and for可以说是错误的。clientWidthclientHeightgl.viewport

您可以将gl.viewport其视为定义要绘制的区域。将其设置gl.viewport(0, 0, gl.canvas.width, gl.canvas.height)为基本上是说您要在整个画布上绘制。

但这还不是全部真相。gl.viewport基本上设置如何从剪辑空间(-1 <-> +1),即着色器中使用的空间,转换回当前绘图表面(画布或帧缓冲区)上的像素空间。因此,将视口设置gl.viewport(x, y, width, height)为表示 x 中的 -1 到 +1 从当前绘图表面上的像素 x 到 x + w - 1 和 y 中的 -1 到 +1 从像素 y 到 y + height - 1 在当前绘图表面。

因为在大多数情况下,您想要在整个绘图表面上绘制,所以您需要将其设置gl.viewport为要绘制的表面的大小。

希望这能说明为什么使用clientWidthandclientHeight是错误的,gl.viewport因为它clientWidthclientHeight画布的实际大小(其中的像素)无关。它们仅与这些像素被拉伸或收缩的大小有关。换句话说

<canvas width="10" height="20" style="width: 30px; height: 40px"></canvas>

...

console.log("canvas.width       : " + canvas.width);
console.log("canvas.height      : " + canvas.height);
console.log("canvas.clientWidth : " + canvas.clientWidth);
console.log("canvas.clientHeight: " + canvas.clientHeight);

将打印

canvas.width       : 10
canvas.height      : 20
canvas.clientWidth : 30
canvas.clientHeight: 40

这意味着画布中只有 10x20 的实际像素,但它们在页面上被拉伸到 30x40。将视口设置gl.viewport(0, 0, canvas.clientWidth, canvas.clientHeight)为表示您要绘制到 30 像素宽和 40 像素高的区域,但实际上您只有 10 像素宽和 20 像素下方

就处理 resize 而言,如果您不断渲染(看起来就像您在代码中一样),那么在渲染循环开始时调用 resize 是最简单且可以说最好的。

于 2014-06-04T17:27:02.520 回答