Three.js源码解读一:Object3D
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Three.js源码解读一:Object3D相关的知识,希望对你有一定的参考价值。
参考技术A 可能很多同学会发现,学习Three.js的API非常容易,但是真正理解API的作用却非常难。其实让大家感到难的并不是Three.js本身,而是Three.js背后所隐藏的3D图形学知识。本系列Three.js源码解读文章,会帮你一边补齐3D图形学的基础知识,一边真正理解到Three.js的实现原理,知其然,知其所以然。Object3D是ThreeJS中大部分物体的基类,它包含了物体的位移,旋转,缩放,以及各个物体父子关系的js实现。选取Object3D几个重要的属性做解释:
一个3D对象往往由多个父子对象组成,父对象的位移, 旋转, 缩放会传递给所有的子对象。
this.parent指向父对象,this.children包含了所有的子对象。
通过 add 为物体添加子对象。需要注意的是,如果该子对象有其他的父对象,会先解除子对象和旧的父对象的父子关系,然后将子对象添加到新的父对象中。
this.matrix表示物体自身的本地形变,this.matrixWorld表示物体的全局形变。当物体没有父对象时,全局形变就是本地形变。
为什么对象组合这么重要呢?看下面的例子:
这两个立方体共同组成了一个3D对象,下面的立方体为底座,上面的立方体为操作臂。当底座转动的时候,操作臂会同样转动,所以操作臂的形变会传递给底座。当操作臂旋转时,底座不会被影响。
这里,底座就是操作臂的父对象。只要简单的将底座的全局形变(this.parent.matrixWorld)和操作臂的本地形变(this.matrix)相乘,就能得到操作臂的最终形变。是不是很方便?
3D物体的位移,旋转,缩放都可以通过矩阵表示。其中,旋转除了通过矩阵,还可以通过欧拉角和四元数表示。
Object3D的rotation代表物体旋转的欧拉角表示,quaternion代表了四元数表示,他们是3D物体统一旋转的不同数学表达方式。(矩阵,欧拉角,四元数表示旋转
onRotationChange , onQuaternionChange 这两个回调用于同步欧拉角和四元数,保证他们代表着相同的旋转角度。
3D交互一个很大一部分工作量是需要在物体的本地空间( this.matrix )和世界空间( this.matrixWorld )进行坐标转换。
Three.js DeviceOrientationControl源码解析
/** * @author richt / http://richt.me * @author WestLangley / http://github.com/WestLangley * * W3C Device Orientation control (http://w3c.github.io/deviceorientation/spec-source-orientation.html) */ THREE.DeviceOrientationControls = function( object ) { var scope = this; this.object = object; this.object.rotation.reorder( "YXZ" ); this.enabled = true; this.deviceOrientation = {}; this.screenOrientation = 0; this.alpha = 0; this.alphaOffsetAngle = 0; var onDeviceOrientationChangeEvent = function( event ) { scope.deviceOrientation = event; }; var onScreenOrientationChangeEvent = function() { scope.screenOrientation = window.orientation || 0; }; // The angles alpha, beta and gamma form a set of intrinsic Tait-Bryan angles of type Z-X\'-Y\'\' var setObjectQuaternion = function() { var zee = new THREE.Vector3( 0, 0, 1 ); var euler = new THREE.Euler(); var q0 = new THREE.Quaternion(); // Math.cos(Math.PI / 4) = Math.sqrt(0.5) // 四元数中x=nx * Math.sin(Math.PI / 4) // 因为手机平放时候alpha/beta/gamma都是0;而在3d中相当于相机绕x轴旋转90度,所以这里需要做一个旋转 var q1 = new THREE.Quaternion( - Math.sqrt( 0.5 ), 0, 0, Math.sqrt( 0.5 ) ); // - PI/2 around the x-axis return function( quaternion, alpha, beta, gamma, orient ) { // 同理因为上文中提到绕x轴旋转90度后角度对应轴关系变为: // alpha->y; // -gamma->z; // beta->x ///Euler对象的构造函数.用来创建一个欧拉角的对象.Euler对象的功能函数采用 ///定义构造的函数原型对象来实现. /// /// 用法: var euler = new Euler(5,3,2,\'XYZ\') /// 创建一个绕某轴旋转5度,绕y轴旋转某度,绕某轴旋转2度,旋转顺序为\'XYZ\'.有了旋转顺序才能确定每个x,y,z轴分别旋转多少度. /// NOTE: 参数x,y,z代表3个轴的旋转角度,具体哪个轴旋转多少度,需要后面的参数(order)旋转顺序来确定. /// NOTE: 参数(x,y,z,order)为可选参数,如果不指定参数(x,y,z,order),将创建一个坐标为(0,0,0,\'XYZ\')的Eular(欧拉角)对象. /// NOTE: 参数order(旋转顺序) 默认顺序是\'XYZ\' 取值范围是[\'XYZ\', \'YZX\', \'ZXY\', \'XZY\', \'YXZ\', \'ZYX\' ] /// /// 通俗的讲,欧拉角就是用来描述一个物体在三维空间中方向的一种常用的方法.举例来说,一个物体在三维空间中,绕x轴转了多少度, /// y轴转了多少度,z轴转了多少度,来描述物体在三维空间中的方向. /// 有点类似香港电影里飞虎队队员之间说,"飞鹰,飞鹰,在你的正前方,5点钟方向,发现目标,准备聚集目标." euler.set( beta, alpha, - gamma, \'YXZ\' ); // \'ZXY\' for the device, but \'YXZ\' for us quaternion.setFromEuler( euler ); // orient the device quaternion.multiply( q1 ); // camera looks out the back of the device, not the top quaternion.multiply( q0.setFromAxisAngle( zee, - orient ) ); // adjust for screen orientation } }(); this.connect = function() { onScreenOrientationChangeEvent(); // run once on load window.addEventListener( \'orientationchange\', onScreenOrientationChangeEvent, false ); window.addEventListener( \'deviceorientation\', onDeviceOrientationChangeEvent, false ); scope.enabled = true; }; this.disconnect = function() { window.removeEventListener( \'orientationchange\', onScreenOrientationChangeEvent, false ); window.removeEventListener( \'deviceorientation\', onDeviceOrientationChangeEvent, false ); scope.enabled = false; }; this.update = function() { if ( scope.enabled === false ) return; var alpha = scope.deviceOrientation.alpha ? THREE.Math.degToRad( scope.deviceOrientation.alpha ) + this.alphaOffsetAngle : 0; // Z var beta = scope.deviceOrientation.beta ? THREE.Math.degToRad( scope.deviceOrientation.beta ) : 0; // X\' var gamma = scope.deviceOrientation.gamma ? THREE.Math.degToRad( scope.deviceOrientation.gamma ) : 0; // Y\'\' var orient = scope.screenOrientation ? THREE.Math.degToRad( scope.screenOrientation ) : 0; // O setObjectQuaternion( scope.object.quaternion, alpha, beta, gamma, orient ); this.alpha = alpha; }; this.updateAlphaOffsetAngle = function( angle ) { this.alphaOffsetAngle = angle; this.update(); }; this.dispose = function() { this.disconnect(); }; this.connect(); };
以上是关于Three.js源码解读一:Object3D的主要内容,如果未能解决你的问题,请参考以下文章
three.js 在它的中心围绕 Y 轴旋转 Object3d
three.js - 网格组示例? (THREE.Object3D() 高级)
有啥方法可以从 three.js Object3D 中获取边界框?