分享web开发知识

注册/登录|最近发布|今日推荐

主页 IT知识网页技术软件开发前端开发代码编程运营维护技术分享教程案例
当前位置:首页 > 运营维护

three.js 中的矩阵变换及两种旋转表达方式

发布时间:2023-09-06 02:14责任编辑:郭大石关键词:js

本篇简单介绍three.js中矩阵变换及两种旋转表达方式。

矩阵变换

three.js使用矩阵来保存Object3D的变换信息。

矩阵变换的基础

  • 平移变换
  • 比例变换
  • 旋转变换

(x,y,z,1)x轴旋转

(x,y,z,1)y轴旋转

(x,y,z,1)z轴旋转

three.js中的矩阵

 ???var cube = new THREE.Mesh(new THREE.CubeGeometry(1,1,1),new THREE.MeshBasicMaterial()); ???????cube.position.set(1,2,3); ???????cube.scale.set(7,8,9); ???????scene.add(cube);

我们可以看到正如上面的公式 cube的平移(1,2,3)所以elements[12]、elements[13]、elements[14]依次为1,2,3

cube的缩放为(7,8,9)所以elements[02]、elements[5]、elements[10]依次为7,8,9

然后我们选择一下cubex

 ???var cube = new THREE.Mesh(new THREE.CubeGeometry(1,1,1),new THREE.MeshBasicMaterial()); ???????cube.rotation.x = Math.PI/3; ???????scene.add(cube);

三维旋转表达方式

three.js提供了两种三维旋转表达方式:欧拉角(euler)四元数(quaternion)。它们相比较使用矩阵的方式进行变换更加的节省存储空间和更方便的进行插值。
但是欧拉角(euler)存在万向锁问题,配置可能失去一定的自由度所以都是使用在四元数(quaternion)

欧拉角

欧拉角需要指定x,y,z三个轴的角度和旋转的顺序。

 ???Euler( x, y, z, order ) ???

万向锁问题:当三个万向节其中两个的轴发生重合时,会失去一个自由度的情形。

https://zh.wikipedia.org

正常状态:三个独立的旋转轴

万向锁:一旦选择±90°作为pitch角,就会导致第一次旋转和第三次旋转等价,整个旋转表示系统被限制在只能绕竖直轴旋转,丢失了一个表示维度。

四元数

四元数的出现就可以解决欧拉角的万向锁问题和万向锁带来的插值不是线性的问题。

具体的四元数在旋转的使用的原理可以参照:

维基百科—四元数与空间旋转

 ???Quaternion( x, y, z, w ) ???

three.js中的旋转方式

从源码中我们可以看出,three.js都是使用quaternion(四元数)来控制旋转。

 ???setRotationFromAxisAngle: function ( axis, angle ) { ???????// assumes axis is normalized ???????this.quaternion.setFromAxisAngle( axis, angle ); ???}, ???setRotationFromEuler: function ( euler ) { ???????this.quaternion.setFromEuler( euler, true ); ???}, ???setRotationFromMatrix: function ( m ) { ???????// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) ???????this.quaternion.setFromRotationMatrix( m ); ???}, ???setRotationFromQuaternion: function ( q ) { ???????// assumes q is normalized ???????this.quaternion.copy( q ); ???}, ???rotateOnAxis: function () { ???????// rotate object on axis in object space ???????// axis is assumed to be normalized ???????var q1 = new THREE.Quaternion(); ???????return function rotateOnAxis( axis, angle ) { ???????????q1.setFromAxisAngle( axis, angle ); ???????????this.quaternion.multiply( q1 ); ???????????return this; ???????}; ???}(),

object3D rotation 属性

three.js你可以使用rotation来设置object3D的旋转。

我们使用rotation设置的为一个Euler(欧拉角)所以它会先将Euler(欧拉角)转换为一个quaternion(四元数)

源码:

 ???rotation.onChange( onRotationChange ); ???function onRotationChange() { ???????quaternion.setFromEuler( rotation, false ); ???} ???????//setFromEuler() ???????????setFromEuler: function ( euler, update ) { ???????????????if ( euler instanceof THREE.Euler === false ) { ???????????????????throw new Error( ‘THREE.Quaternion: .setFromEuler() now expects a Euler rotation rather than a Vector3 and order.‘ ); ???????????????} ???????????????// http://www.mathworks.com/matlabcentral/fileexchange/ ???????????// ?20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/ ???????????// ?content/SpinCalc.m ???????????????var c1 = Math.cos( euler._x / 2 ); ???????????var c2 = Math.cos( euler._y / 2 ); ???????????var c3 = Math.cos( euler._z / 2 ); ???????????var s1 = Math.sin( euler._x / 2 ); ???????????var s2 = Math.sin( euler._y / 2 ); ???????????var s3 = Math.sin( euler._z / 2 ); ???????????????var order = euler.order; ???????????????if ( order === ‘XYZ‘ ) { ???????????????????this._x = s1 * c2 * c3 + c1 * s2 * s3; ???????????????this._y = c1 * s2 * c3 - s1 * c2 * s3; ???????????????this._z = c1 * c2 * s3 + s1 * s2 * c3; ???????????????this._w = c1 * c2 * c3 - s1 * s2 * s3; ???????????????} else if ( order === ‘YXZ‘ ) { ???????????????????this._x = s1 * c2 * c3 + c1 * s2 * s3; ???????????????this._y = c1 * s2 * c3 - s1 * c2 * s3; ???????????????this._z = c1 * c2 * s3 - s1 * s2 * c3; ???????????????this._w = c1 * c2 * c3 + s1 * s2 * s3; ???????????????} else if ( order === ‘ZXY‘ ) { ???????????????????this._x = s1 * c2 * c3 - c1 * s2 * s3; ???????????????this._y = c1 * s2 * c3 + s1 * c2 * s3; ???????????????this._z = c1 * c2 * s3 + s1 * s2 * c3; ???????????????this._w = c1 * c2 * c3 - s1 * s2 * s3; ???????????????} else if ( order === ‘ZYX‘ ) { ???????????????????this._x = s1 * c2 * c3 - c1 * s2 * s3; ???????????????this._y = c1 * s2 * c3 + s1 * c2 * s3; ???????????????this._z = c1 * c2 * s3 - s1 * s2 * c3; ???????????????this._w = c1 * c2 * c3 + s1 * s2 * s3; ???????????????} else if ( order === ‘YZX‘ ) { ???????????????????this._x = s1 * c2 * c3 + c1 * s2 * s3; ???????????????this._y = c1 * s2 * c3 + s1 * c2 * s3; ???????????????this._z = c1 * c2 * s3 - s1 * s2 * c3; ???????????????this._w = c1 * c2 * c3 - s1 * s2 * s3; ???????????????} else if ( order === ‘XZY‘ ) { ???????????????????this._x = s1 * c2 * c3 - c1 * s2 * s3; ???????????????this._y = c1 * s2 * c3 - s1 * c2 * s3; ???????????????this._z = c1 * c2 * s3 + s1 * s2 * c3; ???????????????this._w = c1 * c2 * c3 + s1 * s2 * s3; ???????????????} ???????????????if ( update !== false ) this.onChangeCallback(); ???????????????return this; ???????????????},

Geometry rotateX方法

通过源码我们可以发现该方法使用的是矩阵变换的方式来旋转物体。

 ???rotateX: function () { ???????// rotate geometry around world x-axis ???????var m1; ???????return function rotateX( angle ) { ???????????if ( m1 === undefined ) m1 = new THREE.Matrix4(); ???????????m1.makeRotationX( angle ); ???????????this.applyMatrix( m1 ); ???????????return this; ???????}; ???}(), ???makeRotationX: function ( theta ) { ???????var c = Math.cos( theta ), s = Math.sin( theta ); ???????this.set( ???????????1, 0, ?0, 0, ???????????0, c, - s, 0, ???????????0, s, ?c, 0, ???????????0, 0, ?0, 1 ???????); ???????return this; ???},

three.js 中的矩阵变换及两种旋转表达方式

原文地址:https://www.cnblogs.com/chenjy1225/p/9640580.html

知识推荐

我的编程学习网——分享web前端后端开发技术知识。 垃圾信息处理邮箱 tousu563@163.com 网站地图
icp备案号 闽ICP备2023006418号-8 不良信息举报平台 互联网安全管理备案 Copyright 2023 www.wodecom.cn All Rights Reserved