使用WebGL渲染文本的技术
正如WebGL中的规则一样,看起来应该很简单的任何东西实际上都非常复杂。绘图线,调试着色器,文本渲染……它们在WebGL中都很难以做到。
那不是很奇怪吗? WebGL没有用于渲染文本的内置功能。尽管文本似乎是最基本的功能。当涉及到实际渲染时,事情变得复杂。您如何解释每种语言的巨大字形?您如何使用固定宽度或比例宽度字体工作?当需要将文本渲染到上下,从左到右或向右右转时,您该怎么办?数学方程式,图表,乐谱?
突然间,为什么文本渲染在像WebGL这样的低级图形API中没有位置。文本渲染是许多细微差别的复杂问题。如果我们想渲染文本,我们需要发挥创造力。幸运的是,许多聪明的人已经为我们所有的WebGL文本需求提出了广泛的技术。
我们将在本文中学习其中的一些技术,包括如何生成所需的资产以及如何与其中包括WebGL渲染器的JavaScript 3D库一起使用。作为奖励,每种技术都将具有演示显示用例。
目录
- WebGL之外的文字快速注释
- 字体几何
- 文本(和画布)纹理
- 位图字体
- 签名的距离字段
- 多通道签名的距离字段
- 生成带有高度图的3D文本
- 进一步阅读
WebGL之外的文字快速注释
尽管本文全部与WebGL中的文本有关,但您应该考虑的第一件事是您是否可以使用覆盖在WebGL帆布顶部的HMTL文本或画布。 3D几何形状不能用作覆盖层的覆盖,但是您可以从开箱即用。在很多情况下,这就是您所需要的。
字体几何
渲染文本的常见方法之一是用一系列三角形构建字形,就像常规模型一样。毕竟,渲染点,线条和三角形是WebGL的优势。
创建字符串时,每个字形都是通过从三角形点的字体文件中读取三角形来制作的。从那里,您可以挤出字形以使其3D或通过矩阵操作扩展字形。
字体几何最适合少量文本。那是因为每个字形都包含许多三角形,这会导致绘画变得有问题。
通过字体几何形状创建185,084个三角形和555,252个顶点,您现在正在阅读此精确段落。这只是259个字母。使用字体几何形状编写整个文章,您的计算机风扇可能会成为飞机涡轮机。
尽管三角形的数量因三角测量的精度和使用的字体而变化,但在使用字体几何时,渲染大量文本可能总是是一个瓶颈。
如何从字体文件创建字体几何形状
如果它像选择想要的字体和渲染文本一样容易。我不会写这篇文章。常规字体格式用曲线定义字形。另一方面,在CPU上绘制WebGL的绘制非常昂贵,并且也很复杂。如果我们想渲染文本,我们需要从bezier曲线中创建三角形(三角剖分)。
我找到了一些三角剖分方法,但是绝不是完美的,它们可能无法与每种字体一起使用。但是,至少他们会让您开始进行三角剖分的字体。
方法1:自动且容易
如果您使用的是三j,则通过faceType.js传递字体,以从字体文件中读取参数曲线并将其放入.json文件中。三j中的字体几何特征会为您提供三角测量:
const几何= new Trix.fontgeometry(“ Hello wance”,{font:font,size:80})
另外,如果您不使用三j,则不需要实时三角剖分。您可以通过使用三角剖分为您的字体来节省手动过程的痛苦。然后,您可以从几何形状中提取顶点和索引,然后将它们加载到您选择的WebGL应用程序中。
方法2:手动和痛苦
至少在最初,三角形文件的手动选项非常复杂且令人费解。这将需要整篇文章以详细解释。也就是说,我们将迅速介绍我从Stackoverflow获取的基本实现的步骤。
实施基本上是这样分解的:
- 将Opentype.js和Earcut.js添加到您的项目中。
- 使用opentype.js从.tff字体文件中获取更偏见的曲线。
- 将Bezier曲线转换为封闭形状,然后通过降序区域对其进行排序。
- 通过找出其他形状内部的形状来确定孔的指标。
- 将所有点作为第二个参数将所有点带到耳塞。
- 使用耳塞的结果作为几何索引。
- 呼吸。
是的,很多。此实现可能对所有字体都不起作用。尽管如此,它仍然会让您入门。
在三j中使用文本几何形状
值得庆幸的是,三台j支持开箱即用的文本几何形状。给它一个.json,介绍了您最喜欢的字体的Bezzier曲线,而TrixJ则可以在运行时为您提供三角剖分。
var loader = new Trix.fontloader(); var font; var text =“ Hello World” var loader = new Trix.fontloader(); loader.load('fonts/helvetiker_regular.typeface.json',function(helvetiker){ 字体= helvetiker; var几何= new Trix.textgeemetry(文本,{ 字体:字体, 尺寸:80, 身高:5, }); }
优势
- 创建3D字符串很容易挤出。
- 矩阵操作使缩放更加容易。
- 根据所使用的三角形数量,它提供了良好的质量。
缺点
- 由于高三角计数,这与大量文本相比并不能很好地扩展。由于每个角色都由许多三角形定义,甚至像“ Hello World”一样简短的东西会导致7,396个三角形和22,188个顶点。
- 这不适合常见的文本效果。
- 反缩减取决于您的后处理混溶或浏览器默认值。
- 扩大太大的缩放可能会显示三角形。
演示:褪色的信件
在以下演示中,我利用了使用字体几何形状创建3D文本的容易。在顶点着色器内部,随着时间的推移,挤出量增加并减少。将其与雾和标准材料搭配,您会得到这些幽灵般的字母进出空白。
请注意,用较低的字母量如何,三角形的数量已经存在数万个!
文本(和画布)纹理
制作文本纹理可能是在WebGL中绘制文本的最简单和最古老的方法。打开Photoshop或其他一些栅格图形编辑器,绘制带有一些文本的图像,然后将这些纹理渲染到四边形上,然后完成!
另外,您可以使用画布在运行时创建按需创建纹理。您也可以将画布作为质地渲染到四轮上。
除了是最不复杂的技术。文本纹理和帆布纹理具有每个纹理或给出的文本只需要一个四轮轴的好处。如果您真的愿意,可以用单个质地编写整个英国百科全书。这样,您只需渲染一个四Quad,六个顶点和两个面。当然,您会以一个规模进行操作,但仍然存在这个想法:您可以将多个字形批量地插入同一四边形。文本和画布纹理都有缩放问题的问题,尤其是在使用大量文本时。
对于文本纹理,用户必须下载构成文本的所有纹理,然后将其保存在内存中。对于帆布纹理,用户不必下载任何内容 - 但是现在,用户的计算机必须在运行时进行所有栅格化,并且您需要跟踪每个单词在画布中的位置。另外,更新大画布可能真的很慢。
如何创建和使用文本纹理
文本纹理对他们没有任何奇特的态度。打开您喜欢的栅格图形编辑器,在画布上绘制一些文本,然后将其导出为图像。然后,您可以将其作为纹理加载,然后将其映射到飞机上:
//加载纹理 令纹理=; const几何=新的三。 const材料新的三。 this.scene.add(新网格(几何,材料));
如果您的WebGL应用程序有很多文本,则下载庞大的文本表可能不是理想的,尤其是对于慢速连接的用户而言。为了避免下载时间,您可以使用屏幕外帆布将其按需栅格化,然后对画布作为质地进行采样。
让我们交易下载时间以进行性能,因为将大量文本栅格化的时间不止一刻。
函数createTextCanvas(String,parameters = {}){ const canvas = document.createelement(“ canvas”); const ctx = canvas.getContext(“ 2d”); //准备可以测量的字体 令fontsize = parameters.fontsize || 56; ctx.font =`$ {fontsize} px monospace`; const textmetrics = ctx.measuretext(text); 令width = textmetrics.width; 让高度= fontsize; //调整帆布大小以匹配文本大小 canvas.width = width; canvas.height =高度; canvas.style.width =宽度“ px”; canvas.style.height =高度“ px”; //重新涂抹字体,因为调整了帆布的大小。 ctx.font =`$ {fontsize} px monospace`; ctx.textalign = parameters.align || “中心” ; ctx.textbaseline = parameters.baseline || “中间”; //使画布透明以简单 ctx.fillstyle =“透明”; ctx.fillect(0,0,ctx.canvas.width,ctx.canvas.height); ctx.fillstyle = parameters.color || “白色的”; ctx.filltext(文本,宽度 / 2,高度 / 2); 返回画布; } 令纹理= new three.texture(createTextCanvas(“ this is text”));
现在,您可以像以前的摘要一样使用飞机上的纹理。或者您可以创建一个精灵。
作为替代方案,您可以使用更有效的库来创建纹理或精灵,例如三text2d或三秒表。而且,如果您想要文本多行文本,则应查看此惊人的教程。
优势
- 这提供了具有静态文本的优质1比1质量。
- 顶点/脸部计数低。每个字符串只能使用六个顶点和两个面。
- 在四边形上实现纹理很容易。
- 使用画布或图形编辑器添加效果,例如边界和发光,这是相当微不足道的。
- 画布使创建多行文本变得容易。
缺点
- 如果射手化后缩放,旋转或转换,则看起来模糊。
- 在非视网膜上,文字看起来松脆。
- 您必须将所有使用的字符串栅格化。许多字符串意味着要下载很多数据。
- 如果您不断不断更新画布,则用画布进行按需栅格化可能会很慢。
演示:帆布纹理
帆布纹理可与有限数量的文本不经常变化的有限文本运作良好。因此,我用四边形构建了一个简单的文本墙,重复使用相同的纹理。
位图字体
字体几何形状和文本纹理都经历了处理大量文本的相同问题。每片文本具有100万个顶点是超级效率的,并且每片文本创建一个纹理并不能真正扩展。
Bitmap字体通过将所有唯一的字形将所有独特的字形(称为纹理地图集)栅式化来解决此问题。这意味着您可以在运行时组装任何给定的字符串,从而为每个字形创建四边形并对纹理地图集的部分进行采样。
这意味着用户只需要为所有文本下载并使用单个纹理。这也意味着您只需要每个字形渲染一个四四分之一:
整个文章的渲染约为117,272个顶点和58,636个三角形。与仅一段段落的字体几何形状相比,这是高效的3.1倍。这是一个巨大的进步!
由于位图字体将字形栅格化成纹理,因此它们与常规图像相同的问题。放大或扩展,您开始看到像素化和模糊的混乱。如果您想以不同的尺寸的文本,则应在该特定尺寸上发送带有字形的辅助位图。或者,您可以使用签名的距离字段(SDF),我们将在下一节中介绍。
如何创建位图字体
有很多可以生成位图的工具。以下是一些更相关的选项:
- Angel Code的BMFont - 这是由位图格式的创建者组成的。
- Hiero - 这是Java开源工具。它与Anglecode的BMFont非常相似,但是它允许您添加文本效果。
- 字形设计师 - 这是一个付费MacOS应用程序。
- 鞋盒 - 这是用于处理精灵(包括位图字体)的工具。
我们将使用AngleCode的BMFont来示例,因为我认为这是最简单的开始。在本节的底部,如果您认为它缺乏所需的功能,则可以找到其他工具。
打开应用程序时,您会看到一个屏幕上充满了可以选择的字母,这是您只能抓住所需的字形而不是发送希腊符号的好处。
该应用程序的侧边栏使您可以选择并选择一组字形。
准备出口了吗?转到选项→将位图保存为。并完成了!
但是我们要领先一些。在导出之前,您应该检查一些重要的设置。
- 字体设置:这让您选择要使用的字体和大小。这里最重要的项目是“匹配的Char Height”。默认情况下,应用程序的“大小”选项使用像素而不是点。您会看到图形编辑器的字体大小与生成的字体大小之间存在实质性差异。如果您希望字形有意义,请选择“匹配的Char Height”选项。
- 导出设置:对于导出,请确保纹理大小为两个功率(例如16×16、32×32、64×64等)。然后,如果需要,您就可以利用“线性MIPMAP线性”过滤。
在设置的底部,您将看到“文件格式”部分。只要您可以读取文件并创建字形,选择这两个选项就可以了。
如果您正在寻找最小的文件大小。我进行了一个超级非科学测试,在其中创建了所有lowcase和大写拉丁字符的位图,并比较了每个选项。对于字体描述符,最有效的格式是二进制的。
字体描述符格式 | 文件大小 |
---|---|
二进制 | 3 kb |
原始文字 | 11 kb |
XML | 12 kb |
纹理格式 | 文件大小 |
---|---|
PNG | 7 KB |
塔加 | 64 KB |
DirectDraw表面 | 65 KB |
PNG是文本纹理的最小文件大小。
当然,它比文件大小要复杂一些。为了更好地了解要使用哪种选项,您应该研究解析时间和运行时间性能。如果您想了解每种格式的优缺点,请查看此讨论。
如何使用位图字体
创建位图字体几何形状比仅使用纹理要多一些,因为我们必须自己构造字符串。每个字形都有其自身的高度和宽度,并采样了纹理的不同部分。我们必须为字符串上的每个雕文创建一个四边形,以便我们可以给他们正确的紫外线以采样其雕文。
您可以在三js中使用三个bmfont-text使用位图,SDFS和MSDF创建字符串。它需要多行文本,并将所有字形批量划分到单个几何形状上。请注意,它需要从NPM安装在项目中。
var createGeementry = require('trix-bmfont-text') var loadfont = require('load-bmfont') loadFont('fonts/arial.fnt',function(err,font){ //创建一个包装的位图字形的几何形状, //包装到300px并右对齐的单词 var几何=创建地理计({{ 字体:字体, 文字:“我的文字” })) var textureloader = new trix trix.textureloader(); textureloader.load('fonts/arial.png',函数(纹理){ //我们可以使用简单的三j材料 var Material = new Trix.meshbasicmaterial({ 地图:纹理, 透明:是的, 颜色:0xaaffff })) //现在用我们的网眼做一些事情! var网格=新的三。网格(几何,材料) })) }))
无论何时将文本绘制为全白色或全白色,请使用倒置选项。
优势
- 快速而简单地渲染。
- 这是独立于1:1的比率和分辨率。
- 给定字形,它可以渲染任何字符串。
- 对于需要经常更改的许多文本来说,这是一件好事。
- 它与数量有限的字形非常好。
- 它包括对kerning,行高和撰写文字包装等事物的支持。
缺点
- 它仅接受有限的字符和样式。
- 它需要预先储存的字形和额外的垃圾箱包装才能进行最佳使用。
- 它是模糊的,在大尺度上像素化,也可以旋转或转换。
- 每个渲染的字形只有一个四四核。
互动演示:闪亮的积分
栅格位图字体非常适合电影信用,因为我们只需要几种尺寸和样式。缺点是文本在响应式设计中并不大,因为它看起来会模糊和像素化的大小更大。
对于鼠标效果,我要通过将鼠标位置映射到视图的大小,然后计算从鼠标到文本位置的距离进行计算。当文本达到Z轴和Y轴上的特定点时,我也在旋转。
签名的距离字段
就像位图字体一样,签名的距离字段(SDF)字体也是纹理地图集。唯一的字形分批成单个“纹理地图集”,可以在运行时创建任何字符串。
但是,与位图字体这样做的方式并没有将栅格化的字形存储在纹理上,而是生成并存储了字形的SDF,而不是从低分辨率图像中产生高分辨率的形状。
像多边形网格(字体几何)一样,SDF代表形状。 SDF上的每个像素都存储到最接近表面的距离。符号指示像素在形状内部或外部。如果符号为负,则像素在内部;如果是积极的,那么像素就在外面。该视频很好地说明了这个概念。
SDF S也通常用于射线缩放和体积渲染。
由于SDF在每个像素中存储距离,因此原始结果看起来像是原始形状的模糊版本。要输出用α在0.5测试的硬形状,这是字形的边界。看看字母“ A”的SDF与常规光栅图像相比:
正如我之前提到的,SDF S的最大好处是能够从低分辨率SDF中呈现高分辨率的形状。这意味着您可以创建16pt字体SDF,并将文本扩展到100分或更多,而不会丢失太多。
SDF S擅长缩放,因为您几乎可以通过双线性插值完美地重建距离,这是一种奇特的方式,说我们可以在两个点之间获得值。在这种情况下,在常规位图字体上两个像素之间的双线性插值使我们具有内在的颜色,从而导致线性模糊。
在SDF上,两个像素之间的双线性插值提供了与最近边缘的内在距离之间的距离。由于这两个像素距离与一开始相似,因此结果值不会丢失有关字形的太多信息。这也意味着SDF越大,丢失的信息就越准确和较少。
但是,此过程带来了警告。如果像素之间的速率变化不是线性的(例如在尖角的情况下),双线性插值会产生不准确的值,从而在缩放SDF缩放量比其原始大小时会导致弯曲或圆角。
除了撞击纹理方面,唯一真正的解决方案是使用多通道SDF S,这是我们将在下一节中介绍的。
如果您想深入了解SDF S背后的科学,请查看Chris Green的主人论文(PDF)。
优势
- 即使旋转,缩放或转换时,它们也保持酥脆。
- 它们是动态文本的理想选择。
- 它们提供了良好的尺寸比率。单个纹理可用于渲染微小和巨大的字体尺寸,而不会失去太多质量。
- 他们的顶点计数低,每个字形仅四个顶点。
- 抗质量很便宜,就像在alpha测试中制作边界,掉落阴影和各种效果一样。
- 它们比MSDF S小(我们会稍微看到)。
缺点
- 当对纹理进行采样时,可以导致圆角或碎裂的角落。 (同样,我们将看到MSDF S可以预防这一点。)
- 它们的小字体大小无效。
- 它们只能与单色字形一起使用。
多通道签名的距离字段
多通道签名的距离字段(MSDF)字体有点像SDF S上有点张开,并且是一种相当最近的变化,它能够使用所有三个颜色通道,能够产生接近完美的尖角。一开始,他们确实看起来很震惊,但不要让您脱颖而出,因为它们易于使用,而不是看起来。
使用所有三个颜色通道确实会导致较重的图像,但这就是使MSDF的质量与空间比的比例要比常规SDF s好得多。以下图像显示了已扩展到50px的字体的SDF和MSDF之间的差异。
像普通的SDF一样,MSDF将距离与最近的边缘保持距离,但只要发现一个尖锐的角落就会更改颜色通道。我们通过绘制两个颜色通道或更多同意的位置来获得形状。尽管涉及更多的技术。查看此MSDF发电机的读书文件,以进行更彻底的解释。
优势
- 它们比SDF S支持更高的质量和空间比。通常是更好的选择。
- 他们在缩放时保持锋利的角落。
缺点
- 它们可能包含小文物,但可以通过增加字形的质地大小来避免这种伪像。
- 他们需要在运行时过滤三个值的中位数,这有点贵。
- 它们仅与单色字形兼容。
如何创建MSDF字体
创建MSDF字体的最快方法是使用MSDF-BMFONT-WEB工具。它具有大多数相关的自定义选项,并且可以在几秒钟内完成工作。另外,有许多Google字体已经由A-Frame的人们转换为MSDF。
如果您还希望生成SDF S或您的字体,则需要一些有问题的字形,需要进行一些特殊的调整。 MSDF-BMFONT-XML CLI为您提供了多种选择,而不会使事情过于混乱。让我们看一下如何使用它。
首先,您需要从NPM全球安装它:
NPM安装MSDF-BMFONT-XML -G
接下来,给它一个.ttf字体文件,其中包括您的选项:
msdf-bmfont ./open-sans-black.ttf-输出型json-font-size 76- texture-size 512,512
这些选项值得一提。虽然MSDF-BMFONT-XML提供了很多选择来调整字体的选项,但实际上,您可能只需要正确地生成MSDF:
- -t
或 - field-type <msdf>:MSDF-BMFONT-XML默认情况下生成MSDFS Glyph Atlases。如果要生成SDF,则需要使用-t SDF来指定它。</msdf>
- -f
或-ASTPUT-TYPE :MSDF-BMFONT-XML生成一个XML字体文件,您必须在运行时将其解析为JSON。您可以通过立即导出JSON来避免这种解析步骤。 - -s, - font-size
:如果字体大小超过,可能会出现某些文物和瑕疵。大部分时间都会碰到字体尺寸。此示例显示了字母“ M”中的一个小缺陷。 - -m
或-Texture-size :如果您的所有角色都不适合相同的纹理,则创建了第二个纹理以适合它们。除非您试图利用多页面的Glyph Atlas,我建议您增加纹理大小,以避免使用一个文本以避免额外的工作。
还有其他工具可以帮助生成MSDF和SDF字体:
- MSDF-BMFONT-WEB:一种可以快速而轻松地创建MSDFS(但不是SDF S)的网络工具
- MSDF-BMFONT:使用开罗和节点canvas的节点工具
- MSDFGEN:所有其他MSDF工具均基于的原始命令行工具
- Hiero:一种生成位图和SDF字体的工具
如何使用SDF和MSDF字体
由于SDF和MSDF字体也是字形图谱,因此我们可以像位图字体一样使用三个BMFONT-TEXT。唯一的区别是,我们必须用碎片着色器来获取距离字段的雕文。
这是对SDF字体的工作方式。由于我们的距离字段的值大于字形以外的0.5,而在字形内的值小于0.5,因此我们需要在每个像素上的碎片着色器中测试alpha,以确保我们只渲染距离小于0.5的像素,仅渲染Glyphs的内部。
const fragmentshader =` 均匀的VEC3颜色; 均匀的采样器2D地图; 变化的vec2 vuv; void main(){ vec4 texcolor = texture2d(Map,vuv); //仅渲染字形的内部。 float alpha =步骤(0.5,texcolor.a); gl_fragcolor = vec4(颜色,alpha); 如果(gl_fragcolor.a <p>同样,我们可以从三个bmfont-text中导入字体,该字体带有抗精神经气。然后,我们可以将其直接在生皮材料上使用:</p><pre rel="JavaScript">令SDFSHADER = require('三bmfont-Text/Shaders/sdf'); 令材料=新的三。 地图:纹理, 透明:是的, 颜色:0x000000 }));
MSDF字体有些不同。他们通过两个颜色通道的交集重新创建尖角。两个或两个以上的颜色渠道必须同意。在进行任何Alpha发短信之前,我们需要获得三个颜色频道的中位数,以查看他们同意的位置:
const fragmentshader =` 均匀的VEC3颜色; 均匀的采样器2D地图; 变化的vec2 vuv; 浮点中位数(浮动R,浮子G,float b){ 返回最大(最小(R,G),Min(Max(R,G),B)); } void main(){ vec4 texcolor = texture2d(Map,vuv); //仅渲染字形的内部。 float sigdist =中值(Texcolor.r,texcolor.g,texcolor.b)-0.5; float alpha =步骤(0.5,sigdist); gl_fragcolor = vec4(颜色,alpha); 如果(gl_fragcolor.a <p>同样,我们还可以使用其MSDFSHADER从三个BMFONT-TEXT导入,该文本还带有抗逆转录和开箱即用。然后,我们可以将其直接在生皮材料上使用:</p><pre rel="JavaScript">令MSDFSHADER = require('trix-bmfont-text/Shaders/msdf'); 令材料=新的三。 地图:纹理, 透明:是的, 颜色:0x000000 }));
演示:星球大战介绍
星球大战绘制介绍是MSDF和SDF字体很好地工作的一个很好的例子,因为效果需要多种尺寸。我们可以使用一个MSDF,文字总是看起来很清晰!虽然,可悲的是,三bm-font尚未支持合理的文本。应用左派辩护将使表现更加平衡。
对于浅剑效果,我正在将平面大小的无形平面播放到相同大小的帆布上,并通过将场景位置映射到纹理坐标来通过画布进行采样。
奖励提示:生成带有高度图的3D文本
除了字体几何形状外,我们涵盖的所有技术都会在单个四边形上生成字符串或字形。如果您想从平坦的纹理中构建3D几何形状,则最好的选择是使用高度图。
高度图是一种使用纹理撞击几何高度的技术。这通常用于在游戏中生成山脉,但事实证明这也是有用的渲染文本。
唯一的警告是,您需要很多面孔才能使文本看起来光滑。
进一步阅读
不同的情况要求不同的技术。我们在这里看到的是一颗银色子弹,它们都有自己的优势和缺点。
那里有很多工具和库可以帮助您充分利用WebGL文本,其中大部分实际上源自外部WebGL。如果您想继续学习,我强烈建议您超越WebGL并查看其中一些链接:
- 在三js中加载字体的几种方法
- 关于文本重型Spotify运动的案例研究
- 关于MSDF的有趣对话
- 更多字体渲染技术
- GPU上渲染矢量艺术(字形)
- freetype如何进行文本渲染
- 用位图字体创建有趣的效果
以上是使用WebGL渲染文本的技术的详细内容。更多信息请关注PHP中文网其他相关文章!

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

关于Flex布局中紫色斜线区域的疑问在使用Flex布局时,你可能会遇到一些令人困惑的现象,比如在开发者工具(d...

在元素个数不固定的情况下如何通过CSS选择第一个指定类名的子元素在处理HTML结构时,常常会遇到元素个数不�...
