在 Three.js 中,SpotLight
(聚光灯)是一种能沿着一个方向发射锥形光束的光源,广泛应用于舞台灯光、聚焦灯、手电筒等模拟场景中。本文将详细介绍 SpotLight 的各个属性和使用方法,并提供一个基于 Vue3 + Composition API 的完整示例帮助理解。
一、SpotLight 基本介绍
1. 创建方式
const spotLight = new THREE.SpotLight(0xffffff, 1);
scene.add(spotLight);
构造函数参数:
new THREE.SpotLight(
color?: ColorRepresentation,
intensity?: number,
distance?: number,
angle?: number,
penumbra?: number,
decay?: number
)
2. 常用属性解释
属性名 | 作用描述 |
---|---|
color | 光的颜色 |
intensity | 光照强度 |
distance | 光照最远距离(0表示无限远) |
angle | 聚光灯锥形角度,单位弧度(0 ~ Math.PI/2) |
penumbra | 半影范围(0~1)边缘柔和度 |
decay | 衰减系数(默认为 1) |
target | 聚光灯照射目标(默认是 (0,0,0),可设置为任意 Object3D) |
castShadow | 是否投射阴影 |
shadow | 光源阴影设置对象(分辨率、模糊度等) |
二、SpotLight 相关方法与注意事项
1. 设置光源位置和目标
spotLight.position.set(10, 10, 10);
spotLight.target.position.set(0, 0, 0);
scene.add(spotLight.target); // 一定要添加 target
2. 控制阴影效果
spotLight.castShadow = true;
spotLight.shadow.mapSize.width = 1024;
spotLight.shadow.mapSize.height = 1024;
spotLight.shadow.camera.near = 0.5;
spotLight.shadow.camera.far = 500;
spotLight.shadow.camera.fov = 30;
3. Helper 可视化工具
const spotLightHelper = new THREE.SpotLightHelper(spotLight);
scene.add(spotLightHelper);
// 若动态更新光源参数,需手动调用 update spotLightHelper.update();
三、完整的 SpotLight 示例(非 Vue)
const scene = new THREE.Scene();
const light = new THREE.SpotLight(0xffffff, 1, 100, Math.PI / 6, 0.2, 2); light.position.set(10, 20, 10);
light.castShadow = true;
scene.add(light);
light.target.position.set(0, 0, 0);
scene.add(light.target);
const helper = new THREE.SpotLightHelper(light);
scene.add(helper);
四、基于 Vue 3 + Composition API 的 SpotLight 案例
✅ 技术栈
-
Vue 3 + Vite
-
Three.js 0.167.2
-
Composition API +
onMounted
生命周期控制
✅ 效果预览
-
聚光灯照射一个立方体,带阴影
-
支持窗口自适应
-
可视化 Helper 显示光照范围
📦 示例组件代码
<!-- SpotLightScene.vue -->
<template>
<div ref="container" class="w-full h-full"></div>
</template>
<script setup lang="ts">
import * as THREE from 'three'
import { onMounted, ref } from 'vue'
const container = ref<HTMLDivElement | null>(null)
onMounted(() => {
const scene = new THREE.Scene()
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000)
camera.position.set(10, 10, 10)
camera.lookAt(0, 0, 0)
const renderer = new THREE.WebGLRenderer({ antialias: true })
renderer.setSize(window.innerWidth, window.innerHeight)
renderer.shadowMap.enabled = true
container.value?.appendChild(renderer.domElement)
// 地板
const plane = new THREE.Mesh(
new THREE.PlaneGeometry(200, 200),
new THREE.MeshStandardMaterial({ color: 0x999999 })
)
plane.rotation.x = -Math.PI / 2
plane.receiveShadow = true
scene.add(plane)
// 立方体
const cube = new THREE.Mesh(
new THREE.BoxGeometry(2, 2, 2),
new THREE.MeshStandardMaterial({ color: 0x00aaff })
)
cube.position.y = 1
cube.castShadow = true
scene.add(cube)
// SpotLight
const spotLight = new THREE.SpotLight(0xffffff, 1, 100, Math.PI / 6, 0.2, 2)
spotLight.position.set(10, 15, 10)
spotLight.castShadow = true
spotLight.shadow.mapSize.set(1024, 1024)
spotLight.shadow.camera.near = 1
spotLight.shadow.camera.far = 100
scene.add(spotLight)
// SpotLight Target
spotLight.target.position.set(0, 0, 0)
scene.add(spotLight.target)
// Helper
const spotHelper = new THREE.SpotLightHelper(spotLight)
scene.add(spotHelper)
// 环境光
scene.add(new THREE.AmbientLight(0x404040))
// 渲染循环
const animate = () => {
requestAnimationFrame(animate)
renderer.render(scene, camera)
spotHelper.update()
}
animate()
// 自适应
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight
camera.updateProjectionMatrix()
renderer.setSize(window.innerWidth, window.innerHeight)
})
})
</script>
<style scoped>
html, body, #app {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
}
</style>
五、SpotLight 常见问题与调试技巧
-
光线没有照射到目标?
-
检查
target
是否设置并添加到场景中 -
检查
angle
是否过小
-
-
阴影效果不明显?
-
调整
shadow.mapSize
提高分辨率 -
调整
shadow.camera.near
和far
范围 -
设置
castShadow
和receiveShadow
正确
-
-
目标改变位置后光线不更新?
-
使用
SpotLightHelper.update()
来强制刷新辅助器
-
六、结语
Three.js 中的 SpotLight 是一个强大而灵活的光源类型,掌握其属性配置与使用技巧对提升 3D 场景表现力至关重要。希望本文的详细讲解和 Vue 示例能帮你更深入地理解它的使用方式。
如果你觉得文章对你有帮助,欢迎点赞、收藏、评论支持!我也会持续分享更多 Three.js 与 Vue 的实战干货 🎉