You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Three.js阴影渲染性能问题排查求助

Troubleshooting Shadow Performance Issues in Your Three.js Minecraft Project

Hey there! Let's break down why your Minecraft-style Three.js build is seeing FPS drop below 30 (and keep falling over time) when shadows are enabled—even though you'd expect this scale to be manageable for a GPU. Here are the most likely culprits and fixes to try:

1. Overly High Shadow Map Resolution & Unnecessary Shadow-Casting Lights

By default, Three.js uses a 1024x1024 shadow map, but if you've got multiple lights casting shadows, each one adds a full render pass. That adds up fast for a blocky world with lots of geometry.

  • Fix: Stick to only your main directional light casting shadows. Disable castShadow on all other lights with light.castShadow = false.
  • Tweak resolution: Lower the shadow map size to 512x512 (or even 256x256 if you can tolerate slightly softer shadows) with:
    light.shadow.mapSize.width = 512;
    light.shadow.mapSize.height = 512;
    

2. Thousands of Individual Meshes Killing Shadow Rendering

Minecraft-style worlds are made of hundreds/thousands of small blocks. If each block is a separate Mesh, the GPU has to process shadow casting for every single one individually—this is a massive waste of resources.

  • Fix: Use THREE.InstancedMesh for repeating block types. This lets you render hundreds of blocks with a single draw call, and shadow rendering will only process the base geometry once instead of thousands of times. Example setup:
    const geometry = new THREE.BoxGeometry(1, 1, 1);
    const material = new THREE.MeshStandardMaterial({ color: 0x888888 });
    const instancedMesh = new THREE.InstancedMesh(geometry, material, totalBlockCount);
    // Set positions for each instance with instancedMesh.setMatrixAt()
    instancedMesh.castShadow = true;
    instancedMesh.receiveShadow = true;
    scene.add(instancedMesh);
    

3. Memory Leaks Causing Progressive FPS Drops

The fact that FPS gets worse over time points to a memory leak—you're probably leaving old geometry/materials/shadow resources hanging around instead of disposing them properly.

  • Fix: Whenever you remove blocks from the scene, make sure to clean up their resources:
    // When deleting a block mesh:
    mesh.removeFromParent();
    mesh.geometry.dispose();
    mesh.material.dispose();
    
  • Also, check if you're creating new materials/geometries every time you spawn blocks instead of reusing existing ones—reuse is key for keeping memory usage stable.

4. Unoptimized Shadow Camera Frustum

If your shadow camera's frustum is way larger than the area that actually needs shadows, the GPU is wasting cycles rendering empty space into the shadow map, which reduces precision and increases load.

  • Fix: Tighten up the shadow camera's bounds to only cover your playable area. For a directional light:
    light.shadow.camera.near = 1;
    light.shadow.camera.far = 50; // Adjust based on your world size
    light.shadow.camera.left = -25;
    light.shadow.camera.right = 25;
    light.shadow.camera.top = 25;
    light.shadow.camera.bottom = -25;
    // Optional: Enable camera helper to visualize bounds
    // const helper = new THREE.CameraHelper(light.shadow.camera);
    // scene.add(helper);
    

5. Overly Expensive Shadow Filtering

If you're using THREE.PCFSoftShadowMap for soft shadows, it looks nicer but is more GPU-intensive than simpler options.

  • Fix: Test switching to THREE.PCFShadowMap (a balance between quality and performance) or even THREE.BasicShadowMap (fastest, harshest shadows) to see if FPS improves:
    renderer.shadowMap.type = THREE.PCFShadowMap;
    

6. Unnecessary Shadow Casting/Receiving

Not every block needs to cast or receive shadows. For example:

  • Blocks underground or behind other blocks can have castShadow = false—their shadows will never be visible.
  • The ground plane only needs to receiveShadow, not cast it (unless you have holes in it).
  • Faraway blocks can have shadow properties disabled entirely, since their shadows are too small to be noticeable.

Try implementing these fixes one at a time to isolate which one is causing the biggest hit. Start with InstancedMesh—that's almost always the biggest win for blocky worlds with lots of repeating geometry.

内容的提问来源于stack exchange,提问作者johnhckuo

火山引擎 最新活动