Three.js中如何使用CSS3DRenderer和CSS3DSprite實現模型標簽文字
導語
在Three.js
中,使用CSS3DRenderer
和CSS3DSprite
可以輕松地實現模型標簽文字的效果,為場景中的模型提供更直觀的信息展示。本文將介紹如何使用這兩個工具來實現模型標簽文字,并提供相應的代碼示例。
引言
Three.js
是一款強大的JavaScript 3D
庫,用于在Web上
創(chuàng)建交互式的3D
圖形應用程序。在Three.js
中,CSS3DRenderer
和CSS3DSprite
是兩個重要的工具,它們可以用于在3D
場景中渲染HTML
元素,為用戶提供更豐富的交互體驗。
實現的效果
實現模型標簽文字的步驟
步驟一、導入所需庫
// Three.js庫 import * as THREE from 'three'; // CSS3DRenderer用于渲染CSS3D對象 import { CSS3DRenderer, CSS3DSprite } from "three/examples/jsm/renderers/CSS3DRenderer.js";
步驟二、初始化CSS3DRenderer
const labelRenderer = new CSS3DRenderer(); labelRenderer.setSize(window.innerWidth, window.innerHeight); // 設置渲染器尺寸 labelRenderer.domElement.style.position = 'absolute'; // 設置渲染器樣式 labelRenderer.domElement.style.top = '0'; // 設置渲染器樣式 document.body.appendChild(labelRenderer.domElement); // 將渲染器掛載到頁面上
步驟三、創(chuàng)建css3D標簽
const div = document.createElement('div'); div.className = 'workshop-text'; // 添加樣式類 div.innerHTML = '<p>浮法車間</p>'; // 添加標簽文字
步驟四、創(chuàng)建CSS3DSprite對象
const sprite = new CSS3DSprite(div); sprite.position.set(8, 3, 42); // 設置標簽位置,這里根據模型具體位置調整
步驟五、將CSS3DSprite添加到模型中,并通過GUI控制器控制文字位置
object.add(sprite); // object是模型對象,這里需要替換為實際的模型對象 // 在GUI中添加文件夾用于調整標簽位置 const tagFolder = gui.addFolder('浮法車間標簽'); tagFolder.add(sprite.position, 'x', -200, 200).name('X Position'); // 調整標簽x位置 tagFolder.add(sprite.position, 'y', -200, 200).name('Y Position'); // 調整標簽y位置 tagFolder.add(sprite.position, 'z', -200, 200).name('Z Position'); // 調整標簽z位置 tagFolder.open(); // 打開文件夾,默認顯示控制器
所有代碼:
<template> <!-- 用于展示Three.js場景的HTML容器 --> <div id="my-three"></div> </template> <script setup> import { ref, onMounted, getCurrentInstance } from 'vue' import * as THREE from 'three' // 導入Three.js庫 import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls' // 導入軌道控制器以實現場景的旋轉、縮放等交互 import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'; // 導入GLTF模型加載器 import { GUI } from "three/examples/jsm/libs/lil-gui.module.min.js"; import { CSS3DRenderer, CSS3DSprite } from "three/examples/jsm/renderers/CSS3DRenderer.js"; const { proxy } = getCurrentInstance(); // 獲取當前Vue組件實例 const gui = new GUI(); // 設置cube紋理加載器,立方體紋理加載器 const cubeTextureLoader = new THREE.CubeTextureLoader(); // 設置環(huán)境貼圖 const envMapTexture = cubeTextureLoader.load([ "../../public/posx.jpg", "../../public/negx.jpg", "../../public/posy.jpg", "../../public/negy.jpg", "../../public/posz.jpg", "../../public/negz.jpg", ]); onMounted(() => { document.getElementById('my-three')?.appendChild(renderer.domElement) // 將渲染器的DOM元素掛載到頁面上 init() // 初始化場景、相機和光源 renderModel() // 設置渲染參數 gltfModel1() // 加載GLTF模型 render() // 啟動渲染循環(huán) }) // 定義場景寬度和高度 const width = window.innerWidth, height = window.innerHeight; const scene = new THREE.Scene(); // 創(chuàng)建場景 const renderer = new THREE.WebGLRenderer() // 創(chuàng)建渲染器 const loader = new GLTFLoader(); // 創(chuàng)建GLTF加載器 const camera = new THREE.PerspectiveCamera(45, width / height, 1, 10000); // 創(chuàng)建透視相機 const controls = new OrbitControls(camera, renderer.domElement) // 創(chuàng)建控制器 let glbModel; function init() { // 光源設置 const ambient = new THREE.AmbientLight(0xffffff, 0.5); // 添加環(huán)境光 scene.add(ambient); const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);// 添加平行光 directionalLight.position.set(95, 585, 39); // 設置光源位置 scene.add(directionalLight); //設置相機位置 camera.position.set(-20, 300, 700); // 設置相機位置 //設置相機方向 camera.lookAt(0, 0, 0); // 設置相機朝向場景中心 //輔助坐標軸 const axesHelper = new THREE.AxesHelper(200);//參數200標示坐標系大小,可以根據場景大小去設置 scene.add(axesHelper); // 設置場景背景色 // scene.background = envMapTexture; // 設置渲染器像素比,適應設備分辨率 renderer.setPixelRatio(window.devicePixelRatio); renderer.antialias = true; // 初始化 GUI 控件 const camFolder = gui.addFolder('Camera'); camFolder.add(camera.position, 'x', -6500, 6500, 10).name('X Axis'); camFolder.add(camera.position, 'y', -6500, 6500, 10).name('Y Axis'); camFolder.add(camera.position, 'z', -6500, 6500, 10).name('Z Axis'); camFolder.open(); const lightFolder = gui.addFolder('Light'); lightFolder.add(directionalLight.position, 'x', -6500, 6500).name('X Axis'); lightFolder.add(directionalLight.position, 'y', -6500, 6500).name('Y Axis'); lightFolder.add(directionalLight.position, 'z', -6500, 6500).name('Z Axis'); lightFolder.add(directionalLight, 'intensity', 0, 1).name('Intensity'); lightFolder.open(); // 設置渲染器參數 renderer.setPixelRatio(window.devicePixelRatio); renderer.setSize(window.innerWidth, window.innerHeight); renderer.toneMapping = THREE.ACESFilmicToneMapping; renderer.toneMappingExposure = 2.5; // 初始化 CSS3DRenderer const labelRender = new CSS3DRenderer(); labelRender.setSize(window.innerWidth, window.innerHeight); labelRender.domElement.style.position = 'absolute'; labelRender.domElement.style.top = '0px'; labelRender.domElement.style.pointerEvents = 'none'; document.getElementById('my-three').appendChild(labelRender.domElement); proxy.labelRender = labelRender; // 更新控制器 controls.update(); } function gltfModel1() { // 加載GLTF模型 loader.load("../../public/yuanqu.glb", function (gltf) { // 模型加載完成后的回調函數 glbModel = gltf.scene; scene.add(gltf.scene) // 將模型添加到場景中 glbModel.traverse((object) => { if (object.name === "fufachejian") { const div = document.createElement('div'); div.className = 'workshop-text'; div.innerHTML = '<p>浮法車間</p>'; // 創(chuàng)建CSS3DSprite const tag = new CSS3DSprite(div); tag.position.set(8, 3, 42); // 調整標簽位置 object.add(tag); // 在GUI中添加一個用于調整tag位置的文件夾 // const tagFolder = gui.addFolder('浮法車間標簽'); // // 將tag.position對象中的x, y, z屬性添加到GUI中 // tagFolder.add(tag.position, 'x', -200, 200).name('X Position'); // tagFolder.add(tag.position, 'y', -200, 200).name('Y Position'); // tagFolder.add(tag.position, 'z', -200, 200).name('Z Position'); // tagFolder.open(); // 打開此文件夾以默認顯示控制器 } if (object.name === "bangongqu") { const div = document.createElement('div'); div.className = 'workshop-text'; div.innerHTML = '<p>辦公樓</p>'; // 創(chuàng)建CSS3DSprite const tag = new CSS3DSprite(div); tag.position.set(8, 3, 78); // 調整標簽位置 object.add(tag); // 在GUI中添加一個用于調整tag位置的文件夾 // const tagFolder = gui.addFolder('辦公區(qū)標簽'); // // 將tag.position對象中的x, y, z屬性添加到GUI中 // tagFolder.add(tag.position, 'x', -200, 200).name('X Position'); // tagFolder.add(tag.position, 'y', -200, 200).name('Y Position'); // tagFolder.add(tag.position, 'z', -200, 200).name('Z Position'); // tagFolder.open(); // 打開此文件夾以默認顯示控制器 } if (object.name === "qiye_01") { const div = document.createElement('div'); div.className = 'workshop-text'; div.innerHTML = '<p>企業(yè)1</p>'; // 創(chuàng)建CSS3DSprite const tag = new CSS3DSprite(div); tag.position.set(8, 3, 38); // 調整標簽位置 object.add(tag); } if (object.name === "qiye_002") { const div = document.createElement('div'); div.className = 'workshop-text'; div.innerHTML = '<p>企業(yè)2</p>'; // 創(chuàng)建CSS3DSprite const tag = new CSS3DSprite(div); tag.position.set(12, 5, 54); // 調整標簽位置 object.add(tag); // 在GUI中添加一個用于調整tag位置的文件夾 // const tagFolder = gui.addFolder('qiye--------'); // // 將tag.position對象中的x, y, z屬性添加到GUI中 // tagFolder.add(tag.position, 'x', -200, 200).name('X Position'); // tagFolder.add(tag.position, 'y', -200, 200).name('Y Position'); // tagFolder.add(tag.position, 'z', -200, 200).name('Z Position'); // tagFolder.open(); // 打開此文件夾以默認顯示控制器 } if (object.name === "chejian_06") { const div = document.createElement('div'); div.className = 'workshop-text'; div.innerHTML = '<p>車間6</p>'; // 創(chuàng)建CSS3DSprite const tag = new CSS3DSprite(div); tag.position.set(8, 3, 38); // 調整標簽位置 object.add(tag); // 在GUI中添加一個用于調整tag位置的文件夾 // const tagFolder = gui.addFolder('食堂標簽'); // // 將tag.position對象中的x, y, z屬性添加到GUI中 // tagFolder.add(tag.position, 'x', -200, 200).name('X Position'); // tagFolder.add(tag.position, 'y', -200, 200).name('Y Position'); // tagFolder.add(tag.position, 'z', -200, 200).name('Z Position'); // tagFolder.open(); // 打開此文件夾以默認顯示控制器 } if (object.name === "chejian_03") { const div = document.createElement('div'); div.className = 'workshop-text'; div.innerHTML = '<p>倉庫3</p>'; // 創(chuàng)建CSS3DSprite const tag = new CSS3DSprite(div); tag.position.set(8, 3, 38); // 調整標簽位置 object.add(tag); // 在GUI中添加一個用于調整tag位置的文件夾 // const tagFolder = gui.addFolder('食堂標簽'); // // 將tag.position對象中的x, y, z屬性添加到GUI中 // tagFolder.add(tag.position, 'x', -200, 200).name('X Position'); // tagFolder.add(tag.position, 'y', -200, 200).name('Y Position'); // tagFolder.add(tag.position, 'z', -200, 200).name('Z Position'); // tagFolder.open(); // 打開此文件夾以默認顯示控制器 } if (object.name === "chejian_02") { const div = document.createElement('div'); div.className = 'workshop-text'; div.innerHTML = '<p>倉庫2</p>'; // 創(chuàng)建CSS3DSprite const tag = new CSS3DSprite(div); tag.position.set(8, 3, 38); // 調整標簽位置 object.add(tag); // 在GUI中添加一個用于調整tag位置的文件夾 // const tagFolder = gui.addFolder('食堂標簽'); // // 將tag.position對象中的x, y, z屬性添加到GUI中 // tagFolder.add(tag.position, 'x', -200, 200).name('X Position'); // tagFolder.add(tag.position, 'y', -200, 200).name('Y Position'); // tagFolder.add(tag.position, 'z', -200, 200).name('Z Position'); // tagFolder.open(); // 打開此文件夾以默認顯示控制器 } if (object.name === "chejian_01") { const div = document.createElement('div'); div.className = 'workshop-text'; div.innerHTML = '<p>倉庫1</p>'; // 創(chuàng)建CSS3DSprite const tag = new CSS3DSprite(div); tag.position.set(8, 3, 38); // 調整標簽位置 object.add(tag); // 在GUI中添加一個用于調整tag位置的文件夾 // const tagFolder = gui.addFolder('食堂標簽'); // // 將tag.position對象中的x, y, z屬性添加到GUI中 // tagFolder.add(tag.position, 'x', -200, 200).name('X Position'); // tagFolder.add(tag.position, 'y', -200, 200).name('Y Position'); // tagFolder.add(tag.position, 'z', -200, 200).name('Z Position'); // tagFolder.open(); // 打開此文件夾以默認顯示控制器 } if (object.name === "yuanliaolou") { const div = document.createElement('div'); div.className = 'workshop-text'; div.innerHTML = '<p>原料樓</p>'; // 創(chuàng)建CSS3DSprite const tag = new CSS3DSprite(div); tag.position.set(-10, -1, 38); // 調整標簽位置 object.add(tag); // 在GUI中添加一個用于調整tag位置的文件夾 const tagFolder = gui.addFolder('食堂標簽'); } if (object.name === "qizhan") { const div = document.createElement('div'); div.className = 'workshop-text'; div.innerHTML = '<p>氣站</p>'; // 創(chuàng)建CSS3DSprite const tag = new CSS3DSprite(div); tag.position.set(-10, -1, 20); // 調整標簽位置 object.add(tag); // 在GUI中添加一個用于調整tag位置的文件夾 // const tagFolder = gui.addFolder('食堂標簽'); } if (object.name === "yuanpian") { const div = document.createElement('div'); div.className = 'workshop-text'; div.innerHTML = '<p>原片倉庫</p>'; // 創(chuàng)建CSS3DSprite const tag = new CSS3DSprite(div); tag.position.set(-6, 7, 30); // 調整標簽位置 object.add(tag); } if (object.name === "yuchuli002" || object.name === "yuchuli003" || object.name === "yuchuli") { const div = document.createElement('div'); div.className = 'workshop-text'; if (object.name === "yuchuli002") { div.innerHTML = '<p>預處理車間1</p>'; } else if(object.name === "yuchuli003") { div.innerHTML = '<p>預處理車間2</p>'; }else if(object.name === "yuchuli"){ div.innerHTML = '<p>預處理車間1</p>'; } // 創(chuàng)建CSS3DSprite const tag = new CSS3DSprite(div); tag.position.set(-6, 7, 30); // 調整標簽位置 object.add(tag); } }) }, function (xhr) { // 加載進度回調 const percent = Math.floor((xhr.loaded / xhr.total) * 100); // 計算加載進度百分比 // console.log(`模型加載進度:${percent}%`); } ) } function renderModel() { //渲染 renderer.setSize(width, height)//設置渲染區(qū)尺寸 renderer.render(scene, camera)//執(zhí)行渲染操作、指定場景、相機作為參數 // renderer.setClearColor(0x00ff00); // 設置背景顏色為綠色/ renderer.toneMapping = THREE.ACESFilmicToneMapping; // 設置曝光度 renderer.toneMappingExposure = 3; // 適當調整曝光度 // 設置控制器的角度限制 controls.minPolarAngle = Math.PI / 4; // 最小極角為 45 度 controls.maxPolarAngle = Math.PI / 2; // 最大極角為 90 度 } //渲染循環(huán)函數 function render() { renderer.render(scene, camera); // 執(zhí)行渲染操作 controls.update() // 更新控制器 proxy.labelRender.render(scene, camera); // 渲染 CSS3D 標簽 requestAnimationFrame(render); // 請求下一幀 } // 畫布跟隨窗口變化 window.onresize = function () { renderer.setSize(window.innerWidth, window.innerHeight); // 重設渲染器尺寸 camera.aspect = window.innerWidth / window.innerHeight; // 更新相機的長寬比 camera.updateProjectionMatrix(); // 更新相機的投影矩陣 }; window.addEventListener('keydown', function (event) { switch (event.key) { case 'ArrowLeft': // 按左箭頭鍵 moveLeft(); break; case 'ArrowRight': // 按右箭頭鍵 moveRight(); break; } }); // 交互事件 addEventListener('dblclick', onMouseDblclick, false) function onMouseDblclick(event) { console.log("event") let intersects = getIntersects(event); if (intersects.length !== 0 && intersects[0].object instanceof THREE.Mesh) { const selectedObject = intersects[0].object; let selectedObjects = []; selectedObjects.push(selectedObject); console.log(selectedObjects) // outlinePass.selectedObjects = selectedObjects; } } function moveLeft() { if (glbModel) { glbModel.position.x -= 10; // 向左移動10單位 } } function moveRight() { if (glbModel) { glbModel.position.x += 10; // 向右移動10單位 } } //獲取與射線相交的對象數組 function getIntersects(event) { let rayCaster = new THREE.Raycaster(); let mouse = new THREE.Vector2(); //通過鼠標點擊位置,計算出raycaster所需點的位置,以屏幕為中心點,范圍-1到1 mouse.x = (event.clientX / window.innerWidth) * 2 - 1; mouse.y = -(event.clientY / window.innerHeight) * 2 + 1; //這里為什么是-號,沒有就無法點中 //通過鼠標點擊的位置(二維坐標)和當前相機的矩陣計算出射線位置 rayCaster.setFromCamera(mouse, camera); return rayCaster.intersectObjects(scene.children); } </script> <style> .workshop-text {} .workshop-text p { font-size: 0.9rem; font-weight: bold; padding: 10px; color: #0ff; } #tag { padding: 0px 10px; border: #00ffff solid 1px; height: 40px; border-radius: 5px; width: 65px; } </style>
效果:
到此這篇關于在Three.js中使用CSS3DRenderer和CSS3DSprite實現模型標簽文字的文章就介紹到這了,更多相關Three.js模型標簽文字內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
javascript對下拉列表框(select)的操作實例講解
這篇文章主要介紹了javascript對下拉列表框(select)的操作。需要的朋友可以過來參考下,希望對大家有所幫助2013-11-11