Three.js中如何让PNG云层纹理在地球球体上投射真实阴影
问题核心原因
Three.js 默认阴影计算逻辑不会自动识别透明材质的Alpha通道,会将开启castShadow的网格整体按不透明几何体生成阴影贴图。哪怕云层材质加载了带透明通道的PNG、开启了transparent: true,阴影阶段也会跳过透明度判断,把整个云层球面当成实心物体投影,自然得不到和云层轮廓匹配的效果。
另外代码里还有几个配置问题会加重阴影异常:
- 地球材质错误关闭了
depthWrite,还设置了半透透明度,会干扰阴影深度计算 - 平行光未配置阴影相机视锥体范围、阴影贴图分辨率,默认参数下阴影精度极低、容易裁切
- 部分属性名是Three.js旧版本API,新版本下写法不生效会直接导致阴影功能失效
- 云层材质未做透明区域裁切,阴影计算不会跳过透明像素
分步修复方案
1. 修正基础API与材质配置
首先修正新旧API写法问题,调整地球、云层材质的基础参数:
// 渲染器配置(Three.js r130+ 新版本用shadowMap对象下的属性,旧版本可保留原写法) renderer.shadowMap.enabled = true renderer.shadowMap.type = THREE.PCFSoftShadowMap // 地球材质修正:不透明物体不要关深度写入,非必要不要开半透 const earthMaterial = new THREE.MeshStandardMaterial({ map: earthTexture, bumpMap: bumpMap, bumpScale: .05, roughnessMap: specMap, // 原specMap为旧版Phong材质属性,PBR材质用roughnessMap roughness: 0.7, metalness: 0.1, receiveShadow: true }) // 云层材质增加透明裁切配置 const cloudMaterial = new THREE.MeshStandardMaterial({ map: cloudTexture, transparent: true, castShadow: true, alphaTest: 0.4, // 透明度低于该值的区域不参与渲染和阴影计算,数值根据云贴图透明阈值调整,范围0-1 side: THREE.FrontSide // 若出现阴影缺失可改为DoubleSide })
2. 配置平行光阴影参数
默认平行光阴影相机视锥体范围过大、阴影贴图分辨率极低,会导致阴影模糊、裁切、错位,手动配置适配地球尺寸即可:
const directionalLight = new THREE.DirectionalLight("#ffffff", 1) directionalLight.position.set(3, 0, 0) directionalLight.castShadow = true; directionalLight.shadow.intensity = 0.3; // 原shadowDarkness为旧版本属性,新版本用intensity控制阴影浓度 // 配置阴影相机视锥体,刚好包裹住地球+云层即可,范围不要设太大避免精度损失 directionalLight.shadow.camera.left = -2 directionalLight.shadow.camera.right = 2 directionalLight.shadow.camera.top = 2 directionalLight.shadow.camera.bottom = -2 directionalLight.shadow.camera.near = 0.5 directionalLight.shadow.camera.far = 10 // 提高阴影贴图分辨率,数值越高阴影边缘越清晰,性能消耗也越高 directionalLight.shadow.mapSize.set(2048, 2048)
3. (可选)实现半透明软阴影
如果用alphaTest得到的阴影边缘太硬,想要模拟云层半透产生的软半影效果,需要给云层材质添加自定义深度材质,让阴影计算采样贴图的Alpha值实现半透过渡:
// 自定义云层阴影材质,采样云贴图的透明通道 const cloudCustomDepthMat = new THREE.MeshDepthMaterial({ depthPacking: THREE.RGBADepthPacking, map: cloudTexture, alphaTest: 0.1, transparent: true }) cloudMaterial.customDepthMaterial = cloudCustomDepthMat
调参提示
alphaTest值根据云贴图实际透明阈值调整,通常0.3-0.5之间效果最自然- 如果阴影边缘锯齿明显,可以适当提高
shadow.mapSize数值,或者给阴影贴图添加轻微模糊 - 确保云层和地球的UV映射对齐,否则会出现阴影和云层位置错位的问题
内容的提问来源于stack exchange,提问作者Lukoooooooooo
相关产品推荐
相关产品推荐

