Three.js——learn03
Three.js——learn03
Mesh物体对象基础操作
表示基于以三角形为polygon mesh(多边形网格)的物体的类。 同时也作为其他类的基类,例如SkinnedMesh
实际上Mesh被称为网格,真正到最后生成的物体时Object3D对象
创建
物体对象的创建需要两个参数:
- geometry:几何体类型
- material:材质
//创建几何体对象
const geometry = new THREE.BoxGeometry(1, 1, 1)
//设置基础材质(颜色:0x00ff00)
const material = new THREE.MeshBasicMaterial({ color: 0xffffff })
//创建物体对象(几何体+材质)
const cube = new THREE.Mesh(geometry, material)
//添加物体到材质中
scene.add(cube)
移动(position)
通过x,y,z属性设置移动
//x,y,z属性设置移动
cube.position.x = 3
通过set方法设置移动
set方法直接指定一个Vector3
//set方法设置移动
cube.position.set(0, 2, 1)
通过动画设置移动
const move = () => {
cube.position.x += 0.01
cube.position.y += 0.01
if (cube.position.x >= 2) {
cube.position.set(0, 0, 0)
}
requestAnimationFrame(move)
}
move()
完整代码
import * as THREE from 'three'
//导入轨道控制器
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
//创建场景
const scene = new THREE.Scene()
/**
* 创建相机并设置相机参数
* 参数:
* 1. fov视野角度
* 2.长宽比
* 3.近端距离参数(近截面)最近能看到哪里
* 4.远端距离参数(远截面)最远能看到哪里
*/
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000)
//设置相机位置
camera.position.set(0, 0, 5)
//将相机放置到场景中
scene.add(camera)
//创建渲染器
const renderer = new THREE.WebGLRenderer()
//设置渲染器渲染大小
renderer.setSize(window.innerWidth, window.innerHeight)
//添加渲染器到页面中
document.body.appendChild(renderer.domElement)
//创建几何体对象
const geometry = new THREE.BoxGeometry(1, 1, 1)
//设置基础材质(颜色:0x00ff00)
const material = new THREE.MeshBasicMaterial({ color: 0xffffff })
//创建物体对象(几何体+材质)
const cube = new THREE.Mesh(geometry, material)
//添加物体到材质中
scene.add(cube)
//创建轨道控制器
const control = new OrbitControls(camera, renderer.domElement)
//更新控制器
control.update()
//创建辅助器
const axesHelper = new THREE.AxesHelper(5)
//场景中添加辅助器,用于简单模拟3个坐标轴的对象
scene.add(axesHelper)
/**
* 构建一个三维向量
* x - 向量的x值,默认为0。
* y - 向量的y值,默认为0。
* z - 向量的z值,默认为0。
*/
const dirx = new THREE.Vector3(1, 0, 0)
const diry = new THREE.Vector3(0, 1, 0)
const dirz = new THREE.Vector3(0, 0, 1)
//将该向量转换为单位向量(unit vector), 也就是说,将该向量的方向设置为和原向量相同,但是其长度(length)为1。
dirx.normalize()
diry.normalize()
dirz.normalize()
const origin = new THREE.Vector3(0, 0, 0)
const length = 3
const hex = 0xffffff
/**
* 构建箭头
* dir -- 基于箭头原点的方向. 必须为单位向量.
* origin -- 箭头的原点.
* length -- 箭头的长度. 默认为 1.
* hex -- 定义的16进制颜色值. 默认为 0xffff00.
* headLength -- 箭头头部(锥体)的长度. 默认为箭头长度的0.2倍(0.2 * length).
* headWidth -- The width of the head of the arrow. Default is 0.2 * headLength.
*/
const arrowHelperX = new THREE.ArrowHelper(dirx, origin, length, hex)
const arrowHelperY = new THREE.ArrowHelper(diry, origin, length, hex)
const arrowHelperZ = new THREE.ArrowHelper(dirz, origin, length, hex)
//我们可以给三个轴线添加箭头
//添加到场景中
scene.add(arrowHelperX)
scene.add(arrowHelperY)
scene.add(arrowHelperZ)
//创建摄像机视锥辅助器
const helper = new THREE.CameraHelper(camera)
scene.add(helper)
const size = 10
const divisions = 10
const gridHelper = new THREE.GridHelper(size, divisions)
scene.add(gridHelper)
//给物体添加动画
const an = () => {
//requestAnimationFrame有很多的优点。最重要的一点或许就是当用户切换到其它的标签页时,它会暂停,因此不会浪费用户宝贵的处理器资源,也不会损耗电池的使用寿命
requestAnimationFrame(an)
control.update()
//开始渲染
renderer.render(scene, camera)
}
an()
// //x,y,z属性设置移动
// cube.position.x = 3
// //set方法设置移动
// cube.position.set(0, 2, 1)
const move = () => {
cube.position.x += 0.01
cube.position.y += 0.01
if (cube.position.x >= 2) {
cube.position.set(0, 0, 0)
}
requestAnimationFrame(move)
}
move()
旋转(rotation)
旋转使用是Eular欧拉角,也可以设置x,y,z当然也能用set方法直接设置
cube.rotation.x = 45
//设置Π/4 = 45°,Π/2 = 90°,0
cube.rotation.set(Math.PI / 4, Math.PI / 2, 0)
缩放(scale)
缩放其实也是使用Vector3做的所以和移动一样可以通过x,y,z属性调整,也可以使用set直接设置
cube.scale.x = 0.5
cube.scale.set(0.8, 0.6, 1.2)
通过使用Clock跟踪处理动画
该对象用于跟踪时间。如果performance.now可用,则 Clock 对象通过该方法实现,否则回落到使用略欠精准的Date.now来实现
核心代码
//创建Clock时钟对象
const clock = new THREE.Clock()
const move = () => {
//动画中通过getElapsedTime获取运行总时长
let t = clock.getElapsedTime()
//获取两次运行的间隔时间
let splitTime = clock.getDelta()
console.log('总时长:' + t)
console.log('间隔时间:' + splitTime)
requestAnimationFrame(move)
}
注意点
如上的方式获取的间隔时间为0
我们看文档对于他们的解释:
- oldTime:存储时钟最后一次调用 start, .getElapsedTime() 或 .getDelta() 方法的时间。默认值是 0
- getDelta ()获取自 .oldTime 设置后到当前的秒数。 同时将 .oldTime 设置为当前时间
从这里我们可以知道在使用getElapsedTime的时候已经记录了oldTime,下一行getDelta获取的是oldTime到当前调用的秒数,自然很短很短约等于0,所以会导致输出为0
GSAP
tweenMax 是高性能 JavaScript 动画框架
安装
npm install gsap
导入
//导入GSAP
import gsap from 'gsap'
简单使用
参数:
- 动画对象
- 动画参数
- 动画效果如x表示x轴
- duration:动画持续时间
- ease:动画速率,可选值:(none,power1,power2,power3,power4,back,elastic,bounce,rough,slow,steps,circ,expo,sine,Custom)
写法:“power1.in/inOut/out” - repeat:重复次数 -1表示一直循环
- delay:延迟时间
- yoyo:是否往返 true/false
- onStart:开始回调
- onRepeat:重复回调
- onUpdate:更新回调
- onComplete:完成回调
//设置动画( use gsap)
/**
* 参数:
* 1.动画对象
* 2.动画参数
* - 动画效果如x表示x轴
* - duration:动画持续时间
* - ease:动画速率,可选值:(none,power1,power2,power3,power4,back,elastic,bounce,rough,slow,steps,circ,expo,sine,Custom)
* 写法:"power1.in/inOut/out"
* - repeat:重复次数 -1表示一直循环
* - yoyo:是否往返 true/false
* - delay:延迟时间
* - onStart:开始回调
* - onRepeat:重复回调
* - onUpdate:更新回调
* - onComplete:完成回调
*/
gsap.to(cube.position, {
x: 2,
duration: 3,
ease: 'power1.inOut',
repeat: 3,
onStart: () => {
console.log('start')
},
onRepeat: () => {
console.log('repeat')
},
onUpdate: () => {
console.log('update')
},
onComplete: () => {
console.log('complete')
}
})
效果
控制动画的开始或结束
let gsapAn = gsap.to(cube.position, {
x: 2,
duration: 3,
ease: 'power1.inOut',
repeat: 3,
yoyo: true,
onStart: () => {
console.log('start')
},
onRepeat: () => {
console.log('repeat')
},
onUpdate: () => {
console.log('update')
},
onComplete: () => {
console.log('complete')
}
})
//添加点击事件
window.addEventListener('click', () => {
//pause:暂停
//resume:恢复运动
gsapAn.isActive() ? gsapAn.pause() : gsapAn.resume()
})
视图更新
window.addEventListener('resize', () => {
//更新摄像头
camera.aspect = window.innerWidth / window.innerHeight
//更新投影矩阵
camera.updateProjectionMatrix()
//更新渲染器
renderer.setSize(window.innerWidth,window.innerHeight)
//更新像素比例
renderer.setPixelRatio(window.devicePixelRatio())
})