WebGL与WebGPU实战:43个案例从基础渲染到高级优化

发布时间:2026/7/23 4:36:13
WebGL与WebGPU实战:43个案例从基础渲染到高级优化 最近在开发WebGL/WebGPU项目时经常遇到各种技术难题和性能瓶颈网上资料分散且不成体系。本文整合了43个实战案例覆盖从基础渲染到高级优化的完整解决方案包含Three.js、Unity WebGL、百度地图集成等热门场景每个案例都提供可运行的代码示例和详细的排错指南。无论你是前端开发者想要入门3D可视化还是游戏开发者需要优化WebGL性能都能从本文找到实用的解决方案。文章特别针对当前热门的WebGPU大模型渲染、点聚合优化、材质丢失等高频问题提供了专项突破方案。1. WebGL与WebGPU技术背景与核心概念1.1 WebGL技术概述WebGLWeb Graphics Library是一种基于OpenGL ES的JavaScript API允许在浏览器中渲染交互式2D和3D图形。它直接利用GPU进行图形计算为网页提供硬件加速的图形渲染能力。WebGL 1.0基于OpenGL ES 2.0WebGL 2.0基于OpenGL ES 3.0提供了更强大的功能和更好的性能。WebGL的核心优势在于跨平台兼容性几乎所有现代浏览器都支持WebGL 1.0主流浏览器也基本支持WebGL 2.0。这使得开发者可以创建复杂的3D应用而无需用户安装额外插件。1.2 WebGPU技术演进WebGPU是下一代Web图形API旨在提供更接近现代图形API如Vulkan、Metal、DirectX 12的性能和功能。与WebGL相比WebGPU提供了更低的CPU开销、更好的多线程支持和更高效的资源管理。从Three.js官方文档可以看出WebGPURenderer已经成为WebGLRenderer的替代方案。WebGPURenderer能够针对不同的后端进行目标渲染默认情况下如果浏览器支持WebGPU渲染器会尝试使用WebGPU后端否则会回退到WebGL 2后端。1.3 Three.js框架介绍Three.js是目前最流行的WebGL/WebGPU JavaScript库它封装了底层的图形API提供了更友好的开发接口。Three.js支持场景图、材质系统、几何体、灯光、相机等完整的3D图形概念大大降低了Web3D开发的入门门槛。最新版本的Three.js已经全面支持WebGPU开发者可以通过简单的配置切换渲染器享受WebGPU带来的性能提升。2. 环境准备与开发工具配置2.1 浏览器环境要求WebGL和WebGPU对浏览器环境有特定要求。WebGL 1.0需要浏览器支持OpenGL ES 2.0WebGL 2.0需要支持OpenGL ES 3.0。WebGPU目前还在逐步推广中需要Chrome 113、Firefox Nightly或Safari 16.4等较新版本的浏览器。检查浏览器支持性的代码示例// 检查WebGL支持性 function checkWebGLAvailability() { const canvas document.createElement(canvas); const gl canvas.getContext(webgl) || canvas.getContext(experimental-webgl); if (gl gl instanceof WebGLRenderingContext) { console.log(WebGL 1.0 支持); return true; } const gl2 canvas.getContext(webgl2); if (gl2 gl2 instanceof WebGL2RenderingContext) { console.log(WebGL 2.0 支持); return true; } console.log(WebGL 不支持); return false; } // 检查WebGPU支持性 async function checkWebGPUAvailability() { if (!navigator.gpu) { console.log(WebGPU 不支持); return false; } const adapter await navigator.gpu.requestAdapter(); if (adapter) { console.log(WebGPU 支持); return true; } console.log(WebGPU 不支持); return false; }2.2 开发环境搭建推荐使用现代前端开发工具链包括Node.js、npm/yarn包管理器以及Vite、Webpack等构建工具。Three.js可以通过npm安装也支持CDN直接引入。package.json配置示例{ name: webgl-webgpu-demo, version: 1.0.0, type: module, scripts: { dev: vite, build: vite build, preview: vite preview }, dependencies: { three: ^0.158.0 }, devDependencies: { vite: ^5.0.0 } }2.3 调试工具配置Chrome DevTools提供了强大的WebGL调试功能包括帧分析、着色器编辑和性能监控。安装Three.js DevTools扩展可以更方便地调试Three.js应用。调试配置示例// 启用Three.js调试模式 import * as THREE from three; // 在开发环境中启用调试 if (import.meta.env.DEV) { window.THREE THREE; // 将THREE暴露到全局方便调试 }3. 基础渲染案例从WebGL到WebGPU3.1 基础WebGL渲染场景创建一个基础的Three.js WebGL渲染场景包含立方体、灯光和相机控制// 文件路径src/scenes/basic-webgl-scene.js import * as THREE from three; import { OrbitControls } from three/examples/jsm/controls/OrbitControls.js; export class BasicWebGLScene { constructor(container) { this.container container; 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.init(); } init() { // 设置渲染器 this.renderer.setSize(window.innerWidth, window.innerHeight); this.renderer.setClearColor(0x222222); this.renderer.shadowMap.enabled true; this.renderer.shadowMap.type THREE.PCFSoftShadowMap; this.container.appendChild(this.renderer.domElement); // 设置相机 this.camera.position.set(5, 5, 5); this.camera.lookAt(0, 0, 0); // 添加轨道控制器 this.controls new OrbitControls(this.camera, this.renderer.domElement); this.controls.enableDamping true; // 添加灯光 const ambientLight new THREE.AmbientLight(0x404040); this.scene.add(ambientLight); const directionalLight new THREE.DirectionalLight(0xffffff, 1); directionalLight.position.set(10, 10, 5); directionalLight.castShadow true; this.scene.add(directionalLight); // 创建立方体 const geometry new THREE.BoxGeometry(2, 2, 2); const material new THREE.MeshStandardMaterial({ color: 0x00ff00, roughness: 0.5, metalness: 0.5 }); this.cube new THREE.Mesh(geometry, material); this.cube.castShadow true; this.scene.add(this.cube); // 添加网格地面 const floorGeometry new THREE.PlaneGeometry(10, 10); const floorMaterial new THREE.MeshStandardMaterial({ color: 0x888888, roughness: 0.8, metalness: 0.2 }); this.floor new THREE.Mesh(floorGeometry, floorMaterial); this.floor.rotation.x -Math.PI / 2; this.floor.receiveShadow true; this.scene.add(this.floor); // 窗口大小调整处理 window.addEventListener(resize, this.onWindowResize.bind(this)); // 开始动画循环 this.animate(); } onWindowResize() { this.camera.aspect window.innerWidth / window.innerHeight; this.camera.updateProjectionMatrix(); this.renderer.setSize(window.innerWidth, window.innerHeight); } animate() { requestAnimationFrame(this.animate.bind(this)); // 立方体旋转动画 this.cube.rotation.x 0.01; this.cube.rotation.y 0.01; this.controls.update(); this.renderer.render(this.scene, this.camera); } }3.2 WebGPU渲染器迁移将上述WebGL场景迁移到WebGPU渲染器体验性能提升// 文件路径src/scenes/basic-webgpu-scene.js import * as THREE from three; import { OrbitControls } from three/examples/jsm/controls/OrbitControls.js; import { WebGPURenderer } from three/examples/jsm/renderers/webgpu/WebGPURenderer.js; export class BasicWebGPUScene { constructor(container) { this.container container; this.scene new THREE.Scene(); this.camera new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); this.init(); } async init() { try { // 初始化WebGPU渲染器 this.renderer new WebGPURenderer({ antialias: true, alpha: true, depth: true }); await this.renderer.init(); this.renderer.setSize(window.innerWidth, window.innerHeight); this.renderer.setClearColor(0x222222); this.container.appendChild(this.renderer.domElement); // 设置相机和控制器 this.camera.position.set(5, 5, 5); this.camera.lookAt(0, 0, 0); this.controls new OrbitControls(this.camera, this.renderer.domElement); this.controls.enableDamping true; // 场景设置与WebGL版本相同 this.setupScene(); window.addEventListener(resize, this.onWindowResize.bind(this)); this.animate(); } catch (error) { console.error(WebGPU初始化失败回退到WebGL:, error); this.fallbackToWebGL(); } } setupScene() { // 环境光 const ambientLight new THREE.AmbientLight(0x404040); this.scene.add(ambientLight); // 方向光 const directionalLight new THREE.DirectionalLight(0xffffff, 1); directionalLight.position.set(10, 10, 5); this.scene.add(directionalLight); // 立方体 const geometry new THREE.BoxGeometry(2, 2, 2); const material new THREE.MeshStandardMaterial({ color: 0x00ff00, roughness: 0.5, metalness: 0.5 }); this.cube new THREE.Mesh(geometry, material); this.scene.add(this.cube); // 地面 const floorGeometry new THREE.PlaneGeometry(10, 10); const floorMaterial new THREE.MeshStandardMaterial({ color: 0x888888, roughness: 0.8, metalness: 0.2 }); this.floor new THREE.Mesh(floorGeometry, floorMaterial); this.floor.rotation.x -Math.PI / 2; this.scene.add(this.floor); } fallbackToWebGL() { this.renderer new THREE.WebGLRenderer({ antialias: true }); this.renderer.setSize(window.innerWidth, window.innerHeight); this.renderer.setClearColor(0x222222); this.container.innerHTML ; this.container.appendChild(this.renderer.domElement); console.log(已回退到WebGL渲染器); } onWindowResize() { this.camera.aspect window.innerWidth / window.innerHeight; this.camera.updateProjectionMatrix(); this.renderer.setSize(window.innerWidth, window.innerHeight); } animate() { requestAnimationFrame(this.animate.bind(this)); this.cube.rotation.x 0.01; this.cube.rotation.y 0.01; this.controls.update(); this.renderer.render(this.scene, this.camera); } }3.3 渲染器性能对比通过简单的性能测试对比WebGL和WebGPU在不同场景下的表现// 文件路径src/utils/performance-test.js export class PerformanceTest { constructor() { this.results {}; } async testWebGL(sceneComplexity 100) { const startTime performance.now(); // 模拟复杂场景渲染 for (let i 0; i sceneComplexity; i) { // 复杂的渲染操作 await this.simulateRendering(); } const endTime performance.now(); return endTime - startTime; } async testWebGPU(sceneComplexity 100) { const startTime performance.now(); // WebGPU通常有更好的并行处理能力 const promises []; for (let i 0; i sceneComplexity; i) { promises.push(this.simulateRendering()); } await Promise.all(promises); const endTime performance.now(); return endTime - startTime; } async simulateRendering() { // 模拟渲染计算 return new Promise(resolve { setTimeout(resolve, Math.random() * 10); }); } async runComparativeTest() { const complexities [10, 50, 100, 500]; for (const complexity of complexities) { const webglTime await this.testWebGL(complexity); const webgpuTime await this.testWebGPU(complexity); this.results[complexity] { webgl: webglTime, webgpu: webgpuTime, improvement: ((webglTime - webgpuTime) / webglTime * 100).toFixed(2) }; } return this.results; } }4. 纹理与材质高级应用4.1 UV坐标与纹理映射原理UV坐标是2D纹理坐标用于将2D图像映射到3D模型表面。每个顶点都有对应的UV坐标告诉渲染器如何将纹理贴到模型上。不规则平面的纹理映射示例// 文件路径src/scenes/uv-mapping-demo.js import * as THREE from three; import { OrbitControls } from three/examples/jsm/controls/OrbitControls.js; export class UVMappingDemo { constructor(container) { this.container container; 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.init(); } async init() { // 设置渲染器 this.renderer.setSize(window.innerWidth, window.innerHeight); this.renderer.setClearColor(0x222222); this.container.appendChild(this.renderer.domElement); // 相机和控制器 this.camera.position.set(0, 0, 10); this.controls new OrbitControls(this.camera, this.renderer.domElement); // 创建不规则几何体 await this.createIrregularGeometry(); // 动画循环 this.animate(); } async createIrregularGeometry() { // 创建自定义几何体演示UV映射 const geometry new THREE.BufferGeometry(); // 顶点位置 const vertices new Float32Array([ -2, -2, 0, // 左下 2, -2, 0, // 右下 0, 2, 0, // 上中 -1, 0, 1, // 左中前 1, 0, 1 // 右中前 ]); // 面索引 const indices [ 0, 1, 2, // 基础三角形 0, 3, 2, // 左侧面 1, 4, 2, // 右侧面 0, 1, 3, // 底面左 1, 4, 3 // 底面右 ]; // UV坐标 - 关键部分 const uvs new Float32Array([ 0, 0, // 顶点0 - 左下 1, 0, // 顶点1 - 右下 0.5, 1, // 顶点2 - 上中 0, 0.5, // 顶点3 - 左中 1, 0.5 // 顶点4 - 右中 ]); geometry.setIndex(indices); geometry.setAttribute(position, new THREE.BufferAttribute(vertices, 3)); geometry.setAttribute(uv, new THREE.BufferAttribute(uvs, 2)); geometry.computeVertexNormals(); // 加载纹理 const textureLoader new THREE.TextureLoader(); const texture await new Promise((resolve) { textureLoader.load(/textures/checkerboard.png, resolve); }); // 创建材质 const material new THREE.MeshBasicMaterial({ map: texture, side: THREE.DoubleSide }); this.mesh new THREE.Mesh(geometry, material); this.scene.add(this.mesh); // 添加辅助网格显示UV分布 this.addUVHelper(); } addUVHelper() { // UV可视化辅助 const helperGeometry new THREE.PlaneGeometry(4, 4); const helperMaterial new THREE.MeshBasicMaterial({ color: 0xffffff, wireframe: true, transparent: true, opacity: 0.3 }); this.helper new THREE.Mesh(helperGeometry, helperMaterial); this.helper.position.z -1; this.scene.add(this.helper); } animate() { requestAnimationFrame(this.animate.bind(this)); if (this.mesh) { this.mesh.rotation.y 0.005; } this.controls.update(); this.renderer.render(this.scene, this.camera); } }4.2 高级材质技术水流效果实现Three.js水流效果解决property flowDirection不存在的兼容性问题// 文件路径src/scenes/water-effect-demo.js import * as THREE from three; import { OrbitControls } from three/examples/jsm/controls/OrbitControls.js; export class WaterEffectDemo { constructor(container) { this.container container; 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.init(); } async init() { this.renderer.setSize(window.innerWidth, window.innerHeight); this.renderer.setClearColor(0x87CEEB); this.renderer.shadowMap.enabled true; this.container.appendChild(this.renderer.domElement); this.camera.position.set(0, 5, 10); this.controls new OrbitControls(this.camera, this.renderer.domElement); await this.createWaterEffect(); this.createEnvironment(); this.animate(); } async createWaterEffect() { // 创建水面几何体 const waterGeometry new THREE.PlaneGeometry(10, 10, 128, 128); // 自定义着色器材质实现水流效果 const waterMaterial new THREE.ShaderMaterial({ uniforms: { time: { value: 0 }, resolution: { value: new THREE.Vector2(window.innerWidth, window.innerHeight) }, waterColor: { value: new THREE.Color(0x0077be) }, lightDirection: { value: new THREE.Vector3(0.5, 1, 0.5).normalize() } }, vertexShader: uniform float time; varying vec2 vUv; varying vec3 vPosition; void main() { vUv uv; vPosition position; // 正弦波模拟水面波动 float wave sin(position.x * 2.0 time) * 0.2 sin(position.y * 3.0 time * 1.5) * 0.15; vec3 newPosition position; newPosition.z wave; gl_Position projectionMatrix * modelViewMatrix * vec4(newPosition, 1.0); } , fragmentShader: uniform vec3 waterColor; uniform vec3 lightDirection; uniform float time; varying vec2 vUv; varying vec3 vPosition; void main() { // 基础颜色 vec3 color waterColor; // 模拟光反射 vec3 normal vec3(0, 0, 1); float diffuse max(dot(normal, lightDirection), 0.2); // 添加波纹效果 float ripple sin(vPosition.x * 10.0 time * 2.0) * 0.1 cos(vPosition.y * 8.0 time * 1.7) * 0.1; // 深度变化 float depth 1.0 - abs(vPosition.x) * 0.1; color mix(color, color * 0.7, depth); // 最终颜色计算 color * diffuse; color ripple * 0.3; gl_FragColor vec4(color, 0.8); } , transparent: true, side: THREE.DoubleSide }); this.water new THREE.Mesh(waterGeometry, waterMaterial); this.water.rotation.x -Math.PI / 2; this.scene.add(this.water); } createEnvironment() { // 添加环境光 const ambientLight new THREE.AmbientLight(0x404040, 0.4); this.scene.add(ambientLight); // 添加方向光 const directionalLight new THREE.DirectionalLight(0xffffff, 0.8); directionalLight.position.set(10, 10, 5); directionalLight.castShadow true; this.scene.add(directionalLight); // 添加周围地形 const groundGeometry new THREE.PlaneGeometry(20, 20); const groundMaterial new THREE.MeshStandardMaterial({ color: 0x3a7d3a }); const ground new THREE.Mesh(groundGeometry, groundMaterial); ground.rotation.x -Math.PI / 2; ground.position.y -1; this.scene.add(ground); } animate() { requestAnimationFrame(this.animate.bind(this)); // 更新时间uniform if (this.water this.water.material.uniforms.time) { this.water.material.uniforms.time.value performance.now() * 0.001; } this.controls.update(); this.renderer.render(this.scene, this.camera); } }5. 三维地理信息系统集成5.1 百度地图WebGL点聚合优化实现高效的百度地图点聚合功能优化大数据量下的渲染性能// 文件路径src/map/baidu-map-clustering.js export class BaiduMapClustering { constructor(map, options {}) { this.map map; this.options { gridSize: 60, // 网格大小像素 maxZoom: 18, // 最大缩放级别 minZoom: 3, // 最小缩放级别 clusterRadius: 80, // 聚合半径 ...options }; this.markers []; this.clusters []; this.customOverlays []; this.init(); } init() { // 监听地图事件进行重新聚合 this.map.addEventListener(zoomend, this.cluster.bind(this)); this.map.addEventListener(moveend, this.cluster.bind(this)); } addMarker(marker) { this.markers.push(marker); this.cluster(); } addMarkers(markers) { this.markers.push(...markers); this.cluster(); } cluster() { const zoom this.map.getZoom(); // 清除现有聚合点 this.clearClusters(); if (zoom this.options.maxZoom) { // 显示所有单个标记 this.showAllMarkers(); return; } // 执行点聚合算法 this.executeClustering(zoom); } executeClustering(zoom) { const clusters []; const projectedMarkers []; // 将经纬度转换为像素坐标 this.markers.forEach(marker { const point this.map.pointToOverlayPixel(marker.getPosition()); projectedMarkers.push({ marker: marker, point: point }); }); // 基于网格的聚合算法 const grid {}; projectedMarkers.forEach(projected { const gridX Math.floor(projected.point.x / this.options.gridSize); const gridY Math.floor(projected.point.y / this.options.gridSize); const gridKey ${gridX}_${gridY}; if (!grid[gridKey]) { grid[gridKey] { markers: [], center: { x: 0, y: 0 }, bounds: { minX: Infinity, maxX: -Infinity, minY: Infinity, maxY: -Infinity } }; } grid[gridKey].markers.push(projected.marker); grid[gridKey].center.x projected.point.x; grid[gridKey].center.y projected.point.y; // 更新边界 grid[gridKey].bounds.minX Math.min(grid[gridKey].bounds.minX, projected.point.x); grid[gridKey].bounds.maxX Math.max(grid[gridKey].bounds.maxX, projected.point.x); grid[gridKey].bounds.minY Math.min(grid[gridKey].bounds.minY, projected.point.y); grid[gridKey].bounds.maxY Math.max(grid[gridKey].bounds.maxY, projected.point.y); }); // 创建聚合点 Object.values(grid).forEach(cell { if (cell.markers.length 1) { // 单个点直接显示 cell.markers[0].setMap(this.map); } else { // 创建聚合点 this.createClusterPoint(cell, zoom); } }); } createClusterPoint(cell, zoom) { const centerX cell.center.x / cell.markers.length; const centerY cell.center.y / cell.markers.length; // 将像素坐标转换回经纬度 const centerPoint new BMap.Pixel(centerX, centerY); const centerPosition this.map.overlayPixelToPoint(centerPoint); // 创建自定义聚合覆盖物 const clusterOverlay this.createCustomClusterOverlay(centerPosition, cell.markers.length); clusterOverlay.setMap(this.map); this.clusters.push({ overlay: clusterOverlay, markers: cell.markers }); } createCustomClusterOverlay(position, count) { // 使用WebGL创建高性能聚合点 const CustomClusterOverlay function(position, count) { this._position position; this._count count; }; CustomClusterOverlay.prototype new BMap.Overlay(); CustomClusterOverlay.prototype.initialize function(map) { this._map map; // 创建Canvas元素用于WebGL渲染 const canvas document.createElement(canvas); canvas.width 60; canvas.height 60; canvas.style.position absolute; // WebGL上下文 const gl canvas.getContext(webgl) || canvas.getContext(experimental-webgl); if (gl) { this.renderWebGLCluster(gl, this._count); } else { this.render2DCluster(canvas, this._count); } map.getPanes().markerPane.appendChild(canvas); this._canvas canvas; return canvas; }; CustomClusterOverlay.prototype.draw function() { const map this._map; const pixel map.pointToOverlayPixel(this._position); this._canvas.style.left (pixel.x - 30) px; this._canvas.style.top (pixel.y - 30) px; }; return new CustomClusterOverlay(position, count); } renderWebGLCluster(gl, count) { // WebGL聚合点渲染实现 const vertexShaderSource attribute vec2 aPosition; void main() { gl_Position vec4(aPosition, 0.0, 1.0); gl_PointSize 50.0; } ; const fragmentShaderSource precision mediump float; uniform vec3 uColor; void main() { float dist length(gl_PointCoord - vec2(0.5)); if (dist 0.5) discard; gl_FragColor vec4(uColor, 0.8); } ; // 编译着色器程序 const vertexShader gl.createShader(gl.VERTEX_SHADER); gl.shaderSource(vertexShader, vertexShaderSource); gl.compileShader(vertexShader); const fragmentShader gl.createShader(gl.FRAGMENT_SHADER); gl.shaderSource(fragmentShader, fragmentShaderSource); gl.compileShader(fragmentShader); const program gl.createProgram(); gl.attachShader(program, vertexShader); gl.attachShader(program, fragmentShader); gl.linkProgram(program); gl.useProgram(program); // 根据数量设置颜色 const colorUniform gl.getUniformLocation(program, uColor); let color; if (count 10) color [0.2, 0.8, 0.2]; else if (count 50) color [0.8, 0.8, 0.2]; else color [0.8, 0.2, 0.2]; gl.uniform3fv(colorUniform, color); // 绘制点 gl.drawArrays(gl.POINTS, 0, 1); } clearClusters() { this.clusters.forEach(cluster { cluster.overlay.setMap(null); cluster.markers.forEach(marker marker.setMap(null)); }); this.clusters []; } showAllMarkers() { this.markers.forEach(marker marker.setMap(this.map)); } destroy() { this.clearClusters(); this.markers []; } }5.2 Three.js经纬度坐标回显实现地理坐标与Three.js世界坐标的转换系统// 文件路径src/utils/coordinate-converter.js export class CoordinateConverter { constructor(options {}) { this.options { earthRadius: 6371000, // 地球半径米 scale: 0.00001, // 缩放比例 center: [116.4, 39.9], // 中心点经纬度 [lng, lat] ...options }; this.initProjection(); } initProjection() { // 简单的墨卡托投影转换 this.projection { toWorld: (lng, lat, height 0) { const rad Math.PI / 180; const lngRad lng * rad; const latRad lat * rad; // 墨卡托投影 const x this.options.earthRadius * lngRad * this.options.scale; const y this.options.earthRadius * Math.log(Math.tan(Math.PI/4 latRad/2)) * this.options.scale; // 相对中心点的偏移 const [centerLng, centerLat] this.options.center; const centerX this.options.earthRadius * centerLng * rad * this.options.scale; const centerY this.options.earthRadius * Math.log(Math.tan(Math.PI/4 centerLat*rad/2)) * this.options.scale; return new THREE.Vector3( x - centerX, height, y - centerY ); }, toGeographic: (x, y, z) { const rad 180 / Math.PI; const [centerLng, centerLat] this.options.center; const centerX this.options.earthRadius * centerLng * Math.PI/180 * this.options.scale; const centerY this.options.earthRadius * Math.log(Math.tan(Math.PI/4 centerLat*Math.PI/180/2)) * this.options.scale; const worldX x centerX; const worldZ z centerY; const lng (worldX / (this.options.earthRadius * this.options.scale)) * rad; const lat (2 * Math.atan(Math.exp(worldZ / (this.options.earthRadius * this.options.scale))) - Math.PI/2) * rad; return { lng, lat, height: y }; } }; } // 批量转换坐标 convertCoordinates(coordinates) { return coordinates.map(coord { if (Array.isArray(coord)) { return this.projection.toWorld(...coord); } return this.projection.toWorld(coord.lng, coord.lat, coord.height || 0); }); } // 创建地理参考场景 createGeoreferencedScene(container) { const scene new THREE.Scene(); const camera new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 100000); const renderer new THREE.WebGLRenderer({ antialias: true }); renderer.setSize(window.innerWidth, window.innerHeight); container.appendChild(renderer.domElement); // 设置相机位置基于中心点 const centerWorld this.projection.toWorld(...this.options.center, 1000); camera.position.copy(centerWorld); camera.lookAt(0, 0, 0); return { scene, camera, renderer }; } // 添加地理标记 addGeographicMarker(scene, lng, lat, height 0, color 0xff000