《Three.JS零基础入门教程》第四篇:基础变换

《Three.JS零基础入门教程》第一篇:搭建开发环境

《Three.JS零基础入门教程》第二篇:起步案例

《Three.JS零基础入门教程》第三篇:开发辅助

后续持续更新

接下来, 我们通过三种基础的变换来加深对3D坐标系中坐标单位的理解, 同时也是动画的基础. 分别是:

  • 移动
  • 缩放
  • 旋转
效果

动图

1. 网络辅助工具

为了更好的理解坐标单位, 我们引入网格辅助工具(GridHelper)

// 5. 创建立方体(几何+材质)
const cubeGeometry = new THREE.BoxGeometry(2, 2, 2)
const cubeMaterial = new THREE.MeshNormalMaterial()
const cube = new THREE.Mesh(cubeGeometry, cubeMaterial)

// 创建网格辅助工具
const gridHelper = new THREE.GridHelper( 20, 20, 0xffffff, 0xffffff )
// 为了更方便观察, 设置opacity透明度
gridHelper.material.transparent = true
gridHelper.material.opacity = 0.5

// 添加到场景中
scene.add( gridHelper )
  1. 为了方便观察, 我们把立方体的大小改成了(2,2,2). 这种x轴的范围为(-1, 1)
  2. 创建网格辅助工具, 并添加到场景中
    1. 第一个参数(size): 网格的总宽高, 设置为20, 对应x轴的坐标范围为(-10, 10), 默认值为10
    2. 第二个参数(divisions): 网格分成多少份, 设置为20, 每份就是1个单位, 默认值为10
    3. 第三个参数(colorCenterLine): 中线的颜色, 默认值为0x444444
    4. 第四个参数(colorGrid): 网络线的颜色, 默认值为0x888888

2. 移动

通过改变物体的position属性, 控制物体的移动

// 通过设置三维向量的属性控制移动
cube.position.x = 2
cube.position.y = 2
cube.position.z = 2
// 通过调用三维向量的方法控制移动
cube.position.set(3, 3, 3)
// 添加到场景
scene.add(cube)

通过设置cube的position(三维向量)对象的x, y, z的值来控制立方体分别沿x, y, z轴移动

3. 缩放

通过改变物体的scale属性, 控制物体的缩放

// 通过设置三维向量的属性控制缩放比例
cube.scale.x = 1
cube.scale.y = 2
cube.scale.z = 3
// 通过调用三维向量的方法控制缩放
cube.scale.set(3, 3, 3)

4. 旋转

通过改变物体的rotation属性, 控制物体的旋转.

这里需要注意的是: 旋转的单位是弧度, 不是角度

换算公式

π弧度 = 180度

  • 弧度=角度×(π ÷ 180)
  • 角度=弧度×(180 ÷ π)

常用弧度

π/2弧度 = 90度

π/3弧度 = 60度

π/4弧度 = 45度

π/6弧度 = 30度

按照右手法则, 大拇指指向x轴, 四指方向为正方向, 即从x轴方向观察, 逆时间旋转

// 通过设置三维向量的属性控制旋转
cube.rotation.x = Math.PI / 4
// 通过三维向量的方法控制旋转
cube.rotation.set(Math.PI / 4, 0, 0)

5. 集成Gui工具

我们发现, 如果每次通过修改代码的方式修改属性值效率太低

这里我们可以集成一种Gui工具, 通过UI交互界面来修改方便很多

dat.gui的npm链接

1) 安装

npm i dat.gui

2) 基本使用

// 导入dat
import * as dat from 'dat.gui'
// 初始化
const gui = new dat.GUI()
gui.add(cube.position, 'x').min(-10).max(10).step(1)

这里我们可以做一个分组

// 5. 创建立方体(几何+材质)
const cubeGeometry = new THREE.BoxGeometry(2, 2, 2)
const cubeMaterial = new THREE.MeshNormalMaterial()
const cube = new THREE.Mesh(cubeGeometry, cubeMaterial)

const gui = new dat.GUI()
const guiPosition = gui.addFolder('移动')
guiPosition.add(cube.position, 'x').min(-10).max(10).step(1)
guiPosition.add(cube.position, 'y').min(-10).max(10).step(1)
guiPosition.add(cube.position, 'z').min(-10).max(10).step(1)

const guiScale = gui.addFolder('缩放')
guiScale.add(cube.scale, 'x').min(1).max(10).step(1)
guiScale.add(cube.scale, 'y').min(1).max(10).step(1)
guiScale.add(cube.scale, 'z').min(1).max(10).step(1)

