Three.js中矩阵和向量的使⽤教程
前⾔
提起矩阵,很容易让⼈想起我们曾经学不会的线性代数和离散数学,但是作为图形开发中的核⼼部分,它代表着每⼀次的运动和变换,就像鱼不能脱离⽔⼀样,矩阵并不是⼀个可以避之不谈的话题。
好消息是,Three.js帮助我们把许多矩阵运算封装成了⼀些顶层的⽅法,并提供了⼀个优秀的数学库,我们不太需要知道HowToCalc,只需要知道HowToU,就可以得到绝⼤部分我们想要的东西。
这篇⽂章将要介绍的就是,如何在不了解内部结构的情况下在Three.js中使⽤矩阵和向量。
从⼀个例⼦开始
在讲解⼀些枯燥的概念前先举⼀个⼩例⼦,来简要说明⼀下为什么我们要使⽤矩阵⽅法。
这是我们最终要完成的效果。
⾸先,我们要创建三个⼏何体:
var box_geometry = new THREE.BoxGeometry();
最短的季节打一成语是什么成语
var sphere_geometry = new THREE.SphereGeometry(0.5, 32, 32);
var cylinder_geometry = new THREE.CylinderGeometry(0.1, 0.1, 0.5);
var material = new THREE.MeshLambertMaterial({color: new THREE.Color(0.9, 0.55, 0.4)})
这三个⼏何体分别是盒⼦、球和圆柱体。
然后去创建三个⽹格,并将它们置⼊场景。
var box = new THREE.Mesh(box_geometry, material);
云南白药胶囊var sphere = new THREE.Mesh(sphere_geometry, material);
sphere.position.y += 1;
var cylinder = new THREE.Mesh(cylinder_geometry, material);
cylinder.position.y += 1.75;
scene.add(box);
scene.add(sphere);
scene.add(cylinder);
这段代码将⽣成如下场景:
虽然不那么美观,但作为⽰例已经⾜够了,现在我希望这堆物体尺⼨减半。通常我会把物体的scale属性减半,像这样:
box.scale.multiplyScalar(0.5);
sphere.scale.multiplyScalar(0.5);
cylinder.scale.multiplyScalar(0.5);
和想象中的有些偏差。我的本意是让这⼀组物体进⾏⼀个整体的缩放,并不想让它们彼此偏离,为了修正这件事,我需要根据其他对象的缩放重新计算每个对象的位置。但这并不是⼀件很难解决的问题,three.js提供了⼀种优雅的⽅式,来处理这个问题。我们可以定义⼀个空对象,然后将三个对象放在其中,然后将⽐例应⽤于⽗对象。
var pile = new THREE.Object3D();
pile.scale.multiplyScalar(0.5);
pile.add(box);
pile.add(sphere);
pile.add(cylinder);
小狗钱钱scene.add(pile);
接下来我们做⼀点更有趣的事。
我将在这个物体组合⾥添加旋转,让我们尝试围绕球体表⾯旋转的那个圆柱体,就像他将要滑落⼀样。
它变成了这样,很明显,这不是我想要的东西。我们在这⾥有两个做法可供选择:第⼀,通过数学计算算出圆柱相对于球体的正确位置;第⼆,创建另⼀个Object3D,将圆柱和球放进去并旋转。这听上去挺复杂的,⽽且也很不酷。
所以,我们可以尝试⾃⼰去计算矩阵。
⾸先,我需要将属性maxtrixAutoUpdate设置为fal,然后我就不能再通过position,scale和rotation去修改矩阵。
box.matrixAutoUpdate = fal;
sphere.matrixAutoUpdate = fal;
cylinder.matrixAutoUpdate = fal;
慢性腰腿痛
现在,我将⽤applyMatrix⽅法来解决这个问题。具体做法是:为每个对象创建⼀个Matrix4,然后我们将矩阵与该矩阵相乘以应⽤后续操作。
var sphere_matrix = new THREE.Matrix4().makeTranslation(0.0, 1.0, 0.0);
sphere.applyMatrix(sphere_matrix);
var cylinder_matrix = sphere_matrix.clone(); cylinder_matrix.multiply(new THREE.Matrix4().makeTranslation(0.0, 0.75, 0.0));
cylinder.applyMatrix(cylinder_matrix);
这⼏步下来,可以让我们解锁很多知识,来看看这⾥发⽣了什么。
⾸先,我们把盒⼦单独留下,因为它不需要动。
接着,我创建了⼀个平移矩阵并把它应⽤到了球对象上。
最后,在圆柱体上,我clone了球的矩阵信息,并在此基础上⼜创建了⼀个新的平移矩阵,圆柱体将移动1.75。
凤凰画图片大全理解了上⾯⼏步,你就会知道最后⼀步该做什么了。
只需要⼀⾏代码,作⽤在球上:
sphere_matrix.multiply(new THREE.Matrix4().makeRotationZ(-Math.PI * 0.25));
达成了想要的效果,很酷。
⽰例中⽤到的⽅法
在上⾯的⽰例中,我将球和圆柱体分别沿y轴移动了⼀定的距离,并使⽤了makeTranslation这个⽅法。这个⽅法的作⽤是创建了⼀个平移矩阵。紧接着,我⼜使⽤到了applyMatrix的⽅法。这个⽅法的
作⽤是把平移矩阵作⽤在球和圆柱体上。
那么什么是平移矩阵?它⼜是如何完成⼀次平移呢?
Three.js中最常见的⼀种4x4的矩阵,被称为变换矩阵,它所表⽰的变换类型包括平移、旋转和缩放。
⽤⼀个简单的数学题来说明变换矩阵:
有⼀个起始点,⽤向量来表⽰即为Vector3(20,20,0);现在,我要把它移动到另⼀个位置,Vector3(30,60,0)。
接下来,我设置⼀个平移矩阵,来表⽰向量依照什么⽅式去移动。
t = |1 0 0 10|
|0 1 0 40|
我一直以为你知道|0 0 1 0 |
|0 0 0 1 |
最后,⽤起始的向量去乘以变换矩阵的向量。
|20| |1 0 0 10| |30|
|20| x |0 1 0 40| = |60|
|0 | |0 0 1 0 | |0 |
|1 | |0 0 0 1 | |1 |
变换公式如下:
transformedVector = vector * transformationMatrix
最终的变换向量 = 原始向量 * 变换矩阵
⽤我们上⾯例⼦中的⽅法来还原这个公式,即:
var vector = new THREE.Vector3(20, 20, 0);
var matrix = new THREE.Matrix4();
matrix.makeTranslation(10, 40, 0);
vector.applyMatrix4(matrix);
除了平移,Three的API中还提供了rotation和scale,scale变化很简单,它将使⽤makeScale(x, y, z)这个⽅法来表⽰缩放。
⽽旋转则相对复杂许多,Three.js提供以下旋转⽅法:
matrix.makeRotationX(angle);
matrix.makeRotationY(angle);
matrix.makeRotationZ(angle);
matrix.makeRotationAxis(axis, angle);
matrix.makeRotationFromEuler(euler);
matrix.makeRotationFromQuaternion(quaternion);
前三个⽅法分别代表的是绕X、Y、Z三个轴旋转,⽆需赘述。
第四个⽅法是前三个⽅法的整合版,第⼀个参数表⽰的是代表xyz的THREE.Vector3,第⼆个参数是旋转的弧度。下⾯两⾏代码是等价的:
matrix.makeRotationX(Math.PI);
matrix.makeRotationAxis(new THREE.Vector3(1, 0, 0), Math.PI);
第五个⽅法表⽰围绕x、y和z轴的旋转,这是表⽰旋转最常⽤的⽅式;第六个⽅法是⼀种基于轴和⾓度表⽰旋转的替代⽅法。
最后,Three.js api提供了⼀种⽅法来创建表⽰平移,旋转和缩放的组合的矩阵 -- po:
var translation = new THREE.Vector3();
var rotation = new THREE.Quaternion();
var scale = new THREE.Vector3();
var matrix = new THREE.Matrix4();
矩阵相乘
矩阵乘法的意义在于叠加。
上图表⽰了三个变化:旋转、缩放和移动。
通过按次序相乘,三个变化矩阵可以得出⼀个最终的变化矩阵:
combinedMatrix = rotationMatrix * scaleMatrix * translationMatrix;
Three.js⾥提供了两种矩阵相乘的⽅法:
matrix.multiply(otherMatrix)
matrix.multiplyMatrices(matrixA, matrixB)
第⼀种⽅法表⽰将矩阵乘以另⼀个矩阵;⽽第⼆种⽅法代表的是将矩阵设置为matrixA * matrixB的结果。
我们在⽰例中也使⽤到了第⼀个⽅法:将圆柱体的矩阵乘以新的平移矩阵,和将球的矩阵乘以⼀个旋转矩阵。
需要注意的是,乘法交换律不适⽤于矩阵乘法,矩阵乘法是具有次序的,先旋转再移动和先移动再旋转的结果是完全不同的。
矩阵的逆
在数字的运算⾥,除法相当于是乘法的“撤销”操作:
4 x
5 = 20
20 / 5 = 4
但是在矩阵计算⾥,这个守则同样是不适⽤的。我们不能⽤向量去除⼀个矩阵,我们只能⽤向量去乘以⼀个矩阵的逆矩阵,来完成“撤销”的操作。
变化后的向量 = 原始向量 * 变化矩阵;
逆矩阵 = 变化矩阵.inver();
原始向量 = 变化后的向量 * 逆矩阵;
逆矩阵表⽰的是相反的变换。
Three.js⾥提供了⼀种计算逆矩阵的⽅法:
var matrix = new THREE.Matrix4();
var inverMatrix = new THREE.Matrix4();
除此之外,逆矩阵还应⽤在3D场景中处理相机对象的时候。
最后
矩阵在3D世界⾥是⼀种⼗分强⼤的⼯具,它能够将任意变换都表⽰为⼀种相似的结构,并采⽤相同的计算过程。⽽实际上,矩阵的世界远远⽐这⾥介绍的内容更多,希望通过这些简要的介绍,可以让我们进⼊到⼀个更深的领域,并游刃有余的利⽤他处理图形开发中更复杂的场景。
邮册好了,以上就是这篇⽂章的全部内容了,希望本⽂的内容对⼤家的学习或者⼯作具有⼀定的参考学习价值,谢谢⼤家对的⽀持。