如何实现three.js响应式设计(消除拉伸变形和锯齿)

techbrood 发表于 2019-11-09 15:26:43

标签: three.js, webgl, responsive design

- +

我们先创建一个基本的three.js场景,里面有一个cube对象。

分三步,首先声明一个canvas的html元素并设置其样式:

<canvas id="c"></canvas>
#c {
    width: 100%;
    height: 100%;
    display: block;
}

第二步,使用three.js创建场景、光照、相机和立方体模型(cube):

import * as THREE from '//techbrood.com/threejs/build/three.module.js';

function main() {
  const canvas = document.querySelector('#c');
  const renderer = new THREE.WebGLRenderer({canvas});

  const fov = 75;
  const aspect = 2;  // the canvas default
  const near = 0.1;
  const far = 5;
  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
  camera.position.z = 2;

  const scene = new THREE.Scene();

  {
    const color = 0xFFFFFF;
    const intensity = 1;
    const light = new THREE.DirectionalLight(color, intensity);
    light.position.set(-1, 2, 4);
    scene.add(light);
  }

  const boxWidth = 1;
  const boxHeight = 1;
  const boxDepth = 1;
  const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);

  function makeInstance(geometry, color, x) {
    const material = new THREE.MeshPhongMaterial({color});

    const cube = new THREE.Mesh(geometry, material);
    scene.add(cube);

    cube.position.x = x;

    return cube;
  }

  var cube = makeInstance(geometry, 0x44aa88,  0),

  //TODO: render the scene

}

第三步,循环渲染该场景:

  function render(time) {
    time *= 0.001;

    const speed = 1;
    const rot = time * speed;
    cube.rotation.x = rot;
    cube.rotation.y = rot;

    renderer.render(scene, camera);

    requestAnimationFrame(render);
  }

  requestAnimationFrame(render);

这样一个基本的3D场景就创建好了,其运行效果是一个旋转的立方体。

但是当我们调整网页大小时,会发现有2个问题:

  1. 立方体会发生拉伸变形,变成了长方体

  2. 立方体的边缘会出现明显的锯齿

要解决第1个问题,需要按照canvas的大小来调整camera的aspect和投影矩阵:

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

要解决第2个问题,我们得明白canvas元素有2个尺寸,一个是页面上呈现出来的尺寸(可以通过css来设置的样式),一个是canvas本身的像素值(分辨率),这和一般的图像元素类似。解决的方法也和防止图像拉伸一样,我们需要使显示尺寸和分辨率这两者匹配起来。

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;
}

这样我们就实现了3D场景的响应式设计。

可以在线查看实现效果:https://wow.techbrood.com/fiddle/54855

possitive(1) negative(0) views2118 comments1

发送私信

最新评论

㌍㌫㌶㍊㍍㍑㌫㌶㍍㌫㌍ 2020-07-25 17:50:23

收藏了 不错


请先 登录 再评论.
相关文章