const guiRotate = gui.addFolder('旋转(度)')
const data = {
  x: 0,
  y: 0,
  z: 0,
}
guiRotate.add(data, 'x', -180, 180, 1).onChange((value) => {
  // 在onChange的回调中
  //  1. 通过形参获取修改的数值
  //  2. 使用THREE提供的数学工具, 将 度 转换成 弧度
  cube.rotation.x = THREE.MathUtils.degToRad(value)
})
guiRotate.add(data, 'y', -180, 180, 1).onChange((value) => {
  cube.rotation.y = THREE.MathUtils.degToRad(value)
})
guiRotate.add(data, 'z', -180, 180, 1).onChange((value) => {
  cube.rotation.z = THREE.MathUtils.degToRad(value)
})

完整示例:

// 导入three.js
import * as THREE from 'three'

import { OrbitControls } from 'three/addons/controls/OrbitControls.js'
// 导入dat.gui
import * as dat from 'dat.gui'

// 1. 创建场景
const scene = new THREE.Scene()

// 5. 创建立方体(几何+材质)
const cubeGeometry = new THREE.BoxGeometry(2, 2, 2)
const cubeMaterial = new THREE.MeshNormalMaterial()
const cube = new THREE.Mesh(cubeGeometry, cubeMaterial)

scene.add(cube)

// 集成Gui工具
const gui = new dat.GUI()
/**
 * 添加一个配置项
 * @param Object
 * @param Attr
 */
const guiPosition = gui.addFolder('位置信息')
guiPosition.add(cube.position, 'x', -10, 10, 1)
guiPosition.add(cube.position, 'y', -10, 10, 1)
guiPosition.add(cube.position, 'z', -10, 10, 1)

const guiScale = gui.addFolder('缩放')
guiScale.add(cube.scale, 'x', 1, 10, 1)
guiScale.add(cube.scale, 'y', 1, 10, 1)
guiScale.add(cube.scale, 'z', 1, 10, 1)

const guiRotate = gui.addFolder('旋转(度)')
const data = {
  x: 0,
  y: 0,
  z: 0,
}
guiRotate.add(data, 'x', -180, 180, 1).onChange((value) => {
  // 在onChange的回调中
  //  1. 通过形参获取修改的数值
  //  2. 使用THREE提供的数学工具, 将 度 转换成 弧度
  cube.rotation.x = THREE.MathUtils.degToRad(value)
})
guiRotate.add(data, 'y', -180, 180, 1).onChange((value) => {
  // 在onChange的回调中
  //  1. 通过形参获取修改的数值
  //  2. 使用THREE提供的数学工具, 将 度 转换成 弧度
  cube.rotation.y = THREE.MathUtils.degToRad(value)
})
guiRotate.add(data, 'z', -180, 180, 1).onChange((value) => {
  // 在onChange的回调中
  //  1. 通过形参获取修改的数值
  //  2. 使用THREE提供的数学工具, 将 度 转换成 弧度
  cube.rotation.z = THREE.MathUtils.degToRad(value)
})

// 2. 创建相机
const camera = new THREE.PerspectiveCamera(
  45,
  window.innerWidth / window.innerHeight,
  1,
  1000
)
camera.position.set(20, 20, 20)
camera.lookAt(0, 0, 0)

// 6. 创建坐标轴的辅助对象
const axesHelper = new THREE.AxesHelper(10)
scene.add(axesHelper)

// 创建网格辅助对象
const gridHelper = new THREE.GridHelper(20, 20, 0xffffff, 0xffffff)
gridHelper.material.transparent = true
gridHelper.material.opacity = 0.5
scene.add(gridHelper)

// 3. 创建渲染器
const renderer = new THREE.WebGLRenderer({ antialias: true })
renderer.setSize(window.innerWidth, window.innerHeight)
renderer.setPixelRatio(window.devicePixelRatio)
renderer.setAnimationLoop(animation)
document.body.appendChild(renderer.domElement)

// 4. 渲染
function animation() {
  renderer.render(scene, camera)
}

// 7. 创建轨道控制器
const controls = new OrbitControls(camera, renderer.domElement)

// 8. 监听window的resize事件
window.addEventListener('resize', () => {
  // 重新设置相机的宽高比
  camera.aspect = window.innerWidth / window.innerHeight
  camera.updateProjectionMatrix()

  // 设置渲染器的出图(照片的大小)
  renderer.setSize(window.innerWidth, window.innerHeight)
})
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值