vue使用threeJs導(dǎo)入obj模型并實(shí)現(xiàn)添加標(biāo)注
效果圖
1.安裝threeJs
npm install three
2.安裝軌道控件插件
npm install three-orbit-controls
3.安裝加載.obj和.mtl文件的插件
npm i --save three-obj-mtl-loader
頁(yè)面引用:
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)建變量:
場(chǎng)景 模型 相機(jī) 渲染 控制器 標(biāo)簽 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)建二維平面 }, } },
導(dǎo)入模型,在場(chǎ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);//模型放大或縮小,有的時(shí)候看不到模型,考慮是不是模型太小或太大。 scene.add(obj);//將模型加入場(chǎng)景中 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)建場(chǎng)景
initScene () { scene = new THREE.Scene(); // var axesHelper = new THREE.AxesHelper(250); // 建立xyz坐標(biāo)軸,紅色代表 X 軸. 綠色代表 Y 軸. 藍(lán)色代表 Z 軸.長(zhǎng)度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); },
初始化相機(jī)
initCamera () { camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 ); camera.position.set(20, 20, 20); // 調(diào)整相機(jī)方位 camera.lookAt(new THREE.Vector3(0, 0, 0)); // 讓相機(jī)指向原點(diǎn) 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); // 初始化標(biāo)簽 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); }, // 鼠標(biāo)點(diǎn)擊創(chuàng)建標(biāo)簽 clickEvents () { window.addEventListener('click', this.clickPickPosition); }, // 當(dāng)前鼠標(biāo)點(diǎn)擊坐標(biāo) 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)建點(diǎn)擊事件(默認(rèn)是離攝像頭最近的相交) pickEvents (normalizedPosition, scene, camera, callback) { // 如果存在拾取的對(duì)象,則恢復(fù)顏色 if (this.events.pickedObject) { this.events.pickedObject.material.emissive.setHex(this.events.pickedObjectSavedColor); this.events.pickedObject = undefined; } // 沿著攝像頭的方向投射射線 this.events.raycaster.setFromCamera(normalizedPosition, camera) // 獲取與射線光線相交的對(duì)象列表 const intersectedObjects = this.events.raycaster.intersectObjects(scene.children); if (intersectedObjects.length) { // // 獲取與射線光纖相交的第一個(gè)對(duì)象。也是最近的一個(gè) this.events.pickedObject = intersectedObjects[0].object; // // 保存當(dāng)前對(duì)象的顏色 this.events.pickedObjectSavedColor = this.events.pickedObject.material.emissive.getHex(); // // 將其發(fā)射顏色設(shè)置為閃爍的紅色/黃色 this.events.pickedObject.material.emissive.setHex(0xFFFF00) // 點(diǎn)擊設(shè)置標(biāo)簽 // 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);//將模型加入場(chǎng)景中 if (callback) { callback(this.events.pickedObject) } } }, //創(chuàng)建標(biāo)簽方法 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> ` // 給標(biāo)簽設(shè)置坐標(biāo)位置 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)用點(diǎn)擊事件 this.clickEvents() },
刷新動(dòng)畫
animate () { // requestAnimationFrame 應(yīng)運(yùn)而生,它采用的是系統(tǒng)時(shí)間間隔(約16.7ms),保持最佳繪制效果與效率, // 使各種網(wǎng)頁(yè)動(dòng)畫有一個(gè)統(tǒng)一的刷新機(jī)制,從而節(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é)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
vue兩組件間值傳遞 $router.push實(shí)現(xiàn)方法
兩組件間傳值,可能包含多種情況,這篇文章主要介紹了vue兩組件間值傳遞 $router.push實(shí)現(xiàn)方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來(lái)看看吧2019-05-05Vue——解決報(bào)錯(cuò) Computed property "****" was assigned to but it ha
這篇文章主要介紹了Vue——解決報(bào)錯(cuò) Computed property "****" was assigned to but it has no setter.的方法,幫助大家更好的理解和使用vue框架,感興趣的朋友可以了解下2020-12-12vue、react等單頁(yè)面項(xiàng)目部署到服務(wù)器的方法及vue和react的區(qū)別
這篇文章主要介紹了vue、react等單頁(yè)面項(xiàng)目部署到服務(wù)器的方法,需要的朋友可以參考下2018-09-09vue實(shí)現(xiàn)導(dǎo)出excel的多種方式總結(jié)
在Vue中實(shí)現(xiàn)導(dǎo)出Excel有多種方式,可以通過前端實(shí)現(xiàn),也可以通過前后端配合實(shí)現(xiàn),這篇文章將為大家詳細(xì)介紹幾種常用的實(shí)現(xiàn)方式,需要的可以參考下2023-08-08在Vue3中進(jìn)行單元測(cè)試和集成測(cè)試的操作方法
隨著越來(lái)越多的企業(yè)和開發(fā)者選擇使用 Vue.js 構(gòu)建他們的前端應(yīng)用程序,確保代碼質(zhì)量和可靠性變得尤為重要,在本博客中,我們將深入探討如何在 Vue 3 中進(jìn)行單元測(cè)試和集成測(cè)試,并提供示例代碼來(lái)幫助您上手,需要的朋友可以參考下2025-01-01vue中defineProperty和Proxy的區(qū)別詳解
這篇文章主要介紹了vue中defineProperty和Proxy的區(qū)別詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11