环境光(AmbientLight)、点光源(PointLight)、聚光灯(SpotLight)、平行光(DirectionalLight)
// 设置环境光 AmbientLight
let ambientLight = new THREE.AmbientLight(0xeeff00)
scene.add(ambientLight)
// 设置点光源 PointLight
let pointLight = new THREE.PointLight(0xeeff00)
pointLight.position.set(-10, 20, 20)
pointLight.castShadow = true
scene.add(pointLight)
let pointLightHelper = new THREE.PointLightHelper(pointLight)
scene.add(pointLightHelper)
// 设置聚光灯 SpotLight
let spotLight = new THREE.SpotLight(0xeeff00)
spotLight.position.set(-10, 20, 20)
spotLight.castShadow = true
scene.add(spotLight)
let spotLightHelper = new THREE.SpotLightHelper(spotLight)
scene.add(spotLightHelper)
// 设置平行光 DirectionalLight
let directionalLight = new THREE.DirectionalLight(0xeeff00)
directionalLight.position.set(-10, 20, 20)
directionalLight.castShadow = true
scene.add(directionalLight)
let directionalLightHelper = new THREE.DirectionalLightHelper(
directionalLight
)
scene.add(directionalLightHelper)
以上四种光源的设定上都差不多,关于每种光源的属性,除了环境光只能设定颜色(color)与强度(intensity)之外,其他每一种光源还有像是距离(distance)、投射阴影效果(castShadow)等等属性,或像是聚光灯可以自定义射出光束的角度(angle)及目标(target),一般而言大多使用预设值,但如果需要细调,读者可依照自己需求根据官网文件添加。
后三者都有 helper 可以用来辅助开发,了解目前光源相关的设定是否正确。
要让场景有光影效果,首先要对场景中的各个元素进行投影的设定:
renderer.shadowMap.enabled = true // 设定需渲染阴影效果
renderer.shadowMap.type = 2 // THREE.PCFSoftShadowMap
renderer.shadowMap.type
是设定阴影贴图的种类,总共有三种可以设定:
- THREE.BasicShadowMap = 0
- THREE.PCFShadowMap = 1
- THREE.PCFSoftShadowMap = 2
可以简单理解为阴影的毛边优化,调整成 THREE.PCFSoftShadowMap
影子会看起来比较圆滑。
plane.receiveShadow = true
记得要在地板处将 receiveShadow
这个属性打开才会接收其他元素投影的效果。
// 苦力怕投影设置,利用 traverse 遍历各个子元件设定阴影
this.creeper.traverse(function(object) {
if (object instanceof THREE.Mesh) {
object.castShadow = true
object.receiveShadow = true
}
})
最后是我们的主角苦力怕也需要设定能够有投影的效果,因此这边在苦力怕物件中也加上以上设定开启投影效果。
这边有个 traverse
方法,这是 THREE.Scene
中提供一个用来遍历目标物件(creeper)及其所有后代(head、body、feet)的方法,透过传入的function,可以对苦力怕底下的所有子元件都设定阴影效果。
// 设置环境光提供辅助柔和白光
let ambientLight = new THREE.AmbientLight(0x404040)
scene.add(ambientLight)
// 设置聚光灯帮忙照亮物体
let spotLight = new THREE.SpotLight(0xf0f0f0)
spotLight.position.set(-10, 30, 20)
spotLight.castShadow = true
scene.add(spotLight)
只是简单几行添加光源与阴影有点太无趣了,所以再加了一个移动的点光源来体验一下光影互动的效果。
// 移动点光源
pointLight = new THREE.PointLight(0xccffcc, 1, 100) // 颜色,强度,距离
pointLight.castShadow = true // 投影
scene.add(pointLight)
// 小球体模拟点光源实体
const sphereLightGeo = new THREE.SphereGeometry(0.3)
const sphereLightMat = new THREE.MeshBasicMaterial({ color: 0xccffcc })
sphereLightMesh = new THREE.Mesh(sphereLightGeo, sphereLightMat)
sphereLightMesh.castShadow = true
sphereLightMesh.position.y = 16
scene.add(sphereLightMesh)
先在 Init()
中宣告点光源与模拟光源实体的小球体到场景中,再来要让小球移动的话就需要在 render()
中加上动画效果:
// 点光源绕 Y 轴旋转动画
function pointLightAnimation() {
if (rotateAngle > 2 * Math.PI) {
rotateAngle = 0 // 超过 360 度后归零
} else {
rotateAngle += 0.03 // 递增角度
}
// 光源延椭圆轨道绕 Y 轴旋转
sphereLightMesh.position.x = 8 * Math.cos(rotateAngle)
sphereLightMesh.position.z = 4 * Math.sin(rotateAngle)
// 点光源位置与球体同步
pointLight.position.copy(sphereLightMesh.position)
}
function render() {
...
pointLightAnimation() // update
requestAnimationFrame(render)
renderer.render(scene, camera)
}
由于是绕y 轴旋转,所以要让小球体的 (x, z)
座标随着递增的角度产生绕行圆心的效果,这个座标就会是(r * cos(θ), r * sin(θ))
,而角度会随时间递增并且在超过360 度后归零重算,另外这边让x 与z 所绕的半径不同,看起来就会有椭圆轨道的效果。