1

我有以下代码可以在屏幕外 FBO 上渲染一个矩形和一些文本。然后我尝试在默认/显示帧缓冲区中绑定纹理(附加到 FBO)。我能够渲染矩形,但字体没有被渲染。我尝试调试,但到目前为止还不能。我只需要在 OpenGL ES 2.0 中执行此操作。

我的矩形是橙色的。文本/字体为红色。我使用 Freetype lib 和 glTexImage2D 调用为每种字体创建单独的纹理。当我直接在默认帧缓冲区上渲染时,我成功获得了一个橙色矩形和红色字体。但是当我首先在屏幕外 FBO 上执行此操作时,我会得到一个带红色的矩形和一些垃圾小文本(我假设)。我正在继续调试,但任何输入都会有所帮助。

注意:我是 OpenGL 的新手。

EGLSurface eglsurface;
EGLDisplay egldisplay;
EGLConfig eglconfig;
EGLContext eglcontext;
void* NativeWindow;
GLuint VBO;
FT_Face face;
unsigned int shaderProgram;
unsigned int vertexShader;
unsigned int fragmentShader;
int color_loc;

const GLuint WIDTH = 1920, HEIGHT = 1080;

EGLint Attributes[] = { EGL_RED_SIZE,        1,
                        EGL_GREEN_SIZE,      1,
                        EGL_BLUE_SIZE,       1,
                        EGL_ALPHA_SIZE,      1,
                        EGL_NONE };

EGLint contextAttributes[] = { EGL_CONTEXT_CLIENT_VERSION,
                               2,
                               EGL_NONE };

void GlInit()
{
  glViewport(0, 0, WIDTH, HEIGHT);

  const char *vertexShaderSource = 
    "attribute vec4 vertex;\n"
    "varying vec2 texcoord;\n"
    "void main()\n"
    "{\n"
    "gl_Position = vec4(vertex.xy, 0, 1);\n"
    "texcoord = vertex.zw;\n"
    "}\n";

  const char *fragmentShaderSource =
    "precision highp float;\n"
     "varying vec2 texcoord;\n"
    "uniform sampler2D s_texture;\n"
    "uniform vec4 myColor;\n"
    "void main(void) {\n"
    "gl_FragColor = vec4(1, 1, 1, texture2D(s_texture, texcoord).a) * myColor;\n"
    "}\n";

  unsigned int vertexShader;
  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\n");
  }

  fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
  glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
  glCompileShader(fragmentShader);
  glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
  if(!success) {
    glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
    printf("ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n");
  }

  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::LINKING_FAILED\n");
  }

  glGenBuffers(1, &VBO);
  glUseProgram(shaderProgram);

  //glClearDepthf(1.0f);
  //glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
  //glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  // SAGAR - Blend required for texture
  //glEnable(GL_BLEND);
  //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

  // Get the color location in fragment shader, will fill on need
  color_loc = glGetUniformLocation(shaderProgram, "myColor");
}

void DrawRect()
{
  glBindBuffer(GL_ARRAY_BUFFER, VBO);

  int position_loc = glGetAttribLocation(shaderProgram, "vertex");
  glEnableVertexAttribArray(position_loc);
  glVertexAttribPointer(position_loc, 4, GL_FLOAT, GL_FALSE, 0, 0);

  GLfloat rectangle[4][4] = {
    -0.5f,  0.5f, 0.0f, 1.0f,
     0.5f,  0.5f, 0.0f, 1.0f,
    -0.5f, -0.5f, 0.0f, 1.0f,
     0.5f, -0.5f, 0.0f, 1.0f
  };

  glUniform4f(color_loc, 1.0f, 0.5f, 0.2f, 1.0f); // Orange

  glBufferData(GL_ARRAY_BUFFER, sizeof rectangle, rectangle, GL_DYNAMIC_DRAW);
  glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}

void render_fboTexture()
{
  int TextureLocation = glGetUniformLocation(shaderProgram, "s_texture");
  glUniform1i(TextureLocation, 0);
  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

  // Draw in a small quad for testing
  GLfloat quad[4][4] = {
    {-0.5, 0.5, 0, 0},
    {0.5, 0.5, 1, 0},
    {-0.5, -0.5, 0, 1},
    {0.5, -0.5, 1, 1},
  };

  glBufferData(GL_ARRAY_BUFFER, sizeof quad, quad, GL_DYNAMIC_DRAW);
  glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}

void render_captiondata(const char* caption, float x, float y, float sx, float sy);
void RenderTexture()
{
    int TextureLocation = glGetUniformLocation(shaderProgram, "s_texture");
    glUniform1i(TextureLocation, 0);

    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

    // Set desired text color
    glUniform4f(color_loc, 0.5f, 0.0f, 0.0f, 1.0f); // Red

    FT_Library ft;
    if (FT_Init_FreeType(&ft)) {
      printf("SAGAR- Could not init FreeType Library\n");
    }

    if (FT_New_Face(ft, "./xyz.ttf", 0, &face)) {
      printf("SAGAR - Failed to load font\n");
    }
    FT_Set_Pixel_Sizes(face, 0, 48);

    GLuint texture;
    glActiveTexture(GL_TEXTURE0);
    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);

    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);

    // Calculate the scales both sides
    float sx = 2.0 / WIDTH;
    float sy = 2.0 / HEIGHT;
    float x = -0.4;
    float y = 0.3;

    render_captiondata("-- Hello OpenGL! --", x, y, sx, sy);
}

void render_captiondata(const char* caption, float x, float y, float sx, float sy)
{
  const char *p;
  for(p = caption; *p; p++) {
    if (FT_Load_Char(face, *p, FT_LOAD_RENDER)) {
        printf("SAGAR - Failed to load Glyph\n");
    }

    float x2 = x + face->glyph->bitmap_left * sx;
    float y2 = -y - face->glyph->bitmap_top * sy;
    float w = face->glyph->bitmap.width * sx;
    float h = face->glyph->bitmap.rows * sy;

    GLfloat fontVertices[4][4] = {
        {x2,     -y2    , 0, 0},
        {x2 + w, -y2    , 1, 0},
        {x2,     -y2 - h, 0, 1},
        {x2 + w, -y2 - h, 1, 1},
    };

    glTexImage2D(
      GL_TEXTURE_2D, 0, GL_ALPHA, face->glyph->bitmap.width, face->glyph->bitmap.rows, 0,
      GL_ALPHA, GL_UNSIGNED_BYTE, face->glyph->bitmap.buffer);

    glBufferData(GL_ARRAY_BUFFER, sizeof fontVertices, fontVertices, GL_DYNAMIC_DRAW);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

    x += (face->glyph->advance.x/64) * sx;
    y += (face->glyph->advance.y/64) * sy;
  }
}

int main()
{
  EglInit();
  GlInit();

  // FBO experiment: SAGAR
  GLuint fbo;
  glGenFramebuffers(1, &fbo);
  glBindFramebuffer(GL_FRAMEBUFFER, fbo);

  GLuint texture;
  glGenTextures(1, &texture);
  glBindTexture(GL_TEXTURE_2D, texture);
  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);
  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1920, 1080, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
  glBindTexture(GL_TEXTURE_2D, 0);

  GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
  if (status != GL_FRAMEBUFFER_COMPLETE) {
    printf("Problem with OpenGL framebuffer : %x\n", status);
  }

  DrawRect();
  RenderTexture(); // Does not work
  glBindTexture(GL_TEXTURE_2D, 0);
  eglSwapBuffers(egldisplay, eglsurface);

  glBindFramebuffer(GL_FRAMEBUFFER, 0);
  glBindTexture(GL_TEXTURE_2D, texture);
  glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  render_fboTexture();
  glBindTexture(GL_TEXTURE_2D, 0);

  //RenderTexture(); // Directly onto default/main framebuffer works
  eglSwapBuffers(egldisplay, eglsurface);
  sleep(10);

  glDeleteShader(vertexShader);
  glDeleteShader(fragmentShader);
  glDeleteBuffers(1, &VBO);
  glDeleteProgram(shaderProgram);

  return 0;
}

egl 相关的初始化。

void EglInit()
{   
  EGLint configCount;
  egldisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
  if (egldisplay == EGL_NO_DISPLAY) {
    printf("eglGetDisplay() failed: %d\n", eglGetError());
  }

  EGLint majorVersion = 0;
  EGLint minorVersion = 0;
  if (!eglInitialize(egldisplay, &majorVersion, &minorVersion)) {
   printf("eglInitialize() failed: %d\n", eglGetError());
  }

  if (!eglChooseConfig(egldisplay, Attributes, &eglconfig, 1, &configCount))
  {
    printf("eglChooseConfig failed : %d\n", eglGetError());
  }

  eglcontext = eglCreateContext(egldisplay, eglconfig, EGL_NO_CONTEXT, contextAttributes);
  if (eglcontext == EGL_NO_CONTEXT) {
    printf("eglCreateContext() failed\n");
  }

  eglsurface = eglCreateWindowSurface(egldisplay, eglconfig, NativeWindow, NULL);
  if (eglsurface == EGL_NO_SURFACE) {
    printf("eglCreateWindowSurface() failed\n");
  }

  eglMakeCurrent(egldisplay, eglsurface, eglsurface, eglcontext);
}
4

1 回答 1

1

有一些问题。

渲染文本时启用混合:

DrawRect();

glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
RenderTexture();
glDisable(GL_BLEND);

但主要问题是片段着色器。片段着色器采用纹理的 alpha 通道和颜色形成统一。

gl_FragColor = vec4(1, 1, 1, texture2D(s_texture, texcoord).a) * myColor;

这适用于渲染四边形和文本。请注意,字形存储在纹理中,其中红绿色和蓝色为零,Alpha 通道包含字形掩码。

您使用相同的着色器来对帧缓冲区进行 blit,这根本不起作用,因为要复制帧缓冲区,您需要一个从纹理中读取颜色的着色器(您的着色器从制服中获取颜色)。例如:

gl_FragColor = texture2D(s_texture, texcoord);

如果要为所有绘图使用 1 个着色器,则创建一个片段着色器,它使用 的 alpha 通道myColor,到mix纹理的颜色通道和myColor. 如果为 1,则从 中读取颜色myColor,如果 ti 为 0.0,则从纹理中读取颜色:

vec4 texColor   = texture2D(s_texture, texcoord);
vec3 finalColor = mix(texColor.rgb, myColor.rgb, myColor.a);
gl_FragColor    = vec4(finalColor, texColor.a);

DrawRect在和中设置颜色RenderTexture

void DrawRect()
{
    // [...]

    glUniform4f(color_loc, 1.0f, 0.5f, 0.2f, 1.0f); // Orange
void RenderTexture()
{
    // [...]

    glUniform4f(color_loc, 0.5f, 0.0f, 0.0f, 1.0f); // Red

但是在 中设置 0.0 的 alpha 通道render_fboTexture

void render_fboTexture()
{
    // [...]

    glUniform4f(color_loc, 1.0f, 1.0f, 1.0f, 0.0f); // use texture
} 

此外,四边形的纹理坐标的 y 分量render_fboTexture被翻转。改变纹理坐标:

void render_fboTexture()
{
    // [...]

    GLfloat quad[4][4] = {
        {-1.0,  1.0,  0, 1},
        { 1.0,  1.0,  1, 1},
        {-1.0, -1.0,  0, 0},
        { 1.0, -1.0,  1, 0},

    // [...]
};
于 2020-04-28T09:50:31.987 回答