前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Three.js基础之变换3D对象 | 《Three.js零基础直通04》

Three.js基础之变换3D对象 | 《Three.js零基础直通04》

作者头像
大帅老猿
发布2022-06-06 11:03:05
3.4K0
发布2022-06-06 11:03:05
举报
文章被收录于专栏:大帅老猿大帅老猿

前言

经过上一小节《使用Three.js构建基础3D场景 | 《Three.js零基础直通03》》,基础场景已经有了,现在我们来探索Three.js的一些功能。

让三维场景中的3D对象发生变换,有很多方式,甚至不需要操作3D对象本身。比如在前一小节中,我们已经通过使相机向后移动camera.position.z = 3来实现了立方体的缩小。

任意的3D对象都有4个用于变换的属性

  • position (在三个轴向上移动)
  • scale (在三个轴向上缩放)
  • rotation (在三个轴向上旋转)
  • quaternion (四元数,也是用于处理旋转的)

所有继承自Object3D的子类都具有这些属性,比如PerspectiveCameraMesh之类也都有。我们可以从Three.js的文档中看到类的继承关系。

这些属性最终将被转换成我们对应的矩阵数值。Three.jsWebGLGPU内部都使用矩阵Matrix来进行变换。不过还好,我们并不需要自己去计算矩阵,只需修改前面提到的属性即可。

准备工作

打开上一小节中最后的项目,可以看见在漆黑的场景中有一个红色的立方体,虽然它现在看起来只是一个正方形。

/assets/lessons/05/step-01.png

移动

position位置属性又有3个基本变量,x,y和z。这些是在3D空间中用于定位的3个轴向。

每个轴的方向并不能单纯的用水平垂直纵深去描述,因为它可以根据环境而变化,比如旋转。在Three.js中采用右手笛卡尔坐标系,y轴向上,z轴向后,x轴向右。

这些变量的值,是向量单位,也就是1到底代表多少完全由我们自己决定。1可以是1厘米,1米,甚至1公里。

“现在让我们来随意的修改一下这个立方体的position属性,没事,尽管玩,但每一次修改尽量只改变一个轴的值,方便我们观测这个值产生的效果。”

由于我们看见的画面都是经过调用渲染器渲染出来的,所以要确保在进行变换后调用一次渲染器的渲染方法render(...)

代码语言:javascript
复制
mesh.position.x = 0.7
mesh.position.y = - 0.6
mesh.position.z = 1

/assets/lessons/05/step-02.png

position熟悉除了x,y,z以外还有很多实用的方法 比如通过length方法可以得到一个向量的长度:

代码语言:javascript
复制
console.log(mesh.position.length())

比如通过distanceTo计算和另一个向量坐标的距离:

代码语言:javascript
复制
console.log(mesh.position.distanceTo(camera.position))

再比如通过normalize归一化来仅保留方向特性:

代码语言:javascript
复制
console.log(mesh.position.normalize())

或者通过set方法来一次性更改x,y,z三个值:

代码语言:javascript
复制
mesh.position.set(0.7, - 0.6, 1)

轴辅助工具

在三维空间中,要确切的知道一个3D对象的轴向并不简单,尤其当我们旋转移动过相机之后。

不过,好在我们可以使用Three.js提供的轴辅助工具 AxesHelper。AxesHelper 将始终显示与x,y和z轴相对应的3个轴向指示,每一个轴向的指示都从场景的中心开始并沿相应的方向延伸。

创建AxesHelper,并将其添加到场景中。我们可以设置轴向指示的长度,比如2:

代码语言:javascript
复制
/**
 * Axes Helper
 */
const axesHelper = new THREE.AxesHelper(2)
scene.add(axesHelper)

/assets/lessons/05/step-03.png

创建后,我们应该看能到一条绿线y轴和红线x轴。还有一条蓝色的线z轴,不过由于目前它和相机的位置完全对其,所以我们看不见它。

一般情况下,我们不会使用这个轴辅助工具,当我们在三维世界中迷失方向的时候,才会用它来提供视觉辅助。

缩放

缩放也是一个具有x,y,z三个变量的向量对象。在创建3D对象时,默认的缩放比例x,y和z皆为1,就是没有缩放的意思。如果将设置某一个轴的值为0.5,则对象在该轴上将是原大小的一半,如果设置为2,则在该轴上将是原大小的2倍。

“试着更改这些值,去缩放场景中的立方体。”

代码语言:javascript
复制
mesh.scale.x = 2
mesh.scale.y = 0.25
mesh.scale.z = 0.5

/assets/lessons/05/step-04.png

旋转

有两种处理旋转的方法,使用rotation很简单直观,而使用quaternion会相对麻烦一些。但使用任意方法旋转时,两种方法对应的值都会自动更新。

使用rotation

