本文簡介
點贊 + 關注 + 收藏 = 學會了
渲染陰影效果需要消耗一定的資源,所以 Three.js 默認是關閉陰影效果的。
想要在 Three.js 中實現(xiàn)陰影效果,只需記住接下來要講的幾個點即可。
本文要實現(xiàn)的效果

本文適合 Three.js 入門級的工友閱讀~
如果你還不了解 Three.js ,可以先看看 《Three.js 起飛》 。
本文使用 Three 的版本是 137 。
基礎概念
在學習 Three.js 時,很多知識點其實記住幾個重要的步驟就能實現(xiàn)相應的效果。
比如在 《Three.js 起飛》 中提到的,只要有 場景、攝像機、渲染器、物體 就能在頁面中展示一些東西出來了。
要實現(xiàn)陰影效果同樣需要幾個重要的概念。
我們首先研究一下日常生活中是如何產生陰影效果的。
- 需要有光。
- 需要一個物體,比如蘋果、狗等。
- 需要一個接受投影的元素,比如地面、桌面等。
在 Three.js 中要產生陰影效果其實和現(xiàn)實世界的原理差不多。
但考慮到性能原因,Three.js 默認關閉了陰影效果,需要手動開啟陰影效果:
- 渲染器開啟陰影效果。
- 有一個能產生陰影的光源,并開啟陰影效果。
- 有一個接受陰影投射的元素(比如地面),并設置 接受陰影的屬性 為
true。 - 有一個能產生陰影效果的物體,并開啟陰影效果。
動手實現(xiàn)
動手之前先觀察一下最終效果

上圖有一個立方體、地面、光源。
還有基礎元素:場景、攝像機、渲染器。
我把用到的元素整理成一個表格:
| 元素 | 描述 | 相關代碼 |
|---|---|---|
| 場景 | 容器,光源、立方體、地面等元素都要添加到場景中。 | let scene = new Scene() |
| 攝像機 | 場景中的相機,代替人眼去觀察的工具。 | let camera = new PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000) |
| 渲染器 | 渲染工具,本文主要講的是開啟陰影渲染功能。 | 需要開啟陰影渲染功能 renderer.shadowMap.enabled = true
|
| 地面 | 地面,接收陰影的元素。 | 用 PlaneGeometry 生成一個平面,并設置該平面的 receiveShadow 屬性為 true 就能接受別的物體投射過來的陰影。 |
| 立方體 | 本例的物體元素。 | 用 BoxGeometry 創(chuàng)建一個立方體,并設置該立方體的 castShadow 屬性為 true ,就能產生投影效果。 |
| 光源 | 要使用 可產生陰影效果 的光源,比如本例的 SpotLight 聚光燈。像 AmbientLight 環(huán)境光 、PointLight 點光源 是不能產生陰影效果的。 |
使用 SpotLight 創(chuàng)建光源,并設置該光源的 castShadow 為 true 開啟陰影效果。 |
第1步:搭建基礎場景
在 Three 中搭建基礎場景需要3要素:場景 Scene、攝像機 PerspectiveCamera、渲染器 WebGLRenderer 。

