這是Three.js源碼閱讀筆記第三篇。之前兩篇主要是關于核心對象的,這些核心對象主要圍繞著矢量vector3對象和矩陣matrix4對象展開的,關注的是空間中的單個頂點的位置和變化。這一篇將主要討論Three.js中的物體是如何組織的:即如何將頂點、表面、材質組合成為一個具體的對象。
Object::Mesh
該構造函數構造了一個空間中的物體。之所以叫“網格”是因為,實際上具有體積的物體基本都是建模成為“網格”的。
代碼如下:
THREE.Mesh = function ( geometry, material ) {
THREE.Object3D.call( this );
this.geometry = geometry;
this.material = ( material !== undefined ) ? material : new THREE.MeshBasicMaterial( { color: Math.random() * 0xffffff, wireframe: true } );
/* 一些其他的與本節無關的內容 */
}
實際上,Mesh類只有兩個屬性,表示幾何形體的geometry對象和表示材質的material對象。geometry對象在上一篇博文中已經介紹過,還有部分派生類會在這篇博文中介紹(通過這些派生類的構造過程,能更加清晰地了解到Mesh對象的工作原理);matrial對象及其派生類也將在這篇筆記中介紹。Mesh對象的這兩個屬性相互緊密關聯,geometry對象中的face數組中,每個face對象的materialIndex用來匹配material屬性對象,face對象的vertexUVs數組用以依次匹配每個頂點在數組上的取值。值得注意的是,Mesh只能有一個material對象(不知這樣設計的意圖何在),如果需要用到多個材質,應當將材質按照materialIndex順序初始化在geometry本身的materials屬性中。
Geometry::CubeGeometry
該構造函數創建了一個立方體對象。
代碼如下:
THREE.CubeGeometry = function ( width, height, depth, widthSegments, heightSegments, depthSegments ) {
THREE.Geometry.call( this );
var scope = this;
this.width = width;
this.height = height;
this.depth = depth;
var width_half = this.width / 2;
var height_half = this.height / 2;
var depth_half = this.depth / 2;
/* 略去 */
buildPlane( 'z', 'y', - 1, - 1, this.depth, this.height, width_half, 0 ); // px
/* 略去 */
function buildPlane( u, v, udir, vdir, width, height, depth, materialIndex ) {
/* 略去 */
}
this.computeCentroids();
this.mergeVertices();
};
構造函數做的最重要的事在buildPlane中。該函數最重要的事情就是對scope的操作(上面的代碼塊中,scope就是this),包括:調用scope.vertices.push(vector)將頂點加入geometry對象;調用scope.faces.push(face)將表面加入到geometry對象,調用scope.faceVertexUvs[i].push(uv)方法將對應于頂點的材質坐標加入geometry對象。代碼的大部分都是關于生成立方體的邏輯,這些邏輯很容易理解,也很容易擴展到其他類型的geometry對象。
構造函數的參數包括長、寬、高和三個方向的分段數。所謂分段,就是說如果將widthSeqments等三個參數都設定為2的話,那么每個面將被表現成2×2=4個面,整個立方體由24個表面組成,正如同網格一樣。