irpas技术客

游戏引擎Flax Engine源码分析(九)渲染_AnHeee

irpas 4292

?2021SC@SDUSC


一、概述

? ? ? ? 这篇文章我们主要分析一下文本渲染,也就是DrawText()函数及其几个重载。仍然是2D渲染的部分、

二、分析

? ? ? ? DrawText有一下几个重载:

static void DrawText(Font* font, const StringView& text, const Color& color, const Vector2& location, MaterialBase* customMaterial = nullptr); static void DrawText(Font* font, const StringView& text, API_PARAM(Ref) const TextRange& textRange, const Color& color, const Vector2& location, MaterialBase* customMaterial = nullptr); static void DrawText(Font* font, const StringView& text, const Color& color, API_PARAM(Ref) const TextLayoutOptions& layout, MaterialBase* customMaterial = nullptr); static void DrawText(Font* font, const StringView& text, API_PARAM(Ref) const TextRange& textRange, const Color& color, API_PARAM(Ref) const TextLayoutOptions& layout, MaterialBase* customMaterial = nullptr);

? ? ? ? 第三第四个重载用于绘制带格式的文本。

? ? ? ? 我们简单分析一下函数的几个参数:

font: 使用的字体

text: 被渲染的文本

color: 使用的颜色

location: 二维向量,表示文本的位置

customMaterial:用于字体字符呈现的自定义材质。它必须包含用于取样字体纹理的名为Font的纹理参数

textRange:?输入文本范围(输入文本参数的子字符串范围)

layout:文本布局属性

? ? ? ? ?下面来看具体的函数实现:


?????????第一个重载(没有参数textRange和layout):

????????检车是否需要进行渲染操作

if (font == nullptr || text.IsEmpty() || (customMaterial && (!customMaterial->IsReady() || !customMaterial->IsGUI()))) return;

? ? ? ? 临时数据:

uint32 fontAtlasIndex = 0; FontTextureAtlas* fontAtlas = nullptr; Vector2 invAtlasSize = Vector2::One; FontCharacterEntry previous; int32 kerning; float scale = 1.0f / FontManager::FontScale;

? ? ? ? 接下来渲染所有字符:

? ? ? ? 首先判断了自定义材质(customMaterial)是否为空,根据情况进行不同的2D渲染调用。(2D渲染调用的类型在之前的博客中已提及)

FontCharacterEntry entry; Render2DDrawCall drawCall; if (customMaterial) { drawCall.Type = DrawCallType::DrawCharMaterial; drawCall.AsChar.Mat = customMaterial; } else { drawCall.Type = DrawCallType::DrawChar; drawCall.AsChar.Mat = nullptr; } Vector2 pointer = location;

? ? ? ? 然后对每一个字符进行渲染:

for (int32 currentIndex = 0; currentIndex <= text.Length(); currentIndex++)

????????缓存当前字符

const Char currentChar = text[currentIndex];

? ? ? ? 检查是否是换行符,若不是:

????????获取字符条目????????检查是否需要选择/更改字体图集(因为相同字体的字符可能位于不同的地图集中),获取包含当前字符的纹理图谱。????????检查字符是否是空格,调整字距,省略空格字符,计算字符大小和地图坐标,添加绘图调用。? ? ? ? 移动。

? ? ? ? 若是换行符:

? ? ? ? 仅执行移动操作。

if (currentChar != '\n') { font->GetCharacter(currentChar, entry); if (fontAtlas == nullptr || entry.TextureIndex != fontAtlasIndex) { fontAtlasIndex = entry.TextureIndex; fontAtlas = FontManager::GetAtlas(fontAtlasIndex); if (fontAtlas) { fontAtlas->EnsureTextureCreated(); drawCall.AsChar.Tex = fontAtlas->GetTexture(); invAtlasSize = 1.0f / fontAtlas->GetSize(); } else { drawCall.AsChar.Tex = nullptr; invAtlasSize = 1.0f; } } const bool isWhitespace = StringUtils::IsWhitespace(currentChar); if (!isWhitespace && previous.IsValid) { kerning = font->GetKerning(previous.Character, entry.Character); } else { kerning = 0; } pointer.X += kerning * scale; previous = entry; if (!isWhitespace) { const float x = pointer.X + entry.OffsetX * scale; const float y = pointer.Y + (font->GetHeight() + font->GetDescender() - entry.OffsetY) * scale; Rectangle charRect(x, y, entry.UVSize.X * scale, entry.UVSize.Y * scale); Vector2 upperLeftUV = entry.UV * invAtlasSize; Vector2 rightBottomUV = (entry.UV + entry.UVSize) * invAtlasSize; drawCall.StartIB = IBIndex; drawCall.CountIB = 6; DrawCalls.Add(drawCall); WriteRect(charRect, color, upperLeftUV, rightBottomUV); } pointer.X += entry.AdvanceX * scale; }

? ? ? ? 第二个重载(带有参数textRange):

DrawText(font, StringView(text.Get() + textRange.StartIndex, textRange.Length()), color, location, customMaterial);

? ? ? ? StringView类型将静态文本视图表示为 utf-16字符序列。?可见此处仅是将text和textRange重新组装后再次调用之前的文本渲染函数。


? ? ? ? 第三个重载(带有参数layout):

? ? ? ? 大体上与第一个重载一样,这里仅分析不同之处:

? ? ? ? 首先是在准备阶段,除了判断是否需要进行渲染和声明临时数据外,对文本进行处理以获取行:

Lines.Clear(); font->ProcessText(text, Lines, layout);

? ? ? ? 注意后面对每个字符渲染的部分在这里做了一些改变,变成了两层循环,及将之前的获取每个字符的for语句改成如下结构:

for (int32 lineIndex = 0; lineIndex < Lines.Count(); lineIndex++) { const FontLineCache& line = Lines[lineIndex]; Vector2 pointer = line.Location; for (int32 charIndex = line.FirstCharIndex; charIndex <= line.LastCharIndex; charIndex++)

? ? ? ? 即首先对上面获取的行进行一次位置的处理,在对每一行的每一个字符进行渲染,以这样的方式完成布局。?


? ? ? ? 第四个重载(带有layout和textRange):?

? ? ? ? 这里就不再赘述,textRange与text参数组合后调用第三个重载方法即可。


? ? ? ? 本次的分析就到这里,感谢。?


1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,会注明原创字样,如未注明都非原创,如有侵权请联系删除!;3.作者投稿可能会经我们编辑修改或补充;4.本站不提供任何储存功能只提供收集或者投稿人的网盘链接。

标签: #游戏引擎Flax #Engine源码分析九渲染 #2021SCSDUSC一概述 #仍然是2D渲染的部分二分析