rotation属性也具有x,y和z三个变量,和移动、缩放不同,这里的值是旋转角度。让我们逐个改变三个轴向的旋转角度,然后对照轴辅助工具来观察旋转是如何生效的。

“关于旋转角度,你会使用π吗?”

代码语言:javascript
复制
mesh.rotation.x = Math.PI * 0.25
mesh.rotation.y = Math.PI * 0.25

/assets/lessons/05/step-05.png

挺容易的对不对?但是这里面有个坑,当我们同时旋转多个轴时可能会得到一些意想不到的结果。因为,当你旋转x轴时,也会改变其他轴的方向。因而我们可以通过使用reorder(...) 方法对象来更改旋转轴的应用顺序。比如rotation.reorder('yxz'),就将先执行y轴的旋转。

虽然rotation使用起来更容易理解,但这个顺序问题挺讨厌的。这就是为什么大多数引擎和3D软件使用另一种名为Quaternion的解决方案的原因。

使用quaternion

quaternion四元数这个属性也用于旋转,但它是一种更加数学的方式,并且能解决顺序问题。

不过在本课程中,我们并不会学习quaternion四元数的工作原理,但请记住,当我们更改rotation时,四元数也会更新。我们可以随意使用两者中的任何一个。

使用lookAt

Object3D这个类有一个名为lookAt(...) 的方法,这个方法可太好用了。它可以让指定的3D物体自动旋转朝向一个坐标,不需要我们去计算角度。

我们可以使用它轻而易举的将相机转向某个3D物体,或在游戏中将大炮面向敌人,亦或将角色的视野移到某个对象上。

这个方法接受一个vector3的对象作为参数,也就是三维坐标:

代码语言:javascript
复制
camera.lookAt(new THREE.Vector3(0, - 1, 0))

/assets/lessons/05/step-06.png

这个立方体看上去移动到了更高的位置,但实际上,相机的视点正位于立方体的下方。

当然我们也可以使用任何现有的3D对象的position作为参数:

代码语言:javascript
复制
camera.lookAt(mesh.position)

组合应用变换

我们可以任意组合位置、旋转 (或四元数) 和缩放。结果和赋值这些变量的顺序无关。试着同时应用前面学到的几个变换属性吧:

代码语言:javascript
复制
mesh.position.x = 0.7
mesh.position.y = - 0.6
mesh.position.z = 1
mesh.scale.x = 2
mesh.scale.y = 0.25
mesh.scale.z = 0.5
mesh.rotation.x = Math.PI * 0.25
mesh.rotation.y = Math.PI * 0.25

/assets/lessons/05/step-07.png

成组

大部分真正的业务场景中,不会只有一个立方体。比如我们在三维世界里搭建一所房子,其中有墙壁,门,窗户,屋顶等各种3D对象。假设我们觉得房子有点小的时候,是否需要重新缩放每个对象并重新设置它们的坐标呢?如果是这样,那也太麻烦了。

“这个时候就需要Group成组,也可以把它理解为一个单纯的容器。”

所以,当我们想对很多3D对象同时进行缩放时,将所有这些3D对象都放到一个Group中,再对这个Group进行缩放即可。

实例化一个Group并将其添加到Scene场景中。当我们再创建新的3D对象时,可以直接将它直接add (...) 到刚刚创建的Group中,而不是将其添加到场景中。

由于Group类也继承自Object3D类,因此前面提到的属性和方法,例如位置,比例,旋转,四元数和lookAt都可以作用在Group上。

代码语言:javascript
复制
/**
 * Objects
 */
const group = new THREE.Group()
group.scale.y = 2
group.rotation.y = 0.2
scene.add(group)

const cube1 = new THREE.Mesh(
    new THREE.BoxGeometry(1, 1, 1),
    new THREE.MeshBasicMaterial({ color: 0xff0000 })
)
cube1.position.x = - 1.5
group.add(cube1)

const cube2 = new THREE.Mesh(
    new THREE.BoxGeometry(1, 1, 1),
    new THREE.MeshBasicMaterial({ color: 0xff0000 })
)
cube2.position.x = 0
group.add(cube2)

const cube3 = new THREE.Mesh(
    new THREE.BoxGeometry(1, 1, 1),
    new THREE.MeshBasicMaterial({ color: 0xff0000 })
)
cube3.position.x = 1.5
group.add(cube3)

/assets/lessons/05/step-08.png

现在我们知道如何变化3D对象了,下一小节我们将学习如何创建动画。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-05-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 大帅老猿 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 准备工作
  • 移动
  • 轴辅助工具
  • 缩放
  • 旋转
    • 使用rotation
      • 使用quaternion
        • 使用lookAt
        • 组合应用变换
        • 成组
        相关产品与服务
        图像处理
        图像处理基于腾讯云深度学习等人工智能技术,提供综合性的图像优化处理服务,包括图像质量评估、图像清晰度增强、图像智能裁剪等。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档