关于webgl:根据浏览器窗口大小调整视口/画布的大小

Resize viewport/canvas according to browser window size

我希望我的webgl应用视口和画布对浏览器窗口大小的更改(包括F11按钮)做出反应。 IE。我希望画布的宽度和高度始终为100%,并且希望视口的大小和纵横比适当。我用简单的方法实现的:

1
<canvas style="width: 100%; height:100%;">

尽管我不确定这是否可行。我试图用在这里找到的一些信息来实现后者:Webgl gl.viewport更改,但显然我在做错什么。我确实意识到:

1
canvas.onresize = resizeViewport;

是错误的,因为画布的大小不会经常更改(宽度和高度始终为100%),但我不知道该怎么做。

这是该应用程序的在线版本:http://nps.netarteria.pl/gallery。


我认为这可行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
var canvas;
var gl;

function render() {
  gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
   
  // Draw a 1 pixel border around the edge using
  // the scissor test since it's easier than setting up
  // a lot of stuff
  gl.clearColor(1, 0, 0, 1);  // red
  gl.disable(gl.SCISSOR_TEST);
  gl.clear(gl.COLOR_BUFFER_BIT);
   
  gl.enable(gl.SCISSOR_TEST);
  gl.scissor(1, 1, gl.canvas.width - 2, gl.canvas.height - 2);
  gl.clearColor(0, 0, 1, 1);  // blue
  gl.clear(gl.COLOR_BUFFER_BIT);
};

function resizeCanvas() {
  var width = canvas.clientWidth;
  var height = canvas.clientHeight;
  if (canvas.width != width ||
      canvas.height != height) {
    canvas.width = width;
    canvas.height = height;
         
    // in this case just render when the window is resized.
    render();
  }
}

function main() {
  canvas = document.getElementById("c");
  gl = canvas.getContext("webgl");
  resizeCanvas();
}

window.addEventListener('resize', resizeCanvas);
main();
1
2
3
4
5
6
7
8
body {
  margin: 0;
}
#c {
  width: 100vw;
  height: 100vh;
  display: block;
}

1
<canvas id="c"></canvas>

据我所知,调整大小仅在窗口上有效。不幸的是,HTML5规范未将调整大小事件添加到其他元素。

注意:如果您一直在渲染(例如游戏),则无需监听resize事件。只需在渲染循环开始时调用resizeCanvas。如果浏览器调整了画布的大小,则无论其容器是什么,代码都将看到该大小不再匹配,并更新画布的drawingbuffer的大小。

用于渲染画布的适当视口大小几乎总是:

1
2
3
// Set the viewport to be the size of the canvas's drawingBuffer.

gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);

如果您使用的是典型的3D数学库,则还具有一个投影矩阵和一个通常称为perspective的函数,该函数需要一个fieidOfView,aspect,zNear和zFar参数。几乎所有WebGL程序的正确方面是:

1
2
3
4
5
// Set the aspect of our perspective matrix to match the size
// the canvas is displayed at.

var aspect = gl.canvas.clientWidth / gl.canvas.clientHeight
???.perspective(fieldOfView, aspect, zNear, zFar);

更新

显然,您需要缓存clientWidth和clientHeight。原因是设置canvas.width将更改CSS布局,该布局可以更改clientHeight

更新了上面的代码。

更新2

从使用100%切换到100vw100vw,因为它们可能更正确。他们描述了您想要的是使画布成为视口大小的地方,因为先前的解决方案使画布成为文档的大小,然后尝试将文档强制为窗口的大小。由于文档的内容可能大于可能是错误解决方案的窗口。