VUE+THREE.JS 點擊模型相機緩入查看模型相關信息

點擊模型相機緩入查看模型相關信息

  • 1.引入
  • 2.初始化CSS3DRenderer
  • 3.animate 加入一直執行渲染
  • 4.點擊事件
    • 4.1 初始化renderer時加入監聽事件
    • 4.2 觸發點擊事件
  • 5. 關鍵代碼分析
    • 5.1 移除模型
    • 5.2 創建模型上方的彈框
    • 5.3 相機緩入動畫
    • 5.4 動畫執行

1.引入

引入模型所要呈現的3DSprite精靈模型,優勢在于可以隨著視野的變化,跟隨方向變化,大小是近大遠小的模式

import { CSS3DRenderer, CSS3DSprite } from "three/examples/jsm/renderers/CSS3DRenderer.js";
import TWEEN from "@tweenjs/tween.js";//相機緩入動畫

在這里插入圖片描述

2.初始化CSS3DRenderer

// 初始化 CSS3DRenderer 設備信息框initObjectRender() {labelRender = new CSS3DRenderer();labelRender.setSize(this.$refs.draw.offsetWidth, this.$refs.draw.offsetHeight);labelRender.domElement.style.position = "absolute";labelRender.domElement.style.top = "0px";labelRender.domElement.style.pointerEvents = "none";document.getElementById("workshop").appendChild(labelRender.domElement);},

3.animate 加入一直執行渲染

labelRender.render(scene, camera);
TWEEN.update();

4.點擊事件

4.1 初始化renderer時加入監聽事件

renderer.domElement.addEventListener("click", this.onClick, false);

4.2 觸發點擊事件

