
three.js 中阴影无法显示的常见原因包括光源、物体和接收面未正确配置;本文直击你代码中的关键拼写错误,并系统梳理阴影启用的完整必要条件。
在你的代码中,阴影未显示的直接原因是一个易被忽略的拼写错误:你为地面平面(planeObj)设置了 plane.receiveShadow = true,但变量名实际是 planeObj,因此这行赋值根本未生效——plane 是几何体(THREE.PlaneGeometry 实例),它没有 receiveShadow 属性;而真正需要接收阴影的是网格对象 planeObj(THREE.Mesh 实例)。
✅ 正确写法应为:
planeObj.receiveShadow = true; // ✅ 作用于 Mesh 实例
但这只是“冰山一角”。要让 Three.js 阴影正常工作,必须同时满足以下全部条件:
? 四大必备条件(缺一不可)
-
渲染器启用阴影映射
renderer.shadowMap.enabled = true; renderer.shadowMap.type = THREE.PCFSoftShadowMap; // 推荐软阴影
-
光源启用阴影投射且配置合理尺寸
light.castShadow = true; light.shadow.mapSize.width = 1024; // 建议 ≥ 512,越大越清晰(但性能开销增加) light.shadow.mapSize.height = 1024; // ⚠️ 补充:点光源阴影需注意视锥范围(可选) light.shadow.camera.near = 0.1; light.shadow.camera.far = 10; light.shadow.camera.fov = 90;
-
投射阴影的物体显式开启 castShadow
sphere.castShadow = true; // ✅ 已正确设置
-
接收阴影的物体显式开启 receiveShadow
planeObj.receiveShadow = true; // ✅ 必须作用于 Mesh 对象,非 Geometry!
? 额外优化建议
- 使用 MeshStandardMaterial 或 MeshPhysicalMaterial(你已正确选用)——基础 MeshBasicMaterial 和 MeshLambertMaterial 不支持阴影。
- 确保接收面(如地面)有足够几何细分(当前 PlaneGeometry(20,20,1,1) 足够),但若使用自定义着色器,需手动处理 shadow map 采样。
- 若阴影仍模糊或缺失,检查光源位置是否被遮挡,或调用 light.shadow.camera.updateProjectionMatrix() 强制更新(尤其动态移动光源时)。
✅ 完整修正片段(关键行已高亮)
// ... 其他初始化保持不变
// add plane object: ground
const plane = new THREE.PlaneGeometry(20, 20);
const planeMaterial = new THREE.MeshStandardMaterial({ color: 0xeeeeee });
const planeObj = new THREE.Mesh(plane, planeMaterial);
planeObj.position.y = -1;
planeObj.rotation.x = -Math.PI / 2;
planeObj.receiveShadow = true; // ✅ 修正:作用于 planeObj,非 plane
scene.add(planeObj);? 提示:可通过 renderer.debug = { showShadowMap: true }(Three.js r160+)临时可视化阴影贴图,快速定位映射问题。
只要严格满足上述四点,阴影将立即呈现。你遇到的问题看似微小,却恰恰暴露了 Three.js 渲染管线中「对象层级」的关键逻辑——阴影属性永远属于 Mesh,而非其几何体或材质。










