vue使用threeJs導入obj模型并實現(xiàn)添加標注
更新時間:2024年05月23日 11:09:02 作者:看點博客
這篇文章主要介紹了vue使用threeJs導入obj模型并實現(xiàn)添加標注方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
效果圖

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';
在外部創(chuàng)建變量:
場景 模型 相機 渲染 控制器 標簽 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(),//創(chuàng)建二維平面
},
}
},
導入模型,在場景中加載
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");
});
});
},
創(chuàng)建場景
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); // 環(huán)境光
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); // 調(diào)整相機方位
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);
},
// 鼠標點擊創(chuàng)建標簽
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)
}
})
},
// 創(chuàng)建點擊事件(默認是離攝像頭最近的相交)
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();
// // 將其發(fā)射顏色設置為閃爍的紅色/黃色
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)
}
}
},
//創(chuàng)建標簽方法
createLableObj (text, vector) {
let laberDiv = document.createElement('div');//創(chuàng)建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中調(diào)用
init () {
this.initScene();
this.initCamera();
this.initRenderer();
this.initOrbitControls()
//調(diào)用點擊事件
this.clickEvents()
},
刷新動畫
animate () {
// requestAnimationFrame 應運而生,它采用的是系統(tǒng)時間間隔(約16.7ms),保持最佳繪制效果與效率,
// 使各種網(wǎng)頁動畫有一個統(tǒng)一的刷新機制,從而節(jié)省系統(tǒng)資源,提高系統(tǒng)性能。
requestAnimationFrame(this.animate);
// controls.update();
renderer.render(scene, camera);
labelRenderer.render(scene, camera)
},
在mounted中調(diào)用,
mounted () {
this.$nextTick(() => {
this.init();
this.loadMTL()
this.animate();
}
}
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
vue兩組件間值傳遞 $router.push實現(xiàn)方法
兩組件間傳值,可能包含多種情況,這篇文章主要介紹了vue兩組件間值傳遞 $router.push實現(xiàn)方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-05-05
Vue——解決報錯 Computed property "****" was assigned to but it ha
這篇文章主要介紹了Vue——解決報錯 Computed property "****" was assigned to but it has no setter.的方法,幫助大家更好的理解和使用vue框架,感興趣的朋友可以了解下2020-12-12
vue、react等單頁面項目部署到服務器的方法及vue和react的區(qū)別
這篇文章主要介紹了vue、react等單頁面項目部署到服務器的方法,需要的朋友可以參考下2018-09-09
vue實現(xiàn)導出excel的多種方式總結(jié)
在Vue中實現(xiàn)導出Excel有多種方式,可以通過前端實現(xiàn),也可以通過前后端配合實現(xiàn),這篇文章將為大家詳細介紹幾種常用的實現(xiàn)方式,需要的可以參考下2023-08-08
vue中defineProperty和Proxy的區(qū)別詳解
這篇文章主要介紹了vue中defineProperty和Proxy的區(qū)別詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-11-11

