第八章 创建、加载高级网格和几何体
对象的组合
当从一个几何体中创建网格,并使用多种材质时,Three.js就会创建一个组。
该几何体的多个副本就会添加到这个组里,每份副本都有自己特定的材质。
我们看到的结果是,一个网格拥有多个材质,实际上它是一个包含多个网格的组。
sphere = createMesh(new THREE.SphereGeometry(5,10,10));
cube = createMesh(new THREE.CubeGeometry(6,6,6));
group = new THREE.Object3D();
group.add(sphere);
group.add(cube);
scene.add(group);
如果旋转一个组,不是旋转组中的每个对象,而是旋转整个组。
为了方便观察,在组的中心放置一个箭头。
var arrow = new THREE.ArrowHelper (new THREE.Vector3(0,1,0),group.position,10,0x0000ff);
scene.add(arrow);
使用组的时候,依然可以引用和修改组中的一个单独的几何体。
将多个网格合并成一个网格
当渲染的对象比较多时,即使在组中,每个对象还是独立的,需要对它们分别进行处理和渲染。
通过THREE.GeometryUtils.merge函数可以将多个几何体合并起来,创建一个联合体。
var geometry = new THREE.Geometry();
for(var i = 0 ;i//addCube()返回一个THREE.CubeGeometry对象
THREE.GeometryUtils.merge(geometry,addCube());
//最大的缺点:不能对单独的对象进行控制。
}
scene.add(new THREE.Mesh(geometry,cubeMaterial));
从外部资源加载几何体
JSON:Three.js有它自己的json格式,你可以使用它以声明的方式定义几何体和场景。但是它不是一种正式的格式。
OBJ和MTL:OBJ是一种简单的三维文件格式,用来定义对象的几何体。MTL文件通常和OBJ文件一起使用,在一个MTL文件中,定义对象的材质。
Collada:用来定义XML类文件中数字内容的格式。差不多所有的三维软件和渲染引擎都支持这个格式。
STL:立体成型术 。 广泛用于快速成型。例如,三维打印机的模型文件通常是STL文件。Three.js有一个可定制的STL导出工具,STLExporter.js。可以将Three.js中的模型导出到一个STL文件。
CTM:由openCTM创建的格式。可以用来压缩存储表示三维网格的三角形面片。
VTK:Visualization Tookit 定义的文件格式,用来指定顶点和面。VTK有两种格式,Three.js支持旧的格式,即Asscii格式。
PDB:特别的数据格式,由 蛋白质数据银行 场景,用来定义蛋白质的形状。Three.js可以加载并显示这种描述格式的蛋白质。
PLY:多边形文件格式。通常保存三维扫描仪的数据。
Three.js的json格式
1.保存和加载几何体
HTML5本地存储API,通过这个API可以很容易将持久化信息保存在客户端的浏览器中,以后还可以读取,即使浏览器关闭,重启之后也可以。
示例:
1.引入GeometryExporter.js。
2.保存几何体到浏览器本地存储中。
var exporter = new THREE.GeometryExporter();
var result = exporter.parse(knot.geometry);
localStorage.setItem("json",JSON.stringfy(result));
//将一个json对象转换为一个字符串
JSON.stringfy(result);
json对象的格式如下:
{
'metadata':{
'version':4,
'type':'geometry',
'generator':GeometryExporter''
},
'vertices':[14.00044545,-0.0065944,...],
'nvs':[
[]
],
'faces':[49,0,8,...]
}
Three.js保存的是原始的几何体。它将所有顶点和面的信息保存起来,但是你并不知道这到底是一个怎样的几何体。
加载保存的几何体到场景中。
var json = localStorage.getItem('json');
if(json){
var localGeometry = JSON.parse(json);
var loader = new THREE.JSONLoader();
var geom = loader.parse(localGeometry);
loadedMesh = createMesh(geom.geometry);
loadedMesh.position.x = -35;
loadedMesh.position.z = -5;
scene.add(loadedMesh);
}
JSONLoader还提供了一个load函数,可以传递一个url地址,改地址指向一个含有json定义的文件。
这里,我们只保存了几何体,其他的信息都丢失了,比如材质、光源、位置等。我们可以使用SceneExporter保存这些信息。
保存和加载场景
1.引入SceneExporter.js
2.导出场景
var exporter = new THREE.SceneExporter();
var sceneJson = JSON.stringfy(exporter.parse(scene));
localStorage.setItem('scene',sceneJson);
3.加载场景
var json = localStorage.getItem('scene');
var sceneLoader = new THREE.SceneLoader();
sceneLoader.parse(JSON.parse(json),function(e){
scene = e.scene;
},'.');
传递给loader的最后一个参数”.”是一个URL相对地址。例如,在材质中使用的纹理,就可以从这个相对地址中获取。本例中,我们没有使用纹理,所以传递但其概念目录即可。
同GeometryLoader一样,你也可以使用load函数直接加载一个JSON文件。
使用Blender
在blender中安装Three.js导出器:
G:\Study\WebGL\three.js-r73\utils\exporters\blender\addons中的io_three目录拷贝到Blender安装目录下的addons目录下。
激活导出器:
打开Blender->File->User Preferences->Addons->搜索three->勾选复选框
在Blender里加载和导出模型
File->Open->assets/models/misc_chair01.blend
File->Export->Three.js
导出的json文件中引用了纹理图片,所以我们要确保Three.js能够找到这个纹理文件。
在Blend中打开UV/Image Editor视图。File->…
Image->Save as Image 保存到和json模型相同的文件夹下。
在Three.js中加载模型:
var loader = new THREE.JsonLoader();
loader.load('../assets/models/misc_chair01.js',function(geometry,material){
mesh = new THREE.Mesh(geometry,material[0]);
mesh.scale.x = 15;
mesh.scale.y = 15;
mesh.scale.z = 15;
scene.add(mesh);
},'../assets/models');
Three.js导入三维文件格式
1.OBJ和MTL格式
两种格式相互配合。OBJ定义几何体格式,而MTL定义所用的材质。两者都是文本格式。
在Three.js中如果只加载几何体,则只需引入OBJLoader.js
var loader = new THREE.OBJLoader();
loader.load('../assets/models/pinecone.obj',function(geometry){
var material = new THREE.MeshLambertMaterial({
color:0x5C3A21
});
geometry.children.forEach(function(child){
if(child.children.length==1){
if(child.children[0] instanceof THREE.Mesh){
child.children[0].material = material;
}
}
});
geometry.scale.set(100,100,100);
geometry.rotation.x = -0.3;
scene.add(geometry);
});
如果加载几何体并直接赋予材质,需要引入:
OBJLoader.js
MTLLoader.js
OBJMTLLoader.js
var loader = new THREE.OBJMTLLoader();
loader.load('load',function(event){
var object = event.content;
var wing2 = object.children[5].children[0];
var wing1 = object.children[4].children[0];
wing1.material.alphaTest = 0.5;
wing1.material.opacity = 0.6;
wing1.material.transparent = true;
wing2.material.alphaTest = 0.5;
wing2.material.opacity = 0.6;
wing2.material.transparent = true;
object.scale.set(140,140,140);
object.rotation.x = 0.2;
object.rotation.y = -1.3;
scene.add(object);
});
loader.load('../assets/models/butterfly.obj','../assets/models/butterfly.mtl');
有时间加载的模型源文件中材质的设置可能有问题,为此我们不得不去检查模型材质的定义,并修改一些属性。
2.加载Collada模型
扩展名.dae ,是另一种通用的、定义场景和模型(以及动画)的文件格式。
Collada不仅可以定义几何体,也定义了材质,甚至还可以定义光源。
引入js库:ColladaLoader.js
var mesh ;
loader.load('../assets/models/dae/Trunck_dae.dae',function(result){
mesh = result.scene.children[0].children[0].clone();
mesh.scale.set(4,4,4);
scene.add(mesh);
});
result对象的结构如下:
var result = {
scene:scene,
morphs:morphs,
skins:skins,
animations:animData,
dar:{
...
}
};
第一次加载该模型的时候,材质不能正确的渲染。因为材质的纹理使用TGA格式,而Three.js不支持该格式。
所以我们将TGA格式转换为PNG格式,再修改.dar模型文件中的xml元素,使其指向转换后的PNG文件。
3.加载STL、CTM和VTK模型
<1>引入[NameOfFormat]Loader.js文件
<2>使用[NameOfFormat]Loader.load()函数从URL中加载。
<3>检查回调函数的返回结果,并对它进行渲染。
4.展示蛋白质数据银行中的蛋白质
蛋白质数据银行收集了很多分子、蛋白质的详细信息。还可以以PDB格式下载这些分子的数据结构。
Three.js中解析PDB文件:
引入:PDBLoader.js
var loader = new THREE.PDBLoader();
var group = new THREE.Obeject3D();
loader.load('../assets/models/diamond.pdb',function(geometry,geometryBonds){
var i = 0;
//每个顶点代表顶点的位置
geometry.vertices.forEach(function(position){
var sphere = new THREE.SphereGeometry(0.2);
var material = new THREE.MeshPhongMaterial({
color:geometry.colors[i++];
});
var mesh = new THREE.Mesh(sphere,material);
mesh.position = position;
group.add(mesh);
});
//定义原子之间的键
for(var j = 0 ;j2){
//创建一条三维路径,作为原子键
var path = new THREE.SplineCurve3([
geometryBonds.vertices[j],
geometryBonds.vertices[j+1]
]);
var tube = new THREE.TubeGeometry(path,1,0.04);
var material = new THREE.MeshPhongMaterial({
color:0xcccccc
});
var mesh = new THREE.Mesh(tube,material);
group.add(mesh);
}
console.log(geometry);
console.log(geometryBonds);
scene.add(group);
});
引入:PLYLoader.js
var loader = new THREE.PLYLoader();
var group = new THREE.Object3D();
loader.load('../assets/models/test.ply',function(geometry){
var material = new THREE.ParticleBasicMaterial({
color:0xffffff,
size:0.4,
opacity:0.6,
transparent:true,
blending:THREE.AdditiveBlending,
map:generateSprite()
});
group = new THREE.ParticleSystem(geometry,material);
group.sortParticles = true;
console.log(group);
scene.add(group);
});