【问题标题】:How commercial games handles on-the-fly font loading?商业游戏如何处理动态字体加载?
【发布时间】:2012-10-11 10:26:44
【问题描述】:

这就是我在伪代码(简化)中处理字体渲染的方式:

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 中找不到有用的信息。

任何帮助将不胜感激!

【问题讨论】:

    标签: c++ fonts directx freetype direct3d11


    【解决方案1】:

    与其逐个字形地进行,为什么不在软件中一次将整个字符串渲染为单个位图,然后将其渲染为单个纹理?由于文本在最初显示后通常不会频繁更改,因此您可以在第一次显示时按需渲染有问题的字符串,然后将字符串的纹理保留在 GPU 中直到它离开屏幕。

    【讨论】:

    • 好主意!可能这种技术可以非常快速地渲染刚刚选择的字体的小和/或静态字符串。它显着减少了多边形的数量(1 个字符串 = 1 个四边形)。但是,对于许多字符串和/或快速变化(例如,如果用户打开快速滚动游戏聊天/控制台或将在字段中逐个字符输入文本),由于字符串处理和设备资源生成,整体性能将较低。
    【解决方案2】:

    明显的改进是不预先渲染所有 50.000+ Unicode 字符。你真的需要中文吗?相反,使FontFace 能够根据需要即时传输字符,并且最初仅传输U+0020 - U+007E (ASCII)。

    一个更聪明的解决方案可能是在您需要第一个时渲染脚本中的所有字符。毕竟,如果您需要一个泰语字符,您可能需要更多。但这显然需要一些额外的表格来对 Unicode 字符进行分组。

    【讨论】:

    • 感谢您的想法!乍一看,将图集拆分到不同的语言环境,然后将字符串排序到每个语言环境的批处理不会太困难。我会考虑的。但是,即使加载纯 ASCII 字符也太慢了,无法在游戏运行时完成。所以实现即时自定义字体仍然是不可能的。
    【解决方案3】:

    游戏中的字体渲染通常通过位图完成,该位图包含在编译/离线时生成的所有字形。您可以使用像AngelCode BMFont 这样的位图字体生成器,它非常易于使用且非常适合游戏,因为它支持对 GPU 带宽更友好的 DXTx 压缩位图。

    对于高分辨率字体,Alpha Texted Magnification 技术目前是游戏中的首选技术,主要是在渲染贴花时。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-05-05
      • 1970-01-01
      • 1970-01-01
      • 2012-10-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多