<script type="module">
import {
Scene, // 場景
PerspectiveCamera, // 攝像機
WebGLRenderer, // 渲染器
Color, // 顏色(不是本例重點)
PlaneGeometry, // 平面幾何(創(chuàng)建地面時會用到)
BoxGeometry, // 立方幾何體(創(chuàng)建立方體時會用到)
MeshLambertMaterial, // 非光澤表面的材質(可接受光照產生陰影效果)
Mesh, // 網(wǎng)格,合成物體元素時會用到
SpotLight // 聚光燈
} from '../js/Three/src/Three.js'
// 場景
let scene = new Scene()
// 攝像機
let camera = new PerspectiveCamera(
45,
window.innerWidth / window.innerHeight,
0.1,
1000
)
// 設置攝像機位置
camera.position.set(-30, 60, 60)
// 鎖定攝像機鏡頭方向
camera.lookAt(scene.position)
// 渲染器
let renderer = new WebGLRenderer()
renderer.setClearColor(new Color(0xEEEEEE)) // 設置渲染器顏色
renderer.setSize(window.innerWidth, window.innerHeight) // 渲染器尺寸
// 將渲染器添加到頁面
document.body.appendChild(renderer.domElement)
// 渲染
renderer.render(scene, camera)
</script>
我把場景的背景色設置成灰色 renderer.setClearColor(new Color(0xEEEEEE)) 。
此時頁面上是一片空白,還沒元素可以展示。
第2步:創(chuàng)建光源
因為本例 沒有使用 基礎材質(MeshBasicMaterial) ,渲染出來的物體沒有光源是不會顯示的,所以我先把光源添加到場景中,之后添加地面和立方體時就比較方便觀察了。
要實現(xiàn)陰影效果,我選擇了 SpotLight 聚光燈。
// 省略部分代碼
// 光源
let spotLight = new SpotLight(0xFFFFFF)
spotLight.position.set(-40, 50, 30)
scene.add(spotLight) // 將聚光燈添加到場景中
雖然創(chuàng)建了光源,但此時場景中并沒有其他物體,所以場景還是一片空白。
第3步:創(chuàng)建地面
在本例中地面是用來接受物體投影的載體。
創(chuàng)建地面我使用了 PlaneGeometry 平面,該方法只需傳入寬和高即可。
然后使用 MeshLambertMaterial 材質,設置地面顏色為白色。
// 省略部分代碼
// 地面
let planeGeometry = new PlaneGeometry(60, 20) // 骨架
let planeMaterial = new MeshLambertMaterial({ color: 0xffffff }) // 可產生陰影的材質
let plane = new Mesh(planeGeometry, planeMaterial) // 網(wǎng)格
scene.add(plane) // 將地面添加到場景中

此時看到的地面呈現(xiàn)上圖的樣子(一點都不想地面)。
由于燈光的關系,地面看上去并不是純白色,離燈光越近的地方就越白,越遠就越灰。
我希望地面可以水平放置,所以我將地面沿x軸旋轉 -90° 。
// 省略部分代碼
plane.rotation.x = -90 * Math.PI / 180 // 地面 x軸 旋轉-90度

第4步:創(chuàng)建立方體
我使用 BoxGeometry 創(chuàng)建立方體,設置一個紅色的紋理。
// 省略部分代碼
// 立方體
let cubeGeometry = new BoxGeometry(6, 6, 6)
let cubeMaterial = new MeshLambertMaterial({ color: 0xff0000 }) // 可產生陰影的材質
let cube = new Mesh(cubeGeometry, cubeMaterial)
scene.add(cube)

修改一下立方體的位置
cube.position.set(-6, 6, 3)

第5步:開啟陰影效果
用回上面提到的四句口訣就能開啟陰影效果
- 渲染器開啟陰影效果。
- 有一個能產生陰影的光源,并開啟陰影效果。
- 有一個接受陰影投射的元素(比如地面),并設置 接受陰影的屬性 為
true。 - 有一個能產生陰影效果的物體,并開啟陰影效果。
// 省略部分代碼
// 渲染器開啟陰影效果
renderer.shadowMap.enabled = true
// 光源開啟陰影效果
spotLight.castShadow = true
// 地面接受陰影
plane.receiveShadow = true
// 立方體開啟陰影效果
cube.castShadow = true

完成!
如果想設置陰影的精細度,還可以通過聚光燈的三個屬性進行控制:
spotLight.shadow.mapSizespotLight.shadow.camera.farspotLight.shadow.camera.nera
本文主要講解陰影的基礎使用方法,先入個門,后面的案例文章會和結合其他效果完成更好玩的東西~
代碼倉庫
推薦閱讀
點贊 + 關注 + 收藏 = 學會了
代碼倉庫