1.环境贴图
目的:在物体贴上四周环境在物体上的反射画面内容,其实还是贴图
初始化环境(utils/init.js)
// 初始化 three.js 基础环境
import * as THREE from 'three'
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'
export let scene, camera, renderer, controls;
(function init() {
scene = new THREE.Scene()
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000)
camera.position.set(0, 0, 5)
renderer = new THREE.WebGLRenderer({ antialias: true })
renderer.setSize(window.innerWidth, window.innerHeight)
app.appendChild(renderer.domElement)
})();
(function createControls() {
controls = new OrbitControls(camera, renderer.domElement)
controls.enableDamping = true
})();
(function createHelper() {
const axesHelper = new THREE.AxesHelper(5)
scene.add(axesHelper)
})();
(function resizeRender() {
window.addEventListener('resize', () => {
renderer.setSize(window.innerWidth, window.innerHeight)
camera.aspect = window.innerWidth / window.innerHeight
camera.updateProjectionMatrix()
})
})();
(function renderLoop() {
renderer.render(scene, camera)
controls.update()
requestAnimationFrame(renderLoop)
})();
import { scene } from './utils/init'
import * as THREE from 'three'
// import * as dat from 'dat.gui'
function initBase() {
// const geometry = new THREE.SphereGeometry(1, 32, 16)
// 1. 使用 CubeTextureLoader (立方体纹理加载器)- 6 个面的图片,得到纹理对象
const cubeTL = new THREE.CubeTextureLoader()
const cubeTexture = cubeTL.setPath('image/sky/').load(['px.jpg', 'nx.jpg', 'py.jpg', 'ny.jpg', 'pz.jpg', 'nz.jpg'])
// const material = new THREE.MeshStandardMaterial({
// // 2. 设置给物体的 envMap 环境贴图属性
// envMap: cubeTexture,
// roughness: 0,
// metalness: 1
// })
// 3. 借助 GUI 工具,修改物体材质的粗糙度和金属度观察效果
// const gui = new dat.GUI()
// gui.add(material, 'roughness', 0, 1, 0.1)
// gui.add(material, 'metalness', 0, 1, 0.1)
// 天空盒子-scene 场景添加一个背景
scene.background = cubeTexture
// const mesh = new THREE.Mesh(geometry, material)
scene.add(mesh)
}
initBase()
2.认识模型文件并使用
目的:建模师建好的模型物体,可以通过 three.js 提供的加载器,加载到网页中显示此物体和操作
import { scene } from './utils/init'
import * as THREE from 'three'
// 1. 引入加载 gltf/glb 模型文件的加载器
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'
function initBase() {
// 2. 引入public文件下的model的ferrari.glb文件,实例化加载器并加载模型文件:load() 异步
new GLTFLoader().load('model/ferrari.glb', gltf => {
// 3. 取出模型对象并添加到场景中
const model = gltf.scene
// 遍历物体内部每个小物体组成
model.traverse(obj => {
console.log(obj)
})
scene.add(model)
})
}
function createLight() {
const light = new THREE.AmbientLight(0xffffff, 1)
scene.add(light)
}
initBase()
createLight()
借助 three.js 网页提供的模型.编辑器,查找建模师的模型中某个小物体名字,并回扣应用到代码里操作修改自己网站中的这个模型效果 。
打开网址:three.js editor
可导入对应的模型文件进行操作
3.光源-环境光
环境光:没有方向,不能投射阴影,只能照亮物体,但是没有光斑
注意1:没有方向,不能投射阴影,只能照亮物体,没有光斑
注意2:金属度1,粗糙度0,无环境贴图,放射颜色为黑色,物体自身为黑色并不是灯光的问题
import { scene, camera } from './utils/init'
import * as THREE from 'three'
function createFloor() {
// 1. 创建平面缓冲几何体
const geometry = new THREE.PlaneGeometry(10, 10)
const material = new THREE.MeshStandardMaterial({
color: 0xffffff
})
const plane = new THREE.Mesh(geometry, material)
plane.rotation.set(- Math.PI / 2, 0, 0)
scene.add(plane)
}
function createLight() {
// 2. 创建环境光
const light = new THREE.AmbientLight(0xffffff, 1)
scene.add(light)
}
camera.position.set(5, 5, 5)
createFloor()
createLight()
4.光源-点光源
从一个点向各个方向发射的光源。模拟灯泡发出的光。有方向可投射阴影和光斑
import { scene, camera } from './utils/init'
import * as THREE from 'three'
function createFloor() {
const geometry = new THREE.PlaneGeometry(10, 10)
const material = new THREE.MeshStandardMaterial({
color: 0xffffff
})
const plane = new THREE.Mesh(geometry, material)
plane.rotation.set(- Math.PI / 2, 0, 0)
scene.add(plane)
}
function createLight() {
// 点光源(灯泡)
const light = new THREE.PointLight(0xffffff, 1, 100);
light.position.set(3, 3, 3);
scene.add(light);
const pointLightHelper = new THREE.PointLightHelper(light, 1);
scene.add(pointLightHelper);
}
camera.position.set(5, 5, 5)
createFloor()
createLight()
5.光源-平行光
沿着特定方向发射的光线。模拟太阳光,太阳足够远,因为我们认为太阳光是平行的。
import { scene, camera } from './utils/init'
import * as THREE from 'three'
function createFloor() {
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 directionalLight = new THREE.DirectionalLight(0xffffff, 1);
directionalLight.position.set(3, 3, 3);
scene.add(directionalLight);
const helper = new THREE.DirectionalLightHelper(directionalLight, 1);
scene.add(helper);
}
camera.position.set(5, 5, 5)
createFloor()
createLight()
6.光源-聚光灯
从一个点沿一个方向射出,距离越远,光锥尺寸越大,模拟手电筒/舞台聚光灯
import { scene, camera } from './utils/init'
import * as THREE from 'three'
function createFloor() {
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 spotLight = new THREE.SpotLight(0xffffff, 1);
spotLight.position.set(3, 3, 3);
// 灯光的纹理(会把图片和聚光灯颜色混合后打在目标物体上)
spotLight.map = new THREE.TextureLoader().load('image/desert.jpg');
scene.add(spotLight)
const spotLightHelper = new THREE.SpotLightHelper(spotLight);
scene.add(spotLightHelper);
}
camera.position.set(5, 5, 5)
createFloor()
createLight()
7.灯光与阴影
每个光特点不同,产生的光斑和阴影不相同
名字 | 构造函数 | 特点 | 产生阴影/光斑 |
---|---|---|---|
环境光 | AmbientLight | 照亮所有受光照影响物体 | 无方向,不产生 |
点光源 | PointLight | 一个点向四周发射光线(灯泡) | 有方向,能产生 |
平行光 | DirectionalLight | 平行发射光线(太阳光) | 有方向,能产生 |
聚光灯 | SpotLight | 一个点向一个方向散射光线(手电筒/舞台灯) | 有方向,能产生 |
import { scene, camera, renderer } from './utils/init'
import * as THREE from 'three'
function createFloor() {
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)
plane.receiveShadow = true
scene.add(plane)
}
function createLight() {
// 聚光灯(手电)
const spotLight = new THREE.SpotLight(0xffffff, 1);
spotLight.position.set(13, 13, 13);
// spotLight.map = new THREE.TextureLoader().load('image/desert.jpg');
spotLight.castShadow = true // 灯光产生阴影
// 让聚光灯打出阴影贴图大小(2 的几次幂值)
spotLight.shadow.mapSize.width = 2048;
spotLight.shadow.mapSize.height = 2048;
scene.add(spotLight)
const spotLightHelper = new THREE.SpotLightHelper(spotLight);
scene.add(spotLightHelper);
}
function createSphere() {
const geometry = new THREE.SphereGeometry(1, 32, 16)
const material = new THREE.MeshStandardMaterial({
color: 0x00ff00
})
const mesh = new THREE.Mesh(geometry, material)
mesh.position.set(0, 1, 0)
mesh.castShadow = true // 物体产生阴影(参与阴影计算)
scene.add(mesh)
}
camera.position.set(5, 5, 5)
renderer.shadowMap.enabled = true // 开启阴影渲染支持
createLight()
createSphere()
createFloor()
8.gsap 动画库
基于 gsap 第三方库实现动画效果
使用步骤:
1.下载并引入 gsap 动画库
2.使用 gsap.to() 设置动画
3.根据文档调整动画相关效果
import { scene, camera, renderer } from './utils/init'
import * as THREE from 'three'
// 1. 下载并引入 gsap 动画库
import gsap from 'gsap'
let sphere // 球体对象
let helper // 平行光辅助对象
function createFloor() {
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)
plane.receiveShadow = true
scene.add(plane)
}
function createLight() {
// 平行光(太阳)
const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
directionalLight.position.set(3, 3, 3);
directionalLight.castShadow = true
directionalLight.target = sphere
scene.add(directionalLight);
helper = new THREE.DirectionalLightHelper(directionalLight, 1);
scene.add(helper);
}
function createSphere() {
const geometry = new THREE.SphereGeometry(1, 32, 16)
const material = new THREE.MeshStandardMaterial({
color: 0x00ff00
})
sphere = new THREE.Mesh(geometry, material)
sphere.position.set(0, 1, 0)
sphere.castShadow = true
scene.add(sphere)
}
function initAnimation() {
// 2. 使用 gsap.to() 做一个补间动画
// 参数1:标签选择器/DOM对象/物体对象
// 参数2:动画相关配置项
const aniObj = gsap.to(sphere.position, {
// 3. 根据文档调整相关效果
x: 5, // 对参数 1 目标对象做什么属性的变化
duration: 3, // 动画持续时间
delay: 2, // 延迟 2 秒后在做当前动画
repeat: -1, // 无限次反复运动
yoyo: true, // 回到原点过程也有一个动画
ease: "expo.out", // 设置缓冲效果(参考: https://greensock.com/docs/v3/Eases)调整使用的内置字符串模式
onStart() {
console.log('开始动画')
},
onUpdate() {
console.log('动画更新')
helper.update() // 让平行光辅助对象可以实时更新角度和射线
},
onComplete() {
console.log('动画结束')
}
})
// 补充:控制动画暂停/恢复
window.addEventListener('dblclick', () => {
if (aniObj.isActive()) {
// 当前动画运行中为 true
aniObj.pause()
} else {
// 暂停->恢复
aniObj.resume()
}
})
}
camera.position.set(5, 5, 5)
renderer.shadowMap.enabled = true
createSphere()
createFloor()
createLight()
initAnimation()
9.CSS2D 渲染器
把原生 DOM 标签转换到空间中,作为一个 2D 物体加载显示
CSS3D与CSS2D 区别:
CSS3D:始终不面向摄像机,场景缩放时跟随着变大/变小,不被模型遮挡,通过 DOM 事件点击
CSS2D:始终面向摄像机, 场景缩放时不跟随变化, 不被模型遮挡,通过 DOM 事件点击
import { scene, camera, renderer } from './utils/init2d'
import * as THREE from 'three'
import { CSS2DObject } from 'three/addons/renderers/CSS2DRenderer.js';
let sphere
let helper
function createFloor() {
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)
plane.receiveShadow = true
scene.add(plane)
}
function createLight() {
// 平行光(太阳)
const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
directionalLight.position.set(3, 3, 3);
directionalLight.castShadow = true
directionalLight.target = sphere
scene.add(directionalLight);
helper = new THREE.DirectionalLightHelper(directionalLight, 1);
scene.add(helper);
}
function createSphere() {
const geometry = new THREE.SphereGeometry(1, 32, 16)
const material = new THREE.MeshStandardMaterial({
color: 0x00ff00
})
sphere = new THREE.Mesh(geometry, material)
sphere.position.set(0, 1, 0)
sphere.castShadow = true
scene.add(sphere)
}
function create2d() {
const div = document.createElement('div')
div.innerHTML = '球体'
div.style.color = 'red'
div.style.fontSize = '32px'
// 与 CSS3D 区别:2D 物体 px 像素单位还可以生效,而不是平移到三维空间中的单位
const object2d = new CSS2DObject( div )
object2d.position.set(0, 3, 0)
scene.add(object2d)
}
camera.position.set(5, 5, 5)
renderer.shadowMap.enabled = true
createSphere()
createFloor()
createLight()
create2d()
10three.js 精灵物体
精灵(Sprite)物体:精灵是一个总面朝摄像机的平面,通常使用一个半透明的纹理
import { scene, camera, renderer } from './utils/init2d'
import * as THREE from 'three'
import { CSS2DObject } from 'three/addons/renderers/CSS2DRenderer.js';
let sphere
let helper
function createFloor() {
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)
plane.receiveShadow = true
scene.add(plane)
}
function createLight() {
// 平行光(太阳)
const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
directionalLight.position.set(3, 3, 3);
directionalLight.castShadow = true
directionalLight.target = sphere
scene.add(directionalLight);
helper = new THREE.DirectionalLightHelper(directionalLight, 1);
scene.add(helper);
}
function createSphere() {
const geometry = new THREE.SphereGeometry(1, 32, 16)
const material = new THREE.MeshStandardMaterial({
color: 0x00ff00
})
sphere = new THREE.Mesh(geometry, material)
sphere.position.set(0, 1, 0)
sphere.castShadow = true
scene.add(sphere)
}
function create2d() {
const div = document.createElement('div')
div.innerHTML = '球体'
div.style.color = 'red'
div.style.fontSize = '32px'
// 与 CSS3D 区别:2D 物体 px 像素单位还可以生效,而不是平移到三维空间中的单位
const object2d = new CSS2DObject(div)
object2d.position.set(0, 3, 0)
scene.add(object2d)
}
function createSprite() {
// 使用:
// 1. 准备纹理对象并加载图片素材
const texture = (new THREE.TextureLoader()).load('image/pkq.jpg')
// 2. 使用 SpriteMaterial 精灵材质
const material = new THREE.SpriteMaterial({ map: texture })
// 3. 使用 Sprite 创建精灵物体并加入场景
const sprite = new THREE.Sprite(material)
sprite.position.set(3, 0.5, -3)
scene.add(sprite)
}
camera.position.set(5, 5, 5)
renderer.shadowMap.enabled = true
createSphere()
createFloor()
createLight()
create2d()
createSprite()