这是Three.js源码阅读笔记的第二篇,直接开始。 
Core::Object3D 
Object3D似乎是Three.js框架中最重要的类,相当一部分其他的类都是继承自Object3D类,比如场景类、几何形体类、相机类、光照类等等:他们都是3D空间中的对象,所以称为Object3D类。Object3D构造函数如下: 
复制代码 代码如下:
 
THREE.Object3D = function () { 
THREE.Object3DLibrary.push( this ); 
this.id = THREE.Object3DIdCount ++; 
this.name = ''; 
this.properties = {}; 
this.parent = undefined; 
this.children = []; 
this.up = new THREE.Vector3( 0, 1, 0 ); 
this.position = new THREE.Vector3(); 
this.rotation = new THREE.Vector3(); 
this.eulerOrder = THREE.Object3D.defaultEulerOrder; 
this.scale = new THREE.Vector3( 1, 1, 1 ); 
this.renderDepth = null; 
this.rotationAutoUpdate = true; 
this.matrix = new THREE.Matrix4(); 
this.matrixWorld = new THREE.Matrix4(); 
this.matrixRotationWorld = new THREE.Matrix4(); 
this.matrixAutoUpdate = true; 
this.matrixWorldNeedsUpdate = true; 
this.quaternion = new THREE.Quaternion(); 
this.useQuaternion = false; 
this.boundRadius = 0.0; 
this.boundRadiusScale = 1.0; 
this.visible = true; 
this.castShadow = false; 
this.receiveShadow = false; 
this.frustumCulled = true; 
this._vector = new THREE.Vector3(); 
}; 
在介绍函数之前,需要先介绍一下这个类的几个重要属性。
属性parent和children说明,通常需要使用树来管理众多Object3D对象。比如一辆行驶的汽车是一个Object3D对象,控制汽车行驶路线的逻辑在该对象内部实现,汽车的每个顶点经过模型矩阵的处理后,都位于正确的位置;但是汽车摆动的雨刮器,其不但随着汽车行驶方向运动,而且自身相对汽车也在左右摆动,这个摆动的逻辑无法在汽车这个对象内部的实现。解决的方法是,将雨刮器设定为汽车的chidren,雨刮器内部的逻辑只负责其相对于汽车的摆动。在这种树状结构下,一个场景Scene实际上就是最顶端的Object3D,它的模型矩阵就是视图矩阵(取决于相机)的逆矩阵。
属性matrix和matrixWorld就很好理解了,matrix表示本地的模型矩阵,仅仅表示该对象的运动,而matrixWorld则需要依次向父亲节点迭代,每一次迭代都左乘父亲对象的本地模型矩阵,直到Scene对象——当然,实际上是左乘父亲对象的全局模型矩阵。
属性position、rotation、scale表示模型矩阵的三种变换部分,在Matrix4类中有相关说明。rotation和eulerOrder共同描述了一个旋转状态,quaternion也可以描述一个旋转状态,具体使用哪种方法要看useQuation的布尔值。
可以看到,关于该Object3D对象最重要的“变换状态”信息实际上是存储在两个“备份”中的,一个是matrix对象,还有一个是position等属性,两部分应当保持一致,如果通过某种方法改变了一个备份,则另一个备份也应该在适当的时候更新。还有一些其他属性从字面和类型上就能看出其含义,不再单独列出了。下面说函数:
函数applyMatrix(matrix)将参数matrix左乘到this.matrix上,实际上就是对该Object3D对象实行某个变换(该变换可能要经过好几步基本变换,但是已经存储在参数matrix里面了)。注意,在对this.matrix执行完左乘之后,;立刻更新了position等参数的值。比起下面几个变换函数,该函数更“高级”,允许开发者自由指定变换矩阵,而不是说“朝着x轴前进5单位距离”。
复制代码 代码如下:
 
applyMatrix: function ( matrix ) { 
this.matrix.multiply( matrix, this.matrix ); 
this.scale.getScaleFromMatrix( this.matrix ); 
var mat = new THREE.Matrix4().extractRotation( this.matrix ); 
this.rotation.setEulerFromRotationMatrix( mat, this.eulerOrder ); 
this.position.getPositionFromMatrix( this.matrix ); 
}, 
函数translate(distance, axis)令该对象向axis轴指定的方向前进distance距离。函数translateX(distance),translateY(distance),translateZ(distance)令其向X,Y,Z轴前进distance距离。注意这些函数仅仅改变了position对象的值,而不曾改变matrix的值。
复制代码 代码如下:
 
translate: function ( distance, axis ) { 
this.matrix.rotateAxis( axis ); 
this.position.addSelf( axis.multiplyScalar( distance ) ); 
}, 
translateX: function ( distance ) { 
this.translate( distance, this._vector.set( 1, 0, 0 ) ); 
}, 
函数localToWorld(vector)将本地坐标转化为世界坐标中,函数worldToLocal则正好相反。注意这里的vector本地坐标指的是未变换之前的坐标,也就是说雨刮器的默认位置的顶点坐标。
函数lookAt(eye,center,up)执行其matrix属性对象的lookAt函数(之前介绍过,matrix4对象也有一个lookAt函数),一般用于相机对象。该函数仅仅改变了旋转状态,所以当matrix属性对象执行完之后,如果属性rotationAutoUpdate为真,则会更新rotation或quaternion的值,更新哪一个取决于属性useQuation。
函数add(object)和函数remove(object)从当前Object3D对象中添加一个子对象,或删除一个子对象,了解到场景中的众多Object3D对象是用树来管理的,这就很容易理解了。
函数traverse(callback)遍历调用者和调用者的所有后代,callback参数是一个函数,被调用者和每一个后代对象调用callback(this)。
复制代码 代码如下:
