我不确定我是否理解这个问题,但看看你的代码,如果你的帧缓冲区附件(在这种情况下是纹理)的大小与你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();
在大多数情况下,当绘制到画布时,视口应始终设置为画布的大小(width
而height
不是clientWidth
and clientHeight
)。使用clientWidth
andclientHeight
来调整大小和/或计算投影的纵横比,无论该投影是 2d 还是 3d。事实上,使用and for可以说是错误的。clientWidth
clientHeight
gl.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
为要绘制的表面的大小。
希望这能说明为什么使用clientWidth
andclientHeight
是错误的,gl.viewport
因为它clientWidth
与clientHeight
画布的实际大小(其中的像素)无关。它们仅与这些像素被拉伸或收缩的大小有关。换句话说
<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 是最简单且可以说最好的。