浅谈3d文字技术方案

简介: three.js如何去展示中文字体首先「three.js」原生有个「textGeometry」, 原生是支持的,但是你如果想支持各种中文字体,首先你需要一个下载字体的ttf文件。然后你就去一个网站叫做, http://gero3.github.io/facetype.js/ 。你把你的「ttf」文件上传,然后将这些字体转成「json」, 再用three.js 自带的「fontLoader」 去解析这个json, 配合「textGeometry」 你就可以实现了。我这里做了一个简单的实现:const loader = new THREE.FontLoader()loader.load(

three.js如何去展示中文字体



首先「three.js」原生有个「textGeometry」, 原生是支持的,但是你如果想支持各种中文字体,首先你需要一个下载字体的ttf文件。然后你就去一个网站叫做,


 http://gero3.github.io/facetype.js/ 。你把你的「ttf」文件上传,然后将这些字体转成「json」, 再用three.js 自带的「fontLoader」 去解析这个json, 配合「textGeometry」 你就可以实现了。我这里做了一个简单的实现:


const loader = new THREE.FontLoader()
loader.load('../json/alibaba.json', (font) => {
  const geometry = new THREE.TextGeometry('我爱掘金', {
    font: font,
    size: 20,
    height: 5,
    curveSegments: 12,
    bevelEnabled: false,
    bevelThickness: 10,
    bevelSize: 8,
    bevelOffset: 0,
    bevelSegments: 5,
  })
  const material = new THREE.MeshBasicMaterial({ color: 0x50ff22 })
  const mesh = new THREE.Mesh(geometry, material)
  this.scene.add(mesh)
})


给大家看下gif效果图:


image.png


3d文字字体加载


其实不同的字体,对应不同的加载「json」,至于字体加粗,其实就是看字体有没有加粗的类型,如果有加粗的类型, 你就去展示就好了,其实还是不同的「json」, 我们这次的3D文字其实是没有采用这个「three」 这一套的。


3d文字技术选型



首先第一点不满足的就是我们的造型, 我们是做家居的,我们不光有3D视图展示,还有2D视图展示,所以就是一套数据分别在「3D」「2D」都有对应的表达。看下面两张图:


image.png


3D视图image.gif2D视图


对吧,所以这是我当时去做技术评估不去考虑的最重要问题, 我们2D所有的数据都是用「SVG」去展示。所以说当时第一时间思考🤔,有没有一个库是可以支持解析字体文件转成「svg」的,功夫不负有心人哇,终于找到去「npm」找到了一个叫opentype.js 我们看下这个库的介绍:


opentype.js is a JavaScript parser and writer for TrueType and OpenType fonts.

It gives you access to the 「letterforms」 of text from the browser or Node.js. See https://opentype.js.org/ for a live demo.


其实他的特性总结下来有下面:


  1. 非常高效


  1. 支持跑在浏览器和nodejs 中


其实当时我找到了很多社区方案, 有一个叫「text-to-svg」这个库, 看名字好像很满足我们的要求, 但是本着学习的本质,我只喜欢看源码,看看他到底用了啥,结果发现他是基于上面「opentype.js」 这个库去做了封装,那我肯定不用它了。我只需要字体被转换出来的「svg」信息,其实选用opentype.js 这个库还有两个原因哈**,第一支持ts ,第二的话他的周下载量是十分高的,至少说明他是稳定的。**


2d


有了「opentype.js」的加成,我们可以把输入的文字变成了转成「svg」的信息,这里主要用的一个api就是loadFont,然后就可以根据我们输入的文字,然后生成对应的「svg」, 我下面写一些伪代码:


async function make() {
  const font = await opentype.load(
          'https://backend-public-asset-alpha.oss-cn-shanghai.aliyuncs.com/resources/website/font/11c302dd8c50619e4131da5d645fb422.otf'
        )
  const map = new Map()
  return function (text) {
    // 防止重复添加
    for (let i = 0; i < text.length - 1; i++) {
      const parseFont = font.getPath(text[i], 0, 150, 72)
      const char = text[i]
      console.log(text[i], '999')
      if (!map.has(char)) {
        map.set(text[i], parseFont.commands)
      }
    }
    return map
  }
}


