1、關於模型的基礎知識
3D模型由頂點(vertex)組成,頂點之間連成三角形或四邊形(在一個平面上),多個三角形或四邊形就能夠組成復雜的立體模型;
使用ParaView查看3D模型;
2、模型在three.js中的表示
模型由面組成,面分為三角形和四邊形。三角形和四邊形面組成了網格模型。在three.js中用THREE.Mesh來表示網格模式。
THREE.Mesh可以和THREE.Line相提並論;區別是THREE.Line表示的是線條,THREE.Mesh表示面的集合;
THREE.Mesh = function(geometry,material)
參數說明:① geometry 是一個THREE.Geometry類型的對象,是一個包含頂點和頂點之間的連接關系對象;
② Material:是一個定義的材質;
3、模型的加載
① 服務器上的模型文件大多是存儲模型的頂點信息,這些信息可以以文本的方式存儲的(並不一定需要文本的方式存儲)。
Three.js支持很多種3D模型格式,例如:ply,stl,obj,vtk等等。隨着three.js的升級,會支持越來越多的文件格式;
② 第二步是瀏覽器下載文本文件,這是一件很普通的事情,只需要使用javascript的異步請求就可以實現;
③ javascript 解析文本並生成一個geometry,最終生成Mesh;
4、頂點和面索引之間的關系
加載vtk模型,主要分為2步:
① 將vtk文件中的點,轉換為geometry的vertices數組中;
② 將vtk文件中每個點的索引,轉換為geometry的faces中;
關於vtk文件的加載
//構造函數
THREE.VTKLoader = function(){
THREE.EventDispatcher.call(this);//繼承自監聽器,使這個類有監聽的功能;
};
//VTKLoader的原型函數,里面包含了VTKLoader的成員函數,成員變量的定義;
THREE.VTKLoader.prototype = {
//構造函數
constructor: THREE.VTKLoader,
//加載函數:url表示要加載的vtk文件的url路徑,callback表示加載完成后要調用的后續處理函數;
load: function(url,callback){
//將類自身保存在scope中,scope表示域的意思,這里為了避免this的歧義
var scope = this;
//ajax異步請求
var request = new XMLHttpRequest();
//加載完成的監聽器,加載完成后,將調用第二個參數定義的回調函數
request.addEventListener('load',function(event){
//對服務器加載下來的數據進行解析;
var geometry = scope.parse(event.target.responseText);
//解析完成后,發一個load事件,表示數據解析完成
scope.dispatchEvent({ type:'load',content: geometry });
//如果設置了回調函數,那么調用回調函數
if(callback) callback(geometry);
},false);
//加載過程中,向自身發送進度progress信息,信息中包含了已經加載的數據的字節數和文件總共的字節數
//通過兩者的比例了解加載的進度;
request.addEventListener('progress',function(event){
//發送正在加載的信息,兩個參數分別是已經加載了多少字節,總共多少字節
scope.dispatchEvent({ type:'progress',loader:event.loader,total: event.total});
},false);
//加載出錯的監聽器,加載的過程中也可能出錯;
request.addEventListener('error',function(){
//加載出錯后需要發布的錯誤消息
scope.dispatchEvent({ type:'error',message: 'could not load url'});
},false);
//初始化HTTP請求參數,例如: url和http方法,但是並不發送請求。
request.open('get',url,true);
//發送http請求,開始下載
request.send(null);
},
//data是從服務器傳過來的數據,其實就是vtk文件中的文本數據;
parse:function(data){
//new 一個幾何體
var geometry = new THREE.Geometry();
//定義一個內部函數vertex,用參數x,y,z生成一個頂點,並放入geometry的vertices數組中
function vertex(x,y,z){
geometry.vertices.push(new THREE.Vector3(x,y,z));
}
//定義一個面索引函數face3,將面的3個點的索引放入geometry的faces數組中;
function face3(x,y,z){
geometry.faces.push(new THREE.Face3(x,y,z));
}
//定義一個面索引函數face4,將面的四個點的索引放入;
function face4(a,b,c,d){
geometry.faces.push(new THREE.Face4(a,b,c,d));
}
//pattern存放模式字符串,result是臨時變量;
var pattern,result;
//float float float ,pattern是一個正在表達式,能夠匹配3個空格隔開的float
pattern = /([\+|\-]?[\d]+[\.][\d|\-|e]+)[ ]+([\+|\-]?[\d]+[\.][\d|\-|e]+)[ ]+([\+|\-]?[\d]+[\.][\d|\-|e]+)/g;
// exec是正則表達式的執行匹配函數,result返回一個包含3個字符串的數組,如果data讀到了最后,那么result將返回null // while 循環在data中,尋找符合正則表示式的數據,將符合條件的數據,轉換為一個頂點 while ( ( result = pattern.exec( data ) ) != null ) { // ["1.0 2.0 3.0", "1.0", "2.0", "3.0"] // 將字符串轉換為float,並放入geometry中 vertex( parseFloat( result[ 1 ] ), parseFloat( result[ 2 ] ), parseFloat( result[ 3 ] ) ); }
// 3 int int int,這里匹配面數據,如3 21216 21215 20399,這類數據是面索引數據 pattern = /3[ ]+([\d]+)[ ]+([\d]+)[ ]+([\d]+)/g; // 取出data中的所有面索引數據, while ( ( result = pattern.exec( data ) ) != null ) { // ["3 1 2 3", "1", "2", "3"] // 將面數據放入geometry的faces中 face3( parseInt( result[ 1 ] ), parseInt( result[ 2 ] ), parseInt( result[ 3 ] ) ); } // 4 int int int int // 這里是4個頂點一個面的情況,本例的vtk文件,沒有這種情況 pattern = /4[ ]+([\d]+)[ ]+([\d]+)[ ]+([\d]+)[ ]+([\d]+)/g; while ( ( result = pattern.exec( data ) ) != null ) { // ["4 1 2 3 4", "1", "2", "3", "4"] face4( parseInt( result[ 1 ] ), parseInt( result[ 2 ] ), parseInt( result[ 3 ] ), parseInt( result[ 4 ] ) ); } // 這里的4個函數,在后面解釋 geometry.computeCentroids(); geometry.computeFaceNormals(); geometry.computeVertexNormals(); geometry.computeBoundingSphere(); return geometry;
}
}