美文网首页Three.js学习笔记
Three.js笔记(五)变换坐标

Three.js笔记(五)变换坐标

作者: BIM科学家小张 | 来源:发表于2022-03-10 16:24 被阅读0次

    简述

    现在探索Three.js功能。

    在为场景制作动画之前,我们需要知道如何变换场景中的对象。

    我们已经使用相机完成了此操作,方法是使用

    camera.position.z = 3

    有 4 个属性可用于变换对象

        position(移动对象)

        scale(调整对象大小)

        rotation(旋转对象)

        quaternion(也可以旋转对象;稍后会详细介绍)

    从Object类继承的透视相机类、网格体类以及我们尚未介绍的类都具有这样的属性。

    您可以在 Three.js 文档看到哪些类继承了这个类。

    这些属性将被编译为我们所谓的矩阵。矩阵 在Three.js、WebGL 和 GPU 内部使用,用于变换对象坐标。幸运的是,不必自己处理矩阵,只需修改前面提到的属性即可。

    设置

    在一开始,画布中只有之前几节创建的立方体,立方体处在视角中心。

    移动对象

    position位置具有 3 个基本属性x、y、z。

    每个轴的方向都是自己定义的。在 Three.js 中,我们通常认为y轴向上,z轴向后,x轴向右。

    至于数量1的单位也可以是任意的,这根据自己的需要来决定。

    尝试调整mesh网格体的position位置属性,推测下立方体会去哪里。

    请确保在执行渲染操作render()前完成移动操作,否则网格体会在移动前被渲染。

    mesh.position.x = 0.7

    mesh.position.y = - 0.6

    mesh.position.z = 1

    position位置不是对象。它是Vector3类的一个实例,不光有x、y、z属性,还有许多拥有的方法。

    可以得到向量的模

    console.log(mesh.position.length())

    两个Vector3类之间的距离,但以下代码先要确保创建相机后运行

    console.log(mesh.position.distanceTo(camera.position))

    您可以规范化其值(这意味着您将向量的长度减少到单位1,但保留其方向):

    console.log(mesh.position.normalize())

    若要更改值,而不是单独更改 x、y、z,还可以使用以下方法:

    mesh.position.set(0.7, - 0.6, 1)

    辅助轴

    在空间中盲目定位很困难,尤其是在移动相机之后就更加困难。此时就需要调用Three.js的AxesHelper辅助轴。

    AxesHelper辅助轴会从场景中心向x、y、z方向放射出与轴同向的线。

    要创建AxesHelper辅助轴,首先需要实例化并在实例化场景后,将其添加到场景,可以通过一个参数修改线的长度。

    /**

        * AxesHelper辅助轴

        */

    const axesHelper = new THREE.AxesHelper(2)

    scene.add(axesHelper)

    此时应该看到

    您应该看到一条绿线和一条线。

    绿线对应于y轴。线对应于x轴,有一条线对应于z轴,但看不到它,因为它与相机完全同向。

    如果需要视觉参考,请随时添加它。

    缩放对象

    scale缩放也是Vector3。默认情况下,x、y、z都是1。这就意味着对象没有被缩放。如果设置成0.5,对象将在该轴方向上的尺寸缩小一半;如果设置成2,对象将在该轴方向上的尺寸放大一倍。

    如果更改了这些值,对象将会相应缩放。注释掉之前的position位置,然后添加缩放

    mesh.scale.x = 2

    mesh.scale.y = 0.25

    mesh.scale.z = 0.5

    很明显,无法直观的看到z轴的缩放,因为网格体是正对相机的。

    缩放可以使用负值,但是会出现BUG,尽量避免这样做。

    旋转对象

    旋转有两个不同的属性,rotation旋转和quaternion四元数两种,当修改一个,另一个也会有相应变化。

    旋转

    rotation旋转也有x、y、z,但是它不是Vector3,而是欧拉数。当更改欧拉数的x、y、z时,你可以想象是绕对应轴旋转对象的操作。

    旋转的值以弧度表示,如果想要实现旋转半圈,就需要写Π。在JavaScript的原生环境中,可以使用Math.PI,来表示这个数。

    注释掉之前的scale缩放,然后添加绕x、y轴八分之一圈的旋转。

    mesh.rotation.x = Math.PI * 0.25

    mesh.rotation.y = Math.PI * 0.25

    容易吧?但是当把这些旋转混合在一起,反而会出现不同的结果。其原因就在于当绕x旋转时,同时也影响了其他两个轴的方向。这就导致了旋转的结果和预期的不同。

    我们可以使用reorder()方法来更正旋转的顺序,object.rotation.reorder('yxz')

    虽然欧拉数易于理解,但是旋转的顺序会导致这些问题。这就是为什么大多数引擎和3D软件使用quaternion四元数方案

    四元数

    Quaternion四元数属性同样表达了旋转,但是使用了更数学化的方式,从而解决了顺序的问题。

    这里不会讲解四元数如何运作,但是要记得Quaternion四元数随rotation旋转的变化而更新。这意味着可以随意使用两者中的任何一个。

    大突破

    Object3D实例有一个很棒的方法,名字是lookAt(),这个方法可以控制对象直接面向某个东西。对象会自动将-z轴旋转到提供的目标,而无需复杂的数学。

    这可以被用在将相机看向物体的操作上,或是将大炮定向以面对敌人,或将角色的眼睛移动到物体上。

    该参数是目标,必须是 Vector3。可以尝试创建一个:

    camera.lookAt(new THREE.Vector3(0, - 1, 0))

    立方体似乎变高了,但实际上,相机正在观察立方体下方。

    我们也可以使用任何现有的 Vector3,例如前面的网格体的位置,但这将导致相机指向默认的位置,因为我们位于场景的中心。

    camera.lookAt(mesh.position)

    组合变换

    可以将position(移动对象)、scale(调整对象大小)、rotation(旋转对象 也可以用quaternion)以任意顺序组合。运行的结果将是相同的。因为它就是对象的状态。

    尝试把之前的所有变换组合在一起

    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

    场景分组

    在某些时候,可能希望对事物进行分组。假设正在建造一座有墙壁,门,窗户,屋顶,灌木丛等的房子。

    当认为已经完成了时,可能就会意识到房子太小了,那么必须重新缩放每个对象并更新它们的位置。

    一个好的替代方法是将所有这些对象分组到一个容器中,并缩放该容器。

    可以使用Group组类执行此操作。

    实例化Group组,并把它添加到场景。现在,当要创建一个新的对象的时候,只需使用add()方法把他添加到组中,而非直接添加到场景中。

    由于Group组类继承了Object3D类,所以它也具备前述的所有属性和方法。

    注释掉之前的lookAt()调用,创建三个立方体并添加到一个组中,来替代之前的立方体。然后向组应用变换。

    /**

    * 创建对象

    */

    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)

    顺序不重要,重要的是它是有效的JavaScript。

    相关文章

      网友评论

        本文标题:Three.js笔记(五)变换坐标

        本文链接:https://www.haomeiwen.com/subject/jyctdrtx.html