然后输入任何文字会产生,一些「SVG」path 信息。我们看下「2」 这个「svg」path信息。然后你可以看下:


image.gif信息


M其实对应的就是画布移动, L 就是画直线, C就是三阶贝塞尔曲线, Z 就是闭合path。svg的path 信息有了, 这里第一个难点出来了


贝塞尔曲线的离散


因为我们2d 可以用贝塞尔曲线去表达,但是我们3D的dataModel 中是没有这个数据去表示的,所以说什么呢,我得想好一个替代方案, 这里其实就设计到一个离散, 就是我将贝塞尔曲线,离散成多个点, 然后用直线去表达。这里不清楚的话,可以看我之前的一篇文章, 我里面对贝塞尔曲线做了详情讲解: 面试官问我会canvas? 我可以绘制一个烟花🎇动画


所以我将这些数组信息,去都转成2d点,去存储, 然后到这里很多人以为结束了,然后把这些2D线段去转成3D线段,你以为这样就结束了?


单一文字分组


我也以为事情就这么简单,直到我打了个 「e」,才发现事情并没有辣么简单。我们看下他的「svg」信息。


image.png


复杂信息


好家伙不仔细一看,原来有两个闭合路径,为什么会有这样呢?我这里给大家画个图 就知道了。


image.png


e字母


蓝色的其实对应的是「第一个path」 我们称作「Outer」, 红色其实对应的是内部。然后我就自然而然去思考了, 我去对数组进行分类。主要是根据闭合曲线的「Z」 去分组, 也就是一个字分成多个数据。


射线检测法


这里的话很多人以为结束了,但是其实并没有。这里涉及到射线检测法。算出一个文字每一个对应的「order」 ,大概是由【true, false..】组成的数组。false 表示逆时针, true表示 顺时针。 射线检测法的目的, 其实去判断这个path 和其他path 有没有交点, 交点为奇数其实就是逆时针, 为偶数其实就是顺时针。


「射线检测法」:其实就是取每个path 的第一个点在X轴方向上发出射线,然后算出与其他path 的交点个数,这里我不细讲了, 感兴趣的可以看我这篇文章  canvas 实现事件系统


至于为什么要去判断顺序, 与我们用的算法库「clipper」 有关系。有外轮廓和内轮廓之分, 内轮廓我们一般叫做洞也就是「hole」, 为了让大家有简单的概念, 我还是画图去表示:我就以「回」这个字举例子:


首先回这个字是也就是有两个path,  第二个path 肯定是内轮廓 也就是顺序肯定是【false,true】


我们先看下正确✅的图形:


image.png


正确


注意方向:外轮廓是「逆时针」, 内轮廓是「顺时针」


看下都是顺序是【true,true】的图形是这样的:


image.png


错误图形


顺序错误会导致,区域都会填充。所以为什么要有顺序了相信你也就明白了。 看下一个复杂的字吧感受下中国文字的博大精深。圗 和国


image.png


show


生成几何体


我们现在其实只是一个平面图形,文字肯定是个立方体, 这里 其实主要是生成顶面和侧面, 顶面的话其实就是通过底面上的点, 在底面的法向量延长一定距离。侧面的话,其实还是底面的点和顶面对应的点连起来的一条直线, 然后形成侧面。我还是画图:


image.png


几何体


每一个侧面大概是这样的一个过程。虚线就是对应点的连线,然后形成侧面。这个过程看着十分简单,其实在去写的时候还是十分复杂的。


交互层的思考🤔



交互层面的思考主要是三维空间中矩阵的应用。我们主要讲下这几点:


  1. 2d 坐标转换到3d坐标


  1. 垂直、水平、偏移、缩放


  1. 吸附


2d——3d


这里的话是这样的生成的「svg」 信息比如说他的开始点, 并不是在原点,但是我转到3d的世界坐标系,肯定默认是在原点的。所以的话,这里算出输入的字体的所有2d的信息,都要做一个「偏移Matrix」,因为在画布中移动,也就是文字跟着鼠标的点移动, 鼠标在哪里然后文字就在那里。这时候的「移动Matrix」 是相对世界原点的。所以这一层转换是非常重要的,而且还有一个「非常值得注意的点」是:svg 和canvas 的坐标系是在左上角的,也就是转到3d下来Y轴是要取反。我还是画图表示下哈:

image.png

image.gif2d-3d


垂直、水平、偏移、缩放


其实是这样的, 当你输入一行字默认是水平的,但是有需求我想把他搞成垂直的。这里就是对应的就是在X轴偏移和 Y轴偏移的问题。openType 默认是 可以批量解析字体的,但是呢我们不采用, 我还是一个个文字去处理,做到可控制。问题来了,每一个文字之间的间距, 怎么确保他们不相交呢?其实这里又涉及到计算每一个文字的「boundingBox」, 算出boundingBox之后呢,然后做一个距离叠加, 类似于reduce。因为输入的字有很多越往后面, 距离越大呗。缩放的话,其实是这样的,根据现有字体的大小  除上 基础字体大小  比如是20  算出一个scale, scale 可以算出缩放矩阵。物体字体大小变大, 然后✖️ 缩放矩阵。那么「bounding box」 自然也变化了。


整个一流程就是这样的:


image.png


变化


虚线框可以想象成每个矩形的bouding, 就是每个字, 每个字变化了, 矩形变化,想在 X轴 就在X轴,想在Y轴 就在Y轴。


吸附


吸附这东西其实没有啥悬乎的东西:


  1. 面对照相机📷


  1. 算旋转矩阵


总结下来就这两个东西。这里因为文字默认加载到的是相对于 世界坐标系的原点的, 比如你想吸附三维空间中的任意平面。所以说你可以基于这个平面建立一个局部坐标系,其实本质上就是「世界坐标系 —— 局部坐标系」的转换, 吸附到任意平面本质上,你可以只可以获得一个平面的法向量, 至少2个轴去确定一个局部坐标系, 这里默认选取X轴的正方向, 这样。这里 用到了three.js 的一个方法叫做「lookat」, 其实也就是模拟相机去算出这个矩阵。


参数就是个vector


vector - 一个表示世界空间中位置的向量。

也可以使用世界空间中x、y和z的位置分量。

旋转物体使其在世界空间中面朝一个点。


由于还要让文字始终面对照相机📷 ,所以要计算照相机的方向 和平面的法向量去做点乘,来判断其他轴是否反向。大概就是这样:


我们看下gif:

image.png


image.gif

相关文章
|
8月前
|
敏捷开发 前端开发 数据可视化
如何用低代码的思路设计文字描边渐变组件
如何用低代码的思路设计文字描边渐变组件
86 1
|
8月前
|
机器学习/深度学习 人工智能 自然语言处理
从文字到视频:借助ChatGPT与剪映轻松生成高质量视频
从文字到视频:借助ChatGPT与剪映轻松生成高质量视频
397 0
|
8月前
|
前端开发 JavaScript 双11
双十一互动图片和文字的处理方案
双十一互动图片和文字的处理方案
113 0
|
数据可视化 PyTorch 算法框架/工具
AIGC背后的技术分析 | 图像风格迁移
本文为实战篇,介绍图像风格迁移
428 0
AIGC背后的技术分析 | 图像风格迁移
|
人工智能 编解码
图片无损放大-AI为图片开光
图片无损放大的, 免费的, AI加持, 全平台的开源软件, 放大后的图片是 1352X1352, 如果觉得不够大, 还可以选择第二个步骤中的 dobule 放大, 那样生成的图片就是 2704X2704
719 0
|
存储 Web App开发 JavaScript
前端语音转文字实践总结
前端语音转文字实践总结
前端语音转文字实践总结
|
存储 PHP
业界对生成图片缩略图的做法归纳
网站如果有很多用户上传图片(相册,商品图片),一般的做法是将用户图片保存在磁盘上面(数据库中记录图片的地址)。用户上传的时候按照原图、中图、小图等各个尺寸都生成一份保存在磁盘上。比如php的网店系统echsop就是这么做的,而shopex之类也大同小异。
1564 0
|
JavaScript 前端开发
文字到底能玩出多少花样(四)实现跃动的文字
文字到底能玩出多少花样(四)实现跃动的文字
165 0
文字到底能玩出多少花样(四)实现跃动的文字
|
机器学习/深度学习 安全 定位技术
在手机上长按文字进行选择,其背后的技术不简单
本文介绍联邦学习技术在手机文字复制功能上的应用。

热门文章

最新文章