three.js 鼠标选中模型弹出标签

效果:请关注抖音


 

代码:

<template><div><el-container><el-main><div class="box-card-left"><div id="threejs" style="border: 1px solid red;position: relative;"></div></div></el-main></el-container></div>
</template>
<script>
// 引入轨道控制器扩展库OrbitControls.js
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
// 效果制作器
import { EffectComposer } from "three/examples/jsm/postprocessing/EffectComposer.js";
// 渲染通道
import { RenderPass } from "three/examples/jsm/postprocessing/RenderPass.js";
// 发光描边OutlinePass
import { OutlinePass } from "three/examples/jsm/postprocessing/OutlinePass.js";
import { CSS2DObject, CSS2DRenderer } from "three/examples/jsm/renderers/CSS2DRenderer.js";export default {data() {return {name: "",scene: null,camera: null,renderer: null,css2DRenderer: null,effectComposer: null,mesh: null,geometry: null,group: null,material: null,texture: null,position: null,outlinePass: null,canvasWidth: 1000,canvasHeight: 800,color: [],meshArr: [],};},created() {},mounted() {this.name = this.$route.query.name;this.init();},methods: {goBack() {this.$router.go(-1);},init() {// 思路:有六个模型,分别代表人的头,身体,左右手臂,左右腿;当点击某一个模型时,高亮,并且显示标签名称this.scene = new this.$three.Scene();const axesHelper = new this.$three.AxesHelper(300);this.scene.add(axesHelper);this.group = new this.$three.Group();this.group.translateY(150);this.creatMesh_tou();this.creatMesh_body();this.creatMesh_hand();this.creatMesh_foot();this.scene.add(this.group);// 创建相机对象this.camera = new this.$three.PerspectiveCamera(60,1,0.01,2000);this.camera.position.set(300,300,300);this.camera.lookAt(0,0,0);// 创建渲染器对象this.renderer = new this.$three.WebGLRenderer();this.renderer.setSize(this.canvasWidth, this.canvasHeight);this.renderer.render(this.scene, this.camera);window.document.getElementById("threejs").appendChild(this.renderer.domElement);// this.css2DRenderer = new CSS2DRenderer();this.css2DRenderer.setSize(this.canvasWidth, this.canvasHeight);this.css2DRenderer.render(this.scene, this.camera);this.css2DRenderer.domElement.style.position = "absolute";this.css2DRenderer.domElement.style.top = 0;this.css2DRenderer.domElement.style.pointerEvents = 'none';window.document.getElementById("threejs").appendChild(this.css2DRenderer.domElement);// 创建空间轨道控制器对象const controls = new OrbitControls(this.camera, this.renderer.domElement);controls.addEventListener("change", () => {this.renderer.render(this.scene, this.camera);})this.rayCasterFn();this.effectComposerFn();},renderFun() {// 调用后处理对象的render方法进行渲染,this.effectComposer.render();this.css2DRenderer.render(this.scene, this.camera);window.requestAnimationFrame(this.renderFun);},rayCasterFn() {// 画布添加事件监听document.getElementById("threejs").addEventListener("click", e => {this.scene.traverse(one => {if(one.isCSS2DObject) {this.scene.remove(one);}})// 坐标转换const p_x = e.offsetX;const p_y = e.offsetY;const x = (p_x / this.canvasWidth) * 2 - 1;const y = -(p_y / this.canvasHeight) * 2 + 1;// 创建射线拾取器对象const raycaster = new this.$three.Raycaster();// 射线计算raycaster.setFromCamera(new this.$three.Vector2(x, y), this.camera);// 射线交叉计算const intersects = raycaster.intersectObjects(this.group.children);if(intersects.length > 0) {let obj = intersects[0].object;this.outlinePass.selectedObjects = [obj];let dom = this.createDiv(obj.name);let css2_obj = new CSS2DObject(dom);const wp = new this.$three.Vector3();obj.getWorldPosition(wp)css2_obj.position.set(wp.x, wp.y, wp.z);this.scene.add(css2_obj);this.renderFun();} else {this.outlinePass.selectedObjects = [];}})},effectComposerFn() {// 创建后处理对象this.effectComposer = new EffectComposer(this.renderer);// 创建后处理通道const renderPass = new RenderPass(this.scene, this.camera);this.effectComposer.addPass(renderPass);// 创建发光描边对象this.outlinePass = new OutlinePass(new this.$three.Vector2(this.canvasWidth, this.canvasHeight), this.scene, this.camera);this.outlinePass.edgeStrength = 20;this.outlinePass.edgeThickness = 5;this.outlinePass.visibleEdgeColor.set(0xffaadd);this.outlinePass.pulsePeriod = 2;this.effectComposer.addPass(this.outlinePass);},createDiv(name) {let dom = document.createElement("div");dom.style.padding = '5px 10px';dom.style.border = '1px solid skyblue';dom.style.color = 'red';dom.style.background = '#2FF885';dom.style.borderRadius = '15px';dom.innerHTML = name;// dom.innerHTML = "龙年大吉";return dom;},creatMesh_tou() {const geometry = new this.$three.SphereGeometry(30,64,64);const material = new this.$three.MeshBasicMaterial({color: 0xdfdf});const mesh = new this.$three.Mesh(geometry, material);mesh.name = "头";this.group.add(mesh);},creatMesh_body() {const geometry = new this.$three.BoxGeometry(50,100,80);const material = new this.$three.MeshBasicMaterial({color: 0xdaafdf});const mesh = new this.$three.Mesh(geometry, material);mesh.translateY(-80);mesh.name = "身体";this.group.add(mesh);},creatMesh_hand() {const geometry = new this.$three.BoxGeometry(10,10,120);const material = new this.$three.MeshBasicMaterial({color: 0x11afdf});const mesh = new this.$three.Mesh(geometry, material);mesh.translateY(-60);mesh.translateZ(-100);mesh.name = "右手";this.group.add(mesh);const mesh2 = mesh.clone();mesh2.translateZ(200);mesh2.name = "左手";this.group.add(mesh2);},creatMesh_foot() {const geometry = new this.$three.BoxGeometry(10,190,10);const material = new this.$three.MeshBasicMaterial({color: 0xD63DF0});const mesh = new this.$three.Mesh(geometry, material);mesh.translateY(-220);mesh.translateZ(-30);mesh.name = "右腿";this.group.add(mesh);const mesh2 = mesh.clone();mesh2.translateZ(60);mesh2.name = "左腿";this.group.add(mesh2);},},
};
</script>
//
<style lang="less" scoped>
.box-card-left {display: flex;align-items: flex-start;flex-direction: row;position: relative;width: 100%;.box-right {img{width:500px;user-select: none;}}
}
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/434366.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深入理解Spring EL表达式的高级功能

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 深入理解Spring EL表达式的高级功能 前言使用EL表达式操作集合和数组1. 访问集合元素&#xff1a;2. 数组访问&#xff1a;3. 获取集合或数组的大小&#xff1a;4. 遍历数组的部分元素&#xff1a; 条…

1.25号c++

1.引用 引用就是给变量起别名 格式&#xff1a; 数据类型 &引用名 同类型的变量名 &#xff08;& 引用符号&#xff09; eg: int a 10; int &b a; //b引用a,或者给a变量取个别名叫b int *p; //指针可以先定义 后指向 p &a; //int &a…

解析Go语言中HTTP代理的请求和响应过程

在Go语言中&#xff0c;构建一个HTTP代理服务器其实非常简单。那么&#xff0c;当你发送一个请求给代理服务器时&#xff0c;代理服务器到底做了哪些事情呢&#xff1f; 首先&#xff0c;当你向代理服务器发送一个HTTP请求时&#xff0c;代理服务器会先接收到这个请求。这个请…

YOLOv8训练自己的数据集,通过LabelImg

记录下labelImg标注数据到YOLOv8训练的过程,其中容易遇到labelImg的坑 数据集处理 首先在mydata下创建4个文件夹 images文件夹下存放着所有的图片&#xff0c;包括训练集和测试集等。后续会根据代码进行划分。 json文件夹里存放的是labelImg标注的所有数据。需要注意的是&…

【代码随想录-数组】长度最小的子数组

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学习,不断总结,共同进步,活到老学到老导航 檀越剑指大厂系列:全面总结 jav…

Redis-持久机制

文章目录 为什么有持久化什么是持久化RDB文件创建SAVEBGSAVE 文件载入 优缺点 AOF日志步骤 对比数据恢复 总结 Redis是一个开源的内存数据结构存储系统&#xff0c;被广泛应用于Web应用中&#xff0c;可以用作数据库和缓存服务器。它具有高性能、高并发、高可用性等特点&#x…

ORB-SLAM中的RANSAC算法解析

RANSAC算法解析 RANSAC是一种在具有噪声的模型中去估计最优的一个算法&#xff0c;其核心思想是采用不断迭代的方法去选择一组全是内点的集合&#xff0c;并采用该集合进行模型估计的一种方法&#xff0c;可以提高模型估计的鲁棒性。 假设目前有 K K K组采集到的数据&#xff…

2024年人工智能产业十大发展趋势

2024年人工智能产业十大发展趋势 技术变革1. 多模态预训练大模型将是人工智能产业的标配2. 高质量数据愈发稀缺将倒逼数据智能飞跃3. 智能算力无处不在的计算新范式加速实现 应用创新4. 人工智能生成内容&#xff08;AIGC&#xff09;应用向全场景渗透5. 人工智能驱动科学研究&…

仅使用 Python 创建的 Web 应用程序(前端版本)第07章_商品列表

在本章中,我们将实现一个产品列表页面。 完成后的图像如下 创建过程与User相同,流程如下。 No分类内容1Model创建继承BaseDataModel的数据类Item2MockDB创建产品表并生成/添加虚拟数据3Service创建一个 ItemAPIClient4Page定义PageId并创建继承自BasePage的页面类5Applicati…

ElasticSearch7.7.1集群搭建

前言 Elasticsearch&#xff08;ES&#xff09;是一个基于Apache Lucene的分布式、高扩展、近实时的搜索引擎&#xff0c;主要用于海量数据快速存储、实时检索、高效分析的场景。通过简单易用的RESTful API&#xff0c;Elasticsearch隐藏了Lucene的复杂性&#xff0c;使得全文搜…

DDT数据驱动测试

简单介绍 ​ DDT&#xff08;Date Driver Test&#xff09;&#xff0c;所谓数据驱动测试&#xff0c; 简单来说就是由数据的改变从而驱动自动化测试的执行&#xff0c;最终引起测试结果的改变。通过使用数据驱动测试的方法&#xff0c;可以在需要验证多组数据测试场景中&…

齐俊元或转岗至Flow,童遥升任飞书产品负责人;霍启刚赴天津履职 ;广州放开120平方米以上住房限购

今日精选 • 齐俊元或转岗至Flow&#xff0c;童遥升任飞书产品负责人• 霍启刚赴天津履职• 广州放开120平方米以上住房限购 科技动态 • 年轻人的第一个多模态大模型: Vary-toy ,模型大小不到2B,代码和模型均已开源&#xff0c;并有在线demo可试玩。 地址&#xff1a; htt…