我正在使用FTGL库在我的C ++,OpenGL应用程序中渲染文本,但我发现它非常慢,尽管据说它是快速高效的库。
即使是少量文本,性能下降也是可见的,但是当我尝试渲染几行文本时,FPS从350减少到30~:
是的,我已经知道FPS不是检查效率的好方法,但在这种情况下应该没有那么大的差异。
我发现了一个允许我在内部使FTGL使用显示列表以提高速度的功能,但它似乎默认打开。无论如何,我尝试使用它,但它没有给我任何东西。所以我认为它可能已经被腐蚀了,或者我不太了解它,所以我决定将渲染文本放到我自己的显示列表中,但差别要么太小,以至于我甚至看不到它,或者没有区别。
bool TFontManager::renderWrappedText(font_ptr font, int lineLength, const TPoint& position, const std::string& text) {
if(font == nullptr) {
return false;
}
string key = sizeToString(font->FaceSize()); // key to look for it in map
key.append(TUtil::intToString(lineLength));
key.append(text);
GLuint displayListId = getDisplayListId(key); // get display list id from internal map
if(displayListId != 0) { // if display list id was found in map, i can call it
glCallList(displayListId);
return true;
}
// if id was not found, i'm creating new display list
FTSimpleLayout simpleLayout;
simpleLayout.SetLineLength((float)lineLength);
simpleLayout.SetFont(font.get());
displayListId = glGenLists(1);
glNewList(displayListId, GL_COMPILE);
glPushMatrix();
glTranslatef(position.x, position.y, 0.0f);
simpleLayout.Render(TUtil::stringToWString(text).c_str(), -1, FTPoint(), FTGL::RENDER_FRONT | FTGL::RENDER_BACK); // according to visual studio's profiler, bottleneck is inside this function. more exactly in drawing textured quads when i looked into FTGL code.
glPopMatrix();
glEndList();
m_textDisplayLists[key] = displayListId;
glCallList(displayListId);
return true;
}
我在调试模式下使用断点检查 - 它只创建一次显示列表,之后它只调用以前创建的一个。
渲染速度慢的原因可能是什么?我怎样才能加快速度呢?
修改
我正在使用FTTextureFont
(每个字形使用一个纹理)。根据{{3}} FTGL教程,我宁愿使用FTBufferFont
,因为它每行只使用一个纹理。缓冲区字体应该更快,但在我尝试之后它更加丑陋甚至更慢(6 fps而纹理字体给了我30 fps)。
EDIT2:
这是我创建字体的方式:
font_ptr TFontManager::getFont(const std::string& filename, int size) {
string fontKey = filename;
fontKey.append(sizeToString(size));
FontIter result = fonts.find(fontKey);
if(result != fonts.end()) {
return result->second; // Found font in list
}
// If font wasn't found, create a new one and store it in list of fonts
font_ptr font(new FTTextureFont(filename.c_str()));
font->UseDisplayList(true);
if(font->Error()) {
string message = "Failed to open font";
message.append(filename);
TError::showMessage(message);
return nullptr;
}
if(!font->FaceSize(size)) {
string message = "Failed to set font size";
TError::showMessage(message);
return nullptr;
}
fonts[fontKey] = font;
return font;
}
EDIT3:
这是从FTGL库源代码中获取的函数,该源代码在FTTextureFont
中呈现字形。它对单独的字形使用相同的纹理,只使用其他坐标,所以这不应该是一个问题。
const FTPoint& FTTextureGlyphImpl::RenderImpl(const FTPoint& pen,
int renderMode)
{
float dx, dy;
if(activeTextureID != glTextureID)
{
glBindTexture(GL_TEXTURE_2D, (GLuint)glTextureID);
activeTextureID = glTextureID;
}
dx = floor(pen.Xf() + corner.Xf());
dy = floor(pen.Yf() + corner.Yf());
glBegin(GL_QUADS);
glTexCoord2f(uv[0].Xf(), uv[0].Yf());
glVertex2f(dx, dy);
glTexCoord2f(uv[0].Xf(), uv[1].Yf());
glVertex2f(dx, dy - destHeight);
glTexCoord2f(uv[1].Xf(), uv[1].Yf());
glVertex2f(dx + destWidth, dy - destHeight);
glTexCoord2f(uv[1].Xf(), uv[0].Yf());
glVertex2f(dx + destWidth, dy);
glEnd();
return advance;
}
答案 0 :(得分:2)
从普通字体文件渲染排版是一项计算密集型操作。字体字形被读取为一组样条线,用于生成字符边界,这些字符边界被细分并送入图形管道。我对FreeType2不是很熟悉,但我使用过FTGL。您应该使用FontAtlas来呈现类型。 FontAtlas是一个常规纹理图集(很像精灵图纸),每个字体大小渲染一次,然后存储以供将来的字形渲染使用。
查看此链接以获取有关该流程的更多信息: http://antongerdelan.net/opengl4/freetypefonts.html
这应该会大大提高性能。虽然你可能会失去一些字体渲染的灵活性。