Three.js——learn03
创始人
2025-05-31 10:15:13

Three.js——learn03

  • Three.js——learn03
    • Mesh物体对象基础操作
      • 创建
      • 移动(position)
        • 通过x,y,z属性设置移动
        • 通过set方法设置移动
        • 通过动画设置移动
        • 完整代码
      • 旋转(rotation)
      • 缩放(scale)
    • 通过使用Clock跟踪处理动画
      • 核心代码
      • 注意点
    • GSAP
      • 安装
      • 导入
      • 简单使用
      • 效果
      • 控制动画的开始或结束
    • 视图更新

Three.js——learn03

Mesh物体对象基础操作

表示基于以三角形为polygon mesh(多边形网格)的物体的类。 同时也作为其他类的基类,例如SkinnedMesh
实际上Mesh被称为网格,真正到最后生成的物体时Object3D对象

创建

物体对象的创建需要两个参数:

  1. geometry:几何体类型
  2. 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.01cube.position.y += 0.01if (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 = 10const 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.01cube.position.y += 0.01if (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'

简单使用

参数:

  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表示一直循环
    • 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())
})

相关内容

热门资讯

云龙天池国家级自然保护区入选世... 转自:云南日报记者近日从云龙天池国家级自然保护区获悉,该保护区正式入选世界自然保护联盟绿色名录,成为...
芒果干里的“暖心账”​ 我 为 群 众 办 实 事我是楚雄彝族自治州楚雄市八角镇大麦地村委会泥期苴小组的鲁晓玲。天还没亮,新...
在亲戚借条上签名被判连带清偿责...   三湘都市报12月14日讯  欠钱逾期未还,双方公堂对簿,竟因借据上的“担保人”“连带担保人”起了...
学分能换“高级工”证书?湖南暂...   毕业就能拿到“高级工”的技能证书,实现“毕业即持证”,这是种什么样的体验?近日,安徽皖江工学院土...
长赣高铁湖南段首座隧道进洞施工     12月13日,位于浏阳市荷花街道和澄潭江镇的长赣高铁湖南段首座隧道——苏家庵隧道正式进洞。 ...