这就是我在伪代码(简化)中处理字体渲染的方式:
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 中找不到有用的信息。
任何帮助将不胜感激!