Three.js 阴影不显示的常见原因与完整解决方案

1次阅读

Three.js 阴影不显示的常见原因与完整解决方案

本文详解 three.js 中阴影无法渲染的三大典型问题:全局阴影未启用、拼写错误(receiveshadow 误写为 recieveshadow)、语法错误导致脚本中断,并提供可直接运行的修复代码与关键配置要点。

本文详解 three.js 中阴影无法渲染的三大典型问题:全局阴影未启用、拼写错误(receiveshadow 误写为 recieveshadow)、语法错误导致脚本中断,并提供可直接运行的修复代码与关键配置要点。

在 Three.js 中实现真实感阴影看似简单,实则对配置完整性要求极高——哪怕一个拼写错误或一行遗漏,都会导致阴影完全不可见。你提供的代码中,立方体(cube)设置了 castShadow = true,地面(ground)意图启用接收阴影,光源也启用了 castShadow,但阴影仍未出现。根本原因在于三个关键疏漏,下面逐一解析并给出专业级修复方案。

✅ 必须满足的四大阴影前提条件

Three.js 的阴影系统是显式启用的,需同时满足以下四点,缺一不可:

  1. 全局启用阴影渲染器:renderer.shadowMap.enabled = true(必须在渲染循环前设置);
  2. 光源支持阴影投射:light.castShadow = true(且建议调整 shadow.mapSize 提升精度);
  3. 投射物体启用阴影:mesh.castShadow = true;
  4. 接收物体启用阴影接收:mesh.receiveShadow = true(注意拼写:receive,非 recieve)。

⚠️ 特别注意:receiveShadow 是标准属性名,拼错(如 recieveShadow)会导致静默失败——属性被忽略,无控制台报错,极易排查遗漏。

? 修复后的完整可运行代码

以下是修正全部问题(包括删除末尾非法字符 j、修正拼写、补充阴影优化配置)的精简可靠版本:

<!DOCTYPE html> <html> <head>   <meta charset="utf-8">   <title>Three.js Shadow Fix</title>   <style>body { margin: 0; overflow: hidden; }</style> </head> <body> <script async src="https://unpkg.com/es-module-shims@1.10.0/dist/es-module-shims.js"></script> <script type="importmap"> {   "imports": {     "three": "https://unpkg.com/three@0.163.0/build/three.module.js",     "three/addons/": "https://unpkg.com/three@0.163.0/examples/jsm/"   } } </script> <script type="module"> import * as THREE from 'three'; import { OrbitControls } from 'three/addons/controls/OrbitControls.js';  // 场景、相机、渲染器 const scene = new THREE.Scene(); scene.background = new THREE.Color(0xf0f0f0); const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); camera.position.set(0, 5, 8);  const renderer = new THREE.WebGLRenderer({ antialias: true }); renderer.setSize(window.innerWidth, window.innerHeight); renderer.shadowMap.enabled = true; // ✅ 全局启用阴影(关键!) renderer.shadowMap.type = THREE.PCFSoftShadowMap; // 推荐:软阴影更自然 document.body.appendChild(renderer.domElement);  // 控制器 const controls = new OrbitControls(camera, renderer.domElement);  // 立方体(投射阴影) const cubeGeometry = new THREE.BoxGeometry(1, 1, 1); const cubeMaterial = new THREE.MeshStandardMaterial({ color: 0x00ff00 }); const cube = new THREE.Mesh(cubeGeometry, cubeMaterial); cube.castShadow = true; // ✅ 启用投射 scene.add(cube);  // 方向光(带阴影) const light = new THREE.DirectionalLight(0xffffff, 1); light.position.set(5, 10, 7); light.castShadow = true; // ? 优化阴影贴图分辨率与投影范围(提升清晰度与稳定性) light.shadow.mapSize.width = 1024; light.shadow.mapSize.height = 1024; light.shadow.camera.near = 0.5; light.shadow.camera.far = 50; light.shadow.camera.left = -10; light.shadow.camera.right = 10; light.shadow.camera.top = 10; light.shadow.camera.bottom = -10; scene.add(light);  // 地面(接收阴影) const groundGeometry = new THREE.PlaneGeometry(10, 10); const groundMaterial = new THREE.MeshStandardMaterial({    color: 0x0000ff,   side: THREE.DoubleSide  }); const ground = new THREE.Mesh(groundGeometry, groundMaterial); ground.rotation.x = -Math.PI / 2; // 水平放置 ground.position.y = -3; ground.receiveShadow = true; // ✅ 正确拼写:receiveShadow(原代码为 recieveShadow ❌) scene.add(ground);  // 环境光(保证非阴影区可见) const ambientLight = new THREE.AmbientLight(0x404040, 2); scene.add(ambientLight);  // 动画循环 function animate() {   requestAnimationFrame(animate);   cube.rotation.x += 0.005;   cube.rotation.y += 0.008;   renderer.render(scene, camera); } animate();  // 响应窗口大小变化 window.addEventListener('resize', () => {   camera.aspect = window.innerWidth / window.innerHeight;   camera.updateProjectionMatrix();   renderer.setSize(window.innerWidth, window.innerHeight); }); </script> </body> </html>

? 关键注意事项与进阶提示

  • 阴影性能开销大:仅对必要物体启用 castShadow/receiveShadow,避免全场景开启;
  • 阴影贴图尺寸影响质量与内存:light.shadow.mapSize 默认为 512×512,低精度易出现锯齿或“阴影漂移”,建议设为 1024×1024 或更高(但需权衡 GPU 内存);
  • 光源视锥(camera)裁剪范围至关重要:若 light.shadow.camera.far 过小,远处物体将无法生成阴影;过大则降低阴影精度。务必根据场景尺度合理设置 near/far 及 left/right/top/bottom;
  • 材质限制:MeshBasicMaterial 和 MeshDepthMaterial 不支持阴影,必须使用 MeshStandardMaterial、MeshPhongMaterial 等光照计算材质;
  • 调试技巧:临时将 light.shadow.camera.visible = true 并添加 scene.add(light.shadow.camera),可直观查看阴影投射区域是否覆盖目标物体。

遵循以上配置规范,你的 Three.js 场景即可稳定呈现高质量动态阴影。记住:阴影不是“开了就亮”,而是“配对、对齐、调优”的系统工程。

text=ZqhQzanResources