学习资料:B站 老陈打码
three.js官网
创建第一个3D 立方体
创建立方体之前需要准备场景、摄像机、渲染器
相机
官方示例 参数:
- fov:摄像机视锥体垂直视野角度;
- aspect:摄像机视锥体长宽比;
- near:摄像体视锥体近端面;
- far:摄像机视锥体远端面
// 导入 Three.js
import * as THREE from "three"
// 1、 创建场景
const scenc = new THREE.Scenc()
// 2、创建相机
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000)
// 3、设置相机位置 x、y、z
camera.position.set(0, 0, 10)
// 在场景中添加相机
scenc.add(camera)
// 4、添加几何体
// 创建几何体 x,y,z 坐标
const cubeGeometry = new THREE.BoxGeometry(1,1,1)
// 几何体材质
const cubeMaterial = new THREE.MeshBasicMaterial({colo:0xfff00})
// 根据坐标、材质创建几何体
const cube = new THREE.Mesh(cubeGeometry, cubeMaterial)
// 5、将几何体添加到场景
scenc.add(cube)
// 6、创建渲染器
const renderer = new THREE.WebGlRenderer()
// 设置渲染器大小
renderer.setSize(window.innerWidth, window.innerHeight)
// 将渲染器生成的canvas 添加到body
document.body.appendChild(renderer.domElement)
// 通过渲染器,将场景和相机渲染出来
renderer.render(scenc, camera)
第一个立方体就创建好了
使用轨道控制器 + 坐标线
但刚刚创建的立体图形目前的效果看起来是平面的,现在只需要添加一个控制器,使相机围绕目标进行运动才能看到立体效果。
控制器也有很多种,在官网可以查看不同的控制器的不同应用场景,目前根据需求选择,这里使用轨道控制器(OrbitControls)
// 使用轨道控制器查看3D物体
// 导入轨道控制器
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
// 创建轨道控制器 相机,事件监听的HTML元素
const controls = new OrbitControls(camera, renderer.domElement)
// 为动画添加阻尼效果,更加逼真,必须在动画循环里调用controls.update()。
controls.enableDamping = true
// 添加坐标辅助线 x轴:红色;y轴:绿色;z轴:蓝色
const axesHelper = new THREE.AxesHelper( 5 );
// 添加到场景
sence.add( axesHelper );
// 渲染函数
function render () {
// 通过改变 cube.position.x 实现平行移动效果
cube.position.x > 5 ? cube.position.x = 0 : cube.position.x += 0.01
controls.update()
renderer.render(scenc, camera)
// requestAnimationFrame 浏览器自带函数 渲染下一帧的时候调用render 函数
requestAnimationFrame(render)
}
使用Clock构造函数,实现物体匀速移动
// 创建时钟
const clock = new THREE.Clock()
function render () {
controls.update()
// let deltaTime = clock.getDelta()
// console.log("两次获取时间的间隔时间:", deltaTime);
let time = clock.getElapsedTime()
let t = time % 5
cube.position.x = t * 1
// console.log("运行时间总时长:", time);
renderer.render(scenc, camera)
// 渲染下一帧的时候调用render 函数
requestAnimationFrame(render)
}
监听window resize事件,动态更新渲染器、摄像头
// 根据尺寸变化实现自适应画面
window.addEventListener("resize", () => {
// 更新渲染器尺寸大小
renderer.setSize(window.innerWidth, window.innerHeight)
// 设置渲染器像素比 window.devicePixelRatio 当前像素比
renderer.setPixelRatio(window.devicePixelRatio)
// 更新摄像头
camera.aspect = window.innerWidth / window.innerHeight
// 更新摄像头投影矩阵
camera.updateProjectionMatrix()
})
使用GSAP动画库
安装:npm install gsap
引入:import { gsap } from "gsap";
// 导入gsap 动画库
import gsap from "gsap"
// 创建 立方体 X轴平移动画
let animate1 = gsap.to(cube.position, {
// x坐标
x: 5,
// 多少秒内完成
duration: 5,
// 动画效果
ease: "power1.inOut",
// 执行的次数,无限次:-1
repeat: -1,
// 往返运动
yoyo: true,
// 延迟执行时间
delay: 1,
// 动画开始回调
onStart: () => { console.log('动画开始了!') },
// 执行完成的回调函数
onComplete: () => { console.log("执行完成") },
})
// 创建 立方体 旋转效果
let animate2 = gsap.to(cube.rotation, {
x: 2 * Math.PI,
duration: 5,
ease: "power1.inOut",
repeat: -1,
yoyo: true,
delay: 1
})
添加单机暂停/恢复动画事件,双击进入,退出全屏事件
window.addEventListener("dblclick", () => {
// document.fullscreenElement 获取到当前进入全屏的元素
const fullscreenElement = document.fullscreenElement
if (!fullscreenElement) {
// renderer 进入全屏
renderer.domElement.requestFullscreen()
} else {
// 退出全屏 使用document对象
document.exitFullscreen()
}
})
window.addEventListener("click", () => {
// animate1.isActive() 获取到 animate1 的状态 true 为在运行中
if (animate1.isActive()) {
// 暂停动画
animate1.pause()
animate2.pause()
} else {
// 恢复动画
animate1.resume()
animate2.resume()
}
})
使用dat.gui 插件
安装:npm install --save dat.gui
引入: import * as dat from 'dat.gui'
// 导入
import * as dat from 'dat.gui'
// 创建 gui实例
const gui = new dat.GUI()
const params = {
color: "#ffff00",
rotationFn: () => {
if (animate2.isActive()) {
animate2.pause()
} else {
animate2.resume()
}
},
positionFn: () => {
if (animate1.isActive()) {
animate1.pause()
} else {
animate1.resume()
}
}
}
gui.add(cube.position, "x").min(0).max(5).step(0.01).name("修改X值")
gui.add(params, "color").name("修改立方体颜色").onChange(val => {
cube.material.color.set(val)
})
gui.add(cube, "visible").name("显示立方体")
// 添加操作文件夹
let folder = gui.addFolder("设置立方体")
folder.add(params, "rotationFn").name("旋转立方体")
folder.add(params, "positionFn").name("立方体移动")
// 设置线框
folder.add(cube.material, "wireframe")
完整代码
import * as THREE from "three"
// 导入轨道控制器
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
// 导入gsap 动画库
import gsap from "gsap"
import * as dat from 'dat.gui'
// 目标:使用dat.gui 库
// 1、创建场景
const scenc = new THREE.Scene()
// 2、创建相机
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000)
// 3、设置相机位置
camera.position.set(0, 0, 10)
scenc.add(camera)
// 4、添加物体
// 创建几何体
const cubeGeometry = new THREE.BoxGeometry(1, 1, 1)
// 几何体材质
const cubeMaterial = new THREE.MeshBasicMaterial({ color: 0xfff00 })
// 根据几何体,材质 创建物体
const cube = new THREE.Mesh(cubeGeometry, cubeMaterial)
// 将几何体添加到场景
scenc.add(cube)
let animate1 = gsap.to(cube.position, { x: 5, duration: 5, repeat: -1, ease: "power1.inOut", yoyo: true })
let animate2 = gsap.to(cube.rotation, {
x: Math.PI * 2,
duration: 5,
repeat: -1,
ease: "power1.inOut",
yoyo: true
})
const params = {
color: "#ffff00",
rotationFn: () => {
if (animate2.isActive()) {
animate2.pause()
} else {
animate2.resume()
}
},
positionFn: () => {
if (animate1.isActive()) {
animate1.pause()
} else {
animate1.resume()
}
}
}
const gui = new dat.GUI()
gui.add(cube.position, "x").min(0).max(5).step(0.01).name("修改X值")
gui.add(params, "color").name("修改立方体颜色").onChange(val => {
cube.material.color.set(val)
})
gui.add(cube, "visible").name("显示立方体")
// 添加操作文件夹
let folder = gui.addFolder("设置立方体")
folder.add(params, "rotationFn").name("旋转立方体")
folder.add(params, "positionFn").name("立方体移动")
// 设置线框
folder.add(cube.material, "wireframe")
// 修改物体位置
// cube.position.set(5, 0, 0)
// cube.position.x = 3;
// 控制物体缩放
// cube.scale.set(1, 2, 3)
// cube.scale.x = 3
// 控制物体旋转
// cube.rotation.set(Math.PI / 4, 0, 0)
// cube.rotation.x = Math.PI / 6
// 创建渲染器
const renderer = new THREE.WebGLRenderer()
// 设置渲染器尺寸大小
renderer.setSize(window.innerWidth, window.innerHeight)
// 将渲染器生成的canvas 添加到body
document.body.appendChild(renderer.domElement)
// 通过渲染器,将场景和相机渲染出来
renderer.render(scenc, camera)
// 创建轨道控制器 相机,事件监听的HTML元素
const controls = new OrbitControls(camera, renderer.domElement)
// 为动画添加阻尼效果,更加逼真,必须在动画循环里调用.update()。
controls.enableDamping = true
// 添加坐标辅助线 x轴:红色;y轴:绿色;z轴:蓝色
const axesHelper = new THREE.AxesHelper(5)
scenc.add(axesHelper)
window.addEventListener("dblclick", () => {
// document.fullscreenElement 获取到当前进入全屏的元素
const fullscreenElement = document.fullscreenElement
if (!fullscreenElement) {
// renderer 进入全屏
renderer.domElement.requestFullscreen()
} else {
// 退出全屏 使用document对象
document.exitFullscreen()
}
})
function render () {
controls.update()
renderer.render(scenc, camera)
// 渲染下一帧的时候调用render 函数
requestAnimationFrame(render)
}
render()
// 根据尺寸变化实现自适应画面
window.addEventListener("resize", () => {
// 更新渲染器尺寸大小
renderer.setSize(window.innerWidth, window.innerHeight)
// 设置渲染器像素比 window.devicePixelRatio 当前像素比
renderer.setPixelRatio(window.devicePixelRatio)
// 更新摄像头
camera.aspect = window.innerWidth / window.innerHeight
// 更新摄像头投影矩阵
camera.updateProjectionMatrix()
})