//監聽點擊事件
onClick(event) {const raycaster = new THREE.Raycaster();const mouse = new THREE.Vector2();// 計算鼠標或觸摸點的位置mouse.x = (event.clientX / this.$refs.draw.offsetWidth) * 2 - 1;mouse.y = -(event.clientY / this.$refs.draw.offsetHeight) * 2 + 1;// 更新射線   注意——> camera 是相機   定義到data里的raycaster.setFromCamera(mouse, camera);// 計算與所有對象的交點const intersects = raycaster.intersectObjects(scene.children, true);if (intersects.length > 0) {//獲取點擊模型的相關信息//以下為我的處理邏輯const interObj = intersects[0].object;//獲取模型名稱,此名稱是用blender創建模型時,創建的名稱const interName = this.getParentName(interObj);//模型的位置const interPoint = intersects[0].point;if (interName) {this.removeOthersEqp(interName); //移除此設備以外的設備this.getEqpInfo(interName, interObj, interPoint); //獲取設備信息} else {console.log("獲取世界坐標", interPoint.x, ",", interPoint.y, ",", interPoint.z);}}
},
//獲取點擊的設備名稱
getParentName(data) {if (!data) {return;}const regex = /[^\_\)]+(?=\()/g;const eqpEnCode = data.name.match(regex);return eqpEnCode?.length > 0 ? eqpEnCode[0] : this.getParentName(data.parent);
},
//移除此設備以外的設備
removeOthersEqp(interName) {const meshes = scene.children.filter((o) => {return o.name !== `${interName}EqpInfo` && o.name.indexOf("EqpInfo") > -1;});meshes.forEach((l) => {l.remove(...l.children);});scene.remove(...meshes);
},
//獲取設備信息
toolTipGroup: new THREE.Group(),//彈框參數
getEqpInfo(interName, interObj, interPoint) {// 獲取設備詳細信息let params = {system: "",enCode: interName,};getEqpInfoReq(params).then((res) => {if (res.code === 200) {const { encode, oeeStatus, taktTime, yield: resYield } = res.result;const shpereMesh = this.createCpointMesh(`${interName}EqpInfo`, interObj.position.x, interObj.position.y + 1000, interObj.position.z);this.toolTipGroup.add(shpereMesh);//關閉彈框標簽const closeInfo = document.createElement("div");closeInfo.setAttribute("style", "width:100%;padding: 0.5rem 0.5rem 0 0;text-align:right");closeInfo.innerHTML = "<i class='iconfont icon-yuyinguanbi' style='font-size:0.5rem;color:#27eeea;cursor: pointer;'></i>";//彈框點擊關閉事件closeInfo.onclick = function (event) {const meshes = scene.children.filter((o) => {return o.name === `${interName}EqpInfo`;});meshes.forEach((l) => {l.remove(...l.children);});scene.remove(...meshes);event.cancelBubble = true;};//基礎信息展示const cardBaseInfo = `<div class='base-infos'><div class='base-info'><span class='name'>編碼:</span><span>${encode}</span></div><div  class='base-info'><span class='name'>名稱:</span><span>${interObj.name.match(/[^\(\)]+(?=\))/g)[0]}</span></div><div class='base-info'><span class='name'>狀態:</span><span>${oeeStatus}</span></div></div>`;//設備其他信息const cardOthersInfo = `<div class='base-infos'><div class='base-info'><span class='name'>Yield:</span><span>${resYield}%</span></div><div class='base-info'><span class='name'>TaktTime:</span><span>${taktTime}</span></div></div>`;const cardInfo = document.createElement("div");cardInfo.style.padding = "0 0 1rem 0";cardInfo.innerHTML = cardBaseInfo + cardOthersInfo;const pContainer = document.createElement("div");pContainer.id = `${interName}EqpInfo`;pContainer.className = "workshop-tooltip";pContainer.style.pointerEvents = "none"; //避免HTML標簽遮擋三維場景的鼠標事件pContainer.appendChild(closeInfo); //關閉按鈕pContainer.appendChild(cardInfo); //基礎信息const cPointLabel = new CSS3DSprite(pContainer);// cPointLabel.scale.set(5, 5, 5); //根據相機渲染范圍控制HTML 3D標簽尺寸cPointLabel.rotateY(Math.PI / 2); //控制HTML標簽CSS3對象姿態角度cPointLabel.position.set(interObj.position.x, interObj.position.y + 1000, interObj.position.z);cPointLabel.name = `${interName}EqpInfo`;scene.add(cPointLabel);//相機位置移動this.handlePosition(interPoint, true);}});
},
//創建基礎模型
createCpointMesh(name, x, y, z) {const geo = new THREE.BoxGeometry(0.1);const mat = new THREE.MeshBasicMaterial({ color: 0xff0000 });const mesh = new THREE.Mesh(geo, mat);mesh.position.set(x, y, z);mesh.name = name;return mesh;
},
// 動態調整相機位置
handlePosition(targetPosition, falg) {// 計算點擊位置與當前相機位置之間的向量const direction = new THREE.Vector3().subVectors(targetPosition, camera.position);// 計算相機與目標位置之間的距離let distance = camera.position.distanceTo(targetPosition);// 以某種方式將距離轉換為縮放因子let scaleFactor = falg ? this.functionOfDistance(distance) : 0;// 縮放向量,使其稍遠一點// const scaleFactor = 0.5; // 縮放因子,可以根據需要進行調整const offset = direction.multiplyScalar(scaleFactor);const finalPosition = camera.position.clone().add(offset);// 創建 Tween 實例const startPosition = camera.position.clone();const duration = 1000; // 動畫持續時間,單位毫秒tween = new TWEEN.Tween(startPosition).to(finalPosition, duration).onUpdate(() => {// 更新相機位置camera.position.copy(startPosition);camera.lookAt(targetPosition);}).start();
},
//計算距離
functionOfDistance(distance) {// 設定最小和最大距離以及對應的縮放因子const minDistance = 4100;const maxDistance = 18000;const minScaleFactor = 0;const maxScaleFactor = 0.8;if (distance < minDistance) {return minScaleFactor;} else if (distance > maxDistance) {return maxScaleFactor;}// 根據距離范圍內的比例,計算縮放因子const ratio = (distance - minDistance) / (maxDistance - minDistance);return minScaleFactor + ratio * (maxScaleFactor - minScaleFactor);
},

5. 關鍵代碼分析

5.1 移除模型

  • 1.獲取想要移除的模型名稱
const meshes = scene.children.filter((o) => {return o.name !== `${interName}EqpInfo` && o.name.indexOf("EqpInfo") > -1;
});
  • 2.移除模型的子模型
meshes.forEach((l) => {l.remove(...l.children);
});
  • 3.移除模型
scene.remove(...meshes)

5.2 創建模型上方的彈框

  • 1.創建基礎模型
const shpereMesh = this.createCpointMesh(`${interName}EqpInfo`, interObj.position.x, interObj.position.y + 1000, interObj.position.z);//創建基礎模型
createCpointMesh(name, x, y, z) {const geo = new THREE.BoxGeometry(0.1);const mat = new THREE.MeshBasicMaterial({ color: 0xff0000 });const mesh = new THREE.Mesh(geo, mat);mesh.position.set(x, y, z);mesh.name = name;return mesh;
},
  • 2.創建動態div,渲染到基礎模型中

