萤火虫飞舞
import * as THREE from 'three'
import { OrbitControls } from '../../js/jsm/controls/OrbitControls.js'; // 引入相机控件
let scene, camera, renderer, controls, flyBall, ball
function init() {
scene = new THREE.Scene()
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000)
camera.position.set(5, 5, 5)
renderer = new THREE.WebGLRenderer({ antialias: true })
renderer.setSize(window.innerWidth, window.innerHeight)
document.body.appendChild(renderer.domElement)
controls = new OrbitControls(camera, renderer.domElement)
controls.enableDamping = true
const axesHelper = new THREE.AxesHelper(5)
scene.add(axesHelper)
// 1. 渲染器开启阴影支持(性能消耗高)
renderer.shadowMap.enabled = true
}
function createBall(){
const geometry = new THREE.SphereGeometry(1, 32, 16)
const material = new THREE.MeshStandardMaterial({
color: 0x00ff00
})
ball = new THREE.Mesh(geometry, material)
ball.position.set(0, 1, 0)
scene.add(ball)
ball.castShadow = true
}
// 目标:练习-萤火虫飞舞
// 1. 创建纯颜色小球体
// 2. 使用点光源,并加入到小球体上
// 3. 在渲染循环,不断修改小球体位移坐标实现旋转跳跃效果
function createFlyBall() {
const geometry = new THREE.SphereGeometry(0.1, 32, 16)
const material = new THREE.MeshBasicMaterial({
color: 0x99ff00
})
flyBall = new THREE.Mesh(geometry, material)
flyBall.position.set(3, 3, 3)
scene.add(flyBall)
}
function createLight() {
const directionalLight = new THREE.PointLight(0x99ff00, 5);
directionalLight.target = ball;
directionalLight.castShadow = true;
// 2. 使用点光源,并加入到小球体上
// 关键1:灯光在到球的位置(光就会跟着球体一起动)
// 关键2:灯光不要再设置偏移位置了(位移是参考父级物体的-就是加到的球体中心点进行偏移)
flyBall.add(directionalLight);
}
function render(t) {
renderer.render(scene, camera)
// 3. 在渲染循环,不断修改小球体位移坐标实现旋转跳跃效果
// t 是毫秒值,转换成秒,正弦范围 -1.0 到 1.0 (随着传入的值增大,得到的值在这个范围反复横跳)
// 乘以 3 就是 -3 到 3 之间运动
flyBall.position.x = Math.cos(t / 1000) * 3
// 余弦范围 -1.0 到 1.0
flyBall.position.z = Math.sin(t / 1000) * 3
// 乘以 0.5 就是范围移动小一些(y 轴默认晚上偏移一些,所以 + 3)
flyBall.position.y = 3 + Math.sin(t / 100) * 0.5
// 注意:x 用 cos,z 用 sin 就变成了顺时针旋转
requestAnimationFrame(render)
}
init()
createBall()
createFlyBall()
createLight()
render()
(环境光)AmbientLight
环境光会均匀的照亮场景中的所有物体。环境光不能用来投射阴影,因为它没有方向。
AmbientLight( color : Integer, intensity : Float )
属性
#.castShadow : Boolean
这个参数在对象构造的时候就被设置成了 undefined 。因为环境光不能投射阴影。
#.isAmbientLight : Boolean
用来校验这个类或者派生类是不是环境光.默认是 true。
目标:使用环境光+标准网格材质,创建一个平面模拟地面效果
1. 创建平面缓冲几何体
2. 创建环境光
//注意1:没有方向,不能投射阴影,只能照亮物体,没有光斑
//注意2:材质是白色,为何不是纯白色而变成灰色了?(因为材质为标准网格材质-需要参考光照的影响一起计算后再绘制每个像素点颜色)
function createFloor(){
// 1. 创建平面缓冲几何体
const geometry = new THREE.PlaneGeometry(10,10);
const material = new THREE.MeshStandardMaterial({
color: 0xffffff,
side: THREE.DoubleSide
})
const plane = new THREE.Mesh(geometry,material);
plane.rotation.set(-Math.PI / 2, 0, 0);
scene.add(plane)
}
function createLight(){
const light = new THREE.AmbientLight(0xffffff,1)
scene.add(light)
}
平行光(DirectionalLight)
平行光是沿着特定方向发射的光。这种光的表现像是无限远,从它发出的光线都是平行的。常常用平行光来模拟太阳光 的效果; 太阳足够远,因此我们可以认为太阳的位置是无限远,所以我们认为从太阳发出的光线也都是平行的。
DirectionalLight( color : Integer, intensity : Float )
color - (可选参数) 16进制表示光的颜色。 缺省值为 0xffffff (白色)。
intensity - (可选参数) 光照的强度。缺省值为1。
属性
# .castShadow : Boolean
如果设置为 true 该平行光会产生动态阴影。 警告: 这样做的代价比较高而且需要一直调整到阴影看起来正确。该属性默认为 false。
const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
directionalLight.position.set(3, 3, 3);
scene.add(directionalLight);
directionalLight.castShadow = true
# .isDirectionalLight : Boolean
用来校验这个类或者派生类是不是平行光.默认是 true。
不应该去改变这个变量,因为内部使用这个变量做了些优化的工作。
# .position : Vector3
假如这个值设置等于 Object3D.DefaultUp (0, 1, 0),那么光线将会从上往下照射。
# .shadow : DirectionalLightShadow
这个 DirectionalLightShadow 对象用来计算该平行光产生的阴影。
# .target : Object3D
平行光的方向是从它的位置到目标位置。默认的目标位置为原点 (0,0,0)。
注意: 对于目标的位置,要将其更改为除缺省值之外的任何位置,它必须被添加到 scene 场景中去。
1. 创建 DirectionalLight 平行光对象,设置位置等添加到场景中
2. 创建 DirectionalLightHelper 平行光辅助对象(可选),辅助我们观察光源位置
// 疑惑:与环境光区别?
// 解答:平行光可以产生光斑,给地面粗糙度设置为 0 旋转摄像机角度查看效果
function createLight(){
// 1. 创建 DirectionalLight 平行光对象,设置位置等添加到场景中
const directionalLight = new THREE.DirectionalLight(0xffffff, 1, 50);
directionalLight.position.set(5,5,5);
scene.add(directionalLight);
// 2. 创建 DirectionalLightHelper 平行光辅助对象(可选),辅助我们观察光源位置
const helper = new THREE.DirectionalLightHelper(directionalLight,1)
scene.add(helper)
}
点光源(PointLight)
从一个点向各个方向发射的光源。一个常见的例子是模拟一个灯泡发出的光。
PointLight( color : Integer, intensity : Float, distance : Number, decay : Float )
color - (可选参数)) 十六进制光照颜色。 缺省值 0xffffff (白色)。
intensity - (可选参数) 光照强度。 缺省值 1。distance - 这个距离表示从光源到光照强度为0的位置。 当设置为0时,光永远不会消失(距离无穷大)。缺省值 0.
decay - 沿着光照距离的衰退量。缺省值 1。 在 physically correct 模式中,decay = 2。
属性
# .decay : Float
沿着光照距离的衰减量
在 physically correct 模式下,decay 设置为等于2将实现现实世界的光衰减。缺省值为 1。
# .distance : Float
如果非零,那么光强度将会从最大值当前灯光位置处按照距离线性衰减到0。 缺省值为 0.0。
# .isPointLight : Boolean
用来校验这个类或者派生类是不是点光源。默认是 true。
不应该去改变这个变量,因为内部使用这个变量做了些优化的工作。
# .shadow : LightShadow
LightShadow用与计算此光照的阴影。
1. 创建 PointLight 点光源对象
2. 创建 PointLightHelper 辅助对象观察所在位置
// 注意:距离光源越远地方越暗
function createLight(){
// 1. 创建 PointLight 点光源对象、
// 参数3:光源照射的最大距离。默认值为 0(无限远)
const pointLight = new THREE.PointLight(0xffffff, 1, 50);
pointLight.position.set(5,5,5);
scene.add(pointLight);
// 2. 创建 PointLightHelper 辅助对象观察所在位置
const pointLightHelper = new THREE.PointLightHelper(pointLight,1)
scene.add(pointLightHelper)
}
聚光灯(SpotLight)
聚光灯是从一个方向上的一个点发出,沿着一个圆锥体,它离光越远,它的尺寸就越大。
SpotLight( color : Integer, intensity : Float, distance : Float, angle : Radians, penumbra : Float, decay : Float )
color - (可选参数) 十六进制光照颜色。 缺省值 0xffffff (白色)。
intensity - (可选参数) 光照强度。 缺省值 1。distance - 从光源发出光的最大距离,其强度根据光源的距离线性衰减。
angle - 光线散射角度,最大为Math.PI/2。
penumbra - 聚光锥的半影衰减百分比。在0和1之间的值。默认为0。
decay - 沿着光照距离的衰减量。
属性
# .angle : Float
从聚光灯的位置以弧度表示聚光灯的最大范围。应该不超过 Math.PI/2。默认值为 Math.PI/3。
# .castShadow : Boolean
此属性设置为 true 聚光灯将投射阴影。警告: 这样做的代价比较高而且需要一直调整到阴影看起来正确。 查看 SpotLightShadow 了解详细信息。 默认值为 false
# .decay : Float
沿着光照距离的衰减量
在 physically correct 模式下,decay 设置为等于2将实现现实世界的光衰减。
缺省值为 1。
# .distance : Float
如果非零,那么光强度将会从最大值当前灯光位置处按照距离线性衰减到0。 缺省值为 0.0。
# .isSpotLight : Boolean
用来校验这个类或者它的派生类是不是聚光灯光源。缺省值是 true。
不应该去改变这个变量,因为内部使用这个变量做了些优化的工作。
# .penumbra : Float
聚光锥的半影衰减百分比。在0和1之间的值。 默认值 — 0.0。
# .position : Vector3
假如这个值设置等于 Object3D.DefaultUp (0, 1, 0),那么光线将会从上往下照射。
1. 创建 SpotLight 聚光灯对象,设置位置等添加到场景中
2. 创建 SpotLightHelper 聚光灯辅助对象(可选),辅助我们观察光源位置
function createLight(){
// 1. 创建 SpotLight 聚光灯对象,设置位置等添加到场景中
// 强度设置高一些,纹理看的清楚
const spotLight = new THREE.SpotLight(0xffffff, 15);
spotLight.position.set(5,5,5);
// 灯光的纹理(会把图片和聚光灯颜色混合后打在目标物体上)
spotLight.map = new THREE.TextureLoader().load('../image/desert.jpg');
// 灯光的角度(0 - Math.PI / 2)
spotLight.angle = 0.16*Math.PI;
// 光的衰减程度(0-1)让光斑周围虚化程度(0 不要)
spotLight.penumbra = 0.8;
scene.add(spotLight)
// 2. 创建 SpotLightHelper 平行光辅助对象(可选),辅助我们观察光源位置
const helper = new THREE.SpotLightHelper(spotLight,1)
scene.add(helper)
// 补充:使用 GUI 工具调整查看具体效果
const gui = new GUI();
gui.add(spotLight, 'intensity', 0, 15, 0.1).name('光照强度')
gui.add(spotLight, 'distance', 0, 15, 0.1).name('光照距离').onChange(() => {
helper.update()
})
gui.add(spotLight, 'angle', 0, Math.PI / 2, 0.1).name('光照角度').onChange(() => {
helper.update()
})
gui.add(spotLight, 'penumbra', 0, 1, 0.1).name('半影衰减').onChange(() => {
helper.update()
})
// 距离越远越暗
// 低版本可能需要设置:渲染器对象.physicallyCorrectLights = true (开启物理衰减模式)
gui.add(spotLight, 'decay', 0, 5, 0.1).name('衰减距离').onChange(() => {
helper.update()
})
}
灯光与阴影
点光源与阴影 或平行光与阴影
聚光灯与阴影
阴影细节修改
// 目标:阴影细节修改
function createLight() {
// 平行光(太阳)
const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
directionalLight.position.set(3, 3, 3);
scene.add(directionalLight);
directionalLight.castShadow = true
// 1. 模糊阴影的边缘(如果贴图宽高不够,会出现马赛克)
directionalLight.shadow.radius = 15
// 2. 阴影贴图的宽度和高度(要求是 2 的幂)
directionalLight.shadow.mapSize.set(1024, 1024)
// 3. 可以通过控制光源摄像机影响阴影的大小效果
// 设置光投射相机的属性(光的位置就是正交相机位置)
// 用于干涉计算阴影的范围,超出摄像机长方体外的物体不计算阴影
directionalLight.shadow.camera.near = 0.5
directionalLight.shadow.camera.far = 20
// 这个会围成一个长方体范围空间
directionalLight.shadow.camera.left = -5
directionalLight.shadow.camera.right = 5
directionalLight.shadow.camera.top = 5
directionalLight.shadow.camera.bottom = -5
const helper = new THREE.DirectionalLightHelper(directionalLight, 1);
scene.add(helper);
}
照射指定物体
function createLight() {
const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
directionalLight.position.set(3, 3, 3);
scene.add(directionalLight);
// 2. 设置光源对象.target 赋予球体
directionalLight.target = ball
const helper = new THREE.DirectionalLightHelper(directionalLight, 1);
scene.add(helper);
// 移动球,看看光源是否跟随移动
gui.add(ball.position, 'x', 0, 5, 0.1).name('移动球体').onChange(() => {
helper.update() // 更新辅助对象
})
}