Three.js 入门(二)

简介

上一篇介绍了Three.js中的主要框架和基础内容并实现了一个简单的Demo,本篇文章会介绍一些简单的优化和辅助工具,包括自带的和使用广泛的工具。

Resize

先解决一个小问题,打开上次的Demo,尝试拖拽一下浏览器,是不是立方体还在原来的位置没有变化?

加上一个监听函数,在浏览器尺寸变化时,获取相应的宽高再更新相机和渲染器的相关参数即可。

arduino 复制代码
window.addEventListener('resize', () => {
    // Update Sizes
    sizes.width = window.innerWidth
    sizes.height = window.innerHeight

    // Update Camera
    camera.aspect = sizes.width / sizes.height
    camera.updateProjectionMatrix()

    // Update Renderer
    renderer.setSize(sizes.width, sizes.height)
})

OrbitControls

先让立方体停止旋转,此时只能观测到一个面。

arduino 复制代码
  //   mesh.rotation.x += 0.01;
  //   mesh.rotation.y += 0.01;

问题来了,如果不希望改动立方体,有什么办法可以观察到它的全貌呢?

很简单,观测物体不动,移动观测点位(相机)就可以了,根据鼠标的移动位置改变相机的position值即可简单模拟。

这里涉及到一些计算相关的问题。

首先,有一个知识点需要大家了解一下,Three.js 的坐标体系和浏览器是不同的。在浏览器中基准点在屏幕左上角 的位置,随向右向下 逐渐增大,而 Three.js 世界中,默认的中心点在正中心 ,随向上向右增大,反方向减小。

因此需要对坐标数据进行一次转化,代码见示例,最终将 cursor 的值限定在了[-0.5, 0.5]之间,因为中心向左向下时,取负值更容易计算,至于 0.5 是个人习惯取值,可以自由设定。

arduino 复制代码
// 定义鼠标的指针值
const cursor = { x: 0, y: 0 }

// 鼠标移动的时候改变 cursor 值
window.addEventListener('mousemove', (e) => {
    cursor.x = e.clientX / sizes.width - 0.5
    cursor.y = -(e.clientY / sizes.height - 0.5)
})

第二个问题,相机如何移动才合适呢?

这个例子比较简单,只考虑XOZ平面的移动。

思考一件事情,当物体在地面上不动时,想要拍摄它的前后左右,并且拍摄出的物体大小尽量保持一致,应该怎么拍呢,是不是以它为圆心,按固定的半径绕一圈勒。

arduino 复制代码
// tick 函数中
const radius = 3
camera.position.x = Math.sin(cursor.x * Math.PI * 2) * radius
camera.position.z = Math.cos(cursor.x * Math.PI * 2) * radius

其实做法也是类似的,大概解释一下里面的一些参数吧:

  1. 一个数学小知识,忘记的同学刚好补一补课:sin(x)² + cos(x)² = 1,使用两个Math方法可以确定按圆周运动。
  2. radius 用于确定旋转半径。
  3. 三角函数内部的值是计算频率的,由于cursor.x取值范围在[-0.5, 0.5],再乘上Math.PI * 2,可以理解为从屏幕最左端到最右端刚好转了一周,这个是可以自由调整的。

对了,相机观测视角是固定的,要记得实时调整它的观测点位哦

arduino 复制代码
// tick 函数中
camera.lookAt(mesh.position)

至于Y的值大致设置一个范围吧,有兴趣的同学可以自行尝试,大致效果是这样的。

如果想观测物体,完全靠自己写一套其实比较麻烦,Three.js 提供了一个比较方便的工具OrbitControls

它的使用方式也很简单

javascript 复制代码
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'

// 需要传入相机和 canvas 节点
const controls = new OrbitControls(camera, canvas)

是的就是这么简单的两行代码,就可以360度拖动了。介绍一个比较常用的参数吧

ini 复制代码
controls.enableDamping = true

这个参数可以开启控制器的阻尼,也就是惯性,具体效果可以自行尝试一下,但是开启了之后必须在每一帧更新一下控制器哦

scss 复制代码
// 如果使用了 damping,必须要在 tick 函数中更新
controls.update()

AxesHelper

在开发的过程中,XYZ轴的显示有时候还是挺有必要的。

csharp 复制代码
const axeshelper = new THREE.AxesHelper(3)
scene.add(axeshelper)

Clock

目前Demo的动画是使用requestAnimationFrame来做时间控制的,但是了解这个函数的同学都知道它的时间实际上是不一定准确的,它可能被很多因素影响。

复制代码
mesh.rotation.x += 0.01

因此动画函数中做上述操作时,时间间隔可能是不同的,有可能存在旋转卡顿或者旋转不匀速的情况,这时候可以使用官方提供的时间类工具Clock,使用方式也很简单。

arduino 复制代码
const clock = new THREE.Clock()

clock中存有一个elapsedTime,它的数值为当前时间减去clock创建时间,这是一个匀速增长的数值,可以直接使用

ini 复制代码
mesh.rotation.x = clock.getElapsedTime()

它会帮助我们更准确的去控制一些变换的操作。

Dat.gui

Three.js 的调试比较麻烦,因为它的属性和方法还有一些事件都并不和DOM挂钩很难去,我们可以借助 Dat.gui 这个UI调试库。它会提供一个面板,在里面进行输入,选择,点击等操作去更新属性或者调用方法。

基础用法大致有以下几种:

csharp 复制代码
import * as dat from 'dat.gui'

// 初始化
const gui = new dat.GUI({ width: 400 })

// 设置一些全局参数
const parameters = {
    color: 0xff0000,
    goUp: () => mesh.position.y += 0.1,
}

// 普通设值
gui.add(mesh.position, 'x', -3, 3, 0.01).name('hello')
// 链式设值
gui.add(mesh.position, 'z').min(-3).max(3).step(0.01)
// 设置单选框
gui.add(mesh, 'visible')
// 设置颜色,这里要注意,点击颜色后要手动更新一下 material 的颜色
gui.addColor(parameters, 'color').onChange(() => material.color.set(parameters.color))
// 点击触发函数
gui.add(parameters, 'goUp')

总结

本文介绍了几种比较通用的工具,给视图和动画显示以及本地调试带来了一些帮助,并介绍了一些基础且使用较多的参数,更多参数方法大家去相应的文档中查看,Three.js 的官方文档 中介绍也很详细。本文相关的代码在 这里

相关推荐
恋猫de小郭25 分钟前
Flutter Zero 是什么?它的出现有什么意义?为什么你需要了解下?
android·前端·flutter
崔庆才丨静觅7 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60618 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了8 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅8 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅8 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅9 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment9 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅9 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊9 小时前
jwt介绍
前端