技术咨询:如何在Mapbox地图上用Three.js添加20000个平面几何体实现等距建筑并优化Threebox性能
Hey there, let's tackle that 20k isometric buildings performance bottleneck with Threebox on Mapbox—this is a super common challenge when scaling up large sets of geometries, so I’ve got some practical, actionable optimizations to share:
The biggest culprit behind poor performance with 20k individual objects is too many draw calls. Each mesh you add makes the GPU stop and start a new render task, which kills frame rates. Here’s how to fix it:
- Instancing for identical/similar buildings: If you’re using the same base isometric building geometry (just different positions/colors), use
THREE.InstancedMeshinstead of creating 20k separate meshes. This lets you render hundreds of thousands of objects in a single draw call.
Example snippet:// Create your base geometry and material once const buildingGeo = new THREE.BoxGeometry(10, 20, 10); // Adjust to your isometric shape const buildingMat = new THREE.MeshLambertMaterial({ color: 0x888888 }); // Create instanced mesh with 20k instances const instancedMesh = new THREE.InstancedMesh(buildingGeo, buildingMat, 20000); // Set position for each instance const matrix = new THREE.Matrix4(); for (let i = 0; i < 20000; i++) { // Get your building's Mapbox coordinates, convert to Threebox world position const worldPos = tb.utils.latLngToWorld([lat, lng], map.getZoom()); matrix.setPosition(worldPos.x, worldPos.y, 0); // Adjust z for isometric height instancedMesh.setMatrixAt(i, matrix); } // Add to Threebox scene tb.add(instancedMesh); - Merge similar geometries: If you have multiple building styles, group them by material/geometry type and use
BufferGeometryUtils.mergeBufferGeometriesto combine them into a single mesh per group. Just make sure all meshes in the group use the same material.
Isometric buildings don’t need hyper-detailed geometry—cut down on vertex count to lighten the GPU’s load:
- Use
THREE.SimplifyModifierto reduce vertex count on existing geometries. - Model low-poly versions upfront: Replace extruded window frames with texture overlays, skip small decorative details that won’t be visible at map zoom levels.
- Avoid using complex shapes like
ExtrudeGeometryif a simpleBoxGeometryorPlaneGeometrycan mimic the isometric look.
Threebox has some default settings that can drag down performance when dealing with large datasets:
- Disable unnecessary features: Turn off shadows (
shadow: falsein Threebox config) if you don’t need them—shadow rendering is expensive. - Sync camera efficiently: Stick with Threebox’s built-in Mapbox camera sync instead of overriding it. This ensures the render loop only updates when the Mapbox camera moves, not on every frame.
- Use a single Threebox layer: Don’t split buildings across multiple layers—keep all your isometric structures in one layer to reduce overhead from layer management.
Not all buildings need to be rendered at full detail, especially when they’re far from the camera:
- Create 2-3 versions of your building geometry: high-detail (close), medium-detail (mid-range), low-detail (far).
- Use
THREE.LODto switch between these versions based on the camera’s distance to the building. - For buildings that are extremely far, replace the 3D mesh with a 2D billboard (a
PlaneGeometrywith a texture of your isometric building) to save even more performance.
Materials can be surprisingly heavy—tweak them to reduce GPU computation:
- Use
MeshLambertMaterialinstead ofMeshPhongMaterialorMeshStandardMaterialif you don’t need specular highlights or complex lighting. - Reuse materials: Don’t create a new material for each building—share the same material instance across all buildings of the same type.
- Compress textures: Use compressed texture formats to reduce memory usage and load times. If you’re using texture atlases, pack all building textures into a single atlas to minimize texture switches.
Small adjustments here can add up to big performance gains:
- Limit render updates: Configure Threebox to only render when the map is panning/zooming, not on every idle frame. You can do this by hooking into Mapbox’s
moveevent to trigger a render, instead of relying on the default continuous render loop. - Clean up unused objects: If buildings are removed from the viewport (e.g., when zooming out), dispose of their geometries/materials to free up memory.
- Adjust WebGL settings: Disable anti-aliasing (
antialias: false) in your Threebox initialization if visual quality allows, or lower the pixel ratio (pixelRatio: Math.min(window.devicePixelRatio, 1.5)).
Give these steps a try—start with instancing/batching first, since that’ll give you the biggest performance jump right away. Let me know if you hit any snags with specific implementations!
内容的提问来源于stack exchange,提问作者Vladislav Chistyakov

