Skip to content

Latest commit

 

History

History
169 lines (127 loc) · 6.75 KB

06 光源与光影效果.md

File metadata and controls

169 lines (127 loc) · 6.75 KB

光源(Light)

环境光(AmbientLight)、点光源(PointLight)、聚光灯(SpotLight)、平行光(DirectionalLight)

光源 说明 图示
AmbientLight 环境光。散布在环境中的光,会将光源的颜色叠加到场景中所有物体上,不能创造阴影,通常拿来增加一些柔性的光线补强色彩。 ambientLight
PointLight 点光源。从特定一点向所有方向发射光线,可以投射阴影。类似灯泡、萤火虫的概念。 PointLight
SpotLight 聚光灯。从特定一点对某个方向发射锥形的光线,可以投射阴影。类似手电筒、舞台聚光灯的概念。 SpotLight
DirectionalLight 平行光、无限光。从一个二维平面发射光线,光线彼此平行,可以投射阴影,类似太阳光的概念。 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 所绕的半径不同,看起来就会有椭圆轨道的效果。