如何在Three.JS中创建定向光阴影?

25

可以从DirectionalLight创建阴影吗?

如果使用SpotLight,则会看到阴影,但如果使用DirectionalLight,它不起作用。


1
你能分享一下你尝试过但没有成功的代码吗? - mrdoob
@mrdoob 我尝试了所有的方法,但仍然不起作用。代码:http://jsfiddle.net/Q4uqE/1/ - eqiproo
3个回答

52
请注意,阴影贴图是与比例相关的。我正在处理一个场景,其中单位距离代表一米,我的物体大约为0.4米。按照Three.js的标准来说,这很小。如果你也有这种情况,那么你可以采取一些重要的步骤:
  • 确保阴影摄像机的近/远平面在您场景的尺寸范围内合理。
  • 确保阴影摄像机的top/left/bottom/right值不要太大,否则每个阴影"像素"可能会非常大,以至于您甚至在场景中都无法注意到阴影。
让我们看看如何做到这一点。

调试

一定要通过 CameraHelper 启用每个灯光的调试渲染:

scene.add(new THREE.CameraHelper(camera)) 

或者在较旧版本的Three.js中:

light.shadowCameraVisible = true;

这将展示你正在计算阴影的体积。这是一个可能看起来像什么的例子:

请注意近平面和远平面(带有黑色十字),以及阴影相机的上/左/下/右(黄色框的外墙)。您希望此框紧贴着您将要投射阴影的任何对象——甚至可能比我展示的更紧密。

代码

以下是一些可能有用的代码片段。

var light = new THREE.DirectionalLight(0xffffff);
light.position.set(0, 2, 2);
light.target.position.set(0, 0, 0);
light.castShadow = true;
light.shadowDarkness = 0.5;
light.shadowCameraVisible = true; // only for debugging
// these six values define the boundaries of the yellow box seen above
light.shadowCameraNear = 2;
light.shadowCameraFar = 5;
light.shadowCameraLeft = -0.5;
light.shadowCameraRight = 0.5;
light.shadowCameraTop = 0.5;
light.shadowCameraBottom = -0.5;
scene.add(light);

确保某些对象投射阴影:

object.castShadow = true;

确保某些对象接收阴影:

object.receiveShadow = true;

最后,在WebGLRenderer上配置一些值:
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(canvasWidth, canvasHeight);
renderer.shadowMapEnabled = true;
renderer.shadowMapSoft = true;

2
有什么诀窍可以让 light.shadowCameraVisible = true 生效吗?在这个分支示例中似乎没有任何作用(来自上面接受的答案):http://jsfiddle.net/Q4uqE/566/ - Ates Goral
在最近的Three.js版本中,应该使用CameraHelper代替light.shadowCameraVisible = truescene.add(new THREE.CameraHelper(camera)) - ezze
1
太棒了。谢谢你。 - taystack
你的解释帮了我很多。非常感谢! 值得一提的是,CameraHelper 应该指向光源的相机,像这样:scene.add(new THREE.CameraHelper(light.shadow.camera)); - Thoronwen

38

是的,你绝对可以使用定向光来投射阴影。你需要确保没有使用不支持阴影的MeshBasicMaterial材质。应该使用MeshLambertMaterial 或者 MeshPhongMaterial 材质代替。

在渲染器中启用阴影需要类似以下的设置:

renderer.shadowMapEnabled = true;
renderer.shadowMapSoft = true;

renderer.shadowCameraNear = 3;
renderer.shadowCameraFar = camera.far;
renderer.shadowCameraFov = 50;

renderer.shadowMapBias = 0.0039;
renderer.shadowMapDarkness = 0.5;
renderer.shadowMapWidth = 1024;
renderer.shadowMapHeight = 1024;

然后你必须针对每个对象和每个光源启用阴影投射和接收,这样你就会拥有

dirLight.castShadow = true;
object.castShadow = true;
otherObject.receiveShadow = true;

然后,如果光源和物体被放置在合适的位置,dirLight 将使得 object 的阴影被投射在 otherObject 上。

[编辑]: 这里有一个可工作的演示,供任何想要做类似事情的人参考。


2
是的,在你的fiddle中,你的定向光源被放置在立方体内部。这里是同样的fiddle,将光源移动到了立方体外面。http://jsfiddle.net/Q4uqE/5/ - Cory Gross
你为什么要移动光源?根据Three.js文档:“创建一个从特定方向照射而不是从特定位置照射的光源。”,改变position.x只会改变方向吗? - Henrik Karlsson
这些参数:shadowCameraNear、shadowCameraFar、shadowCameraFov、shadowMapBias、shadowMapDarkness、shadowMapWidth 和 shadowMapHeight,难道不应该在光源上设置,而不是渲染器上吗? - Hobbes
您知道为什么在此分支示例中 light.shadowCameraVisible 没有作用吗?http://jsfiddle.net/Q4uqE/566/ - Ates Goral
你的演示不再起作用,因为在r74之后,定向光阴影相机的FOV默认缩小了。正如Drew Noakes的答案所提到的,你必须将这个FOV缩放至少与你的对象一样大:请参见fiddle - concat

0
在r139.2中,属性已更改为:
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap; //THREE.BasicShadowMap | THREE.PCFShadowMap |  THREE.VSMShadowMap | THREE.PCFSoftShadowMap

renderer.shadowMap.soft = true;
renderer.shadowMap.bias = -0.0001;
renderer.shadowMap.darkness = 1;
renderer.shadowMap.width = 2048;
renderer.shadowMap.height = 2048;

示例:

const spotLight = new THREE.DirectionalLight();
spotLight.castShadow = true;
scene.add(spotLight);
spotLight.position.set(0, 8, 0);


//Object cast shadow
const cube = new THREE.Mesh( new THREE.BoxGeometry(1,1,1), new THREE.MeshBasicMaterial({color: 0x00ff00}) );
cube.castShadow = true;
scene.add(cube);


//Plane floor receive shadows
const planeShadow = new THREE.Mesh(new THREE.PlaneGeometry(3, 3), new THREE.MeshPhongMaterial()); //Material they have to be MeshPhongMaterial

planeShadow.name = "FloorShadow";
planeShadow.renderOrder = -2;
planeShadow.lookAt(new THREE.Vector3(0, 1, 0));
planeShadow.receiveShadow = true;
planeShadow.position.set(0, 0, 0);
scene.add(planeShadow);

如果您需要更多信息或其他示例,可以查看此链接[https://sbcode.net/threejs/directional-light-shadow/]


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接