第37节:移动端优化与触控交互
第37节:移动端优化与触控交互
概述
移动端3D应用开发面临着性能限制、触控交互、电池续航等多重挑战。本节将深入探索移动端优化的核心技术,包括性能分析工具、渲染优化策略、触控交互设计,以及跨平台适配方案,打造流畅的移动端3D体验。

移动端优化系统架构:
flowchard TDA[移动端优化系统] --> B[性能监控]A --> C[渲染优化]A --> D[触控交互]A --> E[资源管理]B --> B1[帧率监控]B --> B2[内存分析]B --> B3[功耗控制]C --> C1[LOD系统]C --> C2[分辨率缩放]C --> C3[批次合并]D --> D1[手势识别]D --> D2[触觉反馈]D --> D3[自适应UI]E --> E1[资源压缩]E --> E2[流式加载]E --> E3[缓存策略]B1 --> F[性能稳定]C1 --> G[流畅渲染]D1 --> H[自然交互]E1 --> I[快速加载]
核心原理深度解析
移动端性能瓶颈分析
移动设备与桌面设备的性能差异:
| 性能指标 | 高端手机 | 中端手机 | 低端手机 | 桌面电脑 |
|---|---|---|---|---|
| GPU性能 | 1.5 TFLOPS | 0.5 TFLOPS | 0.2 TFLOPS | 10+ TFLOPS |
| 内存带宽 | 50 GB/s | 25 GB/s | 12 GB/s | 500+ GB/s |
| 电池容量 | 4000 mAh | 3000 mAh | 2000 mAh | 无限制 |
| 热限制 | 严格 | 中等 | 宽松 | 宽松 |
移动端渲染优化技术对比
| 优化技术 | 原理 | 性能提升 | 质量影响 | 实现复杂度 |
|---|---|---|---|---|
| 动态分辨率 | 根据帧率调整分辨率 | 30-50% | 轻微 | 简单 |
| LOD系统 | 距离相关细节层次 | 20-40% | 可控 | 中等 |
| 批次合并 | 减少绘制调用 | 40-60% | 无 | 复杂 |
| 纹理压缩 | 使用压缩纹理格式 | 20-30% | 轻微 | 简单 |
| 遮挡剔除 | 跳过不可见物体 | 10-50% | 无 | 复杂 |
完整代码实现
移动端优化3D应用
<template><div class="mobile-optimization-container"><!-- 3D场景画布 --><canvas ref="mobileCanvas" class="mobile-canvas"></canvas><!-- 移动端控制面板 --><div class="mobile-controls" :class="{ 'controls-collapsed': controlsCollapsed }"><div class="controls-header" @click="toggleControls"><h3>📱 移动端优化</h3><span class="collapse-icon">{{ controlsCollapsed ? '▶' : '▼' }}</span></div><div v-if="!controlsCollapsed" class="controls-content"><div class="control-section"><h4>🎯 性能设置</h4><div class="performance-presets"><button v-for="preset in performancePresets" :key="preset.id"@click="applyPerformancePreset(preset)"class="preset-button":class="{ active: currentPreset?.id === preset.id }">{{ preset.name }}</button></div><div class="control-group"><label>目标帧率: {{ targetFPS }} FPS</label><input type="range" v-model="targetFPS" min="30" max="120" step="10"></div><div class="control-group"><label>分辨率缩放: {{ resolutionScale }}%</label><input type="range" v-model="resolutionScale" min="25" max="100" step="5"></div></div><div class="control-section"><h4>🖐️ 触控设置</h4><div class="touch-controls"><div class="control-group"><label>触控灵敏度: {{ touchSensitivity }}</label><input type="range" v-model="touchSensitivity" min="0.5" max="2" step="0.1"></div><div class="control-group"><label>惯性滚动: {{ inertiaStrength }}</label><input type="range" v-model="inertiaStrength" min="0" max="1" step="0.1"></div></div><div class="gesture-controls"><div class="control-group"><label>启用捏合缩放</label><input type="checkbox" v-model="pinchZoomEnabled"></div><div class="control-group"><label>启用旋转</label><input type="checkbox" v-model="rotationEnabled"></div><div class="control-group"><label>启用双击重置</label><input type="checkbox" v-model="doubleTapResetEnabled"></div></div></div><div class="control-section"><h4>⚡ 渲染优化</h4><div class="rendering-optimizations"><div class="control-group"><label>LOD级别: {{ lodLevel }}</label><input type="range" v-model="lodLevel" min="1" max="4" step="1"></div><div class="control-group"><label>阴影质量: {{ shadowQuality }}</label><input type="range" v-model="shadowQuality" min="0" max="3" step="1"></div><div class="control-group"><label>抗锯齿: {{ antiAliasing }}</label><input type="range" v-model="antiAliasing" min="0" max="2" step="1"></div></div><div class="optimization-toggles"><div class="control-group"><label>启用批次合并</label><input type="checkbox" v-model="batchingEnabled"></div><div class="control-group"><label>启用视锥剔除</label><input type="checkbox" v-model="frustumCullingEnabled"></div><div class="control-group"><label>启用纹理压缩</label><input type="checkbox" v-model="textureCompressionEnabled"></div></div></div><div class="control-section"><h4>🔋 电池优化</h4><div class="battery-optimizations"><div class="control-group"><label>功耗模式: {{ powerMode }}</label><select v-model="powerMode" class="mode-select"><option value="performance">性能优先</option><option value="balanced">平衡模式</option><option value="battery">省电模式</option></select></div><div class="control-group"><label>后台暂停: {{ backgroundPauseDelay }}s</label><input type="range" v-model="backgroundPauseDelay" min="1" max="10" step="1"></div></div><div class="thermal-controls"><div class="control-group"><label>温度限制: {{ thermalLimit }}°C</label><input type="range" v-model="thermalLimit" min="40" max="60" step="5"></div></div></div><div class="control-section"><h4>📊 性能监控</h4><div class="performance-stats"><div class="stat-item"><span>当前帧率:</span><span :class="getFPSClass(currentFPS)">{{ currentFPS }} FPS</span></div><div class="stat-item"><span>帧时间:</span><span>{{ frameTime.toFixed(1) }}ms</span></div><div class="stat-item"><span>内存使用:</span><span>{{ formatMemory(memoryUsage) }}</span></div><div class="stat-item"><span>绘制调用:</span><span>{{ drawCalls }}</span></div><div class="stat-item"><span>三角形数量:</span><span>{{ formatNumber(triangleCount) }}</span></div><div class="stat-item"><span>电池状态:</span><span :class="getBatteryClass(batteryLevel)">{{ batteryLevel }}%</span></div></div></div></div></div><!-- 触控控制区域 --><div class="touch-control-area"><div class="virtual-joystick" @touchstart="onJoystickStart" @touchmove="onJoystickMove" @touchend="onJoystickEnd"><div class="joystick-base"><div class="joystick-handle" :style="joystickStyle"></div></div></div><div class="action-buttons"><button class="action-button jump" @touchstart="onJumpTouch">跳跃</button><button class="action-button interact" @touchstart="onInteractTouch">交互</button></div></div><!-- 手势提示 --><div class="gesture-hints" v-if="showGestureHints"><div class="hint-item"><span class="hint-icon">🤏</span><span>捏合缩放</span></div><div class="hint-item"><span class="hint-icon">👆</span><span>拖拽旋转</span></div><div class="hint-item"><span class="hint-icon">👆👆</span><span>双击重置</span></div></div><!-- 性能警告 --><div v-if="showPerformanceWarning" class="performance-warning"><div class="warning-content"><span class="warning-icon">⚠️</span><span>性能警告: 帧率过低 ({{ currentFPS }} FPS)</span><button @click="applyPerformancePreset(performancePresets[2])" class="optimize-button">自动优化</button></div></div><!-- 电池警告 --><div v-if="showBatteryWarning" class="battery-warning"><div class="warning-content"><span class="warning-icon">🔋</span><span>电池电量低 ({{ batteryLevel }}%)</span><button @click="enablePowerSaving" class="power-save-button">开启省电模式</button></div></div><!-- 加载界面 --><div v-if="isLoading" class="loading-overlay"><div class="loading-content"><div class="mobile-loader"><div class="phone-frame"><div class="screen-content"><div class="loading-bar"></div><div class="loading-dots"><div class="dot"></div><div class="dot"></div><div class="dot"></div></div></div></div></div><h3>优化移动端体验...</h3><div class="loading-progress"><div class="progress-bar"><div class="progress-fill" :style="loadingProgressStyle"></div></div><span>{{ loadingMessage }}</span></div><div class="optimization-stats"><div class="stat">压缩纹理: {{ compressedTextures }}/{{ totalTextures }}</div><div class="stat">优化网格: {{ optimizedMeshes }}/{{ totalMeshes }}</div><div class="stat">加载资源: {{ formatMemory(loadedMemory) }}/{{ formatMemory(totalMemory) }}</div></div></div></div><!-- 调试信息 --><div class="debug-overlay" v-if="showDebugOverlay"><div class="debug-info"><div>设备: {{ deviceInfo }}</div><div>GPU: {{ gpuInfo }}</div><div>平台: {{ platformInfo }}</div><div>触控点: {{ touchPoints }} 个</div><div>温度: {{ deviceTemperature }}°C</div></div></div><!-- 快捷操作栏 --><div class="quick-actions"><button @click="toggleDebug" class="quick-button" :class="{ active: showDebugOverlay }">🐛</button><button @click="toggleStats" class="quick-button" :class="{ active: showStats }">📊</button><button @click="screenshot" class="quick-button">📸</button><button @click="toggleFullscreen" class="quick-button">{{ isFullscreen ? '📱' : '🔲' }}</button></div></div>
</template><script>
import { onMounted, onUnmounted, ref, reactive, computed } from 'vue';
import * as THREE from 'three';// 移动端性能监控器
class MobilePerformanceMonitor {constructor() {this.fpsHistory = [];this.frameTimeHistory = [];this.memoryHistory = [];this.maxHistorySize = 60; // 保存60帧数据this.lowFPSThreshold = 30;this.highFrameTimeThreshold = 33; // 对应30FPSthis.memoryWarningThreshold = 100 * 1024 * 1024; // 100MBthis.startTime = performance.now();this.frameCount = 0;}// 开始监控start() {this.startTime = performance.now();this.frameCount = 0;}// 更新监控数据update() {const currentTime = performance.now();const frameTime = currentTime - this.lastFrameTime || 0;this.lastFrameTime = currentTime;// 计算FPSthis.frameCount++;if (currentTime - this.startTime >= 1000) {const fps = Math.round((this.frameCount * 1000) / (currentTime - this.startTime));this.fpsHistory.push(fps);if (this.fpsHistory.length > this.maxHistorySize) {this.fpsHistory.shift();}this.frameCount = 0;this.startTime = currentTime;}// 记录帧时间this.frameTimeHistory.push(frameTime);if (this.frameTimeHistory.length > this.maxHistorySize) {this.frameTimeHistory.shift();}return {fps: this.fpsHistory[this.fpsHistory.length - 1] || 0,frameTime: frameTime,averageFPS: this.getAverageFPS(),averageFrameTime: this.getAverageFrameTime()};}// 获取平均FPSgetAverageFPS() {if (this.fpsHistory.length === 0) return 0;return Math.round(this.fpsHistory.reduce((a, b) => a + b) / this.fpsHistory.length);}// 获取平均帧时间getAverageFrameTime() {if (this.frameTimeHistory.length === 0) return 0;return this.frameTimeHistory.reduce((a, b) => a + b) / this.frameTimeHistory.length;}// 检查性能问题checkPerformanceIssues() {const currentFPS = this.fpsHistory[this.fpsHistory.length - 1] || 0;const averageFrameTime = this.getAverageFrameTime();const issues = [];if (currentFPS < this.lowFPSThreshold) {issues.push({type: 'low_fps',severity: currentFPS < 20 ? 'high' : 'medium',message: `帧率过低: ${currentFPS} FPS`});}if (averageFrameTime > this.highFrameTimeThreshold) {issues.push({type: 'high_frame_time',severity: 'medium',message: `帧时间过长: ${averageFrameTime.toFixed(1)}ms`});}return issues;}// 获取性能建议getPerformanceSuggestions(issues) {const suggestions = [];if (issues.some(issue => issue.type === 'low_fps')) {suggestions.push('降低分辨率缩放');suggestions.push('减少阴影质量');suggestions.push('启用批次合并');}if (issues.some(issue => issue.type === 'high_frame_time')) {suggestions.push('简化场景复杂度');suggestions.push('启用LOD系统');suggestions.push('减少绘制调用');}return suggestions;}
}// 移动端触控控制器
class MobileTouchController {constructor(domElement, camera, renderer) {this.domElement = domElement;this.camera = camera;this.renderer = renderer;this.touchState = {isRotating: false,isZooming: false,isPanning: false,lastTouchX: 0,lastTouchY: 0,scale: 1,touches: []};this.sensitivity = 1.0;this.inertia = 0.9;this.velocity = new THREE.Vector2();this.setupEventListeners();}// 设置事件监听器setupEventListeners() {this.domElement.addEventListener('touchstart', this.onTouchStart.bind(this), { passive: false });this.domElement.addEventListener('touchmove', this.onTouchMove.bind(this), { passive: false });this.domElement.addEventListener('touchend', this.onTouchEnd.bind(this), { passive: false });this.domElement.addEventListener('touchcancel', this.onTouchEnd.bind(this), { passive: false });}// 触摸开始onTouchStart(event) {event.preventDefault();this.touchState.touches = Array.from(event.touches);if (event.touches.length === 1) {// 单指触摸 - 旋转this.touchState.isRotating = true;this.touchState.lastTouchX = event.touches[0].clientX;this.touchState.lastTouchY = event.touches[0].clientY;} else if (event.touches.length === 2) {// 双指触摸 - 缩放/平移this.touchState.isZooming = true;this.touchState.lastTouchDistance = this.getTouchDistance(event.touches);}// 重置速度this.velocity.set(0, 0);}// 触摸移动onTouchMove(event) {event.preventDefault();const touches = Array.from(event.touches);this.touchState.touches = touches;if (this.touchState.isRotating && touches.length === 1) {this.handleRotation(touches[0]);} else if (this.touchState.isZooming && touches.length === 2) {this.handleZoom(touches);}// 更新最后触摸位置if (touches.length === 1) {this.touchState.lastTouchX = touches[0].clientX;this.touchState.lastTouchY = touches[0].clientY;}}// 触摸结束onTouchEnd(event) {event.preventDefault();const touches = Array.from(event.touches);this.touchState.touches = touches;if (touches.length === 0) {// 所有手指抬起this.touchState.isRotating = false;this.touchState.isZooming = false;this.touchState.isPanning = false;} else if (touches.length === 1) {// 从双指变为单指this.touchState.isZooming = false;this.touchState.isRotating = true;this.touchState.lastTouchX = touches[0].clientX;this.touchState.lastTouchY = touches[0].clientY;}}// 处理旋转handleRotation(touch) {const deltaX = (touch.clientX - this.touchState.lastTouchX) * this.sensitivity * 0.01;const deltaY = (touch.clientY - this.touchState.lastTouchY) * this.sensitivity * 0.01;// 更新相机旋转if (this.camera.rotation) {this.camera.rotation.y -= deltaX;this.camera.rotation.x -= deltaY;this.camera.rotation.x = Math.max(-Math.PI / 2, Math.min(Math.PI / 2, this.camera.rotation.x));}// 更新速度this.velocity.x = deltaX;this.velocity.y = deltaY;}// 处理缩放handleZoom(touches) {const currentDistance = this.getTouchDistance(touches);const deltaDistance = currentDistance - this.touchState.lastTouchDistance;// 更新缩放const zoomFactor = 1 + deltaDistance * 0.01;if (this.camera.zoom !== undefined) {this.camera.zoom = Math.max(0.1, Math.min(5, this.camera.zoom * zoomFactor));this.camera.updateProjectionMatrix();}this.touchState.lastTouchDistance = currentDistance;}// 获取触摸点距离getTouchDistance(touches) {const dx = touches[0].clientX - touches[1].clientX;const dy = touches[0].clientY - touches[1].clientY;return Math.sqrt(dx * dx + dy * dy);}// 更新惯性update(deltaTime) {if (!this.touchState.isRotating && (Math.abs(this.velocity.x) > 0.001 || Math.abs(this.velocity.y) > 0.001)) {// 应用惯性if (this.camera.rotation) {this.camera.rotation.y -= this.velocity.x * deltaTime * 10;this.camera.rotation.x -= this.velocity.y * deltaTime * 10;this.camera.rotation.x = Math.max(-Math.PI / 2, Math.min(Math.PI / 2, this.camera.rotation.x));}// 衰减速度this.velocity.multiplyScalar(this.inertia);}}// 设置灵敏度setSensitivity(sensitivity) {this.sensitivity = sensitivity;}// 设置惯性setInertia(inertia) {this.inertia = inertia;}
}// 移动端渲染优化器
class MobileRenderOptimizer {constructor(renderer, scene, camera) {this.renderer = renderer;this.scene = scene;this.camera = camera;this.optimizationState = {resolutionScale: 1.0,lodEnabled: true,shadowsEnabled: true,shadowsQuality: 1,batchingEnabled: false,textureCompressionEnabled: true};this.setupOptimizations();}// 设置优化setupOptimizations() {// 设置移动端友好的渲染参数this.renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));this.renderer.physicallyCorrectLights = false;this.renderer.toneMapping = THREE.ACESFilmicToneMapping;this.renderer.toneMappingExposure = 1.0;// 启用基本的优化this.enableBasicOptimizations();}// 启用基础优化enableBasicOptimizations() {// 使用更高效的阴影映射if (this.optimizationState.shadowsEnabled) {this.renderer.shadowMap.enabled = true;this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;}// 设置适当的抗锯齿this.renderer.antialias = this.optimizationState.resolutionScale >= 0.7;}// 应用分辨率缩放applyResolutionScale(scale) {this.optimizationState.resolutionScale = scale;const width = Math.floor(window.innerWidth * scale);const height = Math.floor(window.innerHeight * scale);this.renderer.setSize(width, height, false);if (this.camera.isPerspectiveCamera) {this.camera.aspect = width / height;this.camera.updateProjectionMatrix();}}// 应用LOD优化applyLODOptimization(level) {this.scene.traverse((object) => {if (object.isMesh && object.geometry) {// 根据LOD级别简化几何体const detailLevel = Math.max(1, Math.floor(level));this.optimizeGeometry(object.geometry, detailLevel);}});}// 优化几何体optimizeGeometry(geometry, level) {// 简化实现 - 实际应该使用更复杂的LOD系统if (level < 3 && geometry.attributes.position && geometry.attributes.position.count > 500) {// 对于复杂网格,可以在这里应用简化// 实际实现应该使用 THREE.SimplifyModifier 或类似工具}}// 应用阴影质量设置applyShadowQuality(quality) {this.optimizationState.shadowsQuality = quality;this.scene.traverse((object) => {if (object.isLight && object.shadow) {const resolution = this.getShadowResolution(quality);object.shadow.mapSize.set(resolution, resolution);object.shadow.needsUpdate = true;}});}// 获取阴影分辨率getShadowResolution(quality) {switch (quality) {case 0: return 512; // 低质量case 1: return 1024; // 中等质量case 2: return 2048; // 高质量case 3: return 4096; // 超高质量default: return 1024;}}// 应用批次合并applyBatchingOptimization() {if (!this.optimizationState.batchingEnabled) return;// 简化实现 - 实际应该使用 THREE.BufferGeometryUtils.mergeBufferGeometriesconsole.log('应用批次合并优化...');}// 应用纹理压缩applyTextureCompression() {if (!this.optimizationState.textureCompressionEnabled) return;this.scene.traverse((object) => {if (object.isMesh && object.material) {this.compressTexture(object.material);}});}// 压缩纹理compressTexture(material) {// 简化实现 - 实际应该使用压缩纹理格式if (material.map) {material.map.minFilter = THREE.LinearMipmapLinearFilter;material.map.generateMipmaps = true;}}// 获取性能统计getPerformanceStats() {const info = this.renderer.info;return {memory: {geometries: info.memory.geometries,textures: info.memory.textures},render: {calls: info.render.calls,triangles: info.render.triangles,points: info.render.points,lines: info.render.lines}};}// 应用性能预设applyPerformancePreset(preset) {switch (preset) {case 'low':this.optimizationState.resolutionScale = 0.5;this.optimizationState.shadowsEnabled = false;this.optimizationState.shadowsQuality = 0;this.optimizationState.lodEnabled = true;break;case 'medium':this.optimizationState.resolutionScale = 0.75;this.optimizationState.shadowsEnabled = true;this.optimizationState.shadowsQuality = 1;this.optimizationState.lodEnabled = true;break;case 'high':this.optimizationState.resolutionScale = 1.0;this.optimizationState.shadowsEnabled = true;this.optimizationState.shadowsQuality = 2;this.optimizationState.lodEnabled = false;break;}this.applyAllOptimizations();}// 应用所有优化applyAllOptimizations() {this.applyResolutionScale(this.optimizationState.resolutionScale);this.applyShadowQuality(this.optimizationState.shadowsQuality);this.applyBatchingOptimization();this.applyTextureCompression();if (this.optimizationState.lodEnabled) {this.applyLODOptimization(2); // 中等LOD级别}}
}// 移动端电池管理器
class MobileBatteryManager {constructor() {this.batteryLevel = 1.0;this.isCharging = false;this.chargeTime = 0;this.dischargeTime = 0;this.powerSavingMode = false;this.thermalThrottling = false;this.setupBatteryMonitoring();}// 设置电池监控async setupBatteryMonitoring() {if ('getBattery' in navigator) {try {const battery = await navigator.getBattery();this.updateBatteryInfo(battery);battery.addEventListener('levelchange', () => this.updateBatteryInfo(battery));battery.addEventListener('chargingchange', () => this.updateBatteryInfo(battery));battery.addEventListener('chargingtimechange', () => this.updateBatteryInfo(battery));battery.addEventListener('dischargingtimechange', () => this.updateBatteryInfo(battery));} catch (error) {console.warn('电池API不支持:', error);this.simulateBattery();}} else {console.warn('电池API不可用');this.simulateBattery();}}// 更新电池信息updateBatteryInfo(battery) {this.batteryLevel = battery.level;this.isCharging = battery.charging;this.chargeTime = battery.chargingTime;this.dischargeTime = battery.dischargingTime;}// 模拟电池(用于不支持API的设备)simulateBattery() {// 模拟电池消耗setInterval(() => {if (!this.isCharging) {this.batteryLevel = Math.max(0, this.batteryLevel - 0.001);} else {this.batteryLevel = Math.min(1, this.batteryLevel + 0.005);}}, 1000);}// 启用省电模式enablePowerSaving() {this.powerSavingMode = true;// 应用省电优化this.applyPowerSavingOptimizations();return {resolutionScale: 0.5,frameRateLimit: 30,shadowsEnabled: false,reflectionsEnabled: false,particleEffects: false};}// 禁用省电模式disablePowerSaving() {this.powerSavingMode = false;}// 应用省电优化applyPowerSavingOptimizations() {// 这些优化应该应用到渲染系统中console.log('应用省电优化...');}// 检查电池状态checkBatteryStatus() {const status = {level: this.batteryLevel,isCharging: this.isCharging,isLow: this.batteryLevel < 0.2,isCritical: this.batteryLevel < 0.1};return status;}// 获取电池建议getBatterySuggestions() {const suggestions = [];const status = this.checkBatteryStatus();if (status.isLow && !this.powerSavingMode) {suggestions.push('启用省电模式');}if (status.isCritical) {suggestions.push('建议连接充电器');}return suggestions;}
}export default {name: 'MobileOptimization',setup() {const mobileCanvas = ref(null);const controlsCollapsed = ref(false);const targetFPS = ref(60);const resolutionScale = ref(75);const touchSensitivity = ref(1.0);const inertiaStrength = ref(0.8);const pinchZoomEnabled = ref(true);const rotationEnabled = ref(true);const doubleTapResetEnabled = ref(true);const lodLevel = ref(2);const shadowQuality = ref(1);const antiAliasing = ref(1);const batchingEnabled = ref(true);const frustumCullingEnabled = ref(true);const textureCompressionEnabled = ref(true);const powerMode = ref('balanced');const backgroundPauseDelay = ref(3);const thermalLimit = ref(45);const currentFPS = ref(0);const frameTime = ref(0);const memoryUsage = ref(0);const drawCalls = ref(0);const triangleCount = ref(0);const batteryLevel = ref(100);const showGestureHints = ref(true);const showPerformanceWarning = ref(false);const showBatteryWarning = ref(false);const isLoading = ref(true);const loadingMessage = ref('初始化移动端优化...');const compressedTextures = ref(0);const totalTextures = ref(50);const optimizedMeshes = ref(0);const totalMeshes = ref(20);const loadedMemory = ref(0);const totalMemory = ref(50 * 1024 * 1024);const showDebugOverlay = ref(false);const showStats = ref(true);const isFullscreen = ref(false);const joystickPosition = reactive({ x: 0, y: 0 });const performancePresets = [{ id: 'low', name: '低功耗' },{ id: 'medium', name: '平衡' },{ id: 'high', name: '高性能' },{ id: 'auto', name: '自动' }];let currentPreset = ref(performancePresets[1]);let scene, camera, renderer, touchController, performanceMonitor, renderOptimizer, batteryManager;let clock, stats;let frameCount = 0;let lastFpsUpdate = 0;// 设备信息const deviceInfo = computed(() => {return isMobileDevice() ? '移动设备' : '桌面设备';});const gpuInfo = computed(() => {return renderer ? renderer.capabilities.getMaxAnisotropy() + 'x 各向异性' : '未知';});const platformInfo = computed(() => {const ua = navigator.userAgent;if (/android/i.test(ua)) return 'Android';if (/iPad|iPhone|iPod/.test(ua)) return 'iOS';if (/Windows/.test(ua)) return 'Windows';if (/Mac/.test(ua)) return 'macOS';if (/Linux/.test(ua)) return 'Linux';return '未知';});const touchPoints = ref(0);const deviceTemperature = ref(35);// 初始化场景const initScene = async () => {// 创建场景scene = new THREE.Scene();scene.background = new THREE.Color(0x87ceeb);// 创建相机camera = new THREE.PerspectiveCamera(75,window.innerWidth / window.innerHeight,0.1,1000);camera.position.set(0, 5, 10);// 创建渲染器renderer = new THREE.WebGLRenderer({canvas: mobileCanvas.value,antialias: true,powerPreference: "high-performance"});// 初始化性能监控器performanceMonitor = new MobilePerformanceMonitor();performanceMonitor.start();// 初始化渲染优化器renderOptimizer = new MobileRenderOptimizer(renderer, scene, camera);// 初始化触控控制器touchController = new MobileTouchController(renderer.domElement, camera, renderer);// 初始化电池管理器batteryManager = new MobileBatteryManager();// 设置初始优化applyCurrentOptimizations();// 创建测试场景loadingMessage.value = '创建优化场景...';await createOptimizedScene();// 设置事件监听setupEventListeners();isLoading.value = false;// 启动渲染循环clock = new THREE.Clock();animate();};// 创建优化场景const createOptimizedScene = async () => {// 添加光照const ambientLight = new THREE.AmbientLight(0x404040, 0.6);scene.add(ambientLight);const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);directionalLight.position.set(50, 50, 25);directionalLight.castShadow = true;scene.add(directionalLight);// 创建优化地面const groundGeometry = new THREE.PlaneGeometry(100, 100);const groundMaterial = new THREE.MeshStandardMaterial({ color: 0x3a9d23,roughness: 0.8,metalness: 0.2});const ground = new THREE.Mesh(groundGeometry, groundMaterial);ground.rotation.x = -Math.PI / 2;ground.receiveShadow = true;scene.add(ground);// 创建优化物体(使用简单的几何体)createOptimizedObjects();// 模拟加载过程await simulateOptimizationProcess();};// 创建优化物体const createOptimizedObjects = () => {// 使用简单几何体创建场景物体const geometries = [new THREE.BoxGeometry(2, 2, 2),new THREE.SphereGeometry(1, 16, 16),new THREE.ConeGeometry(1, 3, 8),new THREE.CylinderGeometry(1, 1, 2, 12)];const materials = [new THREE.MeshStandardMaterial({ color: 0xff4444 }),new THREE.MeshStandardMaterial({ color: 0x44ff44 }),new THREE.MeshStandardMaterial({ color: 0x4444ff }),new THREE.MeshStandardMaterial({ color: 0xffff44 })];for (let i = 0; i < 20; i++) {const geometry = geometries[i % geometries.length];const material = materials[i % materials.length];const mesh = new THREE.Mesh(geometry, material);mesh.position.set((Math.random() - 0.5) * 40,Math.random() * 5,(Math.random() - 0.5) * 40);mesh.castShadow = true;mesh.receiveShadow = true;scene.add(mesh);}};// 模拟优化过程const simulateOptimizationProcess = async () => {const steps = ['压缩纹理...','优化网格...','合并批次...','设置LOD...','应用压缩...'];for (let i = 0; i < steps.length; i++) {loadingMessage.value = steps[i];compressedTextures.value = Math.floor((i + 1) / steps.length * totalTextures.value);optimizedMeshes.value = Math.floor((i + 1) / steps.length * totalMeshes.value);loadedMemory.value = Math.floor((i + 1) / steps.length * totalMemory.value);await new Promise(resolve => setTimeout(resolve, 500));}};// 设置事件监听const setupEventListeners = () => {// 窗口大小变化window.addEventListener('resize', onWindowResize);// 电池状态变化setInterval(updateBatteryStatus, 5000);// 设备温度模拟setInterval(updateDeviceTemperature, 10000);// 隐藏手势提示setTimeout(() => {showGestureHints.value = false;}, 5000);};// 窗口大小变化const onWindowResize = () => {if (!camera || !renderer) return;camera.aspect = window.innerWidth / window.innerHeight;camera.updateProjectionMatrix();renderOptimizer.applyResolutionScale(resolutionScale.value / 100);};// 更新电池状态const updateBatteryStatus = () => {const status = batteryManager.checkBatteryStatus();batteryLevel.value = Math.round(status.level * 100);// 显示电池警告showBatteryWarning.value = status.isLow && !batteryManager.powerSavingMode;};// 更新设备温度const updateDeviceTemperature = () => {// 模拟设备温度变化const baseTemp = 35;const loadFactor = currentFPS.value < 30 ? 0.3 : 0.1;const randomVariation = (Math.random() - 0.5) * 2;deviceTemperature.value = Math.max(30, Math.min(60, baseTemp + loadFactor * 10 + randomVariation));// 温度警告if (deviceTemperature.value > thermalLimit.value) {applyPerformancePreset(performancePresets[0]); // 切换到低功耗模式}};// 应用性能预设const applyPerformancePreset = (preset) => {currentPreset.value = preset;switch (preset.id) {case 'low':resolutionScale.value = 50;shadowQuality.value = 0;targetFPS.value = 30;powerMode.value = 'battery';break;case 'medium':resolutionScale.value = 75;shadowQuality.value = 1;targetFPS.value = 60;powerMode.value = 'balanced';break;case 'high':resolutionScale.value = 100;shadowQuality.value = 2;targetFPS.value = 120;powerMode.value = 'performance';break;case 'auto':// 基于设备性能自动选择applyAutoOptimization();break;}applyCurrentOptimizations();};// 应用自动优化const applyAutoOptimization = () => {// 基于设备性能自动选择设置const isLowEndDevice = isMobileDevice() && !isHighEndDevice();if (isLowEndDevice) {applyPerformancePreset(performancePresets[0]);} else {applyPerformancePreset(performancePresets[1]);}};// 应用当前优化设置const applyCurrentOptimizations = () => {if (!renderOptimizer) return;// 应用分辨率缩放renderOptimizer.applyResolutionScale(resolutionScale.value / 100);// 应用阴影质量renderOptimizer.applyShadowQuality(shadowQuality.value);// 应用LOD优化renderOptimizer.applyLODOptimization(lodLevel.value);// 应用触控设置if (touchController) {touchController.setSensitivity(touchSensitivity.value);touchController.setInertia(inertiaStrength.value);}};// 检查设备类型const isMobileDevice = () => {return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);};// 检查是否高端设备const isHighEndDevice = () => {// 简化检测 - 实际应该使用更复杂的特征检测const hasHighDpi = window.devicePixelRatio >= 2;const hasLargeScreen = window.innerWidth >= 400;return hasHighDpi && hasLargeScreen;};// 切换控制面板const toggleControls = () => {controlsCollapsed.value = !controlsCollapsed.value;};// 虚拟摇杆控制const onJoystickStart = (event) => {event.preventDefault();// 实际实现应该处理触摸事件};const onJoystickMove = (event) => {event.preventDefault();// 实际实现应该处理触摸移动};const onJoystickEnd = (event) => {event.preventDefault();joystickPosition.x = 0;joystickPosition.y = 0;};// 动作按钮const onJumpTouch = () => {console.log('跳跃动作');// 实际实现应该触发跳跃动画};const onInteractTouch = () => {console.log('交互动作');// 实际实现应该触发交互逻辑};// 启用省电模式const enablePowerSaving = () => {batteryManager.enablePowerSaving();applyPerformancePreset(performancePresets[0]);showBatteryWarning.value = false;};// 切换调试信息const toggleDebug = () => {showDebugOverlay.value = !showDebugOverlay.value;};// 切换统计信息const toggleStats = () => {showStats.value = !showStats.value;};// 截图功能const screenshot = () => {if (!renderer) return;renderer.domElement.toBlob((blob) => {const url = URL.createObjectURL(blob);const a = document.createElement('a');a.href = url;a.download = `screenshot-${Date.now()}.png`;a.click();URL.revokeObjectURL(url);});};// 切换全屏const toggleFullscreen = () => {if (!document.fullscreenElement) {document.documentElement.requestFullscreen().catch(err => {console.log(`全屏请求错误: ${err.message}`);});isFullscreen.value = true;} else {if (document.exitFullscreen) {document.exitFullscreen();isFullscreen.value = false;}}};// 动画循环const animate = () => {requestAnimationFrame(animate);const deltaTime = clock.getDelta();// 更新性能监控const performanceData = performanceMonitor.update();currentFPS.value = performanceData.fps;frameTime.value = performanceData.frameTime;// 更新触控控制器if (touchController) {touchController.update(deltaTime);}// 更新性能统计updatePerformanceStats();// 检查性能问题const issues = performanceMonitor.checkPerformanceIssues();showPerformanceWarning.value = issues.length > 0;// 应用动态优化applyDynamicOptimizations(issues);// 渲染场景renderer.render(scene, camera);// 更新FPS计数updateFPSCounter(deltaTime);};// 更新性能统计const updatePerformanceStats = () => {if (!renderOptimizer) return;const stats = renderOptimizer.getPerformanceStats();memoryUsage.value = stats.memory.geometries * 1024 * 1024 + stats.memory.textures * 512 * 1024;drawCalls.value = stats.render.calls;triangleCount.value = stats.render.triangles;};// 应用动态优化const applyDynamicOptimizations = (issues) => {if (currentPreset.value.id === 'auto') {// 自动模式下的动态优化if (issues.some(issue => issue.type === 'low_fps')) {// 如果帧率低,降低质量resolutionScale.value = Math.max(25, resolutionScale.value - 5);applyCurrentOptimizations();} else if (currentFPS.value > targetFPS.value + 10 && resolutionScale.value < 100) {// 如果性能充足,提高质量resolutionScale.value = Math.min(100, resolutionScale.value + 5);applyCurrentOptimizations();}}};// 更新FPS计数器const updateFPSCounter = (deltaTime) => {frameCount++;lastFpsUpdate += deltaTime;if (lastFpsUpdate >= 1.0) {currentFPS.value = Math.round(frameCount / lastFpsUpdate);frameCount = 0;lastFpsUpdate = 0;}};// 计算属性const joystickStyle = computed(() => ({transform: `translate(${joystickPosition.x * 20}px, ${joystickPosition.y * 20}px)`}));const loadingProgressStyle = computed(() => ({width: '100%'}));// 工具函数const getFPSClass = (fps) => {if (fps >= 50) return 'good';if (fps >= 30) return 'warning';return 'bad';};const getBatteryClass = (level) => {if (level >= 50) return 'good';if (level >= 20) return 'warning';return 'bad';};const formatMemory = (bytes) => {if (bytes >= 1024 * 1024) {return (bytes / (1024 * 1024)).toFixed(1) + ' MB';} else if (bytes >= 1024) {return (bytes / 1024).toFixed(1) + ' KB';}return bytes + ' B';};const formatNumber = (num) => {if (num >= 1000000) {return (num / 1000000).toFixed(1) + 'M';} else if (num >= 1000) {return (num / 1000).toFixed(1) + 'K';}return num.toString();};onMounted(() => {initScene();});onUnmounted(() => {if (renderer) {renderer.dispose();}window.removeEventListener('resize', onWindowResize);});return {mobileCanvas,controlsCollapsed,targetFPS,resolutionScale,touchSensitivity,inertiaStrength,pinchZoomEnabled,rotationEnabled,doubleTapResetEnabled,lodLevel,shadowQuality,antiAliasing,batchingEnabled,frustumCullingEnabled,textureCompressionEnabled,powerMode,backgroundPauseDelay,thermalLimit,currentFPS,frameTime,memoryUsage,drawCalls,triangleCount,batteryLevel,showGestureHints,showPerformanceWarning,showBatteryWarning,isLoading,loadingMessage,compressedTextures,totalTextures,optimizedMeshes,totalMeshes,loadedMemory,totalMemory,showDebugOverlay,showStats,isFullscreen,joystickPosition,performancePresets,currentPreset,deviceInfo,gpuInfo,platformInfo,touchPoints,deviceTemperature,joystickStyle,loadingProgressStyle,toggleControls,applyPerformancePreset,onJoystickStart,onJoystickMove,onJoystickEnd,onJumpTouch,onInteractTouch,enablePowerSaving,toggleDebug,toggleStats,screenshot,toggleFullscreen,getFPSClass,getBatteryClass,formatMemory,formatNumber};}
};
</script><style scoped>
.mobile-optimization-container {width: 100%;height: 100vh;position: relative;background: #000;overflow: hidden;touch-action: none;-webkit-touch-callout: none;-webkit-user-select: none;user-select: none;
}.mobile-canvas {width: 100%;height: 100%;display: block;
}.mobile-controls {position: absolute;top: 10px;right: 10px;width: 320px;max-width: 90vw;background: rgba(0, 0, 0, 0.95);border-radius: 12px;color: white;backdrop-filter: blur(20px);border: 1px solid rgba(255, 255, 255, 0.1);box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);transition: all 0.3s ease;overflow: hidden;
}.mobile-controls.controls-collapsed {height: 50px;
}.controls-header {display: flex;justify-content: space-between;align-items: center;padding: 15px;cursor: pointer;background: rgba(0, 0, 0, 0.8);
}.controls-header h3 {margin: 0;color: #00ff88;font-size: 16px;
}.collapse-icon {color: #ccc;font-size: 14px;
}.controls-content {padding: 15px;max-height: 70vh;overflow-y: auto;
}.control-section {margin-bottom: 20px;padding-bottom: 15px;border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}.control-section:last-child {margin-bottom: 0;border-bottom: none;
}.control-section h4 {color: #00aaff;margin-bottom: 15px;font-size: 14px;
}.performance-presets {display: grid;grid-template-columns: 1fr 1fr;gap: 8px;margin-bottom: 15px;
}.preset-button {padding: 8px;border: 1px solid #444;border-radius: 6px;background: rgba(255, 255, 255, 0.05);color: white;cursor: pointer;font-size: 12px;transition: all 0.3s ease;
}.preset-button:hover {border-color: #00ff88;
}.preset-button.active {border-color: #00ff88;background: rgba(0, 255, 136, 0.2);
}.control-group {margin-bottom: 15px;
}.control-group label {display: flex;justify-content: space-between;align-items: center;margin-bottom: 8px;color: #ccc;font-size: 14px;
}.control-group input[type="range"] {width: 100%;height: 6px;background: #444;border-radius: 3px;outline: none;opacity: 0.7;transition: opacity 0.2s;
}.control-group input[type="range"]:hover {opacity: 1;
}.control-group input[type="range"]::-webkit-slider-thumb {appearance: none;width: 18px;height: 18px;border-radius: 50%;background: #00ff88;cursor: pointer;box-shadow: 0 0 10px rgba(0, 255, 136, 0.5);
}.control-group input[type="checkbox"] {width: 20px;height: 20px;accent-color: #00ff88;
}.mode-select {width: 100%;padding: 8px;border: 1px solid #444;border-radius: 6px;background: rgba(255, 255, 255, 0.1);color: white;font-size: 14px;
}.touch-controls,
.rendering-optimizations,
.battery-optimizations {margin-bottom: 15px;
}.gesture-controls,
.optimization-toggles,
.thermal-controls {display: grid;grid-template-columns: 1fr;gap: 10px;
}.performance-stats {display: flex;flex-direction: column;gap: 8px;
}.stat-item {display: flex;justify-content: space-between;align-items: center;padding: 6px 0;font-size: 12px;
}.stat-item span:first-child {color: #ccc;
}.stat-item span:last-child.good {color: #00ff88;
}.stat-item span:last-child.warning {color: #ffaa00;
}.stat-item span:last-child.bad {color: #ff4444;
}.touch-control-area {position: absolute;bottom: 20px;left: 20px;right: 20px;display: flex;justify-content: space-between;align-items: flex-end;pointer-events: none;
}.virtual-joystick {width: 120px;height: 120px;background: rgba(255, 255, 255, 0.1);border-radius: 50%;backdrop-filter: blur(10px);border: 2px solid rgba(255, 255, 255, 0.3);pointer-events: auto;touch-action: none;
}.joystick-base {width: 100%;height: 100%;position: relative;
}.joystick-handle {width: 50px;height: 50px;background: rgba(0, 255, 136, 0.8);border-radius: 50%;position: absolute;top: 50%;left: 50%;transform: translate(-50%, -50%);transition: transform 0.1s ease;box-shadow: 0 0 20px rgba(0, 255, 136, 0.5);
}.action-buttons {display: flex;flex-direction: column;gap: 15px;pointer-events: auto;
}.action-button {padding: 15px 20px;border: none;border-radius: 50%;background: rgba(255, 255, 255, 0.1);color: white;font-size: 14px;backdrop-filter: blur(10px);border: 2px solid rgba(255, 255, 255, 0.3);cursor: pointer;transition: all 0.3s ease;touch-action: manipulation;
}.action-button:active {background: rgba(0, 255, 136, 0.3);transform: scale(0.95);
}.action-button.jump {background: rgba(255, 170, 0, 0.8);
}.action-button.interact {background: rgba(0, 170, 255, 0.8);
}.gesture-hints {position: absolute;top: 50%;left: 50%;transform: translate(-50%, -50%);background: rgba(0, 0, 0, 0.8);padding: 15px;border-radius: 10px;backdrop-filter: blur(10px);border: 1px solid rgba(255, 255, 255, 0.2);display: flex;flex-direction: column;gap: 10px;
}.hint-item {display: flex;align-items: center;gap: 10px;font-size: 14px;color: #ccc;
}.hint-icon {font-size: 18px;
}.performance-warning,
.battery-warning {position: absolute;top: 70px;left: 50%;transform: translateX(-50%);background: rgba(255, 68, 68, 0.9);padding: 10px 15px;border-radius: 8px;backdrop-filter: blur(10px);border: 1px solid rgba(255, 255, 255, 0.2);z-index: 1000;
}.warning-content {display: flex;align-items: center;gap: 10px;font-size: 14px;color: white;
}.warning-icon {font-size: 16px;
}.optimize-button,
.power-save-button {padding: 5px 10px;border: none;border-radius: 4px;background: rgba(255, 255, 255, 0.2);color: white;cursor: pointer;font-size: 12px;transition: background 0.3s;
}.optimize-button:hover,
.power-save-button:hover {background: rgba(255, 255, 255, 0.3);
}.loading-overlay {position: absolute;top: 0;left: 0;width: 100%;height: 100%;background: linear-gradient(135deg, #1a2a6c, #b21f1f, #fdbb2d);display: flex;justify-content: center;align-items: center;z-index: 1000;
}.loading-content {text-align: center;color: white;
}.mobile-loader {margin-bottom: 30px;
}.phone-frame {width: 200px;height: 400px;background: #333;border-radius: 20px;padding: 20px;position: relative;margin: 0 auto;border: 4px solid #555;
}.screen-content {width: 100%;height: 100%;background: #1a1a1a;border-radius: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;gap: 20px;
}.loading-bar {width: 80%;height: 4px;background: rgba(255, 255, 255, 0.2);border-radius: 2px;overflow: hidden;
}.loading-bar::after {content: '';display: block;width: 100%;height: 100%;background: #00ff88;border-radius: 2px;animation: loadingBar 2s infinite ease-in-out;
}.loading-dots {display: flex;gap: 8px;
}.dot {width: 8px;height: 8px;background: #00ff88;border-radius: 50%;animation: loadingDots 1.4s infinite ease-in-out;
}.dot:nth-child(1) { animation-delay: 0s; }
.dot:nth-child(2) { animation-delay: 0.2s; }
.dot:nth-child(3) { animation-delay: 0.4s; }.loading-content h3 {margin-bottom: 20px;color: white;font-size: 18px;
}.loading-progress {width: 300px;margin: 0 auto 15px;
}.progress-bar {width: 100%;height: 6px;background: rgba(255, 255, 255, 0.2);border-radius: 3px;overflow: hidden;margin-bottom: 10px;
}.progress-fill {height: 100%;background: linear-gradient(90deg, #00ff88, #00aaff);border-radius: 3px;transition: width 0.3s ease;
}.optimization-stats {display: flex;flex-direction: column;gap: 8px;font-size: 12px;color: #ccc;
}.debug-overlay {position: absolute;top: 60px;left: 10px;background: rgba(0, 0, 0, 0.8);padding: 10px;border-radius: 6px;backdrop-filter: blur(10px);border: 1px solid rgba(255, 255, 255, 0.1);
}.debug-info {display: flex;flex-direction: column;gap: 4px;font-size: 11px;color: #ccc;
}.quick-actions {position: absolute;bottom: 20px;right: 20px;display: flex;flex-direction: column;gap: 10px;
}.quick-button {width: 50px;height: 50px;border: none;border-radius: 50%;background: rgba(255, 255, 255, 0.1);color: white;font-size: 18px;backdrop-filter: blur(10px);border: 2px solid rgba(255, 255, 255, 0.3);cursor: pointer;transition: all 0.3s ease;display: flex;justify-content: center;align-items: center;
}.quick-button:hover {background: rgba(255, 255, 255, 0.2);
}.quick-button.active {background: rgba(0, 255, 136, 0.3);border-color: #00ff88;
}@keyframes loadingBar {0% { transform: translateX(-100%); }50% { transform: translateX(0); }100% { transform: translateX(100%); }
}@keyframes loadingDots {0%, 80%, 100% {transform: scale(0.8);opacity: 0.5;}40% {transform: scale(1.2);opacity: 1;}
}/* 移动端响应式设计 */
@media (max-width: 768px) {.mobile-controls {width: 280px;right: 10px;top: 10px;}.controls-content {padding: 10px;}.performance-presets {grid-template-columns: 1fr;}.touch-control-area {bottom: 10px;left: 10px;right: 10px;}.virtual-joystick {width: 100px;height: 100px;}.joystick-handle {width: 40px;height: 40px;}.action-button {padding: 12px 16px;font-size: 12px;}.quick-actions {bottom: 10px;right: 10px;}.quick-button {width: 45px;height: 45px;font-size: 16px;}
}@media (max-width: 480px) {.mobile-controls {width: 250px;}.virtual-joystick {width: 80px;height: 80px;}.joystick-handle {width: 35px;height: 35px;}.action-button {padding: 10px 14px;font-size: 11px;}.gesture-hints {font-size: 12px;padding: 10px;}
}/* 防止文本选择 */
.no-select {-webkit-touch-callout: none;-webkit-user-select: none;-khtml-user-select: none;-moz-user-select: none;-ms-user-select: none;user-select: none;
}/* 改善触控反馈 */
@media (hover: none) and (pointer: coarse) {.preset-button:active,.action-button:active,.quick-button:active {transform: scale(0.95);transition: transform 0.1s ease;}
}
</style>
高级移动端优化技术
自适应性能管理系统
// 自适应性能管理器
class AdaptivePerformanceManager {constructor() {this.performanceTiers = this.detectPerformanceTier();this.qualityLevels = {low: this.createLowQualityConfig(),medium: this.createMediumQualityConfig(),high: this.createHighQualityConfig(),ultra: this.createUltraQualityConfig()};this.currentConfig = this.qualityLevels[this.performanceTiers];this.performanceHistory = [];this.adaptationEnabled = true;}// 检测性能等级detectPerformanceTier() {const score = this.calculatePerformanceScore();if (score >= 80) return 'ultra';if (score >= 60) return 'high';if (score >= 40) return 'medium';return 'low';}// 计算性能分数calculatePerformanceScore() {let score = 0;// GPU 性能评估const gpuScore = this.evaluateGPUPerformance();// CPU 性能评估const cpuScore = this.evaluateCPUPerformance();// 内存评估const memoryScore = this.evaluateMemory();// 设备类型加分const deviceBonus = this.getDeviceBonus();score = (gpuScore * 0.5) + (cpuScore * 0.3) + (memoryScore * 0.2) + deviceBonus;return Math.min(100, Math.max(0, score));}// 评估GPU性能evaluateGPUPerformance() {const canvas = document.createElement('canvas');const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');if (!gl) return 30;const debugInfo = gl.getExtension('WEBGL_debug_renderer_info');if (debugInfo) {const renderer = gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL);return this.scoreGPUByRenderer(renderer);}// 基于支持的扩展评估return this.scoreGPUByExtensions(gl);}// 根据渲染器评分GPUscoreGPUByRenderer(renderer) {const highEndGPUs = ['adreno', 'mali-g', 'apple gpu', 'nvidia', 'amd radeon'];const midRangeGPUs = ['mali-t', 'powervr', 'intel hd', 'adreno 5'];const rendererLower = renderer.toLowerCase();if (highEndGPUs.some(gpu => rendererLower.includes(gpu))) {return 80;} else if (midRangeGPUs.some(gpu => rendererLower.includes(gpu))) {return 60;} else {return 40;}}// 根据扩展评分GPUscoreGPUByExtensions(gl) {let score = 30;// 检查支持的扩展const extensions = ['EXT_texture_filter_anisotropic','OES_texture_float','WEBGL_compressed_texture_etc','WEBGL_compressed_texture_astc'];const supportedExtensions = extensions.filter(ext => gl.getExtension(ext));score += supportedExtensions.length * 10;return Math.min(80, score);}// 评估CPU性能evaluateCPUPerformance() {// 通过简单基准测试评估CPU性能const startTime = performance.now();let operations = 0;// 执行一些数学运算for (let i = 0; i < 1000000; i++) {operations += Math.sqrt(i) * Math.sin(i);}const endTime = performance.now();const duration = endTime - startTime;// 基于执行时间评分if (duration < 50) return 80;if (duration < 100) return 60;if (duration < 200) return 40;return 20;}// 评估内存evaluateMemory() {// 检查设备内存(近似值)if (navigator.deviceMemory) {return navigator.deviceMemory * 20; // 1GB = 20分, 8GB = 100分}// 基于用户代理的启发式评估return this.estimateMemoryFromUA();}// 从用户代理估算内存estimateMemoryFromUA() {const ua = navigator.userAgent;if (/iPhone.*OS 1[3-9]/.test(ua)) return 80; // 较新iPhoneif (/iPad.*OS 1[3-9]/.test(ua)) return 70; // 较新iPadif (/Android 1[0-9]/.test(ua)) return 60; // 较新Androidif (/iPhone|iPad/.test(ua)) return 50; // 其他iOS设备if (/Android/.test(ua)) return 40; // 其他Android设备return 70; // 桌面设备默认较高分数}// 获取设备加分getDeviceBonus() {const ua = navigator.userAgent;if (/iPhone1[3-9]/.test(ua)) return 10; // iPhone 12及更新if (/iPad[8-9]/.test(ua)) return 10; // 较新iPadif (/SM-G99/.test(ua)) return 8; // 三星旗舰return 0;}// 创建低质量配置createLowQualityConfig() {return {resolutionScale: 0.5,shadowEnabled: false,antialias: false,textureQuality: 'low',maxLights: 2,maxParticles: 50,lodBias: 2.0,physicsQuality: 'low'};}// 创建中等质量配置createMediumQualityConfig() {return {resolutionScale: 0.75,shadowEnabled: true,shadowQuality: 'low',antialias: false,textureQuality: 'medium',maxLights: 4,maxParticles: 100,lodBias: 1.5,physicsQuality: 'medium'};}// 创建高质量配置createHighQualityConfig() {return {resolutionScale: 1.0,shadowEnabled: true,shadowQuality: 'medium',antialias: true,textureQuality: 'high',maxLights: 8,maxParticles: 200,lodBias: 1.0,physicsQuality: 'high'};}// 创建超高质量配置createUltraQualityConfig() {return {resolutionScale: 1.0,shadowEnabled: true,shadowQuality: 'high',antialias: true,textureQuality: 'ultra',maxLights: 16,maxParticles: 500,lodBias: 0.5,physicsQuality: 'ultra'};}// 动态调整配置adaptBasedOnPerformance(currentFPS, targetFPS) {if (!this.adaptationEnabled) return;this.performanceHistory.push(currentFPS);if (this.performanceHistory.length > 60) {this.performanceHistory.shift();}const averageFPS = this.performanceHistory.reduce((a, b) => a + b) / this.performanceHistory.length;if (averageFPS < targetFPS * 0.8) {// 性能不足,降低质量this.downgradeQuality();} else if (averageFPS > targetFPS * 1.2 && this.canUpgradeQuality()) {// 性能充足,提升质量this.upgradeQuality();}}// 降低质量downgradeQuality() {const tiers = ['ultra', 'high', 'medium', 'low'];const currentIndex = tiers.indexOf(this.performanceTiers);if (currentIndex < tiers.length - 1) {this.performanceTiers = tiers[currentIndex + 1];this.currentConfig = this.qualityLevels[this.performanceTiers];console.log(`性能适配: 降低到 ${this.performanceTiers} 质量`);}}// 提升质量upgradeQuality() {const tiers = ['ultra', 'high', 'medium', 'low'];const currentIndex = tiers.indexOf(this.performanceTiers);if (currentIndex > 0) {this.performanceTiers = tiers[currentIndex - 1];this.currentConfig = this.qualityLevels[this.performanceTiers];console.log(`性能适配: 提升到 ${this.performanceTiers} 质量`);}}// 检查是否可以提升质量canUpgradeQuality() {const tiers = ['ultra', 'high', 'medium', 'low'];const currentIndex = tiers.indexOf(this.performanceTiers);return currentIndex > 0;}// 获取当前配置getCurrentConfig() {return this.currentConfig;}// 启用/禁用自适应setAdaptationEnabled(enabled) {this.adaptationEnabled = enabled;}
}
注意事项与最佳实践
-
性能优化策略
- 优先考虑60FPS的流畅体验
- 使用适当的纹理压缩格式(ASTC、ETC2)
- 实现动态分辨率缩放
- 监控内存使用和温度
-
触控交互设计
- 提供足够的触控目标(最小44px)
- 实现手势反馈和视觉提示
- 支持多指触控和复杂手势
- 优化触摸响应时间
-
电池续航优化
- 在后台时暂停渲染
- 降低非活动标签页的更新频率
- 使用requestAnimationFrame进行节流
- 监控电池状态并调整画质
-
跨平台兼容性
- 测试不同设备和浏览器
- 提供优雅的性能降级
- 支持多种屏幕比例和分辨率
- 处理方向变化和键盘弹出
下一节预告
第38节:WebGL 2.0与Three.js新特性
将深入探索WebGL 2.0的核心功能,包括:计算着色器、变换反馈、多重渲染目标、实例化渲染,以及Three.js对这些新特性的支持实现。
