当前位置: 首页 > news >正文

CSS3DRenderer+ CSS3DObject实现在 Three.js 中添加文本内容

相关 API CSS3DObject,CSS3DRenderer

这里通过 CSS3DObjectCSS3DRenderer 这两个api来创建和渲染3d标签。

1.CSS3DObject:CSS3DObject是Three.js中用于表示一个CSS元素的类。通过创建一个CSS3DObject,你可以将一个普通的DOM元素嵌入到Three.js的3D场景中。你可以通过CSS3DObject的element属性来访问和操作对应的DOM元素,比如设置样式、添加事件监听器等。CSS3DObject可以在3D空间中进行变换、旋转和缩放,与其他3D对象一起渲染在屏幕上。

2.CSS3DRenderer:CSS3DRenderer是Three.js中用于渲染CSS3DObject的渲染器。它负责将CSS3DObject转换为在3D场景中正确显示的2D元素。CSS3DRenderer会根据CSS3DObject的位置、旋转和缩放等属性,将对应的DOM元素进行变换并渲染到屏幕上。通过使用CSS3DRenderer,你可以在Three.js的3D场景中实现与普通的HTML/CSS元素交互。

创建3D文本渲染器

通过 CSS3DRenderer 创建一个3d文本渲染器

注意:这里需要创建两个渲染 WebGLRenderer 用来渲染3d场景,CSS3DRenderer 用来渲染3D文本

	// 创建渲染器initRender() {this.renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true, preserveDrawingBuffer: true }) //设置抗锯齿//设置屏幕像素比this.renderer.setPixelRatio(window.devicePixelRatio)//渲染的尺寸大小const { clientHeight, clientWidth } = this.containerthis.renderer.setSize(clientWidth, clientHeight)this.container.appendChild(this.renderer.domElement)// 创建一个CSS3DRendererthis.css3DRenderer = new CSS3DRenderer();this.css3DRenderer.setSize(clientWidth, clientHeight);this.css3DRenderer.domElement.style.position = 'absolute';this.css3DRenderer.domElement.style.pointerEvents = 'none';this.css3DRenderer.domElement.style.top = 0;this.container.appendChild(this.css3DRenderer.domElement);}

创建3D文本标签方法

将创建3D文本标签的方法单独抽离在一个函数中去 create3dTags , 传入三个参数 clientX(鼠标拖拽结束时的X坐标), clientY(鼠标拖拽结束时的X坐标), name(当前element-plus icon组件的name)’

1.这里通过 THREE.Raycaster() 检测鼠标在三维场景中的位置(x,y,z)
2.通过Vue3 jsx语法的 render 函数和 createApp 方法 创建3D文本节点
3.通过 CSS3DObject 创建一个可以在3D场景中展示的元素
4.将获取到的鼠标坐标 (x,y,z) 赋值给 CSS3DObject 创建的文本标签
5.最后通过 scene.add(cssObject) 添加到场景中去

import { CSS3DObject } from 'three/addons/renderers/CSS3DRenderer.js';
import { ElIcon, ElMessage } from 'element-plus';
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
import { h, createApp } from "vue";function create3dTags(clientX, clientY, name) {const { clientHeight, clientWidth, offsetLeft, offsetTop } = this.container// 计算鼠标在屏幕上的坐标this.mouse.x = ((clientX - offsetLeft) / clientWidth) * 2 - 1this.mouse.y = -((clientY - offsetTop) / clientHeight) * 2 + 1const raycaster = THREE.Raycaster()raycaster.setFromCamera(this.mouse, this.camera);const intersects = raycaster.intersectObjects(this.scene.children, true);if (intersects.length > 0) {var element = document.createElement('div');// 创建容器标签const backgroundColor = 'rgba(0,127,127,' + (Math.random() * 0.5 + 0.25) + ')'const len = this.dragTagList.length + 1// 创建3d标签const tagvMode = createApp({render() {return (<div><div className="element-tag"style={{ width: 60 + 'px', height: 40 + 'px', fontSize: 6 + 'px', color: '#ffffffbf', backgroundColor }}><span className='tag-txt'>{`标签-${len}`}</span></div><div className='tag-icon' ><ElIcon >{h(ElementPlusIconsVue[name])}</ElIcon></div></div>)}});const vNode = tagvMode.mount(document.createElement('div'))element.appendChild(vNode.$el)var cssObject = new CSS3DObject(element);// 获取到鼠标坐标const { x, y, z } = intersects[0].pointcssObject.position.set(x, y, z);cssObject.scale.set(.01, .01, .01)this.scene.add(cssObject)} else {ElMessage.warning('当前角度无法获取鼠标位置请调整“相机角度”在添加')}
}

手动调用 create3dTags 方法

调用多次创建不同icon的文本标签

create3dTags(100,444,"More")
create3dTags(120,644,"MuteNotification")
create3dTags(200,544,"RemoveFilled")
create3dTags(200,144,"Document")
create3dTags(150,744,"FolderAdd")
create3dTags(300,54,"KnifeFork")

在这里插入图片描述

定义拖拽方法实现拖拽添加

1.这里使用的是H5的拖拽API来实现的,dragstart,drag,drop
2.获取到 ElementPlusIconsVue 中所有图标的 name
3.拖拽结束在 drop 函数中获取当前鼠标的坐标
4.调用 create3dTags 方法 实现拖拽创建文本标签

<template><el-scrollbar max-height="150px"><el-row class="tag-row"><el-col draggable="true" v-for="tag in tagList" :key="tag.name" :span="4" @dragstart="(e) => onDragstart(e, tag)" @drag="(e) => onDrag(e)">					<div class="tag-box"><div class="icon"><el-icon size="16px"><component :is="tag.name"></component></el-icon></div></div></el-col></el-row></el-scrollbar><div id="model" @drop="dropEnd" ref="model" @dragover.prevent>  </div>
</template><script setup>
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
import { useMeshEditStore } from '@/store/meshEditStore'
import {ref} from 'vue'const store = useMeshEditStore();
const tagList = computed(() => {const arr = []for (const [key] of Object.entries(ElementPlusIconsVue)) {arr.push({ name: key })}return arr
})const dragTag = ref(null)// 拖拽开始
const onDragstart = (e, tag) => {dragTag.value = tag.name
};
// 拖拽中
const onDrag = (event) => {event.preventDefault();
};// 拖拽结束
const dropEnd = (event) => {const { clientX, clientY } = estore.modelApi.create3dTags(clientX,clientY,dragTag.value);
};
</script>

在这里插入图片描述

新增标签参数更新方法,实现标签内容自定义

在标签创建成功之后,我们可能需要动态的修改文本的相关信息如:文字颜色,背景颜色,图标大小,文本高度,文本宽度等信息。

为了让这个3d文本标签更加的灵活化,这里通过新增 updateTagElement 方法来实现

1.通过 getObjectByProperty 传入 uuid 获取到当前文本节点的内容
2.通过 querySelector 获取到需要改变的元素节点信息
3.将传入的参数赋值给对应元素的内容

import TWEEN from "@tweenjs/tween.js";
function updateTagElement(tag) {const object = this.scene.getObjectByProperty('uuid', tag.uuid)if (object) {const element = object.element.querySelector('.element-tag')const iconElement = object.element.querySelector('.tag-icon')const txtElement = object.element.querySelector('.tag-txt')const { height, backgroundColor, width,fontSize, color, innerText, iconColor,iconSize, positionY, positionX, positionZ } = tagelement.style.height = height + 'px'element.style.backgroundColor = backgroundColorelement.style.boxShadow = `0px 0px 4px ${backgroundColor}`element.style.width = width + 'px'element.style.fontSize = fontSize + 'px'element.style.color = colortxtElement.innerText = innerTexticonElement.style.fontSize = iconSize + 'px'iconElement.style.color = iconColor// 修改坐标位置const Tween = new TWEEN.Tween(object.position)const endPosition = {x: positionX,y: positionY,z: positionZ}Tween.to(endPosition, 500)Tween.onUpdate((val) => {object.position.set(val.x || 0, val.y || 0, val.z || 0)})Tween.start();}}

在这里插入图片描述

结语

ok这样一个有手就行的Three.js拖拽添加和更新3D文本标签的功能就实现了

如果你有更好的方法欢迎评论区留言交流讨论

完整的功能代码地址可参考

gitee:https://gitee.com/ZHANG_6666/Three.js3D

http://www.dtcms.com/a/340600.html

相关文章:

  • 算法230. 二叉搜索树中第 K 小的元素
  • 10M25DCF484C8G Altera FPGA MAX10
  • 云原生俱乐部-RH294知识点归纳(1)
  • RK-Android11-PackageInstaller安装器自动安装功能实现
  • iOS App 混淆工具实战 医疗健康类 App 的安全与合规保护
  • 电脑驱动免费更新? 这款驱动管理工具:一键扫更新,还能备份恢复,小白也会用~
  • 【知识杂记】方差、标准差、均方误差、均方根误差与平均绝对误差,概念、计算公式、物理意义
  • 微型导轨的快速调平技术如何提升激光加工效率?
  • Python默认参数
  • CPTS--Administrator
  • 【clion】调试脚本并cmake构建Fargo项目win32版本
  • Spring Boot 配置
  • C++---向下取整(>>)与向零取整(/)
  • Vue2封装Axios
  • PyTorch - Developer Notes
  • 《录井工程与管理》——第二章井位勘测技术
  • 精品方案 | GCKontrol与OMNeT++联合仿真在机载网络性能分析中的应用
  • 基于单片机环境火灾安全检测
  • 驾驭复杂表单:用 RxJava 实现响应式表单处理
  • mysql-8.0.37-linux-glibc2.12-x86_64安装
  • 数据结构与算法系列(大白话模式)小学生起点(一)
  • 【Kafka】常见简单八股总结
  • 【39】OpenCV C++实战篇——直线拟合、直线测距、平行线段测距;(边缘检测,剔除噪点,轮廓检测,渐进概率霍夫直线)
  • ReAct Agent:让AI像人类一样思考与行动的革命性框架
  • 01_Go语言基础与环境搭建
  • 【自记】Power BI 中 ALLNOBLANKROW的适用场景举例
  • 如何选择汽车ECU的加密方法
  • docker 部署
  • 千康BOH是店易开吗?怎么和金蝶云、用友BIP、鼎捷等ERP集成?
  • 趣打印高级版--手机打印软件!软件支持多种不同的连接方式,打印神器有这一个就够了!