这是我参与11月更文挑战的第20天,活动详情查看:2021最后一次更文挑战
1. 加载模型文件(通过3Dmax、blender等软件导出的三维模型文件)
- .stl格式模型文件加载(.stl格式的三维模型不包含材质Material信息,只包含几何体顶点数据的信息) 三个位置坐标和一个三角形面的法线方向向量是一组数据,这一组数据表示一个三角形面的信息,下面是.syl文件里的内容
solid box //文件名字
//三角面1
facet normal 0 0 -1 //三角形面法向量
outer loop
vertex 50 50 -50 //顶点位置
vertex 50 -50 -50 //顶点位置
vertex -50 50 -50 //顶点位置
endloop
endfacet
//三角面2
facet normal 0 0 -1 //三角形面法向量
outer loop
vertex -50 50 -50 //顶点位置
vertex 50 -50 -50 //顶点位置
vertex -50 -50 -50 //顶点位置
endloop
endfacet
facet normal 0 1 0
.....
.....
//三角面12
facet normal -1 0 0
outer loop
vertex -50 -50 -50
vertex -50 50 50
vertex -50 50 -50
endloop
endfacet
endsolid
通过STLLoader.js加载.stl文件
1.首先导入STLLoader的js文件
<script src="http://www.yanhuangxueyuan.com/threejs/examples/js/loaders/STLLoader.js">
2.通过构造函数THREE.STLLoader()可以把.stl文件中几何体顶点信息提取出来转化为Three.js自身格式的几何体对象BufferGeometry
3.加载完成后会返回一个几何体对象BufferGeometry,你可以通过Mesh、Points等方式渲染该几何体
var loader = new THREE.STLLoader();
loader.load('立方体.stl',function (geometry) {
// 加载完成后会返回一个几何体对象BufferGeometry,你可以通过Mesh、Points等方式渲染该几何体
//网格渲染模式
var material = new THREE.MeshLambertMaterial({
color: 0x0000ff,
}); //材质对象Material
var mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
scene.add(mesh); //网格模型添加到场景中
//点渲染模式
//var material = new THREE.PointsMaterial({
//color: 0x000000,
//size: 0.5//点对象像素尺寸
//}); //材质对象
//var points = new THREE.Points(geometry, material); //点模型对象
//scene.add(points); //点对象添加到场景中
})
- .obj格式模型文件加载(.使用三维软件导出.obj模型文件的时候,会同时导出一个材质文件.mtl, .obj和.stl文件包含的信息一样都是几何体顶点相关数据,材质文件.mtl包含的是模型的材质信息,比如颜色、贴图路径等)
** 通过OBJLoader.js加载.mtl,.obj文件**
1.首先导入OBJLoader和MTLLoader的js文件
<script src="http://www.yanhuangxueyuan.com/threejs/examples/js/loaders/OBJLoader.js"></script>
<script src="http://www.yanhuangxueyuan.com/threejs/examples/js/loaders/MTLLoader.js"></script>
然后通过Loader加载完成之后显示在页面上
/**
* OBJ和材质文件mtl加载
*/
var OBJLoader = new THREE.OBJLoader();//obj加载器
var MTLLoader = new THREE.MTLLoader();//材质文件加载器
MTLLoader.load('./立方体/box.mtl', function(materials) {
// 返回一个包含材质的对象MaterialCreator
console.log(materials);
//obj的模型会和MaterialCreator包含的材质对应起来
OBJLoader.setMaterials(materials);
OBJLoader.load('./立方体/box.obj', function(obj) {
console.log(obj);
obj.scale.set(10, 10, 10); //放大obj组对象
scene.add(obj);//返回的组对象插入场景中
})
})
obj文件可以包含多个网格模型对象,不一定就是一个,这些网格模型对象全部是并列关系,无法通过父子关系构建一个树结构层级模型。
***注意当Loader加载模型文件时,如果没设置材质文件,系统自动设置Phong网格材质***
可以通过.children[index]属性查看某个模型,像数组一样
// 没有材质文件,系统自动设置Phong网格材质
OBJLoader.load('./多个模型/model.obj',function (obj) {
// 控制台查看返回结构:包含一个网格模型Mesh的组Group
console.log(obj);
scene.add(obj);
// 加载后的一些编辑操作
obj.scale.set(20,20,20);//网格模型缩放
// 设置其中一个网格模型的颜色
obj.children[0].material.color.set(0xff0000);
})
.obj文件不包含场景的相机Camera、光源Light等信息,不能导出骨骼动画、变形动画,如果希望导出光照信息、相机信息、骨骼动画信息、变形动画信息,可以选择.fbx、.gltf等格式。
- FBX格式模型文件加载 通过FBXLoader加载.fbx文件(stl、obj都是静态模型,不可以包含动画,fbx除了包含几何、材质信息,可以存储骨骼动画等数据。)
1.首先导入FBXLoader的js文件和辅助文件
2.加载fbx模型文件
3.解析fbx模型骨骼动画
<!-- 引入fbx模型加载库FBXLoader -->
<script src="http://www.yanhuangxueyuan.com/versions/threejsR92/examples/js/loaders/FBXLoader.js"></script>
<!-- 辅助文件 -->
<script src="http://www.yanhuangxueyuan.com/versions/threejsR92/examples/js/libs/inflate.min.js"></script>
var loader = new THREE.FBXLoader();//创建一个FBX加载器
loader.load("SambaDancing.fbx", function(obj) {
// console.log(obj);//查看加载后返回的模型对象
scene.add(obj)
// 适当平移fbx模型位置
obj.translateY(-80);
})
var mixer=null;//声明一个混合器变量
var loader = new THREE.FBXLoader();//创建一个FBX加载器
loader.load("SambaDancing.fbx", function(obj) {
// console.log(obj)
scene.add(obj)
obj.translateY(-80);
// obj作为参数创建一个混合器,解析播放obj及其子对象包含的动画数据
mixer = new THREE.AnimationMixer(obj);
// 查看动画数据
console.log(obj.animations)
// obj.animations[0]:获得剪辑对象clip
var AnimationAction=mixer.clipAction(obj.animations[0]);
// AnimationAction.timeScale = 1; //默认1,可以调节播放速度
// AnimationAction.loop = THREE.LoopOnce; //不循环播放
// AnimationAction.clampWhenFinished=true;//暂停在最后一帧播放的状态
AnimationAction.play();//播放动画
})
// 创建一个时钟对象Clock
var clock = new THREE.Clock();
// 渲染函数
function render() {
renderer.render(scene, camera); //执行渲染操作
requestAnimationFrame(render); //请求再次执行渲染函数render,渲染下一帧
if (mixer !== null) {
//clock.getDelta()方法获得两帧的时间间隔
// 更新混合器相关的时间
mixer.update(clock.getDelta());
}
}
render();