【Three.js】第十三章 3D Text 3D文字

2023-11-14

13. 3D Text 3D文字

介绍

我们已经了解足够的基础知识,现在可以创作一些好看的效果了。对于我们第一个正式的项目,我们将复刻一个开发者ilithya的作品(https://www.ilithya.rocks/),这个作品在场景中间有一个大的 3D 文本,很多几何体漂浮在文字的周围。
这个作品是学习 Three.js 早期可以实现的一个很好的例子。它简单、高效,而且特效看起来很棒。
Three.js 已经通过TextGeometry类支持 3D 文本几何图形。问题是你必须先指定一种字体,而且这个字体必须是一种叫做 typeface 的特定 json 格式。
我们不会涉及数字字体版权授权相关的问题,您使用下载字体后,使用字体时必须保证有权使用该字体,或者字体版权是供开发者免费使用的。

如何获得字体

有很多方法可以获取 typeface 格式的字体。首先,您可以使用如下转换器转换您的字体:https://gero3.github.io/facetype.js/。您必须提供一个文件并单击转换按钮。
您还可以在node_modules文件夹中的 Three.js 库示例中找到字体。/node_modules/three/examples/fonts/你可以把这些字体放在/static/文件夹中,或者你可以直接在你的 JavaScript 文件中导入它们,因为它们是 json 并且 Vite 中.json文件就像.js的文件一样被支持:

import typefaceFont from 'three/examples/fonts/helvetiker_regular.typeface.json'

我们打开/node_modules/three/examples/fonts/,获取helvetiker_regular.typeface.json文件和LICENSE文件并将它们放入/static/fonts/文件夹(您需要创建fonts文件夹)来混合使用这两种技术。
现在只需在基本 URL 的末尾写入即可访问该/fonts/helvetiker_regular.typeface.json字体。

加载字体

要加载字体,我们必须使用一个名为FontLoader的新加载器类。
此类在THREE变量中不可用。像在前面课程中我们所做的,像导入OrbitControls那样导入它:

import { FontLoader } from 'three/examples/jsm/loaders/FontLoader.js'

这个加载器像TextureLoader一样工作。在该部分之后添加以下代码textureLoader(如果您使用的是其他字体,请不要忘记更改路径):

/**
 * Fonts
 */
const fontLoader = new FontLoader()

fontLoader.load(
    '/fonts/helvetiker_regular.typeface.json',
    (font) =>
    {
        console.log('loaded')
    }
)

进入你的控制台发现打印了'loaded'。如果不是,请检查前面的步骤并在控制台中搜索潜在的错误。
我们现在可以通过使用函数内的font变量来访问字体。与TextureLoader不同,我们必须在该函数中的成功回调编写其余代码。

创建几何体

正如我们之前所说,我们将使用TextGeometry来创建几何体。
就像FontLoader一样,我们需要导入它:

import { TextGeometry } from 'three/examples/jsm/geometries/TextGeometry.js'

请注意文档页面上的示例代码;这些值比我们场景中的值大得多。
确保在成功的回调函数中编写代码:

fontLoader.load(
    '/fonts/helvetiker_regular.typeface.json',
    (font) =>
    {
        const textGeometry = new TextGeometry(
            'Hello Three.js',
            {
                font: font,
                size: 0.5,
                height: 0.2,
                curveSegments: 12,
                bevelEnabled: true,
                bevelThickness: 0.03,
                bevelSize: 0.02,
                bevelOffset: 0,
                bevelSegments: 5
            }
        )
        const textMaterial = new THREE.MeshBasicMaterial()
        const text = new THREE.Mesh(textGeometry, textMaterial)
        scene.add(text)
    }
)


您应该得到一个需要改进的白色 3D 文本。
首先,注释掉立方体的代码。其目的是确保一切正常。

如果您想看到一些很酷的网格,请添加wireframe: true到您的材料中。

const textMaterial = new THREE.MeshBasicMaterial({ wireframe: true })


您现在可以看到几何体是有很多三角形生成的。创建文本几何图形对计算机来说既漫长又困难。curveSegments避免这样做太多次,并通过减少多边形和bevelSegments属性使几何体尽可能保持低。
一旦您对几何体渲染详细程度感到满意,请删除wireframe

文本居中

有几种方法可以使文本居中。一种方法是使用边界。边界是与几何相关联的信息,它告诉该几何占用了哪些空间。它可以是一个盒子或一个球体。

你实际上看不到这些边界,但它可以帮助 Three.js 轻松计算对象是否在屏幕上,如果不在屏幕上,则对象甚至不会被渲染。这称为视锥体剔除,但这不是本课的主题。
我们想要的是使用这个边界来了解几何体的大小并使它重新居中。默认情况下,Three.js 使用球体边界。我们想要的是一个盒子边界,更准确地说。为此,我们可以要求 Three.js 通过调用computeBoundingBox()几何来计算此框边界:

textGeometry.computeBoundingBox()

我们可以使用boundingBox几何属性选中此框。

console.log(textGeometry.boundingBox)

结果是一个名为Box3 的对象,它有一个min属性和一个max属性。该min0并不像我们预期的那样。这是由于bevelThicknessand bevelSize,但我们现在可以忽略它。
现在我们有了措施,我们可以移动对象。我们不移动网格,而是移动整个几何体。这样,网格仍将位于场景的中心,文本几何体也将在我们的网格内居中。
为此,我们可以在方法translate(...)之后立即在几何体上使用该方法computeBoundingBox()

textGeometry.translate(
    - textGeometry.boundingBox.max.x * 0.5,
    - textGeometry.boundingBox.max.y * 0.5,
    - textGeometry.boundingBox.max.z * 0.5
)


文本居中,但如果你想非常精确,你还应该减去 bevelSizeis 0.02

textGeometry.translate(
    - (textGeometry.boundingBox.max.x - 0.02) * 0.5, // Subtract bevel size
    - (textGeometry.boundingBox.max.y - 0.02) * 0.5, // Subtract bevel size
    - (textGeometry.boundingBox.max.z - 0.03) * 0.5  // Subtract bevel thickness
)

我们在这里所做的实际上可以通过调用几何上的方法center()更快地完成:

textGeometry.center()

容易多了,不是吗?我们手写居中做的目的是了解边界和截锥体剔除

添加matcap材质

是时候为我们的文本添加一个很酷的材料了。我们将使用 MeshMatcapMaterial 替换 MeshBasicMaterial,因为它看起来很酷,而且性能更好。
首先,让我们选择一个 matcap 纹理。我们将使用位于/static/textures/matcaps/文件夹中的 matcaps,但您可以随意使用您自己的 matcaps
您也可以从此存储库https://github.com/nidorx/matcaps下载一个。不要花太多时间去选择它!如果不是供个人使用,请确保您有版权使用它。您不需要高分辨率的纹理,256x256应该绰绰有余。
我们现在可以使用代码中已有的TextureLoader来加载纹理:

const matcapTexture = textureLoader.load('/textures/matcaps/1.png')

我们现在可以用漂亮的MeshMatcapMaterial替换丑陋的MeshBasicMaterial并将我们的matcapTexture变量与matcap属性一起使用:

const textMaterial = new THREE.MeshMatcapMaterial({ matcap: matcapTexture })


你应该可以渲染出一个可爱的文字,上面有一个很酷的材料。

添加对象

让我们添加漂浮的对象。为此,我们将在循环函数内创建一个甜甜圈。
在成功函数中,紧跟在该text部分之后,添加循环函数:

for(let i = 0; i < 100; i++)
{
    
}

我们可以在 success 函数之外完成此操作,但我们需要将文本和对象一起创建,这是有充分理由的,您稍后会看到。
在此循环中,创建一个TorusGeometry(例如甜甜圈的技术名称),其材质与文本和Mesh相同:

for(let i = 0; i < 100; i++)
{
    const donutGeometry = new THREE.TorusGeometry(0.3, 0.2, 20, 45)
    const donutMaterial = new THREE.MeshMatcapMaterial({ matcap: matcapTexture })
    const donut = new THREE.Mesh(donutGeometry, donutMaterial)
    scene.add(donut)
}


你应该在同一个地方得到 100 个甜甜圈。
让我们为他们的位置添加一些随机性:

donut.position.x = (Math.random() - 0.5) * 10
donut.position.y = (Math.random() - 0.5) * 10
donut.position.z = (Math.random() - 0.5) * 10


你应该把 100 个甜甜圈分散在现场。
为旋转添加随机性。无需旋转所有 3 个轴,并且由于甜甜圈是对称的,旋转半圈就足够了:

donut.rotation.x = Math.random() * Math.PI
donut.rotation.y = Math.random() * Math.PI


甜甜圈应该向各个方向旋转。
最后,我们可以为比例添加随机性。不过要小心;我们需要对所有 3 个轴( x, y, z)使用相同的值:

const scale = Math.random()
donut.scale.set(scale, scale, scale)

优化

我们的代码不是最优的。正如我们在上一课中看到的,我们可以在多个网格上使用相同的材质,但我们也可以使用相同的几何体来节省性能。
thedonutGeometrythedonutMaterial移出循环:

const donutGeometry = new THREE.TorusGeometry(0.3, 0.2, 20, 45)
const donutMaterial = new THREE.MeshMatcapMaterial({ matcap: matcapTexture })

for(let i = 0; i < 100; i++)
{
    // ...
}

你应该得到相同的结果,但我们可以走得更远。text的材料与donut 的相同。
让我们删除donutMaterial,重命名textMaterialbymaterial并将其用于 thetextdonut

const material = new THREE.MeshMatcapMaterial({ matcap: matcapTexture })
                
// ...

const text = new THREE.Mesh(textGeometry, material)

// ...

for(let i = 0; i < 100; i++)
{
    const donut = new THREE.Mesh(donutGeometry, material)
    
    // ...
}

我们可以继续优化,但是有一个关于优化的专门课程,所以先按下不表。

更多优化

如果需要,您可以添加更多形状,为它们设置动画,甚至可以尝试其他 matcaps

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【Three.js】第十三章 3D Text 3D文字 的相关文章

  • 取消html5浏览器中的单图请求

    我正在动态加载 大 图像以绘制到 html5 画布中 如下所示 var t new Image t onload t src http myurl 但每隔一段时间就会想取消图片请求完全地 我想出的唯一方法是设置src to i e t sr
  • 用隐藏单元格补充 colspanned 表格有什么不好吗?

    我一直在表格上开发一些排序和选择功能 我发现在具有跨单元格的表格中定位非常困难 我只是添加了跨区单元格并将其隐藏 它看起来不错 它与我的 js 一起工作 非常适合索引 但我想知道这是否是合法的方法 stuffing display none
  • 如何在ASP.NET Webform中使用Jquery表单插件?

    我遇到了这个插件 http malsup com jquery form getting started http malsup com jquery form getting started 我想知道如何在 ASP NET WebForm
  • jquery 验证错误位置

    这看起来很简单 但我无法弄清楚 我正在使用 jquery 验证插件 我验证所有文件 但我想要的是在输入文本行中显示验证消息警报 例如在电子邮件输入中 请填写电子邮件地址 但现在它出现在所有字段下 在我的html中
  • 使用 moment.js 检查输入日期是否为星期一

    好吧 我想检查日期是否是星期一 例如 var myDate new Date moment myDate DD MM YYYY dayIs monday 在我的国家 一周的第一天是星期一 所以 我真的想检查输入日期是否是一周的开始 我尝试使
  • 如何按照编写的顺序迭代 javascript 对象属性

    我发现了代码中的一个错误 我希望通过最少的重构工作来解决该错误 此错误发生在 Chrome 和 Opera 浏览器中 问题 var obj 23 AA 12 BB iterating through obj s properties for
  • 如何仅在 NextJS 站点构建期间使用 getInitialProps?

    当使用 NextJS 构建静态站点时 我想要getInitialProps方法仅在构建步骤期间触发 而不是在客户端上触发 在构建步骤中 NextJS 运行getInitialProps 方法 https nextjs org docs fe
  • 如何使用canvas.toDataURL()将画布保存为图像?

    我目前正在构建一个 HTML5 Web 应用程序 Phonegap 本机应用程序 我似乎不知道如何将画布保存为图像canvas toDataURL 有人可以帮我吗 这是代码 有什么问题吗 我的画布被命名为 canvasSignature J
  • Javascript - 将值从下拉框传递到 Google Maps API

    我正在使用 Google 地图 API 为一家出租车公司创建报价表 目前 用户在 2 个文本框中输入出发点和接载点 API 会计算两点之间的距离以及行程费用 我正在尝试添加两个具有设定位置的下拉框 以便用户可以选择这些位置之一或使用文本框输
  • Google Chrome 106 可拖动导致元素消失

    使用拖放元素时 绝对定位元素中包含的大多数其他元素都会从屏幕上消失 如果我调整窗口大小 这些元素会出现 但在开始拖动时会再次消失 我在最新版本的 Google Chrome 106 和 Beta 版本 107 0 5304 18 以及现在的
  • 在d3.js中将2D形状转换为3D,并根据ANGULAR中的值调整高度

    我正在使用 d3 js v6 创建以下 2D 图表表示的 3D 图表 这个圆圈中有多个正方形 每个正方形都根据值分配了一种颜色 值越大 正方形越暗 现在我想将其转换为 3D 形状 其中当值变高时 只有特定正方形的高度会增加 因此结果在某种程
  • 使用 JS 合并具有相同值的相邻 HTML 表格单元格

    我已经为此苦苦挣扎了一段时间 我有一个根据一些 JSON 数据自动生成的表 该数据可能会有所不同 我想合并第一列中具有相同值的相邻单元格 例如此表中的 鱼 和 鸟 table tr td fish td td salmon td tr tr
  • 单击关闭按钮后不显示 Google 一键登录 UI

    我正在尝试按照本指南使新的谷歌一键登录工作 https developers google com identity one tap web https developers google com identity one tap web
  • 查询为空 Node Js Sequelize

    我正在尝试更新 Node js 应用程序中的数据 我和邮递员测试过 我的开发步骤是 从数据库 MySQL 获取ID为10的数据进行更新 gt gt 未处理的拒绝SequelizeDatabaseError 查询为空 我认识到 我使用了错误的
  • 如果数字小于 10,则显示前导零 [重复]

    这个问题在这里已经有答案了 可能的重复 JavaScript 相当于 printf string format https stackoverflow com questions 610406 javascript equivalent t
  • 数据表日期范围过滤器

    如何添加日期范围过滤器 like From To 我开始进行常规搜索和分页等工作 但我不知道如何制作日期范围过滤器 我正在使用数据表 1 10 11 版本 My code var oTable function callFilesTable
  • 如何在 Google 地图 V3 中创建编号地图标记?

    我正在制作一张上面有多个标记的地图 这些标记使用自定义图标 但我还想在顶部添加数字 我已经了解了如何使用旧版本的 API 来实现这一点 我怎样才能在V3中做到这一点 注意 当您将鼠标悬停在标记上时 标题 属性会创建一个工具提示 但我希望即使
  • Jquery - 通过在字符串中构建 id 的 id 获取元素

    我在使用 jquery 元素时遇到问题 我正在 var 中构造名称 例如 var myId myGotId myId attr title changed myId 返回空 我想通过 id 获取我的元素 但动态构建我的 Id 连接字符串 编
  • 需要有关 React Js 的帮助

    我是 React Js 新手 我的代码无法正常工作 请看下面 这是我的脚本文件Main jsx 该文件由 React 编译 输出放置在 dist 文件夹下的 main js 文件中 var react require react react
  • 防止文本区域出现新行

    我正在开发聊天功能 使用 Vue 并使用文本区域作为输入 以便溢出换行 并且对于编写较长消息的用户来说更具可读性 不幸的是 当用户按下 Enter 键并提交时 光标会在提交之前移动到新行 从而使用户体验感觉不佳 关于如何使用普通 Javas

随机推荐

  • 【react】 路由的基本使用 ===

    目录 React 路由介绍 react模拟hash路由的实现 React路由使用的基本 路由三大对象之 Router 路由三大对象之 Link Link NavLink 路由三大对象之 Route route的作用和格式 匹配规则 exac
  • unity 导出函数给 Lua 调用

    Assets Core ToLua Editor Custom CustomSettings cs using UnityEngine using System using System Collections Generic using
  • 【敬伟ps教程】亮度与色阶看懂直方图

    文章目录 亮度 对比度 色阶 调整输入色阶 调整输出色阶 调节原色通道 调整图层 亮度 对比度 控制明暗的视觉因素 三要素之一 明度 在拾色器中修改 HSB 中的 B 改为较低的值即可调整明度 明度较低时 RGB色值偏低 CMYK色值较高
  • 旋转矩阵推导

    个人学习 水平不高 请指正 目录 前言 一 前置知识 二 二维平面旋转 编辑 三 三维推广 1 右手坐标系 2 绕x轴旋转 3 z轴与y轴 四 完整草稿 五总结 前言 最近在学平衡小车 学习卡尔曼滤波 加速度计解算姿态角时用到了旋转矩阵 所
  • rabbitmq重试机制

    1 应答模式 NONE 可以称之为自动回调 即使无响应或者发生异常均会通知队列消费成功 会丢失数据 AUTO 自动检测异常或者超时事件 如果发生则返回noack 消息自动回到队尾 但是这种方式可能出现消息体本身有问题 返回队尾其他队列也不能
  • execjs调用第三方js库

    在用python执行js代码时 突然遇到一个问题 execjs怎么才能正常调用js的第三方库使用js内置方法 当时我也是查了好多资料才解决的 截至我写这篇文章 网上的解决方法几乎搜不到 全都是execjs的使用方法 所以记录一下给大家分享出
  • Python爬虫 - 爬取京东商城某页面

    目录 前言 页面分析 Selenium尝试 分析接口 价格是如何出现的 Postman分析请求 寻找SKUID 获取SKUID Postman测试 Demo代码 前言 在CSDN问答中遇到这样一个需求 使用Selenium爬取京东商城某个页
  • SOCKET编程登峰造极之完成端口

    一 什么是完成端口 完成端口 是一种WINDOWS内核对象 完成端口用于异步方式的重叠I 0情况下 当然重叠I O不一定非使用完成端口不可 还有设备内核对象 事件对象 告警I 0等 但是完成端口内部提供了线程池的管理 可以避免反复创建线程的
  • java方法的重载

    package object oriented05 判断是否是重载 跟方法的权限修饰符 返回值类型 形参变量 方法体都没有关系 方法的重载 在同一个类中 允许存在一个以上的同名方法 只要他们的参数个数不同或者参数类型不同即可 两同一不同 参
  • 安装HomeBrew 失败的解决方案

    在安装HomeBrew 或者安装成功 执行相关指令 时遇到错误提示 Error Failure while executing git clone https github com Homebrew homebrew core usr lo
  • 计算机基础知识操作题office2010,计算机系统操作师(中级)试题集(Office 2010版)...

    计算机系统操作师 中级 试题集 Office 2010版 依据 计算机操作员职业标准 编写 内容包括文字设置与编排 表格的基本操作 版面设置与图文混排 工作簿的基本操作 数据处理 办公软件综合应用 演示文稿的制作和Smart Art的制作
  • element表格之表头代码改进

    代码 官网
  • layui的使用

    下载链接 https pan baidu com s 1TIRrwFhua61jTqUCjme58Q pwd 1234 提取码 1234 gt layuiAdmin pro 即 单页版 gt layuiAdmin std 即 iframe
  • 程序员国庆加班调查:你是放假,还是被加班了?(内附加班费算法,最少可拿1711元)

    盼星星盼月亮 祖国的生日终于来了 程序员快发霉的身体 此刻是不是活了过来 想想美美的假期 梦寐以求想去的景点 让人留连忘返的小吃 又可以在朋友圈里愉快地装X了 简直兴奋地不要不要的 But 小编用一毛钱和你打赌 你看到的景点会是这样的 前方
  • android开发:adb安装apk

    参考 使用adb命令安装安卓apk包 1348204588 博客园
  • 解决nginx代理转发post请求变get请求方法

    请求类型变化原因 当使用 Nginx 将 HTTP 跳转到 HTTPS 时 HTTP 请求可能包含不同类型的方法 method 如 GET POST PUT DELETE 等 根据 HTTP 协议的规定 重定向 Redirection 的方
  • 若依框架,新添加服务swagger扫描不到接口问题(亲测有效)

    使用若依框架 新加自己的业务服务后 swagger扫描不到 解决 第一步 引入swagger依赖 如果有公共服务可以放到公共服务 然后每个业务模块引入公共服务
  • Qt扫盲-Qt Paint System 概述

    Qt Paint System 概述 一 概述 二 绘图设备和后端 1 Widget 2 Image 3 Pixmap 4 OpenGL绘制设备 5 Picture 6 自定义绘制后端 三 绘图与填充 1 Drawing 2 填充 Fill
  • 浏览器无法打开网页的解决办法

    相信大家有时候会遇到浏览器无法访问网络的问题 报错信息为无法连接到代理服务器等 在这种情况下 最简单粗暴的方式便是重置浏览器的设置 这里以IE浏览器为例 方法如下 1 在设置里面打开internet选项 我的问题已解决 故而可以直接显示网页
  • 【Three.js】第十三章 3D Text 3D文字

    13 3D Text 3D文字 介绍 我们已经了解足够的基础知识 现在可以创作一些好看的效果了 对于我们第一个正式的项目 我们将复刻一个开发者ilithya的作品 https www ilithya rocks 这个作品在场景中间有一个大的