由于我這里是一個彈框,我希望他能夠點擊關閉,所以多加了個關閉事件

  • 2.1 關閉按鈕的渲染及觸發
//關閉彈框標簽
const closeInfo = document.createElement("div");
closeInfo.setAttribute("style", "width:100%;padding: 0.5rem 0.5rem 0 0;text-align:right");
closeInfo.innerHTML = "<i class='iconfont icon-yuyinguanbi' style='font-size:0.5rem;color:#27eeea;cursor: pointer;'></i>";
//彈框點擊關閉事件
closeInfo.onclick = function (event) {const meshes = scene.children.filter((o) => {return o.name === `${interName}EqpInfo`;});meshes.forEach((l) => {l.remove(...l.children);});scene.remove(...meshes);event.cancelBubble = true;
};
  • 2.2 彈框信息顯示

注意:pContainer.style.pointerEvents = "none"; //避免HTML標簽遮擋三維場景的鼠標事件必須要寫這個 要不然會導致模型無法推拽移動

//基礎信息展示
const cardBaseInfo = `<div class='base-infos'><div class='base-info'><span class='name'>編碼:</span><span>${encode}</span></div><div  class='base-info'><span class='name'>名稱:</span><span>${interObj.name.match(/[^\(\)]+(?=\))/g)[0]}</span></div><div class='base-info'><span class='name'>狀態:</span><span>${oeeStatus}</span></div></div>`;
//設備其他信息
const cardOthersInfo = `<div class='base-infos'><div class='base-info'><span class='name'>Yield:</span><span>${resYield}%</span></div><div class='base-info'><span class='name'>TaktTime:</span><span>${taktTime}</span></div></div>`;const cardInfo = document.createElement("div");
cardInfo.style.padding = "0 0 1rem 0";
cardInfo.innerHTML = cardBaseInfo + cardOthersInfo;const pContainer = document.createElement("div");
pContainer.id = `${interName}EqpInfo`;
pContainer.className = "workshop-tooltip";
pContainer.style.pointerEvents = "none"; //避免HTML標簽遮擋三維場景的鼠標事件
pContainer.appendChild(closeInfo); //關閉按鈕
pContainer.appendChild(cardInfo); //基礎信息const cPointLabel = new CSS3DSprite(pContainer);
// cPointLabel.scale.set(5, 5, 5); //根據相機渲染范圍控制HTML 3D標簽尺寸
cPointLabel.rotateY(Math.PI / 2); //控制HTML標簽CSS3對象姿態角度
cPointLabel.position.set(interObj.position.x, interObj.position.y + 1000, interObj.position.z);
cPointLabel.name = `${interName}EqpInfo`;
scene.add(cPointLabel);

5.3 相機緩入動畫

動態的縮放因子是為了避免彈框占滿整個屏幕,使其稍遠一點,默認是1

// 動態調整相機位置
handlePosition(targetPosition, falg) {// 計算點擊位置與當前相機位置之間的向量const direction = new THREE.Vector3().subVectors(targetPosition, camera.position);// 計算相機與目標位置之間的距離let distance = camera.position.distanceTo(targetPosition);// 以某種方式將距離轉換為縮放因子let scaleFactor = falg ? this.functionOfDistance(distance) : 0;// 縮放向量,使其稍遠一點// const scaleFactor = 0.5; // 縮放因子,可以根據需要進行調整const offset = direction.multiplyScalar(scaleFactor);const finalPosition = camera.position.clone().add(offset);	
},
  • 動態縮放因子的獲取

也不能將縮放因子固定,因為當相近模型點擊時,彈框會越來越近,直至占滿整個屏幕,
所以:設定最小的距離和最大的距離,當模型相對于相機距離遠,就設定縮放因子為0.8,
模型相對相機距離近,就設定縮放因子為0,表示不縮放

//計算距離
functionOfDistance(distance) {// 設定最小和最大距離以及對應的縮放因子(可視情況調整)const minDistance = 4100;const maxDistance = 18000;const minScaleFactor = 0;const maxScaleFactor = 0.8;if (distance < minDistance) {return minScaleFactor;} else if (distance > maxDistance) {return maxScaleFactor;}// 根據距離范圍內的比例,計算縮放因子const ratio = (distance - minDistance) / (maxDistance - minDistance);return minScaleFactor + ratio * (maxScaleFactor - minScaleFactor);
},

