• 原文地址:Day 12. Highdpi displays and webgl viewport
  • 原文作者:Andrei Lesnitsky

这是 WebGL 系列的第 12 天教程,每天都有新文章公布。

订阅或者退出邮件列表以便及时获取更新内容。

源代码在这里

嘿 ???? 欢送回到 WebGL 系列教程。

以前的所有教程都是在默认尺寸画布上实现的,当初让咱们应用更大的图片尺寸!

咱们先要对 CSS 进行一些调整,以便填满整个页面。

???? index.html

      <meta name="viewport" content="width=device-width, initial-scale=1.0" />      <meta http-equiv="X-UA-Compatible" content="ie=edge" />      <title>WebGL Month</title>+ +     <style>+     html, body {+       height: 100%;+     }+ +     body {+       margin: 0;+     }+     </style>    </head>    <body>      <canvas></canvas>

当初咱们能够读取页面尺寸:

???? src/texture.js

  const canvas = document.querySelector('canvas');  const gl = canvas.getContext('webgl');  + const width = document.body.offsetWidth;+ const height = document.body.offsetHeight;+   const vShader = gl.createShader(gl.VERTEX_SHADER);  const fShader = gl.createShader(gl.FRAGMENT_SHADER);  

并设置画布尺寸:

???? src/texture.js

  const width = document.body.offsetWidth;  const height = document.body.offsetHeight;  + canvas.width = width;+ canvas.height = height;+   const vShader = gl.createShader(gl.VERTEX_SHADER);  const fShader = gl.createShader(gl.FRAGMENT_SHADER);  

好的,已更改画布大小,然而咱们的图片并没有全屏显示,为什么?

事实证明,扭转画布大小是不够的,咱们还须要指定一个视口 viewport。将视口设置为矩形,它将用作绘图区域,并将其插值到 [-1...1] 剪贴空间。

???? src/texture.js

        gl.uniform2fv(programInfo.uniformLocations.resolution, [canvas.width, canvas.height]);  +     gl.viewport(0, 0, canvas.width, canvas.height);+       gl.drawElements(gl.TRIANGLES, indexBuffer.data.length, gl.UNSIGNED_BYTE, 0);  });

当初咱们的图片填满了整个文档,然而有点含糊。起因不言而喻的 – 咱们的纹理不够大,为此应该拉伸它并革除品质。然而,还有另一个起因。

古代显示器在物理像素大小(苹果称其为视网膜)中能够包容更多的理论像素,有一个全局变量 devicePixelRatio 能够帮忙咱们。

???? src/texture.js

  const width = document.body.offsetWidth;  const height = document.body.offsetHeight;  - canvas.width = width;- canvas.height = height;+ canvas.width = width * devicePixelRatio;+ canvas.height = height * devicePixelRatio;    const vShader = gl.createShader(gl.VERTEX_SHADER);  const fShader = gl.createShader(gl.FRAGMENT_SHADER);

好的,当初咱们的画布具备适合的尺寸,然而它比视网膜显示屏上的主体大。咱们该如何解决?

咱们能够应用 CSS 的 widthheight 属性将画布放大到理论尺寸。

???? src/texture.js

  canvas.width = width * devicePixelRatio;  canvas.height = height * devicePixelRatio;  + canvas.style.width = `${width}px`;+ canvas.style.height = `${height}px`;+   const vShader = gl.createShader(gl.VERTEX_SHADER);  const fShader = gl.createShader(gl.FRAGMENT_SHADER);  

总而言之,画布的 widthheight 属性指定像素理论大小,但为了使画面显示锐利的 highdpi,咱们须要应用 devicePixelRatio 乘以 widthheight,并用 CSS 放大画布背景的规模。

当初咱们能够让画布从新调整大小。

???? src/texture.js

        gl.drawElements(gl.TRIANGLES, indexBuffer.data.length, gl.UNSIGNED_BYTE, 0);  });+ + + window.addEventListener('resize', () => {+     const width = document.body.offsetWidth;+     const height = document.body.offsetHeight;+ +     canvas.width = width * devicePixelRatio;+     canvas.height = height * devicePixelRatio;+ +     canvas.style.width = `${width}px`;+     canvas.style.height = `${height}px`;+ +     gl.viewport(0, 0, canvas.width, canvas.height);+ });

然而,调整大小后会革除画布内容。原来,对 widthheight 属性的批改,会迫使浏览器革除画布(2d 上下文也是如此),因而咱们须要再次收回绘图调用。

???? src/texture.js

      canvas.style.height = `${height}px`;        gl.viewport(0, 0, canvas.width, canvas.height);+ +     gl.drawElements(gl.TRIANGLES, indexBuffer.data.length, gl.UNSIGNED_BYTE, 0);  });

明天就这样,今天见????