zoukankan      html  css  js  c++  java
  • three.js 中的矩阵变换及两种旋转表达方式

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

    矩阵变换

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

    矩阵变换的基础

    • 平移变换

    outPut

    • 比例变换

    outPut

    • 旋转变换

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

    outPut

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

    outPut

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

    outPut

    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);
    
    
    

    outPut

    我们可以看到正如上面的公式 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);
    
    
    

    outPut

    三维旋转表达方式

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

    欧拉角

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

    
        Euler( x, y, z, order )
        
    

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

    https://zh.wikipedia.org

    outPut

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

    outPut

    万向锁:一旦选择±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;
    
    	},
    
    
  • 相关阅读:
    ios 人脸检测
    改善用户体验的几个alert提示效果(收集整理)
    asp.net中关于《%=》《%#》《%》 的用法——(转帖)
    flash学习网址
    网页数据表格自动填充序号
    <%#..%>与<%=..%>的区别
    用Margin还是用Padding
    由浅入深漫谈margin属性
    css中导入样式表和链接样式表有什么区别,我不是问语法,而是问内在区别,还有我怎么才能体会到他们的区别
    ASP.NET Eval如何进行数据绑定
  • 原文地址:https://www.cnblogs.com/chenjy1225/p/9640580.html
Copyright © 2011-2022 走看看