5.4 動畫執行

// 創建 Tween 實例
const startPosition = camera.position.clone();
const duration = 1000; // 動畫持續時間,單位毫秒
tween = new TWEEN.Tween(startPosition).to(finalPosition, duration).onUpdate(() => {// 更新相機位置camera.position.copy(startPosition);camera.lookAt(targetPosition);}).start();

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/207191.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/207191.shtml
英文地址,請注明出處:http://en.pswp.cn/news/207191.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Dexie 查詢sql速度優化

Dexie查詢速度慢的原因主要一個優化點是復雜查詢下的count執行。 以下摘自Dexie官方文檔&#xff1a;https://dexie.org/docs/Collection/Collection.count() If executed on simple queries, the native IndexedDB ObjectStore count() method will be called (fast execution…

對標Gen-2!Meta發布新模型,進軍文生視頻賽道

隨著擴散模型的飛速發展&#xff0c;誕生了Midjourney、DALLE 3、Stable Difusion等一大批出色的文生圖模型。但在文生視頻領域卻進步緩慢&#xff0c;因為文生視頻多數采用逐幀生成的方式,這類自回歸方法運算效率低下、成本高。 即便使用先生成關鍵幀,再生成中間幀新方法。如…

Flink Window中典型的增量聚合(ReduceFunction / AggregateFunction)

一、什么是增量聚合函數 在Flink Window中定義了窗口分配器&#xff0c;我們只是知道了數據屬于哪個窗口&#xff0c;可以將數據收集起來了&#xff1b;至于收集起來到底要做什么&#xff0c;其實還完全沒有頭緒&#xff0c;這也就是窗口函數所需要做的事情。所以在窗口分配器…

聽GPT 講Rust源代碼--src/tools(9)

File: rust/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs 在Rust源代碼中&#xff0c;apply_demorgan.rs文件位于rust-analyzer工具的ide-assists庫中&#xff0c;其作用是實現一個輔助函數&#xff0c;用于在代碼中應用De Morgan定律的變換。 …

Android : 籃球記分器app _簡單應用

示例圖&#xff1a; 1.導包 在build.gradle 中 加入 // 使用androidx版本庫implementation androidx.lifecycle:lifecycle-extensions:2.1.0-alpha03 2. 開啟dataBinding android{...// 步驟1.開啟data bindingdataBinding {enabled true}...} 3.寫個類繼承 ViewModel pac…

整數與IP地址間的轉換

原理&#xff1a;ip地址的每段可以看成是一個0-255的整數&#xff0c;把每段拆分成一個二進制形式組合起來&#xff0c;然后把這個二進制數轉變成一個長整數。 舉例&#xff1a;一個ip地址為10.0.3.193 每段數字相對應的二進制數 10 00001010 0 00000000 3 00000011 193 110000…

自下而上-存儲全棧(TiDB/RockDB/SPDK/fuse/ceph/NVMe/ext4)存儲技術專家成長路線

數字化時代的到來帶來了大規模數據的產生&#xff0c;各行各業都面臨著數據爆炸的挑戰。 隨著云計算、物聯網、人工智能等新興技術的發展&#xff0c;對存儲技術的需求也越來越多樣化。不同應用場景對存儲的容量、性能、可靠性和成本等方面都有不同的要求。具備存儲技術知識和技…

機器學習-聚類問題

前言 聚類算法又叫做”無監督分類“&#xff0c;目標是通過對無標記訓練樣本來揭示數據的內在性質及 規律&#xff0c;為進一步的數據分析提供基礎。 Kmeans 作為聚類算法的典型代表&#xff0c;Kmeans可以說是最簡單的聚類算法&#xff0c;沒有之一&#xff0c;那她是怎么完…

MySQL為何偏愛B+樹索引

一、MySQL、B樹概念 MySQL是一種關系型數據庫&#xff0c;它使用SQL語言來操作數據。SQL語言可以實現對數據的增刪改查等操作&#xff0c;但是如果數據量很大&#xff0c;那么這些操作的效率就會很低。為了提高效率&#xff0c;MySQL引入了索引的概念。 索引是一種數據結構&am…

人體關鍵點檢測1:人體姿勢估計數據集

人體關鍵點檢測1&#xff1a;人體姿勢估計數據集 目錄 人體關鍵點檢測1&#xff1a;人體姿勢估計數據集 1.人體姿態估計 2.人體姿勢估計數據集 &#xff08;1&#xff09;COCO數據集 &#xff08;2&#xff09;MPII數據集 &#xff08;3&#xff09;Human3.6M &#xf…

PostgreSQL 主鍵和唯一鍵的區別

主鍵和唯一鍵的區別 主鍵&#xff08;Primary Key&#xff09;&#xff1a; 主鍵是用于唯一標識表中的每一條記錄的鍵。主鍵必須是唯一的&#xff0c;不允許為空。一個表只能有一個主鍵。主鍵可以由一個或多個字段組成。主鍵的值在整個表中必須是唯一的&#xff0c;用于確保數據…

編譯器:swc 究竟比 babel 快在哪里?

前言 swc 與 babel 都是 JavaScript 編譯器&#xff0c;它們的主要功能是將 ES2015 以及 TypeScript, Flow, JSX 等語法轉換為瀏覽器或環境中的向后兼容的 JavaScript 代碼。 哪里快了&#xff1f; 1. 開發語言的優勢 swc 是用 Rust 語言開發的&#xff0c;而 babel 是用 Java…

MS5228/5248/5268:2.7V 到 5.5V、 12/14/16Bit、內置基準、八通道數模轉換器

MS5228/MS5248/MS5268 是一款 12/14/16bit 八通道輸出的電壓型 DAC &#xff0c;內部集成上電復位電路、可選內部基準、接口采用四線串口模式&#xff0c; 最高工作頻率可以到 40MHz &#xff0c;可以兼容 SPI 、 QSPI 、 DSP 接口和 Microwire 串口。輸出接到一個 …

IP地址/16或者/24的意義

IP地址/16或者/24的意義 2023-04-26 16:54 獵手家園 閱讀(533) 評論(0) 編輯 收藏 舉報 當創建VPC專有網絡時&#xff0c;許多人會遇到填寫IPv4地址的情況&#xff0c;通常使用的格式是xxx.xxx.xxx.xxx/16或者xxx.xxx.xxx.xxx/24。那么這個斜杠后面的數字代表什么意思呢&#…

<習題集><LeetCode><鏈表><2/19/21/23/24>

目錄 2. 兩數相加 19. 刪除鏈表的倒數第 N 個結點 21. 合并兩個有序鏈表 23. 合并 K 個升序鏈表 24. 兩兩交換鏈表中的節點 2. 兩數相加 https://leetcode.cn/problems/add-two-numbers/ public ListNode addTwoNumbers(ListNode l1, ListNode l2) {//head是cur鏈表頭節點…

pdf轉png的兩種方法

背景:pdf在一般公司,沒有辦公系統,又不是word/wps/Office系統,讀不出來,識別不了,只能將其轉化為圖片png,因此在小公司或者一般公司就需要pdf轉png的功能。本文將詳細展開。 1、fitz庫(也就是PyMuPDF) 直接pip安裝PyMuPDF即可使用,直接使用fitz操作,無需其他庫。 …

Go語言實現深度學習的正向傳播和反向傳播

文章目錄 開發前言開發理論圖解理論數據類型數學函數數據節點統一抽象變量數據節點常量數據節點單目運算封裝雙目運算封裝算子節點統一抽象基礎算子加法算子減法算子乘法算子除法算子指數算子對數算子正切算子正弦算子余弦算子數據流圖正向傳播反向傳播正向訓練反向訓練運行示例…

我的記事本

url uniform resource locator. 統一資源定位符 請求狀態碼 1XX:信息響應 2XX:成功響應 3XX:重定向消息 4XX:客戶端錯誤響應 5XX:服務器端錯誤響應 IP地址分類 本機回環IP地址&#xff1a;127.0.0.1 &#xff5e; 127.255.255.254 局域網IP(私網IP) 192.168.0.0 &am…

船舶機電設備振動數據采集監控系統解決方案

船舶運行中&#xff0c;通常需要通過振動數據采集系統對船舶的各個機電設備運行進行監控&#xff0c;有助于在設備故障時快速預警&#xff0c;進行診斷、分析和維護&#xff0c;保證船舶機電設備正常工作&#xff0c;從而確保工作人員及船舶的安全。 船舶各種機電設備會產生大…

vLLM介紹

簡介 vLLM 工程github地址 Paged attention論文地址 vLLM開發者介紹 Woosuk Kwon vLLM: A high-throughput and memory-efficient inference and serving engine for LLMs. SkyPilot: A framework for easily and cost effectively running machine learning workloads on …