Skip to content

全屏

Responsive / Resize

▶ 在线运行案例

全屏

你将学到什么

  • 窗口尺寸变化时 同步更新 renderer 和 camera
  • camera.aspectupdateProjectionMatrix() 的关系
  • 为什么 resize 后画面会拉伸/压扁

效果说明

拖动浏览器窗口大小时,canvas 和 3D 画面 保持正确比例,物体不会变形。

核心概念

透视相机的 宽高比 aspect 必须等于 canvas 宽高比:

js
camera.aspect = width / height;
camera.updateProjectionMatrix();  // 重新计算投影矩阵
renderer.setSize(width, height);

不 updateProjectionMatrix 会怎样?
Three.js 不会每帧自动重算投影矩阵(性能考虑)。aspect 变了但不 update → 画面 被拉伸

resize 监听

js
window.onresize = () => {
    const box = document.getElementById('box');
    renderer.setSize(box.clientWidth, box.clientHeight);
    camera.aspect = box.clientWidth / box.clientHeight;
    camera.updateProjectionMatrix();
    renderer.render(scene, camera);  // 静态场景需手动重绘
};

若有 rAF 循环,resize 里可以不手动 render(下一帧会自动画)。

实现步骤

  1. 初始 setSize + render
  2. 绑定 window.onresize
  3. resize 内更新 renderer 尺寸 + camera.aspect + updateProjectionMatrix

代码要点

js
window.onresize = () => {
    const box = document.getElementById('box');
    renderer.setSize(box.clientWidth, box.clientHeight);
    camera.aspect = box.clientWidth / box.clientHeight;
    camera.updateProjectionMatrix();
};

devicePixelRatio

高清屏还需 renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)),resize 时一并更新。详见 threejs-fundamentals 场景搭建。

源码

js
import * as THREE from 'three';

const scene = new THREE.Scene();
const geometry = new THREE.BoxGeometry(10, 60, 100);
const material = new THREE.MeshBasicMaterial({ color: 0xff0000 });
const mesh = new THREE.Mesh(geometry, material);
mesh.position.set(0, 10, 0);
scene.add(mesh);

const axesHelper = new THREE.AxesHelper(150);
scene.add(axesHelper);

const camera = new THREE.PerspectiveCamera();
camera.position.set(200, 200, 200);
camera.lookAt(0, 10, 0);

const renderer = new THREE.WebGLRenderer();
const box = document.getElementById('box');
renderer.setSize(box.clientWidth, box.clientHeight);
renderer.render(scene, camera);
box.appendChild(renderer.domElement);

window.onresize = () => {
    const box = document.getElementById('box');
    renderer.setSize(box.clientWidth, box.clientHeight);
    camera.aspect = box.clientWidth / box.clientHeight;
    camera.updateProjectionMatrix();
};

小结

  • 响应式 Three.js = renderer.setSize + camera.aspect + updateProjectionMatrix
  • 入门系列完结 → 继续 基础案例着色器

入门案例 · Three.js · 15/15 · 返回入门目录