方向光 DirectionalLight
具有特定方向;能产生阴影;不能在物体里面;强度、颜色、位置、目标都能影响渲染效果;阴影相机是正交相机。
js
createScene () {
const canvas = document.getElementById('c')
const width = window.innerWidth;
const height = window.innerHeight;
canvas.width = width
canvas.height = height
// 挂载全局上
this.canvas = canvas
this.width = width
this.height = height
// 创建3D场景对象
const scene = new THREE.Scene();
scene.background = new THREE.Color(0xf0f0f0)
this.scene = scene
},
// 创建光照
createLights () {
// 添加全局光照
const ambientLight = new THREE.AmbientLight(0xffffff, 0.95)
// 方向光
const dirLight = new THREE.DirectionalLight(0xffffaa, 0.95)
dirLight.castShadow = true // 让方向光产生阴影
// 方向光辅助工具
const dirHelper = new THREE.DirectionalLightHelper(dirLight, 3)
this.scene.add(ambientLight, dirLight, dirHelper)
this.ambientLight = ambientLight
this.dirLight = dirLight
this.dirHelper = dirHelper
},
// 创建立方体对象
createObjects () {
const box = new THREE.Mesh(
new THREE.BoxGeometry(1, 1, 1),
new THREE.MeshLambertMaterial({
color: 0x1890ff
})
)
const geometry = new THREE.PlaneGeometry(10, 10)
const material = new THREE.MeshLambertMaterial({
side: THREE.DoubleSide
})
const floor = new THREE.Mesh(geometry, material)
const wall = new THREE.Mesh(geometry, material)
floor.rotation.x = -Math.PI / 2
floor.position.y = -1
wall.position.y = 4
wall.position.z = -5
this.dirLight.target = box // 方向光照向物体
box.castShadow = true // 物体产生阴影
floor.receiveShadow = true // 地面接收阴影
wall.receiveShadow = true // 墙面接收阴影
this.scene.add(box, floor, wall)
this.box = box
},
datGui () {
const _this = this
const gui = new dat.GUI();
const ambientFolder = gui.addFolder('环境光')
ambientFolder.add(_this.ambientLight, 'intensity', 0, 1, 0.1).name('环境光强度')
ambientFolder.add(_this.ambientLight, 'visible').name('环境光可见性')
ambientFolder.addColor({ color: 0xffffff }, 'color').onChange(val =>{
_this.ambientLight.color = new THREE.Color(val)
})
ambientFolder.open()
const dirLightFolder = gui.addFolder('方向光')
dirLightFolder.add(_this.dirLight, 'intensity', 0, 1, 0.1)
dirLightFolder.add(_this.dirLight, 'visible')
dirLightFolder.add(_this.dirLight.position, 'x', -20, 20, 0.1)
dirLightFolder.add(_this.dirLight.position, 'y', -20, 20, 0.1)
dirLightFolder.add(_this.dirLight.position, 'z', -20, 20, 0.1)
dirLightFolder.open()
const boxFolder = gui.addFolder('box')
boxFolder.add(_this.box.position, 'x', -20, 20, 0.1).onChange(val =>{
_this.dirHelper.update()
})
boxFolder.add(_this.box.position, 'y', -20, 20, 0.1).onChange(val =>{
_this.dirHelper.update()
})
boxFolder.add(_this.box.position, 'z', -20, 20, 0.1).onChange(val =>{
_this.dirHelper.update()
})
boxFolder.open()
const shadowMapFolder = gui.addFolder('阴影')
// mapSize 改变阴影的位置
shadowMapFolder.add(_this.dirLight.shadow.mapSize, 'x', [512, 1024, 2048, 4096])
shadowMapFolder.add(_this.dirLight.shadow.mapSize, 'y', [512, 1024, 2048, 4096])
// radius 改变阴影的模糊度
shadowMapFolder.add(_this.dirLight.shadow, 'radius', 0, 30, 1)
shadowMapFolder.open()
},
renderer.shadowMap.enabled = true; // 渲染器开启阴影
半球光 HemisphereLight
- 可将天空+地面反射的光照都计算在内,产生柔和、平衡的环境光照;
- 无法产生阴影;
- 环境光AmbientLight 与半球光HemisphereLight 会相互影响 。与环境光类似,可模拟太阳、日出、日落的效果。
js
// 创建光照
createLights () {
// 添加全局光照
const ambientLight = new THREE.AmbientLight(0xffffff, 0.95)
ambientLight.visible = false // 关闭
// 方向光
const dirLight = new THREE.DirectionalLight(0xffffaa, 0.95)
dirLight.position.set(0, 1, 2)
dirLight.castShadow = true // 让方向光产生阴影
// 方向光辅助工具
const dirHelper = new THREE.DirectionalLightHelper(dirLight, 3)
// 半球光
const hemiLight = new THREE.HemisphereLight(0x00ffff, 0xffff55, 0.7)
// 半球光辅助工具
const hemiHelper = new THREE.HemisphereLightHelper(hemiLight, 1)
this.scene.add(ambientLight, dirLight, dirHelper, hemiLight, hemiHelper)
this.ambientLight = ambientLight
this.dirLight = dirLight
this.dirHelper = dirHelper
this.hemiLight = hemiLight
},
// 创建立方体对象
createObjects () {
const box = new THREE.Mesh(
new THREE.BoxGeometry(1, 1, 1),
new THREE.MeshLambertMaterial({
color: 0x1890ff
})
)
const geometry = new THREE.PlaneGeometry(10000, 10000)
const material = new THREE.MeshLambertMaterial({
side: THREE.DoubleSide
})
const floor = new THREE.Mesh(geometry, material)
// const wall = new THREE.Mesh(geometry, material)
// 天空
const sky = new THREE.Mesh(
geometry,
new THREE.MeshLambertMaterial({
side: THREE.DoubleSide,
})
)
floor.rotation.x = -Math.PI / 2
floor.position.y = -1
// wall.position.y = 4
// wall.position.z = -5
sky.position.y = 20
sky.rotation.x = -Math.PI / 2
this.dirLight.target = box // 方向光照向物体
box.castShadow = true // 物体产生阴影
floor.receiveShadow = true // 地面接收阴影
// wall.receiveShadow = true // 墙面接收阴影
this.scene.add(box, floor, sky)
this.box = box
},
点光源 PointLight
js
// 创建光照
createLights () {
// 添加全局光照
const ambientLight = new THREE.AmbientLight(0xffffff, 0.95)
ambientLight.visible = false // 关闭
// 方向光
const dirLight = new THREE.DirectionalLight(0xffffaa, 0.95)
dirLight.position.set(0, 3, 1.5)
dirLight.castShadow = true // 让方向光产生阴影
dirLight.visible = false // 关闭
// 方向光辅助工具
const dirHelper = new THREE.DirectionalLightHelper(dirLight, 3)
// 点光源
const pointLight1 = new THREE.PointLight(0xf3ae3d, 0.8)
const pointLight2 = new THREE.PointLight(0xa1fc8f, 0.8)
// 光源位置默认在原点
pointLight1.position.set(-1, 1, 2)
pointLight2.position.set(1, 1, 2)
// 开启阴影
pointLight1.castShadow = true
pointLight2.castShadow = true
// 创建小球标示光源位置
const sphere1 = new THREE.Mesh(
new THREE.SphereGeometry(0.05, 64, 64),
new THREE.MeshBasicMaterial({
color: 0xf3ae3d,
})
);
const sphere2 = new THREE.Mesh(
new THREE.SphereGeometry(0.05, 64, 64),
new THREE.MeshBasicMaterial({
color: 0xa1fc8f,
})
);
sphere1.position.copy(pointLight1.position)
sphere2.position.copy(pointLight2.position)
this.scene.add(ambientLight, dirLight, dirHelper,sphere1, sphere2, pointLight1, pointLight2, )
},
clock: new THREE.Clock(),
tick () {
// 让点光源运动
const elapsedTime = this.clock.getElapsedTime()
this.pointLight1.position.x = Math.sin(elapsedTime)
this.pointLight1.position.z = Math.cos(elapsedTime)
this.sphere1.position.copy(this.pointLight1.position)
// 更新
this.orbitControls.update()
this.renderer.render(this.scene, this.camera)
window.requestAnimationFrame(()=> this.tick())
},
面光源 RectAreaLight
- 只支持 MeshStandardMaterial 和 MeshPhysicalMaterial 两种材质
- 不能产生阴影
- 从矩形平面上均匀地发射光线
- 必须在场景中,加入 RectAreaLightUniformLib,并调用init()
RectAreaLightUniformsLib.init()
矩形面光源uniforms工具库,包含矩形面光源常用数据,矩形区域光源位置、方向、颜色、强度。只适用于矩形的区域光源,即RectAreaLight
js
// 创建光照
createLights () {
// 添加全局光照
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5)
RectAreaLightUniformsLib.init()
// 面光源
const rectLight = new THREE.RectAreaLight(0xffffff, 10, 2, 4)
rectLight.position.set(0, 1, 5)
const rectHelper = new RectAreaLightHelper(rectLight)
this.scene.add(ambientLight, rectLight, rectHelper);
},
// 创建立方体对象
createObjects () {
const floorTexture = this.textureLoader.load('/src/assets/textures/6.jpg')
const wallTexture = this.textureLoader.load('/src/assets/textures/2.jpg')
const photoTexture = this.textureLoader.load('/src/assets/textures/4.jpg')
this.floorTexture = floorTexture
this.wallTexture = wallTexture
this.photoTexture = photoTexture
const box = new THREE.Mesh(
new THREE.BoxGeometry(1, 1, 1),
new THREE.MeshStandardMaterial({
color: 0x1890ff,
})
)
// 地板
const floor = new THREE.Mesh(
new THREE.PlaneGeometry(20, 20),
new THREE.MeshStandardMaterial({
map: floorTexture,
roughness: 0, // 产生反光
})
)
// 墙面
const wall = new THREE.Mesh(new THREE.PlaneGeometry(20, 20), new THREE.MeshStandardMaterial({
map: wallTexture,
roughness: 0,
}) )
floor.rotation.x = -Math.PI / 2
floor.position.y = -0.8
floor.position.z = -2
wall.position.z = -2
// 添加相框
const frameGeometry = new THREE.PlaneGeometry(4.4, 6.4)
const frameMaterial = new THREE.MeshStandardMaterial({
color: 0xd08a38,
})
const frame = new THREE.Mesh(frameGeometry, frameMaterial)
const photoGeometry = new THREE.PlaneGeometry(4, 6)
const photoMaterial = new THREE.MeshStandardMaterial({
map: photoTexture,
roughness: 0, // 产生反光
})
const photo = new THREE.Mesh(photoGeometry, photoMaterial)
const group = new THREE.Group()
group.add(frame, photo)
frame.position.z = 0.001
photo.position.z = 0.002
group.position.z = -2
group.position.y = 5
this.scene.add(box, floor, wall, group)
this.box = box
},
聚光灯
- 形状类似锥形光源,模拟聚光灯效果
- 能产生明显的光照和阴影效果 阴影属性:
- castShadow:是否产生阴影,默认是false
- receiveShadow:是否接手阴影,默认是false
- bias:阴影偏移量,默认是0,非常小的调整(大约0.0001)可能有助于减少阴影中的伪影
- mapSize:阴影贴图大小,默认是512,必须是2的幂,宽、高不必相同
- radiu:阴影模糊半径,默认是1,值越大,阴影越模糊,较高的值会在阴影中产生不必要的条带效果
- target:阴影的目标,默认是null,若设置了,则阴影会围绕目标产生
- camera:用于计算阴影的相机,默认是SportLight.shadow.camera,SportLight 是透视相机
SportLight 的透视相机属性:
- near: 阴影相机的近裁剪面,决定了阴影的细节程度
- far: 阴影相机的远裁剪面,决定了阴影的覆盖范围
- fov:此处无效 ,会被自动设为90度
js
// 创建光照
createLights () {
// 添加全局光照
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5)
ambientLight.visible = false
// 添加聚光灯
const spotLight = new THREE.SpotLight(0xff00ff, 0.95)
const spotHelper = new THREE.SpotLightHelper(spotLight)
spotLight.intensity = 1
spotLight.distance = 100 // 光源距离
spotLight.angle = Math.PI / 4 // 照射角度
spotLight.penumbra = 0.3 // 半影:阴影边缘模糊度
spotLight.position.y = 10
spotLight.castShadow = true // 开启阴影
spotHelper.update() // 更新
this.scene.add(ambientLight, spotLight, spotHelper );
this.ambientLight = ambientLight
this.spotLight = spotLight
this.spotHelper = spotHelper
},
// 创建立方体对象
createObjects () {
const box = new THREE.Mesh(
new THREE.SphereGeometry(2, 64, 64),
new THREE.MeshLambertMaterial({
color: 0x1890ff
})
)
const geometry = new THREE.PlaneGeometry(1000, 1000)
const floor = new THREE.Mesh(
geometry,
new THREE.MeshLambertMaterial({
color: 0x666666,
// side: THREE.DoubleSide,
})
)
// 天花板
const sky = new THREE.Mesh(
geometry,
new THREE.MeshLambertMaterial({
color: 0x666666,
side: THREE.DoubleSide,
})
)
sky.rotation.x = -Math.PI / 2
sky.position.y = 60
sky.castShadow = true
floor.rotation.x = -Math.PI / 2
floor.position.y = -1
box.position.y = 3
box.castShadow = true // 开启阴影
floor.receiveShadow = true // 接收阴影
this.spotLight.target = box // 聚光灯始终朝向物体
},
// 调试器
const spotFolder = gui.addFolder('聚光灯')
spotFolder.add(_this.spotLight, 'intensity', 0, 1, 0.1).name('强度')
spotFolder.add(_this.spotLight, 'visible').name('可见性')
spotFolder.add(_this.spotLight, 'distance', 0, 100, 1).name('距离').onChange(val =>{
_this.spotHelper.update()
})
spotFolder.add(_this.spotLight, 'angle', 0, Math.PI / 2, 0.1).name('角度').onChange(val =>{
_this.spotHelper.update()
})
spotFolder.add(_this.spotLight, 'penumbra', 0, 1, 0.1).name('半影').onChange(val =>{
_this.spotHelper.update()
})
spotFolder.add(_this.spotLight, 'decay', 0, 10, 0.1).name('衰减量').onChange(val =>{
_this.spotHelper.update()
})
spotFolder.add(_this.spotLight, 'power', 0, 30, 0.1).name('光功率').onChange(val =>{
_this.spotHelper.update()
})
spotFolder.add(_this.spotLight.position, 'x', -30, 30, 0.1).onChange(val =>{
_this.spotHelper.update()
})
spotFolder.add(_this.spotLight.position, 'y', -30, 30, 0.1).onChange(val =>{
_this.spotHelper.update()
})
spotFolder.add(_this.spotLight.position, 'z', -30, 30, 0.1).onChange(val =>{
_this.spotHelper.update()
})
spotFolder.add(_this.spotLight, 'castShadow').name('阴影')
spotFolder.add(_this.spotLight.shadow, 'radius', 0, 5, 0.01).name('阴影半径')
const params = {
near: _this.spotLight.shadow.camera.near,
far: _this.spotLight.shadow.camera.far,
fov: _this.spotLight.shadow.camera.fov,
}
spotFolder.add(params, 'near', 0.01, 10, 0.01).name('阴影相机near')
spotFolder.add(params, 'far', 0.01, 10, 0.01).name('阴影相机far')
this.params = params
renderer.outputEncoding = THREE.sRGBEncoding // 开启渲染