WebGL10---3D模型的加载与使用
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;
}
}