Three.js 入门(二)

简介

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

Resize

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

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

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

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

  //   mesh.rotation.x += 0.01;
  //   mesh.rotation.y += 0.01;

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

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

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

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

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

// 定义鼠标的指针值
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平面的移动。

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

// 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,可以理解为从屏幕最左端到最右端刚好转了一周,这个是可以自由调整的。

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

// tick 函数中
camera.lookAt(mesh.position)

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

Three.js 入门(二)

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

它的使用方式也很简单

import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'

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

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

controls.enableDamping = true

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

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

AxesHelper

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

const axeshelper = new THREE.AxesHelper(3)
scene.add(axeshelper)

Three.js 入门(二)

Clock

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

mesh.rotation.x += 0.01

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

const clock = new THREE.Clock()

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

mesh.rotation.x = clock.getElapsedTime()

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

Dat.gui

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

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

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 入门(二)

总结

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

原文链接:https://juejin.cn/post/7346933141870739494 作者:vancats

(0)
上一篇 2024年3月17日 下午4:36
下一篇 2024年3月17日 下午4:46

相关推荐

发表回复

登录后才能评论