【发布时间】:2015-06-04 13:22:11
【问题描述】:
我目前正在寻找代码中的瓶颈,结果发现 GUI 就是其中之一。好吧,实际上不是 GUI,而是在那里绘制的动态文本。
初始化
if (FT_Init_FreeType(&m_FreeType))
throw Helpers::ExceptionWithMsg("Could not init freetype lib");
if (FT_New_Face(m_FreeType, "res\\fonts\\FreeSans.ttf", 0, &m_FontFace))
throw Helpers::ExceptionWithMsg("Could not open font");
m_ShaderID = ... // Loads the corresponding shader
m_TextColorLocation = glGetUniformLocation(m_ShaderID, "color");
m_CoordinatesLocation = glGetAttribLocation(m_ShaderID, "coord");
glGenBuffers(1, &m_VBO);
FT_Set_Pixel_Sizes(m_FontFace, 0, m_FontSize);
glyph = m_FontFace->glyph;
glGenTextures(1, &m_Texture);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_Texture);
// We require 1 byte alignment when uploading texture data
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
// Linear filtering usually looks best for text
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Clamping to edges is important to prevent artifacts when scaling
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glUseProgram(m_ShaderID);
glUniform4f(m_TextColorLocation, m_TextColor.x, m_TextColor.y, m_TextColor.z, m_TextColor.w);
glUseProgram(0);
我做什么:我初始化 FreeType,获取字体,初始化着色器和所有制服。
然后我为纹理坐标创建 vbo,为字体设置像素,获取字形。
现在我生成纹理,激活它,绑定它...我想设置所有参数,然后设置永不改变的制服。
渲染:
glUseProgram(m_ShaderID);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_Texture);
// Linear filtering usually looks best for text
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Set up the VBO for our vertex data
glEnableVertexAttribArray(m_CoordinatesLocation);
glBindBuffer(GL_ARRAY_BUFFER, m_VBO);
glVertexAttribPointer(m_CoordinatesLocation, 4, GL_FLOAT, GL_FALSE, 0, 0);
GLfloat cursorPosX = m_X;
GLfloat cursorPosY = m_Y;
for (size_t i = 0; i < m_Text.size(); ++i)
{
// If Loading a char fails, just continue
if (FT_Load_Char(m_FontFace, m_Text[i], FT_LOAD_RENDER))
continue;
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, glyph->bitmap.width, glyph->bitmap.rows, 0, GL_ALPHA, GL_UNSIGNED_BYTE, glyph->bitmap.buffer);
// Calculate the vertex and texture coordinates
GLfloat x2 = cursorPosX + glyph->bitmap_left * m_SX;
GLfloat y2 = -cursorPosY - glyph->bitmap_top * m_SY;
GLfloat w = glyph->bitmap.width * m_SX;
GLfloat h = glyph->bitmap.rows * m_SY;
PointStruct box[4] =
{
{ x2, -y2, 0, 0 },
{ x2 + w, -y2, 1, 0 },
{ x2, -y2 - h, 0, 1 },
{ x2 + w, -y2 - h, 1, 1 }
};
// Draw the character on the screen
glBufferData(GL_ARRAY_BUFFER, sizeof box, box, GL_DYNAMIC_DRAW);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
// Advance the cursor to the start of the next character
cursorPosX += glyph->advance.x / 64 * m_SX;
cursorPosY += glyph->advance.y / 64 * m_SY;
}
glDisableVertexAttribArray(m_CoordinatesLocation);
glDeleteTextures(1, &m_Texture);
glDisable(GL_BLEND);
glUseProgram(0);
设置着色器和其他东西是显而易见的。
对于每个渲染调用,我激活纹理,绑定它,启用我存储纹理坐标的 VBO。然后我遍历文本中的每个字符,并使用 FT_LOAD_CHAR 加载它。 然后我用 glTexImage2D 指定纹理,计算顶点和纹理坐标并绘制所有内容。
这似乎非常低效,但我找不到提高性能的方法,但仍然有可读的文本。
我想在 init 中只设置一次文本参数 -> 所有字符都是框。
我想将 GL_DYNAMIC_DRAW 设置为 GL_STATIC_DRAW...差别不大。 我还能做什么?
我渲染的文本是动态的,每一帧都会改变(或可能改变),所以我有点卡住了。
我用查询来查询这些东西的性能。如果我不渲染动态文本,它会非常低,但如果我渲染动态文本,它会变得非常高......在这个过程中没有其他事情发生,它只是在绘制 GUI。
真正困扰我的是什么
有一件事我真的不明白(可能是晴天……)
如果我没有在 render-method() 中设置线性过滤,我会得到奇怪的立方体字形,但这是为什么呢? OpenGL 是一个状态机,纹理参数设置为当前绑定的。那么如果我在初始化时将 Min 和 Mag 过滤器设置为 GL_LINEAR 为什么还不够呢?
如果我在渲染中删除这 2 行,我会从查询中获得更好的性能(数字要低得多),但它不会绘制任何可读的内容。
【问题讨论】:
-
关于您的第二个问题(立方体字形?)您的纹理可能不完整。搜索“opengl 纹理完整性”。