使用FreeType在OpenGL中渲染文本出现黑屏问题求助
OpenGL文本渲染仅显示黑屏的排查与解决
我尝试在OpenGL中使用cglm(C语言版glm)、glad和glfw显示简单文本,但程序运行后仅出现黑屏。程序编译运行无错误,代码如下:
#include <iostream> #include <map> #include <string> #include <vendor/glad/glad.h> #include <vendor/GLFW/glfw3.h> #include <vendor/cglm/cglm.h> #include <ft2build.h> #include FT_FREETYPE_H // settings const unsigned int SCR_WIDTH = 800; const unsigned int SCR_HEIGHT = 600; const char *vertexShaderSource = "#version 330 core\n" "layout (location = 0) in vec4 vertex; // <vec2 pos, vec2 tex>\n" "out vec2 TexCoords;\n" "uniform mat4 projection;\n" "void main()\n" "{\n" " gl_Position = projection * vec4(vertex.xy, 0.0, 1.0);\n" " TexCoords = vertex.zw;\n" "};\n"; const char *fragmentShaderSource = "#version 330 core\n" "in vec2 TexCoords;\n" "out vec4 color;\n" "uniform sampler2D text;\n" "uniform vec3 textColor;\n" "void main()\n" "{\n" " vec4 sampled = vec4(1.0, 1.0, 1.0, texture(text, TexCoords).r);\n" " color = vec4(textColor, 1.0) * sampled;\n" "};\n"; typedef struct my_vec3 { float x; float y; float z; } my_vec3; typedef struct my_vec2 { int x; int y; } my_vec2; typedef struct Character { unsigned int TextureID; // ID handle of the glyph texture my_vec2 Size; // Size of glyph my_vec2 Bearing; // Offset from baseline to left/top of glyph unsigned int Advance; // Horizontal offset to advance to next glyph } Character; void framebuffer_size_callback(GLFWwindow *window, int width, int height); void processInput(GLFWwindow *window); void RenderText(GLuint shader, std::string text, float x, float y, float scale, my_vec3 color); unsigned int VAO, VBO; std::map<GLchar, Character> Characters; int main() { glfwInit(); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); GLFWwindow *window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL); if (window == NULL) { printf("Failed to create GLFW window"); glfwTerminate(); return -1; } glfwMakeContextCurrent(window); glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { printf("Failed to initialize GLAD"); return -1; } glEnable(GL_CULL_FACE); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vertexShader, 1, &vertexShaderSource, NULL); glCompileShader(vertexShader); int success; char infoLog[512]; glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success); if (!success) { glGetShaderInfoLog(vertexShader, 512, NULL, infoLog); printf("ERROR::SHADER::VERTEX::COMPILATION_FAILED %s\n", infoLog); } unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL); glCompileShader(fragmentShader); glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success); if (!success) { glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog); printf("ERROR::SHADER::FRAGMENT::COMPILATION_FAILED %s\n", infoLog); } unsigned int shaderProgram = glCreateProgram(); glAttachShader(shaderProgram, vertexShader); glAttachShader(shaderProgram, fragmentShader); glLinkProgram(shaderProgram); glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success); if (!success) { glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog); printf("ERROR::SHADER::PROGRAM::LINKING_FAILED %s\n", infoLog); } glDeleteShader(vertexShader); glDeleteShader(fragmentShader); mat4 projection; glm_mat4_identity(projection); glm_ortho(0.0, static_cast<float>(SCR_WIDTH), 0.0f, static_cast<float>(SCR_HEIGHT), 0.01, 100.0, projection); // glm_perspective(4.8, (float)SCR_WIDTH/(float)SCR_WIDTH, 0.01, 100.0, projection); glUseProgram(shaderProgram); glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "projection"), 1, GL_FALSE, &projection[0][0]); FT_Library ft; if (FT_Init_FreeType(&ft)) { std::cout << "ERROR::FREETYPE: Could not init FreeType Library" << std::endl; return -1; } std::string font_name = "/home/filip/Downloads/arial/arial.ttf"; FT_Face face; if (FT_New_Face(ft, font_name.c_str(), 0, &face)) { std::cout << "ERROR::FREETYPE: Failed to load font" << std::endl; return -1; } else { FT_Set_Pixel_Sizes(face, 0, 48); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); for (unsigned char c = 0; c < 128; c++) { if (FT_Load_Char(face, c, FT_LOAD_RENDER)) { std::cout << "ERROR::FREETYTPE: Failed to load Glyph" << std::endl; continue; } unsigned int texture; glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); glTexImage2D( GL_TEXTURE_2D, 0, GL_RED, face->glyph->bitmap.width, face->glyph->bitmap.rows, 0, GL_RED, GL_UNSIGNED_BYTE, face->glyph->bitmap.buffer); 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); my_vec2 size; size.x = face->glyph->bitmap.width; size.y = face->glyph->bitmap.rows; my_vec2 bearing; bearing.x = face->glyph->bitmap_left; bearing.y = face->glyph->bitmap_top; Character character = { texture, size, bearing, static_cast<unsigned int>(face->glyph->advance.x)}; Characters.insert(std::pair<char, Character>(c, character)); } glBindTexture(GL_TEXTURE_2D, 0); } FT_Done_Face(face); FT_Done_FreeType(ft); glGenVertexArrays(1, &VAO); glGenBuffers(1, &VBO); glBindVertexArray(VAO); glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6 * 4, NULL, GL_DYNAMIC_DRAW); glEnableVertexAttribArray(0); glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); while (!glfwWindowShouldClose(window)) { processInput(window); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); my_vec3 color1; color1.x = 0.5; color1.y = 0.8; color1.z = 0.2; my_vec3 color2; color2.x = 0.3; color2.y = 0.7; color2.z = 0.9; RenderText(shaderProgram, "This is sample text", 125.0f, 125.0f, 1.0f, color1); RenderText(shaderProgram, "(C) LearnOpenGL123.com", 370.0f, 370.0f, 0.5f, color2); glfwSwapBuffers(window); glfwPollEvents(); } glfwTerminate(); return 0; } void processInput(GLFWwindow *window) { if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) glfwSetWindowShouldClose(window, true); } void framebuffer_size_callback(GLFWwindow *window, int width, int height) { glViewport(0, 0, width, height); } void RenderText(GLuint shader, std::string text, float x, float y, float scale, my_vec3 color) { glUseProgram(shader); glUniform3f(glGetUniformLocation(shader, "textColor"), color.x, color.y, color.z); glActiveTexture(GL_TEXTURE0); glBindVertexArray(VAO); std::string::const_iterator c; for (c = text.begin(); c != text.end(); c++) { Character ch = Characters[*c]; float xpos = x + ch.Bearing.x * scale; float ypos = y - (ch.Size.y - ch.Bearing.y) * scale; float w = ch.Size.x * scale; float h = ch.Size.y * scale; float vertices[6][4] = { {xpos, ypos + h, 0.0f, 0.0f}, {xpos, ypos, 0.0f, 1.0f}, {xpos + w, ypos, 1.0f, 1.0f}, {xpos, ypos + h, 0.0f, 0.0f}, {xpos + w, ypos, 1.0f, 1.0f}, {xpos + w, ypos + h, 1.0f, 0.0f}}; glBindTexture(GL_TEXTURE_2D, ch.TextureID); glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices); // be sure to use glBufferSubData and not glBufferData glBindBuffer(GL_ARRAY_BUFFER, 0); glDrawArrays(GL_TRIANGLES, 0, 6); x += (ch.Advance >> 6) * scale; // bitshift by 6 to get value in pixels (2^6 = 64 (divide amount of 1/64th pixels by 64 to get amount of pixels)) } glBindVertexArray(0); glBindTexture(GL_TEXTURE_2D, 0); }
问题排查与解决
正交矩阵方向错误:当前
glm_ortho的y轴范围是从0到窗口高度,而OpenGL的NDC坐标系中y轴向上,FreeType的字形基线在下方,这会导致文本被渲染到视口外。修正正交矩阵的y轴范围:glm_ortho(0.0f, static_cast<float>(SCR_WIDTH), static_cast<float>(SCR_HEIGHT), 0.0f, 0.01f, 100.0f, projection);纹理采样器未绑定:片段着色器中的
sampler2D text默认使用纹理单元0,但需要显式设置该uniform的值。在设置投影矩阵后添加:glUniform1i(glGetUniformLocation(shaderProgram, "text"), 0);字体路径验证:确认
/home/filip/Downloads/arial/arial.ttf路径正确,若FreeType加载字体失败,会跳过字形纹理生成,导致无内容可渲染。可在FT_New_Face成功后添加日志输出验证。渲染状态检查:确保
GL_BLEND已正确启用(你的代码中已启用),否则文本的透明通道无法正常显示,可能导致文本被黑屏覆盖。
内容的提问来源于stack exchange,提问作者Filip Vuković
相关产品推荐
相关产品推荐

