【Vue】在vue工程中加入Three,并实现obj,mtl加载
在前几篇文章,已经介绍了Threejs的基本使用,本文将讲解如何在Vue中加入Threejs以及OBJ、MTL加载。先上效果:文档结构(注意在vue3之前的版本,obj等资源要放在static下面):其实在vue中使用threejs更加简单,唯一要注意的就是版本问题,我以前用的84版这一次引用的是最新的106版,在相机的处理上感觉与旧版本有区别。步骤:npm cnpm ...
·
在前几篇文章,已经介绍了Threejs的基本使用,本文将讲解如何在Vue中加入Threejs以及OBJ、MTL加载。
先上效果:
文档结构(注意在vue3之前的版本,obj等资源要放在static下面):
其实在vue中使用threejs更加简单,唯一要注意的就是版本问题,我以前用的84版这一次引用的是最新的106版,在相机的处理上感觉与旧版本有区别。
步骤:
npm cnpm vue相关环境不再此处赘言。
1.安装threejs
cnpm install three -s -d
2.安装obj mtl加载
cnpm install three-obj-mtl-loader -s -d
3.前端代码
<template>
<div style="height: 100%">
<div>
<button @click="triggerTips('m1')">m1</button>
<button @click="triggerTips('m2')">m2</button>
<button @click="triggerTips('m3')">m3</button>
</div>
<div id="container">
</div>
</div>
</template>
<script>
import * as Three from 'three';
import {OBJLoader, MTLLoader} from 'three-obj-mtl-loader'
export default {
data() {
return {
camera: null,
scene: null,
renderer: null,
light: null,
elements: [],
tipsBottom: 5 + 200,
tipsTop:5 + 200 + 40
}
},
mounted() {
this.initThree(document.getElementById('container'))
this.animation();
},
methods: {
createSphere(color) {
//创建球体
let radius = 10, segemnt = 16, rings = 16;
let sphereMaterial = new Three.MeshLambertMaterial({
color: color,
transparent: true,
opacity: 0.8
});
let sphere = new Three.Mesh(
new Three.SphereGeometry(radius, segemnt, rings),
sphereMaterial
);
sphere.geometry.verticesNeedUpdate = true;
sphere.geometry.normalsNeedUpdate = true;
return sphere;
},
triggerTips(id) {
let element = this.elements.find(x => {
if (x.id == id) {
return x;
}
})
if (!element) {
console.log("不存在该id");
return;
}
if (element.timeKey) {
clearInterval(element.timeKey);
element.timeKey = undefined;
element.model.children.forEach(o => {
for (let m in element.materials.materials) {
if (o.name.indexOf(m) != -1) {
o.material = element.materials.materials[m];
}
}
})
element.cylis.forEach(x => {
this.scene.remove(x.cyli);
})
element.cylis.splice(0, element.cylis.length);
} else {
this.crateTips(element);
element.timeIndex = 0;
element.timeKey = setInterval(() => {
element.model.children.forEach(o => {
if (element.timeIndex == 0) {
o.material = new Three.MeshBasicMaterial({color: 0xFF0000});
} else {
for (let m in element.materials.materials) {
if (o.name.indexOf(m) != -1) {
o.material = element.materials.materials[m];
}
}
}
})
element.timeIndex = ++element.timeIndex % 2;
}, 500);
}
},
crateTips(element) {
element.cylis = [];
let cyliMesh01 = this.createSphere(0xFF0000);
cyliMesh01.position.set(element.model.position.x, this.tipsBottom, element.model.position.z);
this.scene.add(cyliMesh01);
element.cylis.push({cyli: cyliMesh01});
let cyliMesh02 = this.createSphere(0xFFFF00);
cyliMesh02.position.set(element.model.position.x, this.tipsTop, element.model.position.z);
this.scene.add(cyliMesh02);
element.cylis.push({cyli: cyliMesh02});
},
onResize() {
this.camera.aspect = window.innerWidth / window.innerHeight;
this.camera.updateProjectionMatrix();
this.renderer.setSize(window.innerWidth, window.innerHeight);
},
animation() {
this.elements.forEach(x => {
x.cylis.forEach(c => {
let cyl = c.cyli;
if (cyl.position.y >= this.tipsTop) {
c.direction = -1;
} else if (cyl.position.y <=this.tipsBottom) {
c.direction = 1;
}
cyl.position.setY(cyl.position.y + c.direction * 1.2);
})
})
//刷新页面
this.renderer.render(this.scene, this.camera);
requestAnimationFrame(this.animation);
},
loadObj(id, baseUrl, objName, multiplyScalar, position, materials) {
let obj = {id: id, isTips: false,cylis:[]};
if (!multiplyScalar) {
multiplyScalar = 1;
}
let manager = new Three.LoadingManager();
let loader = new OBJLoader(manager);
if (multiplyScalar) {
loader.setMaterials(materials);
obj.materials = materials;
}
loader.setPath(baseUrl);
loader.load(objName, object => {
//显示比例
object.scale.multiplyScalar(multiplyScalar);
//加入到页面中
this.scene.add(object);
object.castShadow = true;
object.receiveShadow = true;
obj.model = object;
object.position.set(position.x, position.y, position.z);
this.elements.push(obj);
});
},
loadObjWithMaterials(id, baseUrl, objName, mtlName, position, multiplyScalar) {
let mtlLoader = new MTLLoader();
mtlLoader.setPath(baseUrl);
mtlLoader.load(mtlName, materials => {
this.loadObj(id, baseUrl, objName, multiplyScalar, position, materials);
});
},
initThree(element) {
let container = element;
//初始化相机
this.camera = new Three.PerspectiveCamera(70, element.clientWidth / element.clientHeight, 1, 10000);
this.camera.position.x = 0;
this.camera.position.y = 1000;
this.camera.position.z = 1000;
this.camera.rotation.x -= 45 * (Math.PI / 180);
//场景
this.scene = new Three.Scene();
//渲染
this.renderer = new Three.WebGLRenderer({antialias: true});
this.renderer.setSize(element.clientWidth, element.clientHeight);
element.appendChild(this.renderer.domElement);
//灯光
this.light = new Three.AmbientLight(0xFFFFFF);
this.scene.add(this.light);
//创建地面
let plane = new Three.Mesh(
new Three.PlaneBufferGeometry(2000, 2000),
new Three.MeshPhongMaterial({
color: 0x999999,
specular: 0x101010
})
);
plane.rotation.x = -Math.PI / 2;
plane.position.y = -0.5;
this.scene.add(plane);
plane.receiveShadow = true;
window.addEventListener('resize', this.onResize, false);
this.loadObjWithMaterials("m1", 'static/model/female02/', 'female02.obj', 'female02.mtl', {
x: 0,
y: 0,
z: 0
}, 1,)
this.loadObjWithMaterials("m2", 'static/model/female02/', 'female02.obj', 'female02.mtl', {
x: 500,
y: 0,
z: 0
}, 1,)
this.loadObjWithMaterials("m3", 'static/model/female02/', 'female02.obj', 'female02.mtl', {
x: 0,
y: 0,
z: 600
}, 1,)
}
}
}
</script>
<style>
#container {
height: 100%;
}
</style>
最后说一句webstrom写前端是真的爽,不管是vue单页面,还是threejs都很流畅,提示也很到位。
更多推荐
已为社区贡献5条内容
所有评论(0)