Three.js - 调试与统计
Three.js - 调试与性能监控
Section titled “Three.js - 调试与性能监控”在构建 3D 应用程序时,能够实时调整值和监控性能至关重要。这能大大加快开发速度并有助于识别性能瓶颈。在本章中,我们将探讨两个基本工具:一个用于实时代码操作的图形用户界面 (GUI) 和一个用于性能监控的统计面板。
用于实时调整的现代 GUI:lil-gui
Section titled “用于实时调整的现代 GUI:lil-gui”通过不断更改代码和刷新浏览器来试验对象的position、color或scale等变量是一个缓慢而繁琐的过程。调试 UI 面板解决了这个问题。经典的 dat.GUI 已被更现代、更轻量的 lil-gui 所取代,我们将使用它。它与 Three.js 无缝集成,允许您创建简单的 UI 来实时更改代码中的变量。
在现代 JavaScript 项目中,我们使用像 npm 或 yarn 这样的包管理器来管理依赖项。这是推荐的方法。
# 使用 npmnpm install three lil-gui
# 使用 yarnyarn add three lil-gui安装后,您可以将其导入到您的 JavaScript 模块中。
import * as THREE from 'three';import GUI from 'lil-gui';首先,初始化 GUI。这将创建一个面板,通常位于屏幕的右上角。
const gui = new GUI();接下来,您可以为您想要操作的属性添加一个控制器。.add() 方法接受您要控制的对象和属性名称(作为字符串)。
// 假设 'cube' 是一个 THREE.Mesh 对象gui.add(cube.position, 'y'); // 为立方体的 y 轴位置添加控制器您可以通过链式调用方法来增强控制器,以设置最小值/最大值、步长增量和显示名称。
gui.add(cube.position, 'x') .min(-3) .max(3) .step(0.01) .name('Cube X Position');对于非数字属性,lil-gui 提供了特定的控制器。例如,对于颜色使用 .addColor(),对于布尔值(这将创建一个复选框)使用简单的 .add()。
// 对于布尔值(例如,线框)gui.add(cube.material, 'wireframe');
// 对于颜色,最好控制一个单独的对象并使用 onChange 事件const colorParams = { color: 0xff0000}gui.addColor(colorParams, 'color').onChange(() => { cube.material.color.set(colorParams.color);});使用文件夹组织 UI
Section titled “使用文件夹组织 UI”当您有许多可控属性时,您的 UI 面板可能会变得拥挤。您可以使用文件夹来组织和分组相关的控件。
const cubeFolder = gui.addFolder('Cube Properties');
const positionFolder = cubeFolder.addFolder('Position');positionFolder.add(cube.position, 'x', -5, 5);positionFolder.add(cube.position, 'y', -5, 5);positionFolder.add(cube.position, 'z', -5, 5);
const materialFolder = cubeFolder.addFolder('Material');materialFolder.add(cube.material, 'wireframe');// ... 在此处添加颜色控制器使用 Stats.js 监控性能
Section titled “使用 Stats.js 监控性能”另一个重要的调试工具是 Stats.js,它提供了一个简单的面板来监控应用程序的性能,显示每秒帧数 (FPS)、内存使用情况和帧时间。高且稳定的 FPS(通常为 60)表示流畅的体验。
首先,安装该包:
npm install stats.js然后,导入它,创建一个实例,将其添加到页面,并在动画循环的每一帧中更新它。
import Stats from 'stats.js';
// 1. 初始化const stats = new Stats();stats.showPanel(0); // 0: FPS, 1: 帧时间 (毫秒), 2: 内存 (MB), 3+: 自定义document.body.appendChild(stats.dom);
// 2. 在动画循环中更新function animate() { stats.begin(); // 开始监控
// ... 你的动画代码 ... renderer.render(scene, camera);
stats.end(); // 结束监控
requestAnimationFrame(animate);}
animate();这是一个在现代项目设置中集成 Three.js、lil-gui 和 stats.js 的完整示例。此代码通常位于 main.js 文件中。
import * as THREE from 'three';import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';import GUI from 'lil-gui';import Stats from 'stats.js';
/** * 基础设置 */// 调试const gui = new GUI();const stats = new Stats();stats.showPanel(0);document.body.appendChild(stats.dom);
// 画布const canvas = document.querySelector('canvas.webgl');
// 场景const scene = new THREE.Scene();scene.background = new THREE.Color(0x262626);
/** * 对象 */const geometry = new THREE.BoxGeometry(1, 1, 1);const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 });const cube = new THREE.Mesh(geometry, material);scene.add(cube);
/** * 光源 */const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);scene.add(ambientLight);const pointLight = new THREE.PointLight(0xffffff, 0.8);pointLight.position.set(2, 3, 4);scene.add(pointLight);
/** * 尺寸 */const sizes = { width: window.innerWidth, height: window.innerHeight};
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 camera = new THREE.PerspectiveCamera(75, sizes.width / sizes.height, 0.1, 100);camera.position.z = 3;scene.add(camera);
/** * 控制器 */const controls = new OrbitControls(camera, canvas);controls.enableDamping = true;
/** * 渲染器 */const renderer = new THREE.WebGLRenderer({ canvas: canvas});renderer.setSize(sizes.width, sizes.height);renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
/** * 调试 UI */const cubeFolder = gui.addFolder('Cube');cubeFolder.add(cube.position, 'y').min(-3).max(3).step(0.01).name('elevation');cubeFolder.add(cube, 'visible');cubeFolder.add(material, 'wireframe');
const colorParams = { color: 0x00ff00 };cubeFolder.addColor(colorParams, 'color').onChange(() => { material.color.set(colorParams.color);});
/** * 动画 */const clock = new THREE.Clock();
const tick = () => { stats.begin();
const elapsedTime = clock.getElapsedTime();
// 更新控制器 controls.update();
// 渲染 renderer.render(scene, camera);
stats.end();
// 在下一帧再次调用 tick window.requestAnimationFrame(tick);};
tick();常见错误与调试技巧
Section titled “常见错误与调试技巧”- 什么都不可见: 检查您的浏览器开发者控制台 (F12) 中是否有错误。通常是属性名称拼写错误或导入不正确。
- GUI 未出现: 确保您已经使用
new GUI()实例化了它。检查页面上是否有任何 CSS 可能会隐藏它(例如,<body>上的overflow: hidden)。 - 性能低下: 使用 Stats.js 面板。如果 FPS 持续低于 60,您可能有太多对象、几何体过于复杂或动画循环中存在开销大的操作。尝试简化您的场景以找出原因。
- 可视化坐标轴: 为了更好地理解对象的方向和位置,向您的场景添加一个
AxesHelper:const axesHelper = new THREE.AxesHelper(2); scene.add(axesHelper);