11

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

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

虽然我不确定这是否是要走的路。后者我试图用我在这里找到的一些信息来实现:Webgl gl.viewport change但显然我做错了什么。我确实意识到:

canvas.onresize = resizeViewport;

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

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

4

1 回答 1

13

我认为这有效:

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();
body { 
  margin: 0;
}
#c {
  width: 100vw;
  height: 100vh;
  display: block;
}
<canvas id="c"></canvas>

据我所知,调整大小仅适用于窗口。不幸的是,HTML5 规范没有为其他元素添加调整大小事件。

注意:如果您总是在渲染(例如游戏),那么您不需要监听 resize 事件。只需在渲染循环开始时调用 resizeCanvas 即可。如果浏览器调整了画布的大小,无论其容器如何,代码都会看到大小不再匹配并更新画布的绘图缓冲区的大小。

渲染画布的正确视口大小几乎总是:

// 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 程序的正确方面是:

// 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

从 using 切换100%100vwand100vw因为这些可以说是更正确的。他们描述了您想要什么使画布成为视口的大小,而先前的解决方案使画布成为文档的大小,然后尝试强制文档成为窗口的大小。由于文档的内容可能比可能是错误解决方案的窗口大。

于 2012-12-14T07:02:03.080 回答