这就是我在伪代码中处理字体渲染的方法(简化):
FontFace* CreateFontFace(fontName, fontSize)
{
FontFace* fontFace = LoadFromDiskCache(fontName, fontSize);
if ( fontFace == 0 )
{
for(each glyph)
{
Load glyph using FreeType;
Load its size and metric;
}
Pack all glyph bitmaps to a single UV-atlas
{
Calculate rectangles (RectangleBinPack); // Very slow!
Blit glyphs to UV-atlas; // Slow!
Insert rectangles to std::vector; // UV-dictionary;
Insert metrics to std::vector;
}
Wrap it all to a struct FontFace;
AddToDiskCache(fontName, fontSize);
// so on next startup it will be cached on HDD
}
return fontFace;
}
bool OnInit(fontName, fontSize)
{
for (each fontName)
{
for (each fontSize)
{
FontFace* fontFace = CreateFontFace(fontName, fontSize));
Insert fontFace to container based on std::map;
}
}
}
void OnSomtimes(FontFace, pDevice)
{
On demand create texture from FontFace.uvatlas on pDevice;
}
void OnRender(wstring, FontFace)
{
if(needUpdate)
{
// Generate std::vector<Sprite> using given FontFace
sprites = CreateSprites(wstring, FontFace);
}
Draw all vector<Sprite> at once with my SpriteBatch object;
// Big dynamic VertexBuffer, Instancing or GeometryShader
// depending on hardware caps
}
所以我可以缓存一些最常用的字体,甚至是所有曾经使用过的游戏字体。 但在某些应用程序中,用户可以选择另一种应用程序以前从未见过的字体/大小/样式,并立即应用。或者,例如,在一些游戏中,用户可以替换游戏文件夹中的“font.tff”文件,并且游戏将在启动时以多种尺寸/样式和数千个Unicode字符中的每一个使用它,而无需额外的时间预加载。奇迹!
我需要这样的东西 - 即时加载字体。
当然,我可以根据需要单独加载字形,并按字形呈现字形,但这意味着没有批处理,每帧的Draw调用和巨大的GPU带宽。不确定它对OpenGL是否正常,但它不适用于D3D11。
他们如何在游戏工作室中这样做?也许你知道一种不同的方法?我听说过将字体渲染为几何,GPU处理和复杂的曲线算法,但在google中找不到有用的信息。
任何帮助将不胜感激!
答案 0 :(得分:2)
游戏中的字体渲染通常是从包含在编译/离线时生成的所有字形的位图完成的。您可以使用像AngelCode BMFont这样的位图字体生成器,它非常易于使用并且非常适合游戏,因为它支持更加GPU带宽友好的DXTx压缩位图。
对于高分辨率字体,Alpha Texted Magnification技术目前是游戏中的首选技术,主要是在渲染贴花时。
答案 1 :(得分:1)
为什么不在软件中将整个字符串全部渲染为单个位图,而只是将其渲染为单个纹理?由于文本在最初显示时通常不会经常变化,因此您可以在首次显示时按需渲染字符串,然后将字符串的纹理保留在GPU中,直到它离开屏幕。
答案 2 :(得分:1)
显而易见的改进是不预先渲染所有50.000+ Unicode字符。你真的需要中文吗?相反,让FontFace
能够根据需要动态地设置字符,最初只是U+0020 - U+007E
(ASCII)。
一个稍微聪明的解决方案可能是在您需要第一个时从脚本中呈现所有字符。毕竟,如果你需要一个泰国角色,你可能需要更多。但这显然需要一些额外的表来对Unicode字符进行分组。