首页 / 资讯中心 / 文章详情

让游戏文字任意缩放

让游戏文字任意缩放 ★ FEATURED ARTICLE
从一份线下发来的核心算法代码到两次公开 PR社区伙伴与我一起把 SDF 接进了 Dora。游戏里的文字很少老实待在原来的大小做普通文档时文字选好字号便会安静地待在那里。游戏里的文字却没有这么听话标题会放大登场按钮会弹跳伤害数字会从角色头顶冒出来整个 UI 还可能跟着窗口和场景节点一起缩放。程序员只是想让文字动一动文字纹理却会在每次放大时认真交出自己的像素边缘。于是问题来了TrueType 字体里明明保存的是矢量轮廓为什么游戏文字放大以后仍会模糊、露出锯齿答案是字体文件保存着矢量轮廓不等于屏幕上的每一帧都在直接绘制矢量曲线。游戏引擎通常会先把字符轮廓转换成像素图再把许多字符装进 glyph atlas字形图集。以后显示文字时GPU 从纹理中找到相应区域便能快速绘制。这个过程叫作栅格化。它很适合实时渲染但也有代价如果一个字最初只生成了有限的像素再把小图放大纹理过滤只能柔化过渡不能凭空找回没有保存的边缘信息。所以我们真正想解决的并不是一个“中文小字号为什么更糊”的专门问题而是怎样让游戏文字在不同字号和节点缩放下仍然保持接近矢量渲染的稳定质量中文笔画密集很适合检验边缘和细节但这项能力并不只服务中文或小字号。三个很自然的办法为什么还不够第一次看到文字缩放后的质量不理想时我们很容易想到三个办法。第一个是换一款更好的字体。字体当然重要但换字体改变的是轮廓设计不会改变引擎烘焙和缩放字形纹理的方式。再好的字体也可能被一张过小的纹理放大成柔和的马赛克。第二个是把生成字号或纹理分辨率调大。这能为放大保留更多细节却会占据更多图集空间并增加生成、上传成本而且通常只能照顾一段预先猜好的尺寸范围。第三个是继续调整抗锯齿和纹理过滤参数。这些参数可以改善像素边缘的过渡却不能恢复栅格化时已经丢失的轮廓信息。这些方法都不是错的只是没有完整回答“同一份字形怎样覆盖更宽的缩放范围”。这正是 SDF 字体要处理的问题。SDF 保存的不是颜色而是离边缘还有多远SDF 是 Signed Distance Field 的缩写中文通常叫有符号距离场。普通字形纹理记录像素的明暗或透明度SDF 则记录这个位置离字形轮廓还有多远并用正负区分轮廓内外。可以把它想成一张围绕海岸线绘制的地形图海岸是零向陆地和海洋两边移动时数值沿不同方向变化。显示文字时shader 根据距离阈值重新找出边缘并安排平滑过渡。纹理保存的不再只是固定字号下的明暗结果而是关于“边缘在哪里”的可计算信息。文字改变尺寸时shader 可以重新调整过渡宽度让同一份字形缓存覆盖更宽的字号和缩放范围。描边也因此更自然选取另一段距离区间就能画出外轮廓不必另外准备描边图片。不过SDF 仍然是一张有限分辨率的距离纹理不是把字体文件中的全部曲线原样送进了 GPU。它还会受到烘焙尺寸、距离范围、图集空间、纹理采样和 shader 平滑参数影响。所以更准确的说法是SDF 能让字形纹理在更宽的尺寸范围内保持接近矢量缩放的质量但不是无限放大都永远无损。这项能力Dora 曾经放下过一次2018 年项目说明里曾经明确记录因为 SDF 渲染中文字符可能很慢相关字体渲染函数被移除。中文常用字符多单个汉字的轮廓也往往比拉丁字母复杂。SDF 还要为字形周围的像素计算到轮廓的距离。当这些计算在新字形进入缓存时完成速度就可能变成玩家或开发者能够感受到的等待。对个人维护的开源引擎来说“理论上可以实现”和“值得长期承担复杂度”不是同一件事。当时放下这项能力只是因为实现路径还没有给出足够好的交换条件。2024 年 12 月社区伙伴“有个小小杜”把一份 SDF 核心算法代码在线下发给我又和我一起讨论怎样接进 Dora。我负责完成 Label、FontManager、shader、API 和测试的初次整合核心算法则来自他的创作。从功能清单看这件事似乎已经可以打勾。但开源项目里有一种很容易被发布说明忽略的状态代码里已经有了不等于我们愿意默认把它交给所有用户。当时的生成速度和实现状态还没有让我觉得 SDF 真正跨过了可用门槛。他重新想了一遍距离场还能怎样生成接入只是开始。“有个小小杜”随后又把注意力放回生成器本身距离场已经能算出来了但能不能用更适合批量计算的方式重写最初加入 Dora 的SdfBuilder会为字形建立内外两组距离网格通过前后扫描逐步传播最近边缘再逐个计算每个像素的距离。PR #38 用新的sdf_gen2d实现替换了这套 Builder并引入 KTM 的向量计算加速类型把一部分距离结果按四个元素成组计算。这个改动最打动我的不只是速度变得可以接受而是他没有停留在“把现有代码跑快一点”而是重新组织了问题让实现更适合继续维护和整合。后来他又发现批量计算末尾的一到三个像素没有被正确补完于是用 PR #47 修正了循环起点。改动最终只有一行却体现了同一种创作态度既愿意提出新的算法路径也愿意回来把不起眼的边角修完整。可用的算法还要继续长成引擎能力社区 PR 让 SDF 生成跨过关键门槛但还不是字体系统的终点。之后Dora 继续修正参数把 NanoVG 的 SDF 文字接入 FontManager改进缩放平滑并在 2026 年 7 月让 Label 默认启用 SDF。当前 Dora 会把 SDF 字形统一按 64 像素的基础尺寸烘焙进图集。创建字号为 24 的 Label 时不必另生成一套 24 像素字形Label 使用24 / 64的比例计算显示尺寸其他字号也能复用这套缓存。非 SDF 字体则按请求字号烘焙同一字体的 16、24 和 48 像素版本可能需要分别进入缓存。只复用缓存还不够。文字变小边缘过渡太窄容易发硬或闪烁文字放大过渡太宽又会发虚。Label 会根据目标字号与 64 像素基础尺寸的比例计算平滑区间渲染时再结合节点的世界缩放调整。NanoVG 现在也通过同一个 FontCache 和 FontManager 获取字形、字距与图集区域并在绘制和边界测量中计入 SDF padding。Label 和矢量绘图界面不必再维护两套互不相识的字体缓存。从社区算法到缓存、测量、shader 和默认 API这些工作共同完成后“支持 SDF”才变成可以日常使用的引擎能力。我们准备怎样证明它确实更好文字渲染最终要让眼睛说话。但复活多年前的引擎、工具链和运行环境成本很高也容易引入其他变量因此后续素材不会伪装成“旧版与新版复现”。更可控的方法是在当前 Dora 中编写同一份真实 UI 演示只改变 Label 是否启用 SDF使用相同的字体、文字、颜色、背景和输出分辨率。同时创建非 SDF 与 SDF 两组文字。从创建字号开始逐步缩小和放大节点。放入中文、英文和数字混排观察不同复杂度的字形。截取原始尺寸、明显放大和明显缩小三个阶段。这组素材只回答在当前引擎的相同条件下普通字形纹理与 SDF 路径面对缩放时分别发生什么。它不代表历史版本的全部表现也不证明 SDF 在任何倍率下都没有代价但足以形成可观察、可复现的对照。开源贡献不只是发布说明末尾的一行名字回头看Dora 的 SDF 字体不是由某个人在某一天完整做成的。项目曾因中文字符的渲染成本放下这条路线后来“有个小小杜”带来了新的算法思路我把它接进引擎并继续完成字体系统整合。每一步解决的都不是同一个问题却共同决定了最后那一行sdf true能不能放心成为默认值。这也是我很喜欢的开源协作贡献不一定要带来全新的大功能。它也可以走进一个“已经能跑”的功能找到阻挡它被日常使用的门槛再把门槛推过去。有时候一项能力从“已经加入”走到“真正可用”中间差的正是另一位创作者看待问题的新方法。
阅读完成 · 觉得有帮助?
咨询建站