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

141. Sprite标签(Canvas作为贴图)

上节课案例创建标签的方式,是把一张图片作为Sprite精灵模型的颜色贴图,本节给大家演示把Canvas画布作为Sprite精灵模型的颜色贴图,实现一个标签。

注意:本节课主要是技术方案讲解,默认你有Canvas基础,如果没有Canvas基础,可以学习之后再来学习本节课内容。

Canvas画布绘制一个标签

你可以使用Canvas绘制特定轮廓的标签,比如加上指引线或箭头,可以输入特定文字。

下面代码自动适配了不同长度的文字标注,文字符号越多,canvas画布越长。

// 生成一个canvas对象,标注文字为参数name
function createCanvas(name) {/*** 创建一个canvas对象,绘制几何图案或添加文字*/const canvas = document.createElement("canvas");const arr = name.split(""); //分割为单独字符串let num = 0;const reg = /[\u4e00-\u9fa5]/;for (let i = 0; i < arr.length; i++) {if (reg.test(arr[i])) { //判断是不是汉字num += 1;} else {num += 0.5; //英文字母或数字累加0.5}}// 根据字符串符号类型和数量、文字font-size大小来设置canvas画布宽高度const h = 80; //根据渲染像素大小设置,过大性能差,过小不清晰const w = h + num * 32;canvas.width = w;canvas.height = h;const h1 = h * 0.8;const c = canvas.getContext('2d');// 定义轮廓颜色,黑色半透明c.fillStyle = "rgba(0,0,0,0.5)";// 绘制半圆+矩形轮廓const R = h1 / 2;c.arc(R, R, R, -Math.PI / 2, Math.PI / 2, true); //顺时针半圆c.arc(w - R, R, R, Math.PI / 2, -Math.PI / 2, true); //顺时针半圆c.fill();// 绘制箭头c.beginPath();const h2 = h - h1;c.moveTo(w / 2 - h2 * 0.6, h1);c.lineTo(w / 2 + h2 * 0.6, h1);c.lineTo(w / 2, h);c.fill();// 文字c.beginPath();c.translate(w / 2, h1 / 2);c.fillStyle = "#ffffff"; //文本填充颜色c.font = "normal 32px 宋体"; //字体样式设置c.textBaseline = "middle"; //文本与fillText定义的纵坐标c.textAlign = "center"; //文本居中(以fillText定义的横坐标)c.fillText(name, 0, 0);return canvas;
}
const canvas = createCanvas('设备A')

CanvasTexture把canvas转化为纹理对象

canvas画布作为CanvasTexture的参数创建一个纹理对象,本质上你可以理解为CanvasTexture把canvas画布当做图片,读取参数canvas画布上的像素值,创建纹理贴图Texture

loader.load("../工厂.glb", function (gltf) {model.add(gltf.scene);const canvas = createCanvas('设备A');//创建一个canvas画布// canvas画布作为CanvasTexture的参数创建一个纹理对象// 本质上你可以理解为CanvasTexture读取参数canvas画布上的像素值const texture = new THREE.CanvasTexture(canvas);const spriteMaterial = new THREE.SpriteMaterial({map: texture,});const sprite = new THREE.Sprite(spriteMaterial);
})

精灵模型尺寸和位置设置

精灵模型尺寸和位置设置具体思路可以参考上节课讲解。

注意精灵模型宽高比和canvas画布宽高比保持一致即可。

const y = 4;//精灵y方向尺寸
// sprite宽高比和canvas画布保持一致
const x = canvas.width/canvas.height*y;//精灵x方向尺寸
sprite.scale.set(x, y, 1);// 控制精灵大小
sprite.position.y = y / 2; //标签底部箭头和空对象标注点重合  
const obj = gltf.scene.getObjectByName('设备A标注'); // obj是建模软件中创建的一个空对象
obj.add(sprite); //tag会标注在空对象obj对应的位置

cavnas精灵标签封装(标注多个)

封装一个创建cavnas精灵标签的函数,可以根据需要调用,标注任何需要标注的地方。

import * as THREE from 'three';
import createCanvas from './canvas';
// 标注位置对应的模型对象obj
// name:标注文字
function createSprite(obj,name) {const canvas = createCanvas(name);//创建一个canvas画布// canvas画布作为CanvasTexture的参数创建一个纹理对象const texture = new THREE.CanvasTexture(canvas);const spriteMaterial = new THREE.SpriteMaterial({map: texture,});const sprite = new THREE.Sprite(spriteMaterial);// 控制精灵大小(sprite宽高比和canvas画布保持一致)const s = 0.05;//通过canvas宽高度缩放后,设置sprite.scale,避免图文宽高比变形const x = canvas.width*s;const y = canvas.height*s;sprite.scale.set(x, y, 1);sprite.position.y = y / 2; //标签底部箭头和空对象标注点重合  obj.add(sprite); //tag会标注在空对象obj对应的位置
}export default createSprite;

Canvas包含外部图片

如果Canvas包含外部图片作为背景,注意创建CanvasTexture的时候,不管你的代码结构怎么组织,主要要等图像加载完成再执行THREE.CanvasTexture(canvas),如果还未加载完成,创建纹理时候,读取画布像素时候,会不包含图片。

// 生成一个canvas对象,标注文字为参数name
function createCanvas(img,name) {/*** 创建一个canvas对象,绘制几何图案或添加文字*/const canvas = document.createElement("canvas");const w = 140; //根据渲染像素大小设置,过大性能差,过小不清晰const h = 80;canvas.width = w;canvas.height = h;const h1 = h * 0.8;const c = canvas.getContext('2d');c.fillStyle = "rgba(0,0,0,0.0)"; //背景透明c.fillRect(0, 0, w, h);c.drawImage(img, 0, 0, w, h);//图片绘制到canvas画布上// 文字c.beginPath();c.translate(w / 2, h1 / 2);c.fillStyle = "#ffffff"; //文本填充颜色c.font = "normal 32px 宋体"; //字体样式设置c.textBaseline = "middle"; //文本与fillText定义的纵坐标c.textAlign = "center"; //文本居中(以fillText定义的横坐标)c.fillText(name, 0, 0);return canvas;
}
  const img = new Image();img.src = "./标签箭头背景.png";img.onload = function () {const canvas = createCanvas(img,'设备A');//创建一个canvas画布// 图片加载完成后,读取canvas像素数据创建CanvasTextureconst texture = new THREE.CanvasTexture(canvas);...const sprite = new THREE.Sprite(spriteMaterial);...}

相关文章:

141. Sprite标签(Canvas作为贴图)

上节课案例创建标签的方式&#xff0c;是把一张图片作为Sprite精灵模型的颜色贴图,本节给大家演示把Canvas画布作为Sprite精灵模型的颜色贴图&#xff0c;实现一个标签。 注意&#xff1a;本节课主要是技术方案讲解&#xff0c;默认你有Canvas基础&#xff0c;如果没有Canvas基…...

【IDEA】解决总是自动导入全部类(.*)问题

文章目录 问题描述解决方法 我是一名立志把细节说清楚的博主&#xff0c;欢迎【关注】&#x1f389; ~ 原创不易&#xff0c; 如果有帮助 &#xff0c;记得【点赞】【收藏】 哦~ ❥(^_-)~ 如有错误、疑惑&#xff0c;欢迎【评论】指正探讨&#xff0c;我会尽可能第一时间回复…...

python中的OS模块的基本使用

&#x1f389;&#x1f389;&#x1f389;欢迎来到我的博客,我是一名自学了2年半前端的大一学生,熟悉的技术是JavaScript与Vue.目前正在往全栈方向前进, 如果我的博客给您带来了帮助欢迎您关注我,我将会持续不断的更新文章!!!&#x1f64f;&#x1f64f;&#x1f64f; 文章目录…...

【Qt】QComboBox设置默认显示为空

需求 使用QComboBox&#xff0c;遇到一个小需求是&#xff0c;想要设置未点击出下拉列表时&#xff0c;内容显示为空。并且不想在下拉列表中添加一个空条目。 实现 使用setPlaceholderText()接口。我们先来看下帮助文档&#xff1a; 这里说的是&#xff0c;placeholderText是…...

LeetCode - #139 单词拆分

文章目录 前言摘要1. 描述2. 示例3. 答案题解动态规划的思路代码实现代码解析1. **将 wordDict 转换为 Set**2. **初始化 DP 数组**3. **状态转移方程**4. **返回结果** **测试用例**示例 1:示例 2:示例 3: 时间复杂度空间复杂度总结关于我们 前言 本题由于没有合适答案为以往遗…...

服务器作业4

[rootlocalhost ~]# vim 11.sh #关闭防火墙 systemctl stop firewalld setenforce 0 #1.接收用户部署的服务名称 read -p "服务名称:(nginx)" server_name if [ $server_name ! nginx ];then echo "输入的不是nginx,脚本退出" exit 1 fi # 判断是…...

IOC控制反转---相关的介绍和6大注解解读(类注解+方法注解)

文章目录 1.传统方式造车2.传统方法的弊端3.IOC的引入3.IOC对于图书管理系统进行改进&#xff08;初识&#xff09;4.注解的使用说明4.1controller注解4.2service注解4.3component注解4.4关于spring命名的问题4.5component重命名4.6repository注解4.7configuration注解4.8注解之…...

SpringBoot(8)-任务

目录 一、异步任务 二、定时任务 三、邮件任务 一、异步任务 使用场景&#xff1a;后端发送邮件需要时间&#xff0c;前端若响应不动会导致体验感不佳&#xff0c;一般会采用多线程的方式去处理这些任务&#xff0c;但每次都需要自己去手动编写多线程来实现 1、编写servic…...

【机器学习】如何配置anaconda环境(无脑版)

马上就要上机器学习的实验&#xff0c;这里想写一下我配置机器学习的anaconda环境的二三事 一、首先&#xff0c;下载安装包&#xff1a; Download Now | Anaconda 二、打开安装包&#xff0c;一直点NEXT进行安装 这里要记住你要下载安装的路径在哪&#xff0c;后续配置环境…...

java 可以跨平台的原因是什么?

我们对比一个东西就可以了&#xff0c;那就是chrome浏览器。 MacOS/Linux/Windows上的Chrome浏览器&#xff0c;那么对于HTML/CSS/JS的渲染效果都一样的。 我们就可以认为ChromeHTML/CSS/JS是跨平台的。 这里面&#xff0c;HTML/CSS/JS是不变的的&#xff0c;对于一个网页&a…...

Solana应用开发常见技术栈

编程语言 Rust Rust是Solana开发中非常重要的编程语言。它具有高性能、内存安全的特点。在Solana智能合约开发中&#xff0c;Rust可以用于编写高效的合约代码。例如&#xff0c;Rust的所有权系统可以帮助开发者避免常见的内存错误&#xff0c;如悬空指针和数据竞争。通过合理利…...

npm | Yarn | pnpm Node.js包管理器比较与安装

一、包管理器比较 参考原文链接&#xff1a; 2024 Node.js Package Manager 指南&#xff1a;npm、Yarn、pnpm 比较 — 2024 Node.js Package Manager Guide: npm, Yarn, pnpm Compared (nodesource.com) 以下是对 Node.js 的三个包管理工具 npm、Yarn 和 pnpm 的优缺点总结&am…...

Linux下编译MFEM

本文记录在Linux下编译MFEM的过程。 零、环境 操作系统Ubuntu 22.04.4 LTSVS Code1.92.1Git2.34.1GCC11.4.0CMake3.22.1Boost1.74.0oneAPI2024.2.1 一、安装依赖 二、编译代码 附录I: CMakeUserPresets.json {"version": 4,"configurePresets": [{&quo…...

【团购核销】抖音生活服务商家应用快速接入②——商家授权

文章目录 一、前言二、授权流程三、授权Url3.1 Url参数表3.2 授权能力表3.3 源码示例 四、授权回调4.1 添加授权回调接口4.2 授权回调接口源码示例 五、实际操作演示六、参考 一、前言 目的&#xff1a;将抖音团购核销的功能集成到我们自己开发的App和小程序中 【团购核销】抖音…...

django宠物服务管理系统

摘 要 宠物服务管理系统是一种专门为宠物主人和宠物服务提供商设计的软件。它可以帮助用户快速找到附近的宠物医院、宠物美容店、宠物寄养中心等服务提供商&#xff0c;并预订相关服务。该系统还提供了一系列实用的功能。通过使用宠物服务管理系统&#xff0c;用户可以更加方便…...

vue2中使用three.js步骤

1.使用npm 下载依赖这里以0.158.0版本为例 npm install three0.158.0 --save 2. <template><div id"container"></div> </template><script> import * as THREE from three; import { OBJLoader } from three/examples/jsm/loaders/O…...

部落商城App开发笔记 2024.11.21 实现进入app就是短视频

初步效果: 基于图鸟UI二次开发, 这里静态资源没有加载, 我在本机上安装了一个nginx, 需要启动一下. PS C:\dev\nginx-1.26.2> start .\nginx.exe重新刷新就有数据了. 先看看目前的页面吧. 首页. 分类: 发现. 消息. 购物车. 我的. 这个项目是有短视频的功能…...

解决.DS_Store 在项目一致无法排除,.gitignore里也不生效

.DS_Store 是 macOS 操作系统创建的隐藏文件&#xff0c;通常用于存储目录的属性&#xff0c;比如视图设置、图标位置等。它通常不应包含在代码仓库中&#xff0c;因此需要排除它。你提到即使将其添加到 .gitignore 文件中&#xff0c;仍然无法排除它&#xff0c;可能是由于以下…...

MySQL-关键字执行顺序

&#x1f496;简介 在MySQL中&#xff0c;SQL查询语句的执行遵循一定的逻辑顺序&#xff0c;即使这些关键字在SQL语句中的物理排列可能有所不同。 &#x1f31f;语句顺序 (8) SELECT (9) DISTINCT<select_list> (1) FROM <left_table> (3) <join_type> JO…...

极客时间《Redis核心技术与实战》开篇词 知识点总结

Redis 主要的数据持久化方式 RDB&#xff08;Redis Database Backup file&#xff09; RDB 是 Redis 提供的一种数据快照持久化方式&#xff0c;它会在指定的时间间隔内生成数据集的时间点快照&#xff0c;并将这些快照保存到磁盘上的一个 RDB 文件中。RDB 文件是一个压缩的二…...

TCP并发服务器

端口号快速复用函数 通过getsockopt和setsockopt函数&#xff0c;管理套接字的端口号复用设置。具体操作如下&#xff1a; getsockopt函数 int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen);功能&#xff1a;获取套接字的某些选项的属性。…...

Debug-031-近期功能实现小结

由于时间原因&#xff0c;没办法对每个小的功能点进行比较细致的总结&#xff0c;这里统一去记录一下最近的实现了的功能&#xff0c;算是存档备份&#xff0c;为今后开发带来便利和参考。 一、ACEeditor ACEeditor使用手册&#xff08;一&#xff09;_ace editor-CSDN博客 AC…...

Consumer Group

不&#xff0c;kafka-consumer-groups.sh 脚本本身并不用于创建 Consumer Group。它主要用于管理和查看 Consumer Group 的状态和详情&#xff0c;比如列出所有的 Consumer Group、查看特定 Consumer Group 的详情、删除 Consumer Group 等。 Consumer Group 是由 Kafka 消费者…...

.NET架构师学习大纲

目录 微服务 Consul Ocelot Polly Skywalking Exceptionless Apollo Jenkins Docker Kubernetes DDD领域驱动设计 DevOps CDN Nginx 应用服务器集群 数据库高可用 异步化架构 Azure前沿技术 工具排查 O/RM-EFCore IOC&AOP Core WebApi WebServer 数…...

【代码随想录】贪心

455. 分发饼干 题目 随想录 本质&#xff1a; 对于每个孩子&#xff0c;使用可以满足该孩子的最小的饼干。所以对孩子胃口和饼干进行sort排序&#xff0c;依次将大的饼干满足给孩子。 贪心策略&#xff1a; 想一下局部最优&#xff0c;想一下全局最优&#xff0c;如果局部最优…...

Harmony鸿蒙类似与Android中broadcast广播的api使用及释义

EventHub模块提供了事件中心&#xff0c;提供订阅、取消订阅、触发事件的能力。 这里需要注意&#xff0c;该模块接口仅可在Stage模型下使用。且Api>9 EventHub.on on(event: string, callback: Function): void; 订阅指定事件。&#xff08;接收广播&#xff09; 参…...

openGauss 6.0.0主备部署(企业版)

openGauss 6.0.0主备部署&#xff08;企业版&#xff09; 文章目录 openGauss 6.0.0主备部署&#xff08;企业版&#xff09;一、环境准备1.操作系统环境2.修改主机名3.设置字符集编码4.修改openEuler默认yum源5.安装所需工具6.同步网络时间7.关闭防火墙 二、安装openGauss数据…...

【机器学习】聚类算法原理详解

聚类算法 性能度量&#xff1a; 外部指标 jaccard系数&#xff08;简称JC&#xff09;FM指数&#xff08;简称FMI&#xff09;Rand指数&#xff08;简称RI&#xff09; 内部指标 DB指数&#xff08;简称DBI&#xff09;Dunn指数&#xff08;简称DI&#xff09; 距离计算&am…...

Ubuntu20.04从零安装IsaacSim/IsaacLab

Ubuntu20.04从零安装IsaacSim/IsaacLab 电脑硬件配置&#xff1a;安装Isaac sim方案一&#xff1a;pip安装方案二&#xff1a;预构建二进制文件安装1、安装ominiverse2、在ominiverse中安装isaac sim&#xff0c;下载最新的4.2版本 安装Isaac Lab1、IsaacLab环境克隆2、创建con…...

基于Java Springboot大学校园旧物捐赠网站

一、作品包含 源码数据库设计文档万字PPT全套环境和工具资源部署教程 二、项目技术 前端技术&#xff1a;Html、Css、Js、Vue、Element-ui 数据库&#xff1a;MySQL 后端技术&#xff1a;Java、Spring Boot、MyBatis 三、运行环境 开发工具&#xff1a;IDEA/eclipse 数据…...