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像素数据创建CanvasTexture
    const texture = new THREE.CanvasTexture(canvas);
    ...
    const sprite = new THREE.Sprite(spriteMaterial);
    ...
  }

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

「OpenCV交叉编译」ubuntu to arm64

Ubuntu x86_64 交叉编译OpenCV 为 arm64OpenCV4.5.5、cmake version 3.16.3交叉编译器 gcc-arm-10.2-2020.11-x86_64-aarch64-none-linux-gnu 可在arm或linaro官网下载所需版本&#xff0c;本文的交叉编译器可点击链接跳转下载 Downloads | GNU-A Downloads – Arm Developer L…

鸿蒙网络编程系列48-仓颉版UDP回声服务器示例

1. UDP回声服务器简介 回声服务器指的是这样一种服务器&#xff0c;它接受客户端的连接&#xff0c;并且把收到的数据原样返回给客户端&#xff0c;本系列的第2篇文章《鸿蒙网络编程系列2-UDP回声服务器的实现》中基于ArkTS语言在API 9的环境下实现了UDP回声服务器&#xff0c…

【WPF】Prism学习(七)

Prism Dependency Injection 1.注册类型&#xff08;Registering Types&#xff09; 1.1. Prism中的服务生命周期&#xff1a; Transient&#xff08;瞬态&#xff09;&#xff1a;每次请求服务或类型时&#xff0c;都会获得一个新的实例。Singleton&#xff08;单例&#xf…

springboot基于Hadoop的NBA球员大数据分析与可视化(1)(6)

摘 要 科学技术日新月异&#xff0c;人们的生活都发生了翻天覆地的变化&#xff0c;NBA球员大数据分析与可视化系统当然也不例外。过去的信息管理都使用传统的方式实行&#xff0c;既花费了时间&#xff0c;又浪费了精力。在信息如此发达的今天&#xff0c;可以通过网络这个媒…

Q3净利增长超预期,文心大模型调用量大增,百度未来如何分析?

首先&#xff0c;从百度发布的2024年第三季度财务报告来看&#xff0c;其净利润同比增长17%&#xff0c;超出了市场预期&#xff0c;显示出百度整体财务表现的强劲。这一增长不仅体现在总营收和百度核心营收上&#xff0c;更具体地反映在归属百度核心的净利润上&#xff0c;这标…

Vscode/Code-server无网环境安装通义灵码

Date: 2024-11-18 参考材料&#xff1a;https://help.aliyun.com/zh/lingma/user-guide/individual-edition-login-tongyi-lingma?spma2c4g.11186623.0.i0 1. 首先在vscode/code-server插件市场中安装通义插件&#xff0c;这步就不细说了。如果服务器没网&#xff0c;会问你要…

开源TTS语音克隆神器GPT-SoVITS_V2版本地整合包部署与远程使用生成音频

文章目录 前言1.GPT-SoVITS V2下载2.本地运行GPT-SoVITS V23.简单使用演示4.安装内网穿透工具4.1 创建远程连接公网地址 5. 固定远程访问公网地址 前言 本文主要介绍如何在Windows系统电脑使用整合包一键部署开源TTS语音克隆神器GPT-SoVITS&#xff0c;并结合cpolar内网穿透工…

实战 | C#中使用YoloV8和OpenCvSharp实现目标检测 (步骤 + 源码)

导 读 本文主要介绍在C#中使用YoloV8实现目标检测,并给详细步骤和代码。 详细步骤 【1】环境和依赖项。 需先安装VS2022最新版,.NetFramework8.0,然后新建项目,nuget安装 YoloSharp,YoloSharp介绍: https://github.com/dme-compunet/YoloSharp 最新版6.0.1,本文…

IDE配置tomcat

1.导航到 Tomcat 安装目录 E:\apache-tomcat-9.0.95-windows-x64\apache-tomcat-9.0.95 2.启动 Tomcat 服务&#xff1a;bin\startup.bat

python读取Oracle库并生成API返回Json格式

一、安装必要的库 首先&#xff0c;确保已经安装了以下库&#xff1a; 有网模式 pip install flask pip install gevent pi install cx_Oracle离线模式&#xff1a; 下载地址&#xff1a;https://pypi.org/simple/flask/ # a. Flask Werkzeug-1.0.1-py2.py3-none-any.whl J…

MAC借助终端上传jar包到云服务器

前提&#xff1a;保证工程本地已打包完成&#xff1a;图中路径即为项目的target目录下已准备好的jar包 第一步&#xff1a;打开终端&#xff08;先不要连接自己的服务器&#xff09;&#xff0c;输入下面的上传命令&#xff1a; scp /path/to/local/app.jar username192.168.1…

Python数据分析NumPy和pandas(四十、Python 中的建模库statsmodels 和 scikit-learn)

主要学习两个流行的建模工具包&#xff0c;statsmodels 和 scikit-learn。 一、pandas 与模型代码之间的接口 模型开发的常见工作流程是使用 pandas 进行数据加载和清理&#xff0c;然后再切换到建模库来构建模型本身。模型开发过程的一个重要部分在机器学习中称为特征工程&a…

实操案例|TinyVue树表+动态行合并

本文由孟智强同学原创。 背景 团队某个小项目切换 UI 框架&#xff0c;要将 Element 换成 TinyVue。期间遇到一个树表形式的业务表格&#xff0c;支持多级下钻&#xff0c;且第一列有合并行。当初用 Element 实现这个表格时费了一些周折&#xff0c;料想 TinyVue 上场应该也不…

Mesh路由组网

Mesh无线网格网络&#xff0c;多跳&#xff08;multi-hop&#xff09;网络&#xff0c;为解决全屋覆盖信号&#xff0c;一般用于家庭网络和小型企业 原理 网关路由器&#xff08;主路由&#xff0c;连接光猫&#xff09;&#xff0c;Mesh路由器&#xff08;子路由&#xff0c;…

基于Windows系统用C++做一个点名工具

目录 一、前言 二、主要技术点 三、准备工作 四、主界面 1.绘制背景图 2、实现读取花名册功能 3.实现遍历花名册功能 4.实现储存功能 4.1创建数据库 4.2存储数据到数据库表 4.3读取数据库表数据 一、前言 人总是喜欢回忆过去&#xff0c;突然回忆起…

11.9K Star!强大的 Web 爬虫工具 FireCrawl:为 AI 训练与数据提取提供全面支持

在这个信息爆炸的时代&#xff0c;数据就是力量。尤其是对于开发者来说&#xff0c;获取并利用好数据&#xff0c;就意味着拥有更多的主动权和竞争力。 无论是用来训练大语言模型&#xff0c;还是用于增强检索生成&#xff08;RAG&#xff09;&#xff0c;数据都扮演着至关重要…

云原生之k8s服务管理

文章目录 服务管理Service服务原理ClusterIP服务 对外发布应用服务类型NodePort服务Ingress安装配置Ingress规则 Dashboard概述 认证和授权ServiceAccount用户概述创建ServiceAccount 权限管理角色与授权 服务管理 Service 服务原理 容器化带来的问题 自动调度&#xff1a;…

前端面试题整理-前端异步编程

1. 进程、线程、协程的区别 在并发编程领域&#xff0c;进程、线程和协程是三个核心概念&#xff0c;它们在资源管理、调度和执行上有着本质的不同。 首先&#xff0c;进程是操作系统进行资源分配和调度的独立单位&#xff08;资源分配基本单位&#xff09;&#xff0c;每个进…

动静态库:选择与应用的全方位指南

目录 1 软链接 1.1 软链接的建立方式和观察现象 1.2 软链接的原理 2 硬链接 2.1 硬链接的建立方式和观察现象 2.2 硬链接的本质 2.3 我们用户不能给目录建立硬链接 3. 动静态库复习 4 动静态库的制作 4.1 静态库的制作与使用 4.1.2 打包 4.1.3 静态库的使用 4.2 动…

【ROS2】多传感器融合、实现精准定位:robot_localization

1、简述 robot_localization在SLAM建图、导航中常用于将多个传感器融合(IMU、里程计、深度相机、GPS等),以提高定位精度,为机器人提供了在三维空间中的非线性状态估计 robot_localization包含两个状态估计节点: ekf_localization_node:扩展卡尔曼滤波(EKF),缺点是非…