效果图

1.安装threejs
npm install three
2.安装轨道控件插件
npm install three-orbit-controls
3.安装加载.obj和.mtl文件的插件
npm i --save three-obj-mtl-loader
页面引用:
import * as three from "three"; //引入three.js
import { mtlloader } from "three-obj-mtl-loader"; //引入加载外部模型
import { objloader } from "../../public/objjs/objloader.js"; //引入加载外部模型
// const orbitcontrols = require("three-orbit-controls")(three); //引入控制器
import { orbitcontrols } from 'three/examples/jsm/controls/orbitcontrols.js'
import { css2dobject, css2drenderer } from 'three/examples/jsm/renderers/css2drenderer';
在外部创建变量:
场景 模型 相机 渲染 控制器 标签 let scene, scale, camera, renderer, controls, labelrenderer;
data中:
data () {
return {
mesh: null,
events: {
raycaster: new three.raycaster(),
pickedobject: null,
pickedobjectsavedcolor: 0,
pickposition: new three.vector2(),//创建二维平面
},
}
},
导入模型,在场景中加载
loadmtl () {
let that = this;
let mtlloader = new mtlloader();
let objloader = new objloader();
mtlloader.load('/file.mtl', function (materials) {
materials.preload();
objloader.setmaterials(materials);
objloader.load('/file.obj', function (obj) {
obj.position.set(0, -5, 0);//模型摆放的位置
obj.scale.set(0.002, 0.002, 0.002);//模型放大或缩小,有的时候看不到模型,考虑是不是模型太小或太大。
scene.add(obj);//将模型加入场景中
function (xhr) {
// console.log((xhr.loaded / xhr.total) * 100 + "% loaded");
},
// called when loading has errors
function (error) {
console.log(error)
console.log("an error happened");
});
});
},
创建场景
initscene () {
scene = new three.scene();
// var axeshelper = new three.axeshelper(250); // 建立xyz坐标轴,红色代表 x 轴. 绿色代表 y 轴. 蓝色代表 z 轴.长度15
// scene.add(axeshelper);
// 改变外壳颜色
var ambientlight = new three.ambientlight(0xaf8e00); // 环境光
scene.add(ambientlight);
let directionallight = new three.directionallight(0xdfebff, 0.45); // 平行光
scene.add(directionallight);
},
初始化相机
initcamera () {
camera = new three.perspectivecamera(
75,
window.innerwidth / window.innerheight,
0.1,
1000
);
camera.position.set(20, 20, 20); // 调整相机方位
camera.lookat(new three.vector3(0, 0, 0)); // 让相机指向原点
const pointlight = new three.pointlight(0xffffff, 1, 100);
pointlight.position.set(0, 0, 20100);
scene.add(pointlight);
scene.add(camera);
},
初始化加载器
initrenderer () {
renderer = new three.webglrenderer();
let container = document.getelementbyid("container");
let width = document.getelementbyid('container').clientwidth;
let height = document.getelementbyid('container').clientheight;
renderer.setsize(window.innerwidth, window.innerheight);
renderer.setclearcolor(0x8b8b8b, 1.0); // 背景光
container.appendchild(renderer.domelement);
renderer.setpixelratio(window.devicepixelratio);
// 初始化标签
labelrenderer = new css2drenderer();
labelrenderer.setsize(window.innerwidth, window.innerheight);
labelrenderer.domelement.style.position = "absolute";
labelrenderer.domelement.style.top = 0;
labelrenderer.domelement.style.pointerevents = 'none';
labelrenderer.domelement.classname = "alllabel"
container.appendchild(labelrenderer.domelement);
},
// 鼠标点击创建标签
clickevents () {
window.addeventlistener('click', this.clickpickposition);
},
// 当前鼠标点击坐标
clickpickposition (e) {
this.events.pickposition.x = e.clientx / renderer.domelement.clientwidth * 2 - 1;
this.events.pickposition.y = -(e.clienty / renderer.domelement.clientheight * 2) + 1;
this.pickevents(this.events.pickposition, scene, camera, obj => {
obj.userdata.checked = !obj.userdata.checked;
if (!obj.userdata.checked) {
obj.material.emissive.sethex(this.events.pickedobjectsavedcolor)
} else {
obj.material.emissive.sethex(0xffff00)
}
})
},
// 创建点击事件(默认是离摄像头最近的相交)
pickevents (normalizedposition, scene, camera, callback) {
// 如果存在拾取的对象,则恢复颜色
if (this.events.pickedobject) {
this.events.pickedobject.material.emissive.sethex(this.events.pickedobjectsavedcolor);
this.events.pickedobject = undefined;
}
// 沿着摄像头的方向投射射线
this.events.raycaster.setfromcamera(normalizedposition, camera)
// 获取与射线光线相交的对象列表
const intersectedobjects = this.events.raycaster.intersectobjects(scene.children);
if (intersectedobjects.length) {
// // 获取与射线光纤相交的第一个对象。也是最近的一个
this.events.pickedobject = intersectedobjects[0].object;
// // 保存当前对象的颜色
this.events.pickedobjectsavedcolor = this.events.pickedobject.material.emissive.gethex();
// // 将其发射颜色设置为闪烁的红色/黄色
this.events.pickedobject.material.emissive.sethex(0xffff00)
// 点击设置标签
// intersectedobjects[0].point.y *= 1.08;
// intersectedobjects[0].point.x *= -1.08;
console.log(intersectedobjects[0].point)
let pointlabeldom = this.createlableobj(intersectedobjects[0].object.name, intersectedobjects[0].point)
scene.add(pointlabeldom);//将模型加入场景中
if (callback) {
callback(this.events.pickedobject)
}
}
},
//创建标签方法
createlableobj (text, vector) {
let laberdiv = document.createelement('div');//创建div容器
laberdiv.classname = 'laber_name';
// laberdiv.textcontent = text;
laberdiv.innerhtml = `
<div class='label_count'>
${text}
</div>
`
// 给标签设置坐标位置
let pointlabel = new css2dobject(laberdiv);
pointlabel.position.set(vector.x, vector.y, vector.z);
return pointlabel;
}
集成在init中调用
init () {
this.initscene();
this.initcamera();
this.initrenderer();
this.initorbitcontrols()
//调用点击事件
this.clickevents()
},
刷新动画
animate () {
// requestanimationframe 应运而生,它采用的是系统时间间隔(约16.7ms),保持最佳绘制效果与效率,
// 使各种网页动画有一个统一的刷新机制,从而节省系统资源,提高系统性能。
requestanimationframe(this.animate);
// controls.update();
renderer.render(scene, camera);
labelrenderer.render(scene, camera)
},
在mounted中调用,
mounted () {
this.$nexttick(() => {
this.init();
this.loadmtl()
this.animate();
}
}
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论