C openGL ES 2.0与其他线条绘制功能结合使用的字体渲染(Freetype)不起作用
此线程与https://stackoverflow.com/questions/50955558/render-fonts-with-sdl2-opengl-es-2-0-glsl-1-0-freetype相关 我在组合字体呈现和使用此函数时遇到如下问题:C openGL ES 2.0与其他线条绘制功能结合使用的字体渲染(Freetype)不起作用,c,fonts,opengl-es-2.0,sdl-2,freetype,C,Fonts,Opengl Es 2.0,Sdl 2,Freetype,此线程与https://stackoverflow.com/questions/50955558/render-fonts-with-sdl2-opengl-es-2-0-glsl-1-0-freetype相关 我在组合字体呈现和使用此函数时遇到如下问题: // Create VBO (Vertex Buffer Object) based on the vertices provided, render the vertices on the // background buffer and
// Create VBO (Vertex Buffer Object) based on the vertices provided, render the vertices on the
// background buffer and eventually swap buffers to update the display.
// Return index of VBO buffer
GLuint drawVertices(SDL_Window *window, Vertex *vertices, GLsizei numVertices, int mode){
// Number of vertices elements must be provided as a param (see numVertices) because
// sizeof() cannot calculate the size of the type a pointer points to
//GLsizei vertSize = sizeof(vertices[0]);
//SDL_Log("Vertices size is %d, no of vertices is %d", vertSize, numVertices);
// Create a VBO (Vertex Buffer Object)
GLuint VBO = vboCreate(vertices, numVertices);
if (!VBO) {
// Failed. Error message has already been printed, so just quit
return (GLuint)NULL;
}
// Set up for rendering the triangle (activate the VBO)
GLuint positionIdx = 0; // Position is vertex attribute 0
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glVertexAttribPointer(positionIdx, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*)0);
glEnableVertexAttribArray(positionIdx);
if (mode & CLEAR){
// Set color of the clear operation
glClearColor(0.0, 0.0, 0.0, 1.0);
// Clears the invisible buffer
glClear(GL_COLOR_BUFFER_BIT);
}
// Now draw!
// GL_POINTS = Draw only the pixels that correspond to the vertices coordinates
// GL_LINE_STRIP = Draw line that connects the vertices coordinates
// GL_LINE_LOOP = Draw line that connects the vertices coordinates plus a line that re-connects the last coordinate with the first
if (mode & RENDER){ glDrawArrays(GL_LINE_STRIP, 0, numVertices); }
// Don’t forget to flip the buffers as well, to display the final image:
// Update the window
if (mode & UPDATE){ SDL_GL_SwapWindow(window); }
return VBO;
}
此函数使用glDrawArrays()绘制一系列连接所提供顶点的直线。清除、渲染和更新标志用于执行以下操作:
drawVertices(window, vertices, sizeOfVertices, CLEAR | RENDER);
drawVertices(window, vertices, sizeOfVertices, RENDER);
drawVertices(window, vertices, sizeOfVertices, RENDER | UPDATE);
我对字体渲染函数也做了同样的事情,从而使我能够在不同的x,y坐标中绘制多个字符串。接下来的两个函数将根据我首先提交的代码进行字体渲染,并偏离您的更正
void render_text(const char *text, float x, float y, float sx, float sy) {
const char *p;
FT_GlyphSlot g = face->glyph;
SDL_Log("Debug info: glyph w: %d, glyph rows: %d", g->bitmap.width, g->bitmap.rows);
for(p = text; *p; p++) {
// If FT_Load_Char() returns a non-zero value then the glyph in *p could not be loaded
if(FT_Load_Char(face, *p, FT_LOAD_RENDER)){ continue; }
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RED,
g->bitmap.width,
g->bitmap.rows,
0,
GL_RED,
GL_UNSIGNED_BYTE,
g->bitmap.buffer
);
float x2 = x + g->bitmap_left * sx;
float y2 = -y - g->bitmap_top * sy;
float w = g->bitmap.width * sx;
float h = g->bitmap.rows * sy;
GLfloat box[4][4] = {
{x2, -y2 , 0, 0},
{x2 + w, -y2 , 1, 0},
{x2, -y2 - h, 0, 1},
{x2 + w, -y2 - h, 1, 1},
};
glBufferData(GL_ARRAY_BUFFER, sizeof box, box, GL_DYNAMIC_DRAW);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
x += (g->advance.x>>6) * sx;
y += (g->advance.y>>6) * sy;
}
}
void glRenderText(char *text, int _x, int _y, SDL_Color rgb, int mode) {
float x = _x;
float y = _y;
int w=0, h=0;
SDL_GetWindowSize(SDLmain.window, &w, &h);
float xMax = 2.0 / (float)w;
float yMax = 2.0 / (float)h;
GLuint color_loc = glGetUniformLocation( shaderProg, "color" );
float col[4] = { (float)rgb.r/255, (float)rgb.g/255, (float)rgb.b/255, 1 }; // red and opaque
glUniform4fv( color_loc, 1, col);
// Clear invisible buffer
if (mode & CLEAR){ glClearColor(0.0, 0.0, 0.0, 1); glClear(GL_COLOR_BUFFER_BIT); }
// If coordinate system required is:
// COORD_SYS_CONVENTIONAL = (1) left bottom corner is 0,0 and moving towards right and top sides we reach max screen size in pixels e.g 1024 * 768 pixels
// COORD_SYS_CARTECIAN = (2) left bottom corner is -1,-1 and moving towards right and top sides we reach +1,+1 . The center of the display is always 0,0
if (mode & ~COORD_SYS_CARTECIAN){
x = (_x * xMax)-1;
y = (_y * yMax)-1;
}
// Draw the text on the invisible buffer
if (mode & RENDER){ render_text(text, x, y, xMax, yMax); }
// Update display
if (mode & UPDATE){ SDL_GL_SwapWindow(SDLmain.window); }
}
因此,我可以做到:
glRenderText(tmp, 0, 0, Olive, CLEAR | RENDER | UPDATE);
glRenderText(tmp, 0, 150, Yellow_Green, RENDER);
glRenderText(tmp, 0, 300, Light_Coral, RENDER | UPDATE);
事实证明,我可以在不同的x、y坐标下渲染字体,也可以使用函数drawVertices渲染连接这些顶点的线,但不能同时渲染这两个顶点。也就是说,我不能这样做:
glRenderText(tmp, 0, 0, Olive, CLEAR | RENDER);
glRenderText(tmp, 0, 150, Yellow_Green, RENDER);
glRenderText(tmp, 0, 300, Light_Coral, RENDER);
drawVertices(window, vertices, sizeOfVertices, RENDER);
drawVertices(window, vertices, sizeOfVertices, RENDER);
drawVertices(window, vertices, sizeOfVertices, RENDER | UPDATE);
正如您所知,逻辑是,在任何一个函数中,您必须只使用一个清除的| RENDER标志,然后只进行渲染,并且在最后一次调用任何一个函数时使用RENDER | UPDATE
问题:
(1) 在我尝试执行前面的操作时,即组合glRenderText()+drawVertices()失败,因为在逐个调用它们之前,显然有一些东西需要设置
(2) 我面临的另一个问题是,在我的raspi3上运行代码导致drawVertices()工作正常。当谈到字体时,我只能看到glClearColor()和glClear(GL_COLOR_BUFFER_位)的效果,这意味着通过glClearColor()的颜色设置清除了显示,但没有看到字体渲染。我尝试了两种GL驱动模式。有一个称为完整KMS GL驱动程序,另一个称为伪KMS GL驱动程序
此外,为了使drawVertices()工作,我必须对下面提供的代码进行注释:
FT_Set_Pixel_Sizes(face, 0, 200);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
GLuint vbo;
GLuint attribute_coord=0;
glGenBuffers(1, &vbo);
glEnableVertexAttribArray(attribute_coord);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer(attribute_coord, 4, GL_FLOAT, GL_FALSE, 0, 0);
我仍然必须保持以下代码处于活动状态:
// Load the shader program and set it for use
shaderProg = shaderProgLoad("shaderV1.vert", "shaderV1.frag");
GLuint tex_loc = glGetUniformLocation( shaderProg, "tex" );
GLuint color_loc = glGetUniformLocation( shaderProg, "color" );
// Activate the resulting shaders program
glUseProgram(shaderProg);
glUniform1i( tex_loc, 0 ); // 0, because the texture is bound to of texture unit 0
// Define RGB color + Alpha
float col[4] = { 0.0f, 1.0f, 1.0, 1.0f };
glUniform4fv( color_loc, 1, col);
我可以通过重置这两个操作(glRenderText()和drawVertices()不常见的几乎所有内容来解决这个问题 在调用两个函数()glRenderText()和drawVertices()中的任何一个函数之前,以下代码保持原样。这两个函数已更新,以便在到达执行glDrawArrays()的点之前进行适当的重置
// Load the shader program and set it for use
shaderProg = shaderProgLoad("shaderV1.vert", "shaderV1.frag");
// Activate the resulting shaders program
glUseProgram(shaderProg);
// After the shaders (vertex & fragment) have been compiled & linked into a program
// we can query the location index value of a uniform variable existing in the program.
// In this case we are querying uniform variables "tex" that exist in the fragment shader
GLuint tex_loc = glGetUniformLocation( shaderProg, "tex" );
// Set the value of the uniform variable "tex_loc" to 0, because the texture is bound to of texture unit 0
glUniform1i( tex_loc, 0 );
这是一个更新的函数,它重置了一些选项,以便我们得到所需的结果。例如,glDisable(GL_混合);用于在绘制线条时禁用混合。最重要的一点是,每次调用drawVertices()时,我都使用glBindBuffer()设置适当的缓冲区供opengl使用。glGenBuffers()仅在相应的对象名称为0时使用一次,这意味着使用的对象名称尚未分配给vbo
GLuint drawVertices(SDL_Window *window, GLuint vbo, Vertex *vertices, GLsizei numVertices, SDL_Color rgb, int mode){
float col[4] = { (float)rgb.r/255, (float)rgb.g/255, (float)rgb.b/255, 1.0 };
// Get an available object name for glBindBuffer() when object name is ZERO
if (!vbo){ glGenBuffers(1, &vbo); }
// Check for problems
GLenum err = glGetError();
// Deal with errors
if (err != GL_NO_ERROR) {
// Failed
glDeleteBuffers(1, &vbo);
SDL_Log("Creating VBO failed, code %u\n", err);
vbo = 0;
}
else if (!vbo) {
// Failed. Error message has already been printed, so just quit
return (GLuint)NULL;
}
if (mode & CLEAR){
// Set color of the clear operation
glClearColor(0.0, 0.0, 0.0, 1.0);
// Clears the invisible buffer
glClear(GL_COLOR_BUFFER_BIT);
}
if (mode & RENDER){
// Dissable blending when drawing lines
glDisable(GL_BLEND);
// Set up for rendering the triangle (activate the vbo)
// Position is vertex attribute 0
GLuint attribute_coord = 0;
// Specifies the index of the generic vertex attribute and enables it
glEnableVertexAttribArray(attribute_coord);
// Set the buffer to be used from now on
glBindBuffer(GL_ARRAY_BUFFER, vbo);
// Define an array of generic vertex attribute data
glVertexAttribPointer(attribute_coord, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*)0);
// Get the location of the uniform variable "color_loc"
GLuint color_loc = glGetUniformLocation( shaderProg, "color" );
// Set the value of the uniform variable "color_loc" to array "col"
glUniform4fv( color_loc, 1, col);
// Copy vertices into buffer
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * numVertices, vertices, GL_STATIC_DRAW);
// Now draw!
// GL_POINTS = Draw only the pixels that correspond to the vertices coordinates
// GL_LINE_STRIP = Draw line that connects the vertices coordinates
// GL_LINE_LOOP = Draw line that connects the vertices coordinates plus a line that re-connects the last coordinate with the first
// GL_TRIANGLE_FAN =
glDrawArrays(GL_LINE_STRIP, 0, numVertices);
}
// Don’t forget to flip the buffers as well, to display the final image:
// Update the window
if (mode & UPDATE){ SDL_GL_SwapWindow(window); }
return vbo;
}
函数glRenderText()的工作方式基本相同
逻辑是在main()或全局范围中定义了2个VBO(一个用于通过drawVertices绘制线条,一个用于通过glRenderText()绘制字体),并将其传递给glRenderText()&drawVertices()。这两个函数更新其本地副本的值并返回vbo,以便更新主范围或全局范围内的vbo。可以完全通过引用而不是采用我的方法来传递它们
不过,我还没有在我的raspi3中测试该功能。我很快就会回来更新。无论如何,上面给出的函数是完全功能的
再次感谢您抽出时间
// render_text is called by glRenderText()
void render_text(const char *text, float x, float y, float sx, float sy) {
const char *p;
FT_GlyphSlot g = face->glyph;
//SDL_Log("Debug info: glyph w: %d, glyph rows: %d", g->bitmap.width, g->bitmap.rows);
for(p = text; *p; p++) {
// If FT_Load_Char() returns a non-zero value then the glyph in *p could not be loaded
if(FT_Load_Char(face, *p, FT_LOAD_RENDER)){ continue; }
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RED,
g->bitmap.width,
g->bitmap.rows,
0,
GL_RED,
GL_UNSIGNED_BYTE,
g->bitmap.buffer
);
float x2 = x + g->bitmap_left * sx;
float y2 = -y - g->bitmap_top * sy;
float w = g->bitmap.width * sx;
float h = g->bitmap.rows * sy;
GLfloat box[4][4] = {
{x2, -y2 , 0, 0},
{x2 + w, -y2 , 1, 0},
{x2, -y2 - h, 0, 1},
{x2 + w, -y2 - h, 1, 1},
};
glBufferData(GL_ARRAY_BUFFER, sizeof box, box, GL_DYNAMIC_DRAW);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
x += (g->advance.x>>6) * sx;
y += (g->advance.y>>6) * sy;
}
}
GLuint glRenderText(char *text, int fontSize, GLuint vbo, int _x, int _y, SDL_Color rgb, int mode) {
float x = _x;
float y = _y;
float xMax = 2.0 / (float)getWindowWidth();
float yMax = 2.0 / (float)getWindowHeight();
GLuint attribute_coord=0;
float col[4] = { (float)rgb.r/255, (float)rgb.g/255, (float)rgb.b/255, 1 };
// Enable blending when drawing fonts
glEnable(GL_BLEND);
// Set the W & H of the font loaded
FT_Set_Pixel_Sizes(face, 0, fontSize);
// If vbo is ZERO setup and get an object name
if (!vbo){
// Enables blending operations
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// Set texture parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Specifies the alignment requirements for the start of each pixel row in memory
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
// Save into vbo one unused buffer name (index) for use with glBindBuffer
glGenBuffers(1, &vbo);
// Specifies the index of the generic vertex attribute and enables it
glEnableVertexAttribArray(attribute_coord);
}
// Set the buffer to be used from now on to the one indicated by vbo
glBindBuffer(GL_ARRAY_BUFFER, vbo);
// Define an array of generic vertex attribute data
glVertexAttribPointer(attribute_coord, 4, GL_FLOAT, GL_FALSE, 0, 0);
GLuint color_loc = glGetUniformLocation( shaderProg, "color" );
// Set the value of the uniform variable "color_loc" from array "col"
glUniform4fv( color_loc, 1, col);
// Clear invisible buffer
if (mode & CLEAR){
glClearColor(0.0, 0.0, 0.0, 1);
glClear(GL_COLOR_BUFFER_BIT);
}
// If coordinate system required is:
// COORD_SYS_CONVENTIONAL = (1) left bottom corner is 0,0 and moving towards right and top sides we reach max screen size in pixels e.g 1024 * 768 pixels
// COORD_SYS_CARTECIAN = (2) left bottom corner is -1,-1 and moving towards right and top sides we reach +1,+1 . The center of the display is always 0,0
if (mode & ~COORD_SYS_CARTECIAN){
x = (_x * xMax)-1;
y = (_y * yMax)-1;
}
// Draw the text on the invisible buffer
if (mode & RENDER){ render_text(text, x, y, xMax, yMax); }
// Update display
if (mode & UPDATE){ SDL_GL_SwapWindow(SDLmain.window); }
return vbo;
}