Three.js实现无实体投射的动态墙面阴影?恐怖游戏开发问询
能否在Three.js中渲染无投射源的阴影?
当然可行!这种“无来源幽灵阴影”简直是恐怖游戏的标配效果,刚好有几种靠谱的实现方式,你提到的阴影地图方案完全能做到,下面给你详细拆解:
方法一:用隐形光源+隐形投射物实现阴影地图效果
这是最贴合你需求的方案——利用Three.js原生阴影系统,通过“隐藏光源和投射物”来制造阴影无来源的假象:
- 创建隐形光源:选定向光或聚光灯(定向光更适合墙面大面积阴影),把它的
visible设为false,这样玩家看不到光源,但它依然能投射阴影。记得开启castShadow = true,并调整阴影参数提升清晰度(比如mapSize设为2048×2048,视锥体范围适配你的墙面)。 - 制作隐形投射物:创建一个模型(平面、自定义异形都可以),把它的材质
visible设为false,但开启castShadow = true。这个物体就是阴影的“幕后黑手”,玩家看不到它,但它会被隐形光源照射,在墙面上投出阴影。 - 墙面设置:确保墙面的
receiveShadow设为true,这样它才能接收阴影。 - 动态阴影动画:只要动画这个隐形投射物的位置、旋转甚至顶点形态,阴影就会跟着诡异晃动——比如给顶点加随机扰动,模拟幽灵阴影的不规则感。
给你一段极简的示例代码:
// 1. 创建隐形定向光 const ghostLight = new THREE.DirectionalLight(0xffffff, 1); ghostLight.visible = false; ghostLight.castShadow = true; // 优化阴影质量 ghostLight.shadow.mapSize.set(2048, 2048); ghostLight.shadow.camera.near = 0.5; ghostLight.shadow.camera.far = 50; ghostLight.shadow.camera.left = -10; ghostLight.shadow.camera.right = 10; ghostLight.position.set(5, 0, 3); // 调整位置让阴影落在墙面上 scene.add(ghostLight); // 2. 创建隐形阴影投射物(带随机顶点扰动的平面) const casterGeo = new THREE.PlaneGeometry(6, 6); // 给顶点加随机偏移,让阴影看起来扭曲诡异 casterGeo.vertices.forEach(v => { v.z += Math.random() * 0.6 - 0.3; }); casterGeo.verticesNeedUpdate = true; const casterMat = new THREE.MeshBasicMaterial({ visible: false }); const shadowCaster = new THREE.Mesh(casterGeo, casterMat); shadowCaster.castShadow = true; shadowCaster.position.set(0, 0, 2); // 放在光源和墙面之间 scene.add(shadowCaster); // 3. 墙面设置接收阴影 const wallGeo = new THREE.PlaneGeometry(20, 20); const wallMat = new THREE.MeshStandardMaterial({ color: 0x2a2a2a }); const wall = new THREE.Mesh(wallGeo, wallMat); wall.receiveShadow = true; wall.position.set(0, 0, 0); scene.add(wall); // 4. 动画投射物,让阴影动态变化 function animate() { requestAnimationFrame(animate); // 缓慢旋转 shadowCaster.rotation.z += 0.003; // 实时扰动顶点,模拟不规则晃动 casterGeo.vertices.forEach(v => { v.z += (Math.random() * 0.012 - 0.006); }); casterGeo.verticesNeedUpdate = true; } animate();
方法二:动态纹理投影(备选方案)
如果你的阴影形状特别复杂(比如想投射动态视频里的阴影),可以用动态纹理直接投影到墙面上:
- 用Canvas实时生成阴影纹理,或者加载视频纹理
- 创建一个平面作为“投影器”,使用透明材质,只保留纹理的阴影区域(半透明黑色),放在墙面前方
- 或者用自定义着色器实现纹理投影,这种方式不需要依赖阴影地图,视觉效果更灵活
不过如果你更偏好Three.js原生阴影的真实感,第一种方法绝对是首选。
小提示
- 阴影地图分辨率越高,阴影越清晰,建议设为2048或4096(根据性能调整)
- 调整隐形光源的位置和角度,确保阴影精准落在目标墙面上
- 如果场景有其他光源,可以通过
shadow.bias参数避免阴影出现异常瑕疵
内容的提问来源于stack exchange,提问作者Devon Jarvis
相关产品推荐
相关产品推荐

