响应式设计

响应式设计

让一个网页是响应式的通常是指让网页能在从桌面到平板再到手机不同尺寸的显示器上显示良好。

拉伸与块状化

一般来说,我们的响应式设计需要解决两个问题:

  • 第一是我们的立方体被拉伸了。他们不是立方体了更像是个盒子太高或者太宽。在新标签中打开它然后改变尺寸你就能看到立方体是怎么在宽高上被拉伸的。
  • 另一个问题是立方体看起来分辨率太低或者说块状化或者有点模糊,将窗口拉伸的非常大你就能看到问题。

我们先解决拉伸的问题。为此我们要将相机的aspect设置为canvas的宽高比。我们可以通过canvasclientWidthclientHeight属性来实现。

function render(time) {
  time *= 0.001;

  const canvas = renderer.domElement;
  camera.aspect = canvas.clientWidth / canvas.clientHeight;
  camera.updateProjectionMatrix();

  // ...
}

我们现在来解决块状化的问题,canvas元素有两个尺寸。一个是canvas在页面上的显示尺寸,是我们用CSS来设置的。另一个尺寸是canvas本身像素的数量。这和图片一样。比如我们有一个128x64像素的图片然后我们可以通过CSS让它显示为400x200像素。

<img src="some128x64image.jpg" style="width:400px; height:200px" />

一个canvas的内部尺寸,它的分辨率,通常被叫做drawingbuffer尺寸。在three.js中我们可以通过调用renderer.setSize来设置canvasdrawingbuffer,再一次,我们可以使用canvasclientWidthclientHeight属性。

function resizeRendererToDisplaySize(renderer) {
  const canvas = renderer.domElement;
  const width = canvas.clientWidth;
  const height = canvas.clientHeight;
  const needResize = canvas.width !== width || canvas.height !== height;
  if (needResize) {
    renderer.setSize(width, height, false);
  }
  return needResize;
}

一旦我们知道了是否需要调整大小我们就调用renderer.setSize然后 传入新的宽高。在末尾传入false很重要。render.setSize默认会设置canvasCSS尺寸但这并不是我们想要的。我们希望浏览器能继续工作就像其他使用CSS来定义尺寸的其他元素。我们不希望three.js使用canvas和其他元素不一样。注意如果我们的canvas大小被调整了那函数会返回true。我们可以利用 这个来检查是否有其他的东西应该更新。我们修改渲染循环 来使用我们的新函数。

function render(time) {
  time *= 0.001;

  if (resizeRendererToDisplaySize(renderer)) {
    const canvas = renderer.domElement;
    camera.aspect = canvas.clientWidth / canvas.clientHeight;
    camera.updateProjectionMatrix();
  }

  ...

应对HD-DPI显示器

HD-DPI代表每英寸高密度点显示器(视网膜显示器)。它指的是当今大多数的Macwindows机器以及几乎所有的智能手机。浏览器中的工作方式是不管屏幕的分辨率有多高使用CSS像素设置尺寸会被认为是一样的。同样的物理尺寸浏览器会渲染出字体的更多细节。

使用three.js有多种方法来应对HD-DPI。第一种就是不做任何特别的事情。这可以说是最常见的。渲染三维图形需要大量的GPU处理能力。移动端的GPU能力比桌面端的要弱。至少截止到2018,手机都有非常高的分辨率显示器。目前最好的手机的HD-DPI比例为3x,意思是非高密度点显示器上的一个像素在高密度显示器上是9个像素。意味着需要9倍的渲染。计算9倍的像素是个大工程所以如果保持代码不变我们将计算一个像素然后浏览器将以三倍大小绘制(3x3=9像素)。对于大型的three.js应用来说上面就是你想要的否侧你的帧速率会很低。

尽管如此如果你确实想用设备的分辨率来渲染,three.js中有两种方法来实现:

  • 一种是使用renderer.setPixelRatio来告诉three.js分辨率的倍数。访问浏览器从CSS像素到设备像素的倍数然后传给three.js
renderer.setPixelRatio(window.devicePixelRatio);
  • 另一种方法是在调整canvas的大小时自己处理。
function resizeRendererToDisplaySize(renderer) {
  const canvas = renderer.domElement;
  const pixelRatio = window.devicePixelRatio;
  const width = (canvas.clientWidth * pixelRatio) | 0;
  const height = (canvas.clientHeight * pixelRatio) | 0;
  const needResize = canvas.width !== width || canvas.height !== height;
  if (needResize) {
    renderer.setSize(width, height, false);
  }
  return needResize;
}

第二种方法从客观上来说更好,在使用three.js时有很多种情况下我们需要知道canvasdrawingBuffer的确切尺寸。比如制作后期处理滤镜或者我们在操作着色器需要访问gl_FragCoord变量,如果我们截屏或者给GPU读取像素,绘制到二维的canvas等等。通过我们自己处理我们会一直知道使用的尺寸是不是我们需要的。

上一页