Three.js - 光源使用详解(环境光 AmbientLight、点光源 PointLint、聚光灯 SpotLight、平行光 DirectionLight、环境光 HemisphereLight、镜头光晕 LensFlare)
转载来源:
http://www.hangge.com/blog/cache/detail_1810.html
http://www.hangge.com/blog/cache/detail_1812.html
http://www.hangge.com/blog/cache/detail_1811.html
git项目示例源码地址: https://github.com/jdk137/learnThree.js
一些在线示例:
AmbientLight环境光
PointLight 点光源
SpotLight 聚光灯
DirectionalLight 方向光
HemisphereLight 半球环境光
AreaLight 区域光
LensflaresLight 光晕光
Three.js 中有许多不同种类的光源,每种光源都有特别的行为和用法。下面通过一个系列文章介绍它们的用法。
一、THREE.AmbientLight(环境光)
1,基本介绍
-
在创建 THREE.AmbientLight 时,颜色会应用到全局。
-
该光源并没有特别的来源方向,并且 THREE.AmbientLight 不会产生阴影。
2,使用建议
-
通常,不能将 THREE.AmbientLight 作为场景中唯一的光源,因为它会将场景中的所有物体渲染为相同的颜色,而不管是什么形状。
-
在使用其他光源(如 THREE.SpotLight 或者 THREE.DirectionLight)的同时使用它,目的是弱化阴影或给场景添加一些额外的颜色。
3,使用样例
由于 THREE.AmbientLight 光源不需要指定位置并且会应用到全局,所以我们只需要指定个颜色,然后将其添加到场景中即可。
1 2 | var ambientLight = new THREE.AmbientLight(0x523318); scene.add(ambientLight); |
4,效果图
(1)下面是场景中只使用 AmbientLight 这一种光源的情况(颜色分别为:0x523318、0xffffff)
(2)下面场景中除了 AmbientLight 光源外(颜色分别为:0x523318、0xffffff),还添加了个 SpotLight(颜色:0xffffff)
(3)下面是场景只使用一个 SpotLight 光源(颜色:0xffffff)的效果,大家可以比较下。
二、THREE.PointLight(点光源)
1,基本介绍
-
THREE.PointLight 是一种单点发光、照射所有方向的光源(比如夜空中的照明弹就是一个点光源例子)
-
THREE.PointLight 不会产生阴影。因为它会朝所有的方向发射光线,在这种情况下计算阴影对 GPU 是个沉重的负担。「新版Three.js本可以产生阴影!!」
2,属性介绍
-
color:光源的颜色
-
distance:光源照射的距离。默认值为 0,意味着光的强度不会随着距离的增加而减少。
-
intensity:光源照射的强度。默认值为 1。
-
position:光源在场景中的位置。
-
visible:设为 ture(默认值),光源就会打开。设为 false,光源就会关闭。
3,使用样例
这里我们只指定了光源的颜色和位置(其它属性使用默认值),并将其添加到场景中。
1 2 3 | var pointLight = new THREE.PointLight("#ccffcc"); pointLight.position.set(0,10,10); scene.add(pointLight); |
4,效果图
(1)上面样例中我们往场景中添加了个绿色的点光源,效果如下:
(2)我们如果将光源的 intensity 属性设为 2.4,表示亮度为默认的 2.4 倍,效果图如下:
1 | pointLight.intensity = 2.4; |
(3)光源的 distance 属性决定了在光线强度变为 0 之前光线的传播距离。默认为 0,表示光线强度不会随着距离的增加而减弱。
这里我们接着把 distance 属性设为 22,表示光线在距离为22的地方慢慢地减少为 0。
1 | pointLight.distance = 22; |
三、THREE.SpotLight(聚光灯光源)
1,基本介绍
-
THREE.SpotLight 是一种具有锥形效果的光源,该光源拥有产生光的方向和角度。我们可以将其与手电筒或者灯笼产生的光进行对比。
-
THREE.SpotLight 是最常使用的光源之一,特别是如果我们想要使用阴影的话。
2,属性介绍
-
angle:角度。即光源发射出的光束的宽度。单位是弧度,默认值:Math.PI/3
-
castShadow:投影。如果设置为 true,这个光源就会生成阴影。
-
color:光源颜色。
-
distance:光源照射的距离。默认值为 0,这意味着光线强度不会随着距离增加而减弱。
-
exponent:光强衰减指数。使用 THREE.SpotLight 光源,发射的光线的强度随着光源距离的增加而减弱。exponent 属性决定了光线强度递减的速度。使用低值,从光源发出的光线将到达远处的物体,而使用高值,光线仅能到达非常接近 THREE.SpotLight 光源的物体。
-
intensity:光源照射的强度。默认值:1
-
onlyShadow:仅阴影。如果此属性设置为 true,则该光源只生成阴影,而不会在场景中添加任何光照。
-
position:光源在场景中的位置
-
shadow.bias:用来偏置阴影的位置。当你使用非常薄的对象时,可以使用它来解决一些奇怪的效果。如果你看到奇怪的阴影效果,将该属性设置为很小的值(例如 0.01)通常可以解决问题。此属性的默认值为 0。
-
shadow.camera.far:投影远点。表示到距离光源的哪一个位置可以生成阴影。默认值:5000
-
shadow.camera.fov:投影视场。表示用于生成阴影的视场有多大。默认值:50
-
shadow.camera.near:投影近点。表示距离光源的哪一个位置开始生成阴影。默认值为 50
-
shadow.map.width 和 shadow.map.height:阴影映射宽度和阴影映射高度。决定了有多少像素用来生成阴影。当阴影具有锯齿状边缘或看起来不光滑时,可以增加这个值。在场景渲染之后无法更改。两者的默认值均为:512
-
target:目标。使用 THREE.SpotLight 光源时,它的指向很重要。使用 target 属性,你可以将 THREE.SpotLight 光源指向场景中的特定对象或位置。注意,此属性需要一个 THREE.Object3D 对象(如 THREE.Mesh)。
-
visible:是否可见。如果该属性设置为 true(默认值),该光源就会打开。如果设置 false,光源就会关闭。
3,基本用法
(1)创建聚光灯光源非常简单,只要指定颜色(并设置相关属性),然后添加到场景中即可。要特别注意如下几个属性:
-
castShadow:如果想要阴影,该属性要设置为 true。
-
target:该属性决定光源照射的位置。这里我们将其指向 plane 对象(地板)。
1 2 3 4 5 | var spotLight = new THREE.SpotLight(0xffffff); spotLight.position.set(30, 25, -2); spotLight.castShadow = true; spotLight.target = plane; scene.add(spotLight); |
(2)如果我们不想将 target 瞄准一个特定的对象,而是空间中的任意一点。可以通过创建一个 THREE.Object3D() 对象来实现。
1 2 3 4 5 6 7 8 9 10 11 | //创建一个3d对象作为聚光灯的目标 var target = new THREE.Object3D(); target.position.set(30, 0, 0); scene.add(target);
//创建聚光灯 var spotLight = new THREE.SpotLight(0xffffff); spotLight.position.set(30, 25, -2); spotLight.castShadow = true; spotLight.target = target; scene.add(spotLight); |
4,阴影相关用法
(1)除了告诉光源要生成阴影外,还必须通过配置每个几何体的 castShadow 和 receiveShadow 属性来告诉几何体对象是否接收或投射阴影。
1 2 3 4 5 | //平面接收阴影 plane.receiveShadow = true; //方块和球体投射阴影 cube.castShadow = true; sphere.castShadow = true; |
(2)配合使用 THREE.CameraHelper,我们可以把用来决定阴影的光照区域显示出来,方便调试。
1 2 | var helper = new THREE.CameraHelper(spotLight.shadow.camera ); scene.add(helper); |
(3)如果想要阴影更加柔和,可以在 THREE.WebGLRenderer 对象上设置不同的 shadowMap.type 属性值:
-
THREE.PCFShadowMap:默认阴影
-
THREE.PCFSoftShadowMap:更加柔和的阴影
1 2 3 4 5 | var renderer = new THREE.WebGLRenderer(); renderer.setClearColor(new THREE.Color(0xEEEEEE)); renderer.setSize(window.innerWidth, window.innerHeight); renderer.shadowMap.enabled = true; renderer.shadowMap.type = THREE.PCFSoftShadowMap; |
四、THREE.DirectionLight(平行光)
1,基本介绍
-
THREE.DirectionLight 可以看作是距离很远的光,它发出的所有光线都是相互平行的。平行光的一个范例就是太阳光。
-
平行光不像上面的聚光灯(通过 distance 和 exponent 属性来微调)那样离目标越远越暗淡。被平行光照亮的整个区域接受到的光强是一样的。
2,属性介绍
-
position:光源在场景中的位置。
-
target:目标。使用 THREE.DirectionLight 光源时,它的指向很重要。使用 target 属性,你可以将 THREE.SpotLight 光源指向场景中的特定对象或位置。注意,此属性需要一个 THREE.Object3D 对象(如 THREE.Mesh)。
-
intensity:光源照射的强度。默认值:1
-
castShadow:投影。如果设置为 true,这个光源就会生成阴影
-
onlyShadow:仅阴影。如果此属性设置为 true,则该光源只生成阴影,而不会在场景中添加任何光照。
-
shadow.camera.near:投影近点。表示距离光源的哪一个位置开始生成阴影。
-
shadow.camera.far:投影远点。表示到距离光源的哪一个位置可以生成阴影。
-
shadow.camera.left:投影左边界。
-
shadow.camera.right:投影右边界。
-
shadow.camera.top:投影上边界。
-
shadow.camera.bottom:投影下边界。
-
shadow.map.width 和 shadow.map.height:阴影映射宽度和阴影映射高度。决定了有多少像素用来生成阴影。当阴影具有锯齿状边缘或看起来不光滑时,可以增加这个值。在场景渲染之后无法更改。两者的默认值均为:512
3,基本用法
(1)对于 THREE.DirectionLight 来说,由于所有的光线都是平行的,所以不会有光锥,而是一个立方体区域。下面代码我们配合 THREE.CameraHelper 对象,将用来决定阴影的光照区域显示出来,方便调试。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | //创建平行光 var directionalLight = new THREE.DirectionalLight(0xffffff); directionalLight.position.set(25, 17, -2); directionalLight.castShadow = true; directionalLight.target = plane directionalLight.shadow.camera.near = 2; directionalLight.shadow.camera.far = 40; directionalLight.shadow.camera.left = -20; directionalLight.shadow.camera.right = 20; directionalLight.shadow.camera.top = 20; directionalLight.shadow.camera.bottom = -20; scene.add(directionalLight);
//显示光照区域 var helper = new THREE.CameraHelper(directionalLight.shadow.camera ); scene.add(helper); |
(2)有时我们不想将 target 瞄准一个特定的对象,而是空间中的任意一点。可以通过创建一个 THREE.Object3D() 对象来实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | //创建一个3d对象作为平行光的目标 var target = new THREE.Object3D(); target.position.set(8, 0, 5); scene.add(target);
//创建平行光 var directionalLight = new THREE.DirectionalLight(0xffffff); directionalLight.position.set(25, 17, -2); directionalLight.castShadow = true; directionalLight.target = target directionalLight.shadow.camera.near = 2; directionalLight.shadow.camera.far = 40; directionalLight.shadow.camera.left = -20; directionalLight.shadow.camera.right = 20; directionalLight.shadow.camera.top = 20; directionalLight.shadow.camera.bottom = -20; scene.add(directionalLight); |
3,shadowCascade 属性介绍
-
THREE.DirectionLight 还有一个特有的属性:shadowCascade。当我们需要使用 THREE.DirectionLight 在一个很大的区域设置阴影时,这个属性可以帮助创建更好的阴影效果。
-
该属性默认为 false。如果将这个属性设置为 true,Three.js 会使用一个替代方法来生成阴影。它将阴影的生成分裂为由 shadowCascadeCount 指定的值。这将导致靠近摄相机视点会产生更具细节的阴影,而远离摄像机视点阴影的细节更少。
-
要使用这个选项需要尝试设置一下属性:shadowCascadeCount、shadowCascadeBias、shadowCascadeWidth、shadowCascadeHeight、shadowCascadeNearZ 和 shadowCascadeFarZ 属性。
五、THREE.HemisphereLight(环境光)
1,基本介绍
-
使用 THREE.HemisphereLight 可以创建更加贴近自然的户外光照效果。
-
THREE.HemisphereLight 不会产生阴影。
THREE.HemisphereLight 的优势:
如果不使用 THREE.HemisphereLight,要模拟户外光照,通常是创建一个 THREE.DirectionalLight 来模拟太阳光,并且可能再添加一个 THREE.AmbientLight 来为场景提供基础色。
但是,这样的光照效果看起来并不怎么自然。因为在户外,并不是所有的光源都来自上方(很多是来自大气的散射和地面以及其他物体的反射)。
THREE.HemisphereLight 光源就是为这种情形创建的。它为获得更自然的户外光照效果提供了一个简单的方式。
2,属性介绍
-
color:从天空发出的光线的颜色
-
groundColor:从地面发出的光线的颜色
-
intensity:光源照射的强度。默认值为:1。
-
position:光源在场景中的位置。默认值为:(0, 100, 0)
-
visible:设为 ture(默认值),光源就会打开。设为 false,光源就会关闭。
3,使用样例
创建半球光源就像创建其他光源一样简单,只需要给它指定接收自天空的颜色,接收自地面的颜色,以及这些光线的关照强度即可。
1 2 3 | var hemiLight = new THREE.HemisphereLight(0x0000ff, 0x00ff00, 0.6); hemiLight.position.set(0, 100, 0); //这个也是默认位置 scene.add(hemiLight); |
4,效果图
下面左右两个场景中环境光源使用的初始值分别是:(0x0000ff, 0x00ff00, 0.6)、(0xffffff, 0x000000, 1)
六、THREE.LensFlare(镜头光晕)
1,基本介绍
-
当我们直接朝着太阳或者另一个非常明亮的光源拍照时就会出现镜头光晕效果(lens flare)。
-
使用 THREE.LensFlare 可以很方便地在场景中添加一个镜头光晕,这样会让场景看上去更加真实。
-
THREE.LensFlare 自身不会产生任何光照效果,也不会产生阴影。
2,属性介绍
-
texture:纹理。纹理就是一个图片,用来决定光晕的形状。
-
size:尺寸。可以指定光晕多大。这个尺寸的单位是像素。如果将它指定为 -1,那么将使用纹理本身的尺寸。
-
distance:距离。即从光源(0)到摄像机的距离。使用这个参数将镜头光晕放置在正确的位置。
-
blending:混合。我们我们可以为光晕提供多种材质。混合模式决定了如何将它们混合在一起。镜头光晕默认的混合方式是 THREE.AdditiveBlending。
-
color:光晕的颜色。
3,准备工作
如果需要往场景中添加一个镜头光晕,首先我们需要将渲染器 THREE.WebGLRenderer 对象的 alpha 配置属性设置为 true。
1 2 3 | var renderer = new THREE.WebGLRenderer({ alpha: true }); |
4,基本用法
(1)代码说明
由于镜头光晕并不会照亮物体,所以我们首先添加一个平行光源。
接着创建一个镜头光晕,将其放在光源处,这样看起来就像是光源产生的光晕。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | //创建平行光源 var directionalLight = new THREE.DirectionalLight(0xffffff); directionalLight.position.set(30, 10, -50); directionalLight.castShadow = true; directionalLight.target = plane; directionalLight.intensity = 2; directionalLight.distance = 0; directionalLight.shadow.camera.left = -25; directionalLight.shadow.camera.right = 25; directionalLight.shadow.camera.top = 25; directionalLight.shadow.camera.bottom = -25; scene.add(directionalLight);
//创建镜头光晕 var loader = new THREE.TextureLoader() var textureFlare0 = loader.load("./lensflare/lensflare0.png"); var flareColor = new THREE.Color(0xffaacc); var lensFlare = new THREE.LensFlare(textureFlare0, 170, 0.0, THREE.AdditiveBlending, flareColor); lensFlare.position.copy(directionalLight.position); scene.add(lensFlare); |
(2)效果图
5,添加一些小光晕
(1)创建好主光晕后,我们还可以在页面中添加一些小的圆形失真图形。看起来像是光线照射过来时产生的光斑。
这里的小光晕并不是创建一个新的 THREE.LensFlare,而是使用刚创建的主光晕(THREE.LensFlare 对象)的 add 方法。这些新光晕使用的纹理是一个颜色很淡的圆。
add 方法介绍:
这个方法只需要指定纹理(texture)、尺寸(size)、距离(distance)和混合模式(blending)
通过该方法还可以接受两个额外的参数:新光晕的颜色(color)和不透明度(opacity)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | //创建平行光源 //....
//创建镜头光晕 var loader = new THREE.TextureLoader() var textureFlare0 = loader.load("./lensflare/lensflare0.png"); var textureFlare3 = loader.load("./lensflare/lensflare3.png"); var flareColor = new THREE.Color(0xffaacc); var lensFlare = new THREE.LensFlare(textureFlare0, 170, 0.0, THREE.AdditiveBlending, flareColor); lensFlare.add(textureFlare3, 60, 0.6, THREE.AdditiveBlending); lensFlare.add(textureFlare3, 70, 0.7, THREE.AdditiveBlending); lensFlare.add(textureFlare3, 120, 0.9, THREE.AdditiveBlending); lensFlare.add(textureFlare3, 70, 1.0, THREE.AdditiveBlending); lensFlare.position.copy(directionalLight.position); scene.add(lensFlare); |
(2)效果图