Three.js DirectionalLight阴影被截断问题求助
首先得澄清:这不是DirectionalLight的固有问题,核心是你对它的阴影相机参数理解有误!DirectionalLight的阴影相机是正交相机(OrthographicCamera),而不是你场景里的透视相机,所以你之前调整fov的操作根本不会起作用——正交相机是用left/right/top/bottom来控制覆盖范围的,和fov无关。
具体解决步骤
1. 正确配置方向光的阴影相机范围
你的平面是THREE.PlaneGeometry(250, 380),假设它的中心在原点,那阴影相机的范围需要完全覆盖这个平面,还要包含模型投射阴影的区域。直接设置以下参数:
// 方向光阴影相机是正交相机,设置左右上下范围匹配你的平面 mainLight.shadow.camera.left = -125; // 250/2 = 125 mainLight.shadow.camera.right = 125; mainLight.shadow.camera.top = 190; // 380/2 = 190 mainLight.shadow.camera.bottom = -190; // 设置near和far:near要小于模型到平面的最小距离,far要足够大覆盖所有阴影区域 mainLight.shadow.camera.near = 0.1; mainLight.shadow.camera.far = 200; // 关键!更新相机的投影矩阵,不然参数不会生效 mainLight.shadow.camera.updateProjectionMatrix();
如果你的平面不在原点,记得把左右上下的数值加上平面的position坐标,比如平面x轴位置是50,那left就是50-125=-75,right是50+125=175,以此类推。
2. 开启阴影相机辅助(调试神器)
为了直观看到阴影相机的覆盖范围,建议添加相机辅助工具,这样你能实时调整参数直到覆盖整个平面和模型:
const shadowHelper = new THREE.CameraHelper(mainLight.shadow.camera); scene.add(shadowHelper);
调整参数时,你会看到辅助框的范围,只要确保模型的投影区域完全在这个框内,阴影就不会被截断了。
3. 优化阴影贴图质量(可选)
如果阴影边缘还是有锯齿或者截断感,可以提升阴影贴图的分辨率:
mainLight.shadow.mapSize.width = 2048; mainLight.shadow.mapSize.height = 2048;
关于SpotLight的问题
你说换SpotLight后地面完全没阴影,是因为SpotLight的阴影相机是透视相机,需要调整它的fov、near、far,还要设置target指向平面或模型,确保阴影相机的视锥体覆盖地面。比如:
const spotLight = new THREE.SpotLight(0xffffff, 0.5); spotLight.position.set(50, 50, 50); spotLight.castShadow = true; // 设置阴影相机参数 spotLight.shadow.camera.fov = 45; spotLight.shadow.camera.near = 1; spotLight.shadow.camera.far = 300; // 关键:让聚光灯指向平面 spotLight.target = plane; spotLight.shadow.camera.updateProjectionMatrix();
但SpotLight的照明是聚焦的,不符合你要均匀照明的需求,所以还是DirectionalLight更合适。
总结
DirectionalLight的阴影截断完全是阴影相机范围没匹配场景导致的,只要正确设置正交相机的left/right/top/bottom/near/far,并更新投影矩阵,问题就能解决。不用换SpotLight,坚持用方向光就能实现均匀照明+完整阴影的效果。
内容的提问来源于stack exchange,提问作者Tom Chapman

