Three.js - 响应式设计
Three.js - 响应式设计
Section titled “Three.js - 响应式设计”现代网页体验必须是响应式的,这意味着它应该在任何屏幕尺寸下都能良好地显示和运行,无论是大型桌面显示器还是小型智能手机。静态的Three.js场景在不同设备上可能会出现裁剪或拉伸。本章将介绍使你的3D场景完全响应式的基本技术。
核心问题:固定尺寸的Canvas
Section titled “核心问题:固定尺寸的Canvas”默认情况下,Three.js 渲染场景的 <canvas> 元素具有固定尺寸。当浏览器窗口大小调整时,需要更新两项内容:
- 渲染器(Renderer):它需要知道新的尺寸来进行绘制。
- 相机(Camera):透视相机的
aspect宽高比必须与新的视口尺寸匹配,以防止场景看起来被挤压或拉伸。
解决方案:尺寸调整处理器
Section titled “解决方案:尺寸调整处理器”解决方案是监听浏览器的 resize 事件,并在处理函数中更新必要的组件。首先,我们来设置一个现代的项目结构。
1. 项目设置(现代工作流)
Section titled “1. 项目设置(现代工作流)”我们将使用包含独立HTML、CSS和JavaScript文件的标准设置。强烈建议使用像 npm 这样的包管理器和像 Vite 这样的构建工具来管理依赖项和进行开发。
# 1. 创建项目文件夹并进入mkdir my-threejs-appcd my-threejs-app
# 2. 初始化Node项目并安装依赖npm init -ynpm install three lil-guinpm install --save-dev vite
# 3. 创建文件touch index.html style.css main.js2. HTML (index.html)
Section titled “2. HTML (index.html)”HTML文件非常简洁。它提供了一个用于容纳 canvas 的容器,并以模块形式加载我们的主脚本。
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>响应式 Three.js 场景</title> <link rel="stylesheet" href="./style.css"></head><body> <canvas class="webgl"></canvas> <script type="module" src="./main.js"></script></body></html>3. CSS (style.css)
Section titled “3. CSS (style.css)”CSS确保我们的 canvas 填充整个视口。
* { margin: 0; padding: 0;}
html, body { overflow: hidden; /* 防止滚动条 */}
.webgl { position: fixed; top: 0; left: 0; outline: none;}4. JavaScript (main.js)
Section titled “4. JavaScript (main.js)”奇迹在此发生。我们设置场景并创建尺寸调整处理器。
import * as THREE from 'three';import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
// 尺寸const sizes = { width: window.innerWidth, height: window.innerHeight}
// 场景const scene = new THREE.Scene();
// 对象const mesh = new THREE.Mesh( new THREE.BoxGeometry(1, 1, 1, 5, 5, 5), new THREE.MeshBasicMaterial({ color: 0xff0000, wireframe: true }));scene.add(mesh);
// 相机const camera = new THREE.PerspectiveCamera(75, sizes.width / sizes.height, 0.1, 100);camera.position.z = 3;scene.add(camera);
// 渲染器const canvas = document.querySelector('canvas.webgl');const renderer = new THREE.WebGLRenderer({ canvas: canvas, antialias: true });renderer.setSize(sizes.width, sizes.height);renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
// --- 尺寸调整处理器 ---window.addEventListener('resize', () => { // 更新尺寸 sizes.width = window.innerWidth; sizes.height = window.innerHeight;
// 更新相机 camera.aspect = sizes.width / sizes.height; camera.updateProjectionMatrix();
// 更新渲染器 renderer.setSize(sizes.width, sizes.height); renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));});
// 动画循环const tick = () => { mesh.rotation.y += 0.01; renderer.render(scene, camera); window.requestAnimationFrame(tick);}
tick();处理像素密度和抗锯齿
Section titled “处理像素密度和抗锯齿”像素比例实现清晰度
Section titled “像素比例实现清晰度”高密度屏幕(例如苹果的Retina显示屏)比逻辑像素拥有更多的物理像素。为了在这些屏幕上获得清晰锐利的渲染效果,你必须设置渲染器的像素比例。window.devicePixelRatio 提供了这个值。我们使用 Math.min() 将其上限设置为2,因为更高的值在视觉效果上提升有限,但会严重影响性能。
// 为高DPI屏幕设置像素比例以实现清晰渲染renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));抗锯齿实现平滑边缘
Section titled “抗锯齿实现平滑边缘”锯齿(Aliasing)会导致3D对象的边缘看起来不平滑或呈“阶梯状”。通过在创建渲染器时启用抗锯齿(anti-aliasing),我们可以平滑这些边缘。请注意,这会带来性能开销,因此请谨慎使用。
// 在实例化渲染器时启用抗锯齿const renderer = new THREE.WebGLRenderer({ canvas: canvas, antialias: true});- 忘记调用
camera.updateProjectionMatrix():在更改相机的aspect宽高比(或任何其他基本属性,如fov)之后,你必须调用此方法来应用这些更改。 - 性能:
resize事件触发可能非常频繁。对于复杂的尺寸调整逻辑,你可能需要考虑对事件处理器进行“防抖”(debouncing),以防止它运行过于频繁并导致性能问题。 - 可访问性:
<canvas>元素默认情况下无法被屏幕阅读器访问。为了更好的可访问性,请提供备用内容:<canvas>一个旋转立方体的3D可视化。</canvas>