在图形编程和前端可视化领域Three.js 已经成为构建 3D 场景和交互体验的事实标准。但真正把 Three.js 用好的开发者都知道从官方示例到实际项目落地之间存在大量工程化细节需要处理场景初始化、资源加载、性能优化、跨设备兼容以及如何与 Vue 3、React 等现代前端框架深度集成。最近在技术社区中围绕 Claude Opus 5 和 Fable 5 在 Three.js 硬编码测试中的表现对比引发了不少讨论。虽然具体测试细节没有公开但这类对比背后反映的是开发者对高效开发工具和框架选型的持续关注。硬编码测试通常考察的是代码执行效率、内存占用和渲染性能这些指标直接关系到最终用户体验。本文不会停留在表面的性能对比而是深入 Three.js 的实际开发流程从环境搭建、场景构建、性能优化到与 Vue 3 的集成提供一个完整的工程实践指南。无论你是刚开始接触 WebGL 开发还是希望优化现有 Three.js 项目的性能都能在这里找到可落地的解决方案。1. 理解 Three.js 的核心架构和渲染管线Three.js 本质上是一个基于 WebGL 的 3D 图形库它通过抽象化底层 WebGL API 的复杂性让开发者能够用更声明式的方式构建 3D 场景。要真正掌握 Three.js不能只停留在调用 API 的层面还需要理解其内部的工作机制。1.1 Three.js 的四大核心组件每个 Three.js 应用都围绕四个基本概念构建场景Scene、相机Camera、渲染器Renderer和物体Object。场景是所有 3D 对象的容器它定义了整个 3D 世界的坐标系和环境设置。在实际项目中场景管理往往比想象中复杂// 创建场景的最佳实践 const scene new THREE.Scene(); scene.background new THREE.Color(0x222222); // 设置背景色 scene.fog new THREE.Fog(0x222222, 10, 100); // 添加雾效增强深度感 // 环境光配置 const ambientLight new THREE.AmbientLight(0x404040, 0.6); scene.add(ambientLight); // 方向光配置 const directionalLight new THREE.DirectionalLight(0xffffff, 0.8); directionalLight.position.set(50, 50, 50); scene.add(directionalLight);相机决定了观察者视角和投影方式。Three.js 提供多种相机类型最常用的是透视相机PerspectiveCamera它模拟人眼视角物体距离越远显得越小// 透视相机配置参数详解 const camera new THREE.PerspectiveCamera( 75, // 视野角度FOV单位是度 window.innerWidth / window.innerHeight, // 宽高比 0.1, // 近裁剪面 - 距离相机多近开始渲染 1000 // 远裁剪面 - 距离相机多远停止渲染 ); // 相机位置和朝向 camera.position.set(0, 5, 10); camera.lookAt(0, 0, 0); // 看向场景中心渲染器负责将 3D 场景转换为 2D 图像输出到 Canvas 元素。现代 Three.js 项目应该使用 WebGLRenderer并合理配置抗锯齿和性能参数const renderer new THREE.WebGLRenderer({ antialias: true, // 开启抗锯齿 alpha: true, // 支持透明背景 powerPreference: high-performance // 性能优先 }); renderer.setSize(window.innerWidth, window.innerHeight); renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); // 避免过高像素比 renderer.shadowMap.enabled true; // 启用阴影 renderer.shadowMap.type THREE.PCFSoftShadowMap; // 柔和阴影 document.body.appendChild(renderer.domElement);1.2 理解 Three.js 的渲染循环机制Three.js 应用的核心是渲染循环它决定了帧率和性能表现。错误的循环实现会导致内存泄漏和性能问题class ThreeJSApp { constructor() { this.scene new THREE.Scene(); this.camera new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); this.renderer new THREE.WebGLRenderer(); this.clock new THREE.Clock(); // 用于精确的时间计算 this.mixers []; // 动画混合器集合 this.frameId null; this.init(); } init() { // 初始化场景内容 this.setupScene(); this.setupEventListeners(); this.animate(); } animate () { this.frameId requestAnimationFrame(this.animate); const delta this.clock.getDelta(); // 获取上一帧到当前帧的时间差 // 更新所有动画 this.mixers.forEach(mixer mixer.update(delta)); // 更新自定义逻辑 this.update(delta); this.renderer.render(this.scene, this.camera); } update(delta) { // 自定义更新逻辑如物理模拟、用户输入处理等 } cleanup() { // 重要停止动画循环释放资源 if (this.frameId) { cancelAnimationFrame(this.frameId); } // 释放几何体和材质 this.scene.traverse(object { if (object.geometry) object.geometry.dispose(); if (object.material) { if (Array.isArray(object.material)) { object.material.forEach(material material.dispose()); } else { object.material.dispose(); } } }); this.renderer.dispose(); } }1.3 资源管理和内存优化Three.js 应用常见的内存泄漏问题大多源于不当的资源管理。每个几何体Geometry、材质Material和纹理Texture都需要手动释放// 资源管理工具类 class ResourceManager { constructor() { this.geometries new Set(); this.materials new Set(); this.textures new Set(); } trackGeometry(geometry) { this.geometries.add(geometry); return geometry; } trackMaterial(material) { this.materials.add(material); return material; } trackTexture(texture) { this.textures.add(texture); return texture; } dispose() { this.geometries.forEach(geometry geometry.dispose()); this.materials.forEach(material material.dispose()); this.textures.forEach(texture texture.dispose()); this.geometries.clear(); this.materials.clear(); this.textures.clear(); } } // 使用示例 const resourceManager new ResourceManager(); const geometry resourceManager.trackGeometry(new THREE.BoxGeometry(1, 1, 1)); const material resourceManager.trackMaterial(new THREE.MeshStandardMaterial({ color: 0x00ff00 })); const texture resourceManager.trackTexture(new THREE.TextureLoader().load(texture.jpg)); // 应用退出时调用 resourceManager.dispose();2. 搭建现代化的 Three.js 开发环境Three.js 项目开发环境的配置直接影响开发效率和最终性能。现代前端工程化工具链为 Three.js 开发提供了强大的支持。2.1 使用 Vite 构建 Three.js 项目Vite 凭借其快速的冷启动和热更新能力成为 Three.js 开发的首选构建工具# 创建新项目 npm create vitelatest my-threejs-project -- --template vanilla-ts cd my-threejs-project npm install three types/three项目结构应该遵循模块化原则src/ ├── scenes/ │ ├── MainScene.ts # 主场景管理 │ └── SceneInterface.ts # 场景接口定义 ├── objects/ │ ├── MeshObject.ts # 自定义网格对象 │ └── LightManager.ts # 灯光管理 ├── utils/ │ ├── ResourceManager.ts # 资源管理 │ ├── AnimationLoop.ts # 动画循环控制 │ └── DebugHelper.ts # 调试工具 ├── types/ │ └── threejs-types.ts # Three.js 类型扩展 └── main.ts # 应用入口vite.config.ts 需要针对 Three.js 进行优化配置import { defineConfig } from vite export default defineConfig({ server: { port: 3000, open: true // 自动打开浏览器 }, build: { target: esnext, // 使用现代 ES 特性 minify: terser, terserOptions: { compress: { drop_console: true // 生产环境移除 console } } }, optimizeDeps: { include: [three] // 预构建 Three.js } })2.2 TypeScript 配置和类型定义Three.js 对 TypeScript 的支持非常完善正确的类型配置能极大提升开发体验// tsconfig.json { compilerOptions: { target: ES2020, module: ESNext, lib: [ES2020, DOM, DOM.Iterable], moduleResolution: node, strict: true, esModuleInterop: true, skipLibCheck: true, forceConsistentCasingInFileNames: true, resolveJsonModule: true, isolatedModules: true, noEmit: true, types: [three] }, include: [src/**/*] }自定义类型扩展可以增强 Three.js 的类型安全// src/types/threejs-types.ts import * as THREE from three; declare module three { interface Mesh { userData: { isSelectable?: boolean; originalMaterial?: THREE.Material; highlightMaterial?: THREE.Material; }; } interface Scene { findObjectByNameT extends THREE.Object3D(name: string): T | null; } } // 扩展 Scene 的原型方法 THREE.Scene.prototype.findObjectByName functionT extends THREE.Object3D(name: string): T | null { return this.getObjectByName(name) as T | null; };2.3 开发调试工具配置Three.js 项目的调试比传统 2D 应用复杂合理使用调试工具能显著提高效率// src/utils/DebugHelper.ts import * as THREE from three; import { GUI } from dat.gui; export class DebugHelper { private gui: GUI; private scene: THREE.Scene; constructor(scene: THREE.Scene) { this.scene scene; this.gui new GUI(); this.setupDebugUI(); } private setupDebugUI() { // 场景控制 const sceneFolder this.gui.addFolder(Scene); sceneFolder.add(this.scene, visible).name(显示场景); // 相机控制 const cameraFolder this.gui.addFolder(Camera); cameraFolder.add(this.scene.children[0], visible).name(显示参考网格); // 性能监控 const stats new Stats(); stats.showPanel(0); // 0: fps, 1: ms, 2: mb, 3: custom document.body.appendChild(stats.dom); // 集成到渲染循环 const updateStats () { stats.update(); requestAnimationFrame(updateStats); }; updateStats(); } addObjectControls(object: THREE.Object3D, folderName: string) { const folder this.gui.addFolder(folderName); folder.add(object.position, x, -10, 10).name(位置 X); folder.add(object.position, y, -10, 10).name(位置 Y); folder.add(object.position, z, -10, 10).name(位置 Z); folder.open(); } dispose() { this.gui.destroy(); } }3. 构建高性能的 Three.js 场景和交互Three.js 项目的性能瓶颈通常出现在对象数量、材质复杂度、阴影计算和渲染调用等方面。合理的场景设计和优化策略至关重要。3.1 几何体和材质优化策略几何体优化是性能提升最有效的手段之一// src/utils/GeometryOptimizer.ts export class GeometryOptimizer { // 合并几何体减少绘制调用 static mergeGeometries(meshes: THREE.Mesh[]): THREE.BufferGeometry { const geometries meshes.map(mesh mesh.geometry); const mergedGeometry THREE.BufferGeometryUtils.mergeBufferGeometries(geometries); // 清理原始几何体 geometries.forEach(geometry geometry.dispose()); return mergedGeometry; } // 简化几何体顶点数量 static simplifyGeometry(geometry: THREE.BufferGeometry, targetRatio: number): THREE.BufferGeometry { const simplifiedGeometry geometry.clone(); if (typeof THREE.SimplifyModifier ! undefined) { const modifier new THREE.SimplifyModifier(); const count Math.floor(geometry.attributes.position.count * targetRatio); simplifiedGeometry modifier.modify(simplifiedGeometry, count); } return simplifiedGeometry; } // 实例化渲染大量相同物体 static createInstancedMesh(geometry: THREE.BufferGeometry, material: THREE.Material, count: number): THREE.InstancedMesh { const instancedMesh new THREE.InstancedMesh(geometry, material, count); const matrix new THREE.Matrix4(); const position new THREE.Vector3(); const quaternion new THREE.Quaternion(); const scale new THREE.Vector3(1, 1, 1); for (let i 0; i count; i) { position.set( Math.random() * 100 - 50, Math.random() * 100 - 50, Math.random() * 100 - 50 ); quaternion.random(); matrix.compose(position, quaternion, scale); instancedMesh.setMatrixAt(i, matrix); } instancedMesh.instanceMatrix.needsUpdate true; return instancedMesh; } }材质优化同样重要特别是对于移动设备// src/utils/MaterialOptimizer.ts export class MaterialOptimizer { // 创建性能友好的材质 static createOptimizedMaterial(params: { color?: number; transparent?: boolean; receiveShadow?: boolean; castShadow?: boolean; }): THREE.Material { // 移动设备使用更简单的材质 const isMobile /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent); if (isMobile) { return new THREE.MeshLambertMaterial({ color: params.color || 0xffffff, transparent: params.transparent || false, opacity: params.transparent ? 0.8 : 1.0 }); } else { return new THREE.MeshStandardMaterial({ color: params.color || 0xffffff, transparent: params.transparent || false, opacity: params.transparent ? 0.8 : 1.0, roughness: 0.7, metalness: 0.2 }); } } // 材质共享策略 static createMaterialCache() { const cache new Mapstring, THREE.Material(); return { getMaterial(key: string, createFn: () THREE.Material): THREE.Material { if (!cache.has(key)) { cache.set(key, createFn()); } return cache.get(key)!; }, dispose() { cache.forEach(material material.dispose()); cache.clear(); } }; } }3.2 高级光照和阴影技术光照和阴影是 Three.js 性能的主要消耗点需要精细调控// src/objects/LightManager.ts export class LightManager { private scene: THREE.Scene; private lights: THREE.Light[] []; constructor(scene: THREE.Scene) { this.scene scene; this.setupLighting(); } private setupLighting() { // 环境光 - 基础照明 const ambientLight new THREE.AmbientLight(0x404040, 0.4); this.scene.add(ambientLight); this.lights.push(ambientLight); // 主方向光 - 产生阴影 const directionalLight new THREE.DirectionalLight(0xffffff, 0.8); directionalLight.position.set(50, 50, 50); directionalLight.castShadow true; // 阴影映射优化 directionalLight.shadow.mapSize.width 2048; directionalLight.shadow.mapSize.height 2048; directionalLight.shadow.camera.near 0.5; directionalLight.shadow.camera.far 500; directionalLight.shadow.camera.left -100; directionalLight.shadow.camera.right 100; directionalLight.shadow.camera.top 100; directionalLight.shadow.camera.bottom -100; this.scene.add(directionalLight); this.lights.push(directionalLight); // 补充点光源 - 增加场景层次感 const pointLight new THREE.PointLight(0xff4000, 0.5, 100); pointLight.position.set(10, 10, 10); this.scene.add(pointLight); this.lights.push(pointLight); } // 动态光照调整 adjustLightingForPerformance(quality: high | medium | low) { this.lights.forEach(light { if (light instanceof THREE.DirectionalLight light.castShadow) { switch (quality) { case low: light.shadow.mapSize.width 512; light.shadow.mapSize.height 512; light.intensity 0.6; break; case medium: light.shadow.mapSize.width 1024; light.shadow.mapSize.height 1024; light.intensity 0.7; break; case high: light.shadow.mapSize.width 2048; light.shadow.mapSize.height 2048; light.intensity 0.8; break; } } }); } dispose() { this.lights.forEach(light this.scene.remove(light)); this.lights []; } }3.3 交互系统和事件处理Three.js 的交互处理需要将 2D 屏幕坐标转换为 3D 场景坐标// src/utils/InteractionManager.ts export class InteractionManager { private renderer: THREE.WebGLRenderer; private camera: THREE.Camera; private scene: THREE.Scene; private raycaster: THREE.Raycaster; private mouse: THREE.Vector2; constructor(renderer: THREE.WebGLRenderer, camera: THREE.Camera, scene: THREE.Scene) { this.renderer renderer; this.camera camera; this.scene scene; this.raycaster new THREE.Raycaster(); this.mouse new THREE.Vector2(); this.setupEventListeners(); } private setupEventListeners() { const domElement this.renderer.domElement; domElement.addEventListener(click, this.handleClick); domElement.addEventListener(mousemove, this.handleMouseMove); domElement.addEventListener(touchstart, this.handleTouch, { passive: false }); } private handleClick (event: MouseEvent) { this.updateMousePosition(event); this.raycastIntersection(click); } private handleMouseMove (event: MouseEvent) { this.updateMousePosition(event); this.raycastIntersection(hover); } private handleTouch (event: TouchEvent) { event.preventDefault(); if (event.touches.length 1) { this.updateMousePosition(event.touches[0]); this.raycastIntersection(touch); } } private updateMousePosition(event: MouseEvent | Touch) { const rect this.renderer.domElement.getBoundingClientRect(); this.mouse.x ((event.clientX - rect.left) / rect.width) * 2 - 1; this.mouse.y -((event.clientY - rect.top) / rect.height) * 2 1; } private raycastIntersection(type: click | hover | touch) { this.raycaster.setFromCamera(this.mouse, this.camera); // 只检测可交互对象 const interactableObjects this.getInteractableObjects(); const intersects this.raycaster.intersectObjects(interactableObjects); if (intersects.length 0) { const object intersects[0].object; this.dispatchInteractionEvent(type, object, intersects[0].point); } } private getInteractableObjects(): THREE.Object3D[] { const interactableObjects: THREE.Object3D[] []; this.scene.traverse(object { if (object.userData.isInteractable) { interactableObjects.push(object); } }); return interactableObjects; } private dispatchInteractionEvent(type: string, object: THREE.Object3D, point: THREE.Vector3) { const event new CustomEvent(threejs-interaction, { detail: { type, object, point } }); this.renderer.domElement.dispatchEvent(event); } dispose() { const domElement this.renderer.domElement; domElement.removeEventListener(click, this.handleClick); domElement.removeEventListener(mousemove, this.handleMouseMove); domElement.removeEventListener(touchstart, this.handleTouch); } }4. Three.js 与 Vue 3 的深度集成实践Vue 3 的 Composition API 与 Three.js 的结合能够创建声明式、可复用的 3D 组件。这种集成需要解决响应式数据与 Three.js 命令式 API 的协调问题。4.1 创建 Vue 3 的三维场景组件首先构建基础的三维场景组件管理 Three.js 的生命周期!-- src/components/ThreeScene.vue -- template div refcontainer classthree-container/div /template script setup langts import { ref, onMounted, onUnmounted, watch } from vue import * as THREE from three import { InteractionManager } from ../utils/InteractionManager import { ResourceManager } from ../utils/ResourceManager const props defineProps{ backgroundColor: string enableShadows: boolean performanceMode: high | medium | low }() const container refHTMLDivElement() const emit defineEmits{ sceneReady: [scene: THREE.Scene, camera: THREE.Camera, renderer: THREE.WebGLRenderer] objectClicked: [object: THREE.Object3D] }() let scene: THREE.Scene let camera: THREE.Camera let renderer: THREE.WebGLRenderer let animationId: number let interactionManager: InteractionManager let resourceManager: ResourceManager const initThreeJS () { // 初始化场景 scene new THREE.Scene() scene.background new THREE.Color(props.backgroundColor) // 初始化相机 camera new THREE.PerspectiveCamera( 75, container.value!.clientWidth / container.value!.clientHeight, 0.1, 1000 ) camera.position.set(0, 5, 10) // 初始化渲染器 renderer new THREE.WebGLRenderer({ antialias: props.performanceMode ! low, powerPreference: high-performance }) renderer.setSize(container.value!.clientWidth, container.value!.clientHeight) renderer.shadowMap.enabled props.enableShadows renderer.shadowMap.type THREE.PCFSoftShadowMap container.value!.appendChild(renderer.domElement) // 初始化交互管理器 interactionManager new InteractionManager(renderer, camera, scene) renderer.domElement.addEventListener(threejs-interaction, handleInteraction) // 初始化资源管理器 resourceManager new ResourceManager() emit(sceneReady, scene, camera, renderer) setupScene() animate() } const setupScene () { // 基础灯光 const ambientLight new THREE.AmbientLight(0x404040, 0.4) scene.add(ambientLight) const directionalLight new THREE.DirectionalLight(0xffffff, 0.8) directionalLight.position.set(50, 50, 50) directionalLight.castShadow props.enableShadows scene.add(directionalLight) // 参考网格 const gridHelper new THREE.GridHelper(10, 10) scene.add(gridHelper) } const animate () { animationId requestAnimationFrame(animate) renderer.render(scene, camera) } const handleInteraction (event: Event) { const customEvent event as CustomEvent if (customEvent.detail.type click) { emit(objectClicked, customEvent.detail.object) } } const handleResize () { if (!container.value || !camera || !renderer) return const width container.value.clientWidth const height container.value.clientHeight if (camera instanceof THREE.PerspectiveCamera) { camera.aspect width / height camera.updateProjectionMatrix() } renderer.setSize(width, height) } // 响应式属性监听 watch(() props.backgroundColor, (newColor) { if (scene) { scene.background new THREE.Color(newColor) } }) watch(() props.enableShadows, (enabled) { if (renderer) { renderer.shadowMap.enabled enabled scene.traverse(object { if (object instanceof THREE.Mesh object.material) { object.castShadow enabled object.receiveShadow enabled } }) } }) onMounted(() { initThreeJS() window.addEventListener(resize, handleResize) }) onUnmounted(() { window.removeEventListener(resize, handleResize) cancelAnimationFrame(animationId) interactionManager?.dispose() resourceManager?.dispose() if (renderer) { container.value?.removeChild(renderer.domElement) renderer.dispose() } }) /script style scoped .three-container { width: 100%; height: 100%; position: relative; } /style4.2 创建可复用的三维对象组件基于 Vue 3 的 Composition API 创建可复用的三维对象组件!-- src/components/ThreeMesh.vue -- template !-- Vue 模板为空通过 Composition API 控制 Three.js 对象 -- /template script setup langts import { inject, onMounted, onUnmounted, watch } from vue import * as THREE from three interface ThreeContext { scene: THREE.Scene resourceManager: any } const props defineProps{ type: box | sphere | cylinder position: [number, number, number] size: [number, number, number] color: string castShadow: boolean receiveShadow: boolean }() const context injectThreeContext(threeContext) let mesh: THREE.Mesh const createGeometry () { const [width, height, depth] props.size switch (props.type) { case box: return new THREE.BoxGeometry(width, height, depth) case sphere: return new THREE.SphereGeometry(width, 32, 32) case cylinder: return new THREE.CylinderGeometry(width, width, height, 32) default: return new THREE.BoxGeometry(1, 1, 1) } } const createMesh () { if (!context) return const geometry createGeometry() const material new THREE.MeshStandardMaterial({ color: props.color }) mesh new THREE.Mesh(geometry, material) mesh.position.set(...props.position) mesh.castShadow props.castShadow mesh.receiveShadow props.receiveShadow mesh.userData.isInteractable true context.scene.add(mesh) // 注册到资源管理器 context.resourceManager.trackGeometry(geometry) context.resourceManager.trackMaterial(material) } const updateMesh () { if (mesh context) { context.scene.remove(mesh) // 清理旧资源 if (mesh.geometry) mesh.geometry.dispose() if (mesh.material) { if (Array.isArray(mesh.material)) { mesh.material.forEach(m m.dispose()) } else { mesh.material.dispose() } } createMesh() } } // 属性变化监听 watch(() props.position, (newPosition) { if (mesh) { mesh.position.set(...newPosition) } }) watch(() props.color, (newColor) { if (mesh mesh.material instanceof THREE.MeshStandardMaterial) { mesh.material.color.set(newColor) } }) watch(() props.type, updateMesh) watch(() props.size, updateMesh) onMounted(createMesh) onUnmounted(() { if (mesh context) { context.scene.remove(mesh) if (mesh.geometry) mesh.geometry.dispose() if (mesh.material) { if (Array.isArray(mesh.material)) { mesh.material.forEach(m m.dispose()) } else { mesh.material.dispose() } } } }) // 暴露 mesh 实例给父组件 defineExpose({ mesh }) /script4.3 在父组件中集成三维场景!-- src/App.vue -- template div classapp div classcontrols label 背景颜色: input typecolor v-modelbackgroundColor / /label label 启用阴影: input typecheckbox v-modelenableShadows / /label label 性能模式: select v-modelperformanceMode option valuehigh高质量/option option valuemedium平衡/option option valuelow性能优先/option /select /label /div ThreeScene :backgroundColorbackgroundColor :enableShadowsenableShadows :performanceModeperformanceMode scene-readyhandleSceneReady object-clickedhandleObjectClick classscene-container / div v-ifselectedObject classselection-info 选中对象: {{ selectedObject.type }} /div /div /template script setup langts import { ref, provide } from vue import ThreeScene from ./components/ThreeScene.vue import * as THREE from three const backgroundColor ref(#222222) const enableShadows ref(true) const performanceMode refhigh | medium | low(medium) const selectedObject refTHREE.Object3D | null(null) const handleSceneReady (scene: THREE.Scene, camera: THREE.Camera, renderer: THREE.WebGLRenderer) { // 提供 Three.js 上下文给子组件 provide(threeContext, { scene, camera, renderer }) // 可以在这里添加初始场景对象 addDemoObjects(scene) } const handleObjectClick (object: THREE.Object3D) { selectedObject.value object console.log(对象被点击:, object) } const addDemoObjects (scene: THREE.Scene) { // 添加一些演示对象 const geometry new THREE.BoxGeometry(1, 1, 1) const material new THREE.MeshStandardMaterial({ color: 0x00ff00 }) const cube new THREE.Mesh(geometry, material) cube.position.set(0, 0, 0) cube.castShadow true cube.receiveShadow true cube.userData.isInteractable true scene.add(cube) } /script style scoped .app { width: 100vw; height: 100vh; display: flex; flex-direction: column; } .controls { padding: 10px; background: #f5f5f5; border-bottom: 1px solid #ddd; } .scene-container { flex: 1; } .selection-info { padding: 10px; background: #e0e0e0; border-top: 1px solid #ddd; } /style5. 性能优化和常见问题排查Three.js 项目在实际运行中会遇到各种性能问题和兼容性挑战。系统化的优化和排查策略是项目成功的关键。5.1 性能监控和优化策略建立完整的性能监控体系// src/utils/PerformanceMonitor.ts export class PerformanceMonitor { private renderer: THREE.WebGLRenderer; private stats: any; private memoryInfo: { geometries: number; textures: number; programs: number; }; constructor(renderer: THREE.WebGLRenderer) { this.renderer renderer; this.setupMonitoring(); } private setupMonitoring() { // 帧率监控 this.stats new Stats(); this.stats.showPanel(0); document.body.appendChild(this.stats.dom); // 内存监控 this.memoryInfo { geometries: 0, textures: 0, programs: 0 }; this.updateMemoryInfo(); } private updateMemoryInfo() { setInterval(() { this.memoryInfo.geometries this.renderer.info.memory.geometries; this.memoryInfo.textures this.renderer.info.memory.textures; this.memoryInfo.programs this.renderer.info.programs?.length || 0; this.logPerformance(); }, 2000); } private logPerformance() { const info this.renderer.info; console.table({ 渲染调用: info.render.calls, 面片数量: info.render.triangles, 点数量: info.render.points, 几何体数量: this.memoryInfo.geometries, 纹理数量: this.memoryInfo.textures, 着色器程序: this.memoryInfo.programs, 帧率: this.stats.getFPS() }); } getPerformanceRecommendations(): string[] { const recommendations: string[] []; const info this.renderer.info; if (info