乐趣区

Threejs三维模型几何体旋转缩放和平移

Three.js 三维模型几何体旋转、缩放和平移

创建场景中的三维模型往往需要设置显示大小、位置、角度,three.js 提供了一系列网格模型对象的几何变换方法,从 WebGL 的角度看,旋转、缩放、平移对应的都是模型变换矩阵,关于矩阵变换内容可以观看本人博客发布的原生 WebGL 课程。

网格模型对象的旋转、缩放、平移等方法或属性可以查找 three.js 文档的 Object3D 对象,该对象是网格模型对象、点模型对象、线条模型对象的基类。

个人 WebGL/Three.js 技术博客

缩放

立方体网格模型 x 轴方向放大 2 倍,如果连续执行两次该语句,相等于比原来方法 4 倍

mesh.scale.x = 2.0;// x 轴方向放大 2 倍

立方体网格模型整体缩小 0.5 倍,相当于 xyz 三个方向分别缩小 0.5 倍

mesh.scale.set(0.5,0.5,0.5);// 缩小为原来 0.5 倍

网格模型 Mesh 的属性 scale 返回值是一个 Vector3 对象,查看 three.js 官方文档你可以知道 Vector3 对象具有属性 x、y、z 对于上面的代码而言 xyz 表示坐标值,xyz 数据类型是 float,Vector3 对象还具有方法 set(),set 方法有三个表示 xyz 坐标的参数。

平移

立方体网格模型沿着 x 轴正方向平移 100,可以多次执行该语句,每次执行都是相对上一次的位置进行平移变换

mesh.translateX(100);// 沿着 x 轴正方向平移距离 100

网格模型沿着向量 (0,1,0) 表示的方向平移 100

var axis = new THREE.Vector3(0,1,0);// 向量 axis
mesh.translateOnAxis(axis,100);// 沿着 axis 轴表示方向平移 100

translateOnAxis(axis, distance)方法相比.translateX、.translateY、.translateZ 更通用,可以实现立方体沿着任何方向旋平移,参数 axis 表示平移方向,使用对象 Vector3 表示

旋转

立方体网格模型绕立方体的 x 轴旋转 π /4,可以多次执行该语句,每次执行都是相对上一次的角度进行旋转变化

mesh.rotateX(Math.PI/4);// 绕 x 轴旋转 π /4

网格模型绕 (0,1,0) 向量表示的轴旋转 π /8

var axis = new THREE.Vector3(0,1,0);// 向量 axis
mesh.rotateOnAxis(axis,Math.PI/8);// 绕 axis 轴旋转 π /8

rotateOnAxis(axis, angle)方法相比.rotateX、.rotateY、.rotateZ 更通用,可以实现立方体绕任何轴旋转,参数 axis 表示旋转轴,使用对象 Vector3 表示

位置属性 position

立方体网格模型位置坐标(80,2,10)

mesh.position.y = 80;// 设置网格模型几何中心 y 坐标

立方体网格模型几何中心 y 轴坐标值 80

mesh.position.set(80,2,10);// 设置网格模型几何中心三维坐标

position 属性和平移方法 translateX()一样都是设置距离,方法 translateX()设置的相对上次位置进行平移,两次执行该方法,距离会叠加,position 属性设置的距离是相对坐标系原点位置,两次执行 position 属性立方体的会只会更新重新定位,两次的距离参数不是叠加关系,而是替换关系。

角度属性 rotation

立方体网格模型位置坐标(80,2,10)

mesh.position.y = 80;// 设置网格模型几何中心 y 坐标

立方体网格模型几何中心 y 轴坐标值 80

mesh.position.set(80,2,10);// 设置网格模型几何中心三维坐标

rotation 属性和旋转方法 rotateX()差异类似 position 属性和平移方法 translateX()的差异,一个是相对坐标系设置角度、位置,一个是相对当前的三维模型的状态设置角度、位置参数。旋转与平移参考的都是坐标系,不过参考的坐标系稍有不同,平移参考的是世界坐标系或者说三维场景对象 Scene 的坐标系,和相机对象一样,在整个三维场景中的位置,三维模型的旋转参考的是模型坐标系,也就是对三维模型本身建立的坐标系。

基类Object3D

点模型 Points、线模型Line、精灵模型sprite、组对象Group 等 threejs 模型对象的基类都是Object3D,这些模型对象的角度、位置、缩放属性和旋转、平移、缩放方法都可以查看 threejs 文档基类Object3D

几何体变换

几何体 Geometry 和网格模型 Mesh 一样也就有旋转缩放平移等方法,通过网格模型或几何体的方法都可以对模型进行变换,但是本质是不一样的,网格模型 Mesh 执行旋转平移缩放变化,并不会改变自身绑定几何体的顶点坐标,会改变模型对应的模型矩阵ModelMatrix,几何体执行旋转缩放平移变换会改变几何体本身包含的顶点位置、法向量等数据。

如果对上面阐述不太理解,建议最好看看本人博客发布的 threejs 课程中第二章关于几何体顶点的介绍,threejs 进阶课程中关于模型矩阵等概念的介绍。

下面的程序是通过一个几何体创建了多个网格模型,网格模型可以共享几何体对象和材质对象都,几何体对象本质上是一组顶点相关数据,每创建一个网格模型,相当于多次利用显存中的同一组定点相关数据渲染出多个三维模型的效果,几何体顶点虽然是同一组数据,但是可以在 GPU 着色器中对这组数据进行矩阵变换,来呈现出不同的效果。

/**
 * 创建网格模型 1、网格模型 2
 */
var box=new THREE.BoxGeometry(50,50,50);// 创建一个立方体几何对象
var material=new THREE.MeshLambertMaterial({color:0x0000ff});// 材质对象
var mesh1=new THREE.Mesh(box,material);// 网格模型对象 1
var mesh2=new THREE.Mesh(box,material);// 网格模型对象 2
mesh1.translateX(-50);// 沿着 x 轴负方向平移距离 50
mesh2.translateX(50);// 沿着 x 轴正方向平移距离 50
scene.add(mesh1);// 网格模型 1 添加到场景中
scene.add(mesh2);// 网格模型 2 添加到场景中

代码中的网格模型 mesh1、网格模型 mesh2 都是通过同一个几何体对象 Geometry 创建,默认情况下,几何体对象的顶点位置决定了网格模型在场景中的显示位置,两个网格模型执行方法 translateX()进行平移变换错开显示。网格模型的平移变换方法 translateX()会通过 three.js 引擎转化为 WebGL 中 CPU 顶点着色器的矩阵变换程序。

更改上面的程序,插入下面一段代码,放大其中一个网格模型,可以看到另外外一个网格模型的显示大小并不受影响。

mesh2.scale.y = 2.0;// y 轴方向放大 2 倍

网格模型对象可以进行缩放平移旋转变换,几何体对象也拥有相关的几何变换方法和属性,几何体进行几何变换,本质上更改的是显存中的顶点相关数据,网格模型进行几何变换,不会更改显存中的顶点数据,顶点数据的变换是在 GPU 渲染管线的顶点着色器处理单元中借助程序逐顶点执行矩阵乘法运算。

几何体对象执行方法 scale(),尺寸缩小为原来的 0.5 倍,刷新浏览器你会看到两个网格模型代表的立方体都缩小了,对比上面的程序可以看出更改几何体的参数,与之相关的网格模型都会变化。这很好理解,网格模型的几何变换更改的是要与顶点数据进行乘法运算的模型矩阵,几何体对象进行变换更累刷新的是显存上的顶点相关数据,每次渲染出一个网格模型,都会从网格模型构造函数指定的顶点对象获取顶点数据。

var box=new THREE.BoxGeometry(50,50,50);// 创建一个立方体几何对象
box.scale(0.5,0.5,0.5);// 几何体缩小为原来 0.5 倍

几何体对象可以进行上面程序中的缩放变换,自然也有平移、缩放变换的相关方法,具体使用方法可以参考 three.js 文档的 Geometry 对象, 立方体、球体等几何体的构造函数返回的结果都是 Geometry 对象,这些构造函数返回的对象都会继承 Geometry 对象的属性和方法。

退出移动版