ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

WebGL与WebGPU核心技术解析:从Three.js实战到性能优化

WebGL与WebGPU核心技术解析:从Three.js实战到性能优化 WebGL/WebGPU案例合集六十三期从基础到实战的完整技术解析在Web图形开发领域WebGL和WebGPU已经成为构建高性能3D应用的核心技术。随着Three.js等框架的普及越来越多的开发者开始接触这些强大的图形API。本文将系统介绍WebGL和WebGPU的基础概念、技术差异并通过多个实战案例展示如何在实际项目中应用这些技术。1. WebGL与WebGPU技术概述1.1 WebGL基础概念与作用WebGLWeb Graphics Library是一种基于OpenGL ES的JavaScript API允许在浏览器中渲染交互式2D和3D图形。它直接利用GPU的硬件加速能力为Web开发者提供了强大的图形处理能力。WebGL的主要特点包括跨平台兼容性支持所有现代浏览器硬件加速直接调用GPU进行图形渲染基于OpenGL ES遵循成熟的图形标准与HTML5集成可与Canvas元素无缝结合在实际应用中WebGL常用于数据可视化、游戏开发、虚拟现实、产品展示等场景。例如通过Three.js库可以快速构建复杂的3D场景而无需深入理解底层图形API的复杂细节。1.2 WebGPU技术演进与优势WebGPU是新一代的Web图形API旨在解决WebGL在某些方面的局限性。它提供了更底层的GPU访问能力支持现代GPU特性并在性能和多线程处理方面有显著提升。WebGPU相比WebGL的主要优势更好的性能更高效的命令缓冲和并行处理现代GPU特性支持计算着色器、光线追踪等高级功能多线程支持允许在Worker线程中进行图形计算更清晰的抽象提供更直观的GPU编程模型虽然WebGPU目前仍在发展中但已经显示出在复杂图形应用中的巨大潜力。对于需要高性能图形计算的项目WebGPU是值得关注的技术方向。1.3 技术选型考量因素在选择WebGL还是WebGPU时需要考虑以下因素项目复杂度简单3D场景使用WebGLThree.js复杂图形计算考虑WebGPU浏览器兼容性WebGL支持更广泛WebGPU需要较新的浏览器版本团队技术栈Three.js生态成熟学习曲线相对平缓性能要求对性能有极致要求的项目可评估WebGPU2. 环境准备与开发工具配置2.1 基础开发环境搭建要开始WebGL/WebGPU开发需要准备以下环境现代浏览器Chrome 94、Firefox 90、Safari 15代码编辑器VS Code、WebStorm等本地服务器用于测试避免文件协议限制创建基础项目结构webgl-project/ ├── index.html ├── css/ │ └── style.css ├── js/ │ ├── main.js │ └── three.js └── assets/ ├── textures/ └── models/2.2 Three.js库引入与配置Three.js是目前最流行的WebGL库大大简化了3D开发复杂度。可以通过多种方式引入通过CDN引入!DOCTYPE html html head meta charsetutf-8 titleThree.js基础示例/title style body { margin: 0; } canvas { display: block; } /style /head body script srchttps://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js/script script srcjs/main.js/script /body /html通过npm安装npm install three2.3 开发调试工具推荐使用以下工具提升开发效率Chrome DevTools性能分析、内存监控Three.js Inspector浏览器扩展用于调试Three.js场景WebGPU InspectorWebGPU专用调试工具3. Three.js核心概念与基础用法3.1 场景图与对象层次结构Three.js使用场景图Scene Graph来管理3D对象。理解对象层次结构对于处理复杂场景至关重要// 创建场景 const scene new THREE.Scene(); // 创建相机 const camera new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); // 创建渲染器 const renderer new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); // 创建立方体 const geometry new THREE.BoxGeometry(1, 1, 1); const material new THREE.MeshBasicMaterial({ color: 0x00ff00 }); const cube new THREE.Mesh(geometry, material); scene.add(cube); camera.position.z 5; // 渲染循环 function animate() { requestAnimationFrame(animate); cube.rotation.x 0.01; cube.rotation.y 0.01; renderer.render(scene, camera); } animate();3.2 几何体与材质系统Three.js提供了丰富的几何体和材质类型满足不同渲染需求// 多种几何体示例 const geometries { box: new THREE.BoxGeometry(1, 1, 1), sphere: new THREE.SphereGeometry(1, 32, 16), cylinder: new THREE.CylinderGeometry(0.5, 0.5, 1, 32), plane: new THREE.PlaneGeometry(5, 5, 10, 10) }; // 材质类型示例 const materials { basic: new THREE.MeshBasicMaterial({ color: 0xff0000 }), standard: new THREE.MeshStandardMaterial({ color: 0x00ff00, roughness: 0.5, metalness: 0.5 }), phong: new THREE.MeshPhongMaterial({ color: 0x0000ff, shininess: 100 }) };3.3 光照与阴影系统合理的光照设置对3D场景的真实感至关重要// 环境光 const ambientLight new THREE.AmbientLight(0x404040, 0.4); scene.add(ambientLight); // 定向光模拟太阳 const directionalLight new THREE.DirectionalLight(0xffffff, 0.8); directionalLight.position.set(5, 10, 7.5); directionalLight.castShadow true; scene.add(directionalLight); // 点光源 const pointLight new THREE.PointLight(0xff4000, 1, 100); pointLight.position.set(0, 5, 0); scene.add(pointLight); // 启用阴影 renderer.shadowMap.enabled true; renderer.shadowMap.type THREE.PCFSoftShadowMap;4. 实战案例一交互式3D图片墙4.1 项目需求分析创建一个交互式的3D图片墙要求支持多张图片的3D排列展示实现鼠标交互旋转、缩放、点击响应式设计适配不同屏幕尺寸平滑的动画过渡效果4.2 数据结构设计与实现class ImageWall { constructor(container, images) { this.container container; this.images images; this.scene new THREE.Scene(); this.camera new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); this.renderer new THREE.WebGLRenderer({ antialias: true }); this.meshes []; this.selectedMesh null; this.init(); } init() { // 设置渲染器 this.renderer.setSize(window.innerWidth, window.innerHeight); this.renderer.setClearColor(0xf0f0f0); this.container.appendChild(this.renderer.domElement); // 创建图片平面 this.createImagePlanes(); // 设置相机位置 this.camera.position.z 10; // 添加交互控制 this.setupControls(); // 开始动画循环 this.animate(); } createImagePlanes() { const rows 3; const cols 4; const spacing 2.5; for (let i 0; i this.images.length; i) { const row Math.floor(i / cols); const col i % cols; const textureLoader new THREE.TextureLoader(); const texture textureLoader.load(this.images[i]); const geometry new THREE.PlaneGeometry(2, 2); const material new THREE.MeshBasicMaterial({ map: texture, side: THREE.DoubleSide }); const mesh new THREE.Mesh(geometry, material); mesh.position.x (col - (cols - 1) / 2) * spacing; mesh.position.y (row - (rows - 1) / 2) * spacing * -1; // 存储图片信息 mesh.userData { imageUrl: this.images[i], index: i }; this.scene.add(mesh); this.meshes.push(mesh); } } setupControls() { // 鼠标交互实现 const raycaster new THREE.Raycaster(); const mouse new THREE.Vector2(); window.addEventListener(mousemove, (event) { mouse.x (event.clientX / window.innerWidth) * 2 - 1; mouse.y -(event.clientY / window.innerHeight) * 2 1; raycaster.setFromCamera(mouse, this.camera); const intersects raycaster.intersectObjects(this.meshes); // 悬停效果 this.meshes.forEach(mesh { mesh.scale.set(1, 1, 1); }); if (intersects.length 0) { intersects[0].object.scale.set(1.1, 1.1, 1.1); } }); window.addEventListener(click, (event) { raycaster.setFromCamera(mouse, this.camera); const intersects raycaster.intersectObjects(this.meshes); if (intersects.length 0) { this.selectImage(intersects[0].object); } }); } selectImage(mesh) { if (this.selectedMesh) { // 重置之前选中的图片 this.selectedMesh.scale.set(1, 1, 1); } this.selectedMesh mesh; mesh.scale.set(1.2, 1.2, 1.2); console.log(选中图片:, mesh.userData.imageUrl); } animate() { requestAnimationFrame(() this.animate()); // 缓慢旋转整个场景 this.scene.rotation.y 0.005; this.renderer.render(this.scene, this.camera); } } // 使用示例 const imageUrls [ assets/images/1.jpg, assets/images/2.jpg, assets/images/3.jpg, // ...更多图片 ]; const imageWall new ImageWall(document.body, imageUrls);4.3 性能优化与响应式处理// 响应式处理 window.addEventListener(resize, () { imageWall.camera.aspect window.innerWidth / window.innerHeight; imageWall.camera.updateProjectionMatrix(); imageWall.renderer.setSize(window.innerWidth, window.innerHeight); }); // 图片预加载优化 function preloadImages(urls, callback) { let loaded 0; const images []; urls.forEach((url, index) { images[index] new Image(); images[index].onload () { loaded; if (loaded urls.length) { callback(); } }; images[index].src url; }); } // 使用纹理压缩优化内存 const textureLoader new THREE.TextureLoader(); textureLoader.load(image.jpg, (texture) { texture.generateMipmaps true; texture.minFilter THREE.LinearMipmapLinearFilter; });5. 实战案例二Three.js与Vue3集成项目5.1 Vue3项目结构设计集成Three.js与Vue3需要合理的项目结构vue-three-project/ ├── public/ │ └── index.html ├── src/ │ ├── components/ │ │ ├── ThreeScene.vue │ │ ├── ModelViewer.vue │ │ └── ControlsPanel.vue │ ├── composables/ │ │ ├── useThree.js │ │ └── useControls.js │ ├── utils/ │ │ └── threeHelpers.js │ └── main.js ├── package.json └── vite.config.js5.2 组合式API封装Three.js逻辑// composables/useThree.js import { ref, onMounted, onUnmounted } from vue; import * as THREE from three; export function useThree(canvasRef) { const scene ref(null); const camera ref(null); const renderer ref(null); const animationId ref(null); const initThree () { // 初始化场景 scene.value new THREE.Scene(); scene.value.background new THREE.Color(0x222222); // 初始化相机 camera.value new THREE.PerspectiveCamera( 75, canvasRef.value.clientWidth / canvasRef.value.clientHeight, 0.1, 1000 ); camera.value.position.z 5; // 初始化渲染器 renderer.value new THREE.WebGLRenderer({ canvas: canvasRef.value, antialias: true }); renderer.value.setSize( canvasRef.value.clientWidth, canvasRef.value.clientHeight ); // 添加基础光照 const ambientLight new THREE.AmbientLight(0x404040, 0.4); scene.value.add(ambientLight); const directionalLight new THREE.DirectionalLight(0xffffff, 0.8); directionalLight.position.set(1, 1, 1); scene.value.add(directionalLight); }; const animate () { animationId.value requestAnimationFrame(animate); renderer.value.render(scene.value, camera.value); }; const cleanup () { if (animationId.value) { cancelAnimationFrame(animationId.value); } // 释放资源 scene.value.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(); } } }); }; onMounted(() { initThree(); animate(); }); onUnmounted(() { cleanup(); }); return { scene, camera, renderer }; }5.3 Vue组件实现与数据绑定!-- components/ThreeScene.vue -- template div classthree-scene canvas refcanvasRef classthree-canvas/canvas ControlsPanel :rotationrotation update:rotationupdateRotation / /div /template script setup import { ref, watch } from vue; import { useThree } from ../composables/useThree; import ControlsPanel from ./ControlsPanel.vue; const canvasRef ref(null); const rotation ref({ x: 0, y: 0, z: 0 }); const { scene, camera, renderer } useThree(canvasRef); // 创建立方体 const cubeGeometry new THREE.BoxGeometry(1, 1, 1); const cubeMaterial new THREE.MeshStandardMaterial({ color: 0x00ff00, roughness: 0.5 }); const cube new THREE.Mesh(cubeGeometry, cubeMaterial); scene.value.add(cube); // 监听旋转数据变化 watch(rotation, (newVal) { cube.rotation.x newVal.x; cube.rotation.y newVal.y; cube.rotation.z newVal.z; }, { deep: true }); const updateRotation (newRotation) { rotation.value { ...newRotation }; }; /script style scoped .three-scene { position: relative; width: 100%; height: 100vh; } .three-canvas { display: block; width: 100%; height: 100%; } /style6. 实战案例三交互式盒式剖切效果6.1 剖切算法原理与实现盒式剖切Box Clipping是3D可视化中常用的技术用于展示模型内部结构class BoxClipping { constructor(scene, model) { this.scene scene; this.model model; this.clippingPlanes []; this.clipBox new THREE.Box3(); this.initClippingPlanes(); } initClippingPlanes() { // 创建六个裁剪平面 for (let i 0; i 6; i) { this.clippingPlanes.push(new THREE.Plane()); } // 为模型材质启用裁剪 this.model.traverse((child) { if (child.isMesh) { child.material.clippingPlanes this.clippingPlanes; child.material.clipShadows true; child.material.needsUpdate true; } }); } updateClippingBox(min, max) { this.clipBox.set(min, max); this.updateClippingPlanes(); } updateClippingPlanes() { const normalMatrix new THREE.Matrix3(); const inverseMatrix new THREE.Matrix4(); this.model.updateMatrixWorld(true); inverseMatrix.copy(this.model.matrixWorld).invert(); normalMatrix.getNormalMatrix(this.model.matrixWorld); const planes [ new THREE.Plane(new THREE.Vector3(1, 0, 0), -this.clipBox.max.x), new THREE.Plane(new THREE.Vector3(-1, 0, 0), this.clipBox.min.x), new THREE.Plane(new THREE.Vector3(0, 1, 0), -this.clipBox.max.y), new THREE.Plane(new THREE.Vector3(0, -1, 0), this.clipBox.min.y), new THREE.Plane(new THREE.Vector3(0, 0, 1), -this.clipBox.max.z), new THREE.Plane(new THREE.Vector3(0, 0, -1), this.clipBox.min.z) ]; planes.forEach((plane, index) { this.clippingPlanes[index].copy(plane); this.clippingPlanes[index].applyMatrix4(inverseMatrix); }); } createVisualizationBox() { const boxGeometry new THREE.BoxGeometry(1, 1, 1); const boxMaterial new THREE.MeshBasicMaterial({ color: 0xff0000, wireframe: true, transparent: true, opacity: 0.5 }); const boxMesh new THREE.Mesh(boxGeometry, boxMaterial); boxMesh.scale.copy(this.clipBox.getSize(new THREE.Vector3())); boxMesh.position.copy(this.clipBox.getCenter(new THREE.Vector3())); return boxMesh; } }6.2 交互控制与可视化界面class ClippingControls { constructor(renderer, camera, clippingSystem) { this.renderer renderer; this.camera camera; this.clippingSystem clippingSystem; this.isDragging false; this.currentFace null; this.intersectionPoint new THREE.Vector3(); this.setupEventListeners(); } setupEventListeners() { const domElement this.renderer.domElement; domElement.addEventListener(mousedown, this.onMouseDown.bind(this)); domElement.addEventListener(mousemove, this.onMouseMove.bind(this)); domElement.addEventListener(mouseup, this.onMouseUp.bind(this)); // 触摸设备支持 domElement.addEventListener(touchstart, this.onTouchStart.bind(this)); domElement.addEventListener(touchmove, this.onTouchMove.bind(this)); domElement.addEventListener(touchend, this.onTouchEnd.bind(this)); } onMouseDown(event) { this.isDragging true; this.handleInteraction(event.clientX, event.clientY, true); } onMouseMove(event) { if (this.isDragging) { this.handleInteraction(event.clientX, event.clientY, false); } } onMouseUp() { this.isDragging false; this.currentFace null; } handleInteraction(clientX, clientY, isStart) { const mouse new THREE.Vector2(); const raycaster new THREE.Raycaster(); mouse.x (clientX / window.innerWidth) * 2 - 1; mouse.y -(clientY / window.innerHeight) * 2 1; raycaster.setFromCamera(mouse, this.camera); // 检测与裁剪盒的交点 const clipBox this.clippingSystem.clipBox; const intersection raycaster.ray.intersectBox(clipBox, new THREE.Vector3()); if (intersection) { this.intersectionPoint.copy(intersection); if (isStart) { this.currentFace this.detectFace(intersection, clipBox); } else if (this.currentFace) { this.updateClippingBox(intersection); } } } detectFace(point, box) { const tolerance 0.1; const size box.getSize(new THREE.Vector3()); // 检测点靠近哪个面 if (Math.abs(point.x - box.min.x) tolerance) return left; if (Math.abs(point.x - box.max.x) tolerance) return right; if (Math.abs(point.y - box.min.y) tolerance) return bottom; if (Math.abs(point.y - box.max.y) tolerance) return top; if (Math.abs(point.z - box.min.z) tolerance) return back; if (Math.abs(point.z - box.max.z) tolerance) return front; return null; } updateClippingBox(newPoint) { const box this.clippingSystem.clipBox.clone(); switch (this.currentFace) { case left: box.min.x Math.min(Math.max(newPoint.x, box.min.x), box.max.x - 0.1); break; case right: box.max.x Math.max(Math.min(newPoint.x, box.max.x), box.min.x 0.1); break; case bottom: box.min.y Math.min(Math.max(newPoint.y, box.min.y), box.max.y - 0.1); break; case top: box.max.y Math.max(Math.min(newPoint.y, box.max.y), box.min.y 0.1); break; case back: box.min.z Math.min(Math.max(newPoint.z, box.min.z), box.max.z - 0.1); break; case front: box.max.z Math.max(Math.min(newPoint.z, box.max.z), box.min.z 0.1); break; } this.clippingSystem.updateClippingBox(box.min, box.max); } }7. 性能优化与内存管理7.1 资源加载与缓存策略在WebGL项目中合理的资源管理对性能至关重要class ResourceManager { constructor() { this.textures new Map(); this.geometries new Map(); this.models new Map(); this.loadingQueue []; this.isLoading false; } async loadTexture(url, options {}) { if (this.textures.has(url)) { return this.textures.get(url); } return new Promise((resolve, reject) { const loader new THREE.TextureLoader(); loader.load( url, (texture) { // 应用配置选项 if (options.generateMipmaps ! false) { texture.generateMipmaps true; } if (options.wrapS) texture.wrapS options.wrapS; if (options.wrapT) texture.wrapT options.wrapT; this.textures.set(url, texture); resolve(texture); }, undefined, reject ); }); } async loadGLTFModel(url) { if (this.models.has(url)) { return this.models.get(url).clone(); } return new Promise((resolve, reject) { const loader new THREE.GLTFLoader(); loader.load( url, (gltf) { this.models.set(url, gltf); resolve(gltf); }, undefined, reject ); }); } // 批量加载资源 async loadResources(resourceList) { const promises resourceList.map(resource { switch (resource.type) { case texture: return this.loadTexture(resource.url, resource.options); case model: return this.loadGLTFModel(resource.url); default: return Promise.reject(new Error(Unknown resource type: ${resource.type})); } }); return Promise.all(promises); } // 清理未使用的资源 cleanupUnused() { const currentlyUsed new Set(); // 收集当前场景中使用的资源 this.collectUsedResources(currentlyUsed); // 清理未使用的纹理 for (const [url, texture] of this.textures) { if (!currentlyUsed.has(texture)) { texture.dispose(); this.textures.delete(url); } } // 清理未使用的几何体 for (const [key, geometry] of this.geometries) { if (!currentlyUsed.has(geometry)) { geometry.dispose(); this.geometries.delete(key); } } } }7.2 内存优化与垃圾回收WebGL应用需要特别注意内存管理避免内存泄漏class MemoryOptimizer { constructor(renderer) { this.renderer renderer; this.memoryMonitor new MemoryMonitor(); this.cleanupInterval setInterval(() this.cleanup(), 30000); // 30秒清理一次 } cleanup() { // 强制垃圾回收如果浏览器支持 if (window.gc) { window.gc(); } // 清理Three.js内部缓存 THREE.Cache.clear(); // 清理渲染器状态 this.renderer.forceContextLoss(); this.renderer.context.getExtension(WEBGL_lose_context).restoreContext(); console.log(内存清理完成, this.memoryMonitor.getMemoryInfo()); } // 监控内存使用 setupMemoryMonitoring() { setInterval(() { const memoryInfo this.memoryMonitor.getMemoryInfo(); if (memoryInfo.usedJSHeapSize 500 * 1024 * 1024) { // 500MB阈值 this.cleanup(); } }, 5000); } } class MemoryMonitor { getMemoryInfo() { if (performance.memory) { return { usedJSHeapSize: performance.memory.usedJSHeapSize, totalJSHeapSize: performance.memory.totalJSHeapSize, jsHeapSizeLimit: performance.memory.jsHeapSizeLimit }; } return { error: Memory API not supported }; } }8. 常见问题与解决方案8.1 WebGL兼容性与错误处理// WebGL支持检测 function checkWebGLAvailability() { try { const canvas document.createElement(canvas); const gl canvas.getContext(webgl) || canvas.getContext(experimental-webgl); if (!gl) { throw new Error(WebGL not supported); } // 检查必要的扩展 const extensions [ OES_texture_float, WEBGL_depth_texture, OES_standard_derivatives ]; const missingExtensions extensions.filter(ext !gl.getExtension(ext)); if (missingExtensions.length 0) { console.warn(Missing WebGL extensions:, missingExtensions); } return { supported: true, context: gl, missingExtensions }; } catch (error) { return { supported: false, error: error.message }; } } // 错误处理中间件 function createErrorHandledRenderer(options) { const renderer new THREE.WebGLRenderer(options); // 监听WebGL错误 renderer.domElement.addEventListener(webglcontextlost, (event) { console.error(WebGL context lost, event); // 尝试恢复上下文 setTimeout(() { renderer.forceContextRestore(); }, 1000); }); renderer.domElement.addEventListener(webglcontextrestored, () { console.log(WebGL context restored); // 重新初始化场景 initializeScene(); }); return renderer; }8.2 性能问题排查清单问题现象可能原因解决方案帧率下降图形调用过多合并网格使用实例化渲染内存持续增长资源未释放实现资源管理定期清理加载缓慢资源过大使用压缩纹理代码分割动画卡顿复杂计算阻塞使用Web Worker优化算法8.3 跨浏览器兼容性问题不同浏览器对WebGL特性的支持存在差异// 特性检测与降级方案 function getWebGLCapabilities() { const canvas document.createElement(canvas); const gl canvas.getContext(webgl2) || canvas.getContext(webgl); if (!gl) return null; const capabilities { maxTextureSize: gl.getParameter(gl.MAX_TEXTURE_SIZE), maxAnisotropy: getMaxAnisotropy(gl), shaderPrecision: getShaderPrecision(gl), supportedExtensions: gl.getSupportedExtensions() }; return capabilities; } function getMaxAnisotropy(gl) { const extension gl.getExtension(EXT_texture_filter_anisotropic) || gl.getExtension(WEBKIT_EXT_texture_filter_anisotropic) || gl.getExtension(MOZ_EXT_texture_filter_anisotropic); return extension ? gl.getParameter(extension.MAX_TEXTURE_MAX_ANISOTROPY_EXT) : 0; }9. 最佳实践与工程化建议9.1 项目架构设计原则大型WebGL项目需要良好的架构设计// 模块化架构示例 class WebGLApplication { constructor() { this.sceneManager new SceneManager(); this.resourceManager new ResourceManager(); this.renderManager new RenderManager(); this.uiManager new UIManager(); this.animationManager new AnimationManager(); this.init(); } async init() { // 初始化各个模块 await this.resourceManager.preloadCriticalResources(); this.sceneManager.setupDefaultScene(); this.renderManager.setupRenderer(); this.uiManager.setupControls(); // 启动主循环 this.startMainLoop(); } startMainLoop() { const animate (time) { this.animationManager.update(time); this.sceneManager.update(); this.renderManager.render(); requestAnimationFrame(animate); }; animate(); } // 生命周期管理 destroy() { this.sceneManager.cleanup(); this.resourceManager.cleanup(); this.renderer.dispose(); } }9.2 代码质量与可维护性提高代码质量的实践// 配置常量管理 const CONFIG { RENDERING: { MAX_FPS: 60, SHADOW_QUALITY: high, // low, medium, high ANTIALIASING: true }, RESOURCES: { MAX_CONCURRENT_LOADS: 4, TEXTURE_COMPRESSION: true, CACHE_ENABLED: true }, DEBUG: { SHOW_STATS: true, LOG_LEVEL: warn // error, warn, info } }; // 日志系统 class Logger { static error(message, ...args) { if (CONFIG.DEBUG.LOG_LEVEL error) { console.error([ERROR] ${message}, ...args); } } static warn(message, ...args) { if ([error, warn].includes(CONFIG.DEBUG.LOG_LEVEL)) { console.warn([WARN] ${message}, ...args); } } static info(message, ...args) { if ([error, warn, info].includes(CONFIG.DEBUG.LOG_LEVEL)) { console.info([INFO] ${message}, ...args); } } } // 性能监控 class PerformanceMonitor { constructor() { this.metrics new Map(); this.frameTimes []; this.maxFrameSamples 60; } startFrame() { this.frameStart performance.now(); } endFrame() { const frameTime performance.now() - this.frameStart; this.frameTimes.push(frameTime); if (this.frameTimes.length this.maxFrameSamples) { this.frameTimes.shift(); } this.updateMetrics(); } updateMetrics() { const avgFrameTime this.frameTimes.reduce((a, b) a b, 0) / this.frameTimes.length; const fps 1000 / avgFrameTime; this.metrics.set(fps, Math.round(fps)); this.metrics.set(frameTime, avgFrameTime); } getMetric(name) { return this.metrics.get(name); } }9.3 生产环境部署优化生产环境需要考虑的优化措施// 构建优化配置 // webpack.config.js module.exports { // ...其他配置 optimization: { splitChunks: { chunks: all, cacheGroups: { threejs: { test: /[\\/]node_modules[\\/](three|three\.js)[\\/]/, name: threejs, priority: 20 }, vendors:
返回列表