Рендеринг шрифта на FBO вне экрана не работает. (Примечание: шрифты загружаются путем создания текстур с использованием Freetype lib с glTexImage2D) - PullRequest
1 голос
/ 28 апреля 2020

У меня есть следующий код для визуализации прямоугольника и нескольких текстов на внеэкранном FBO. А затем я пытаюсь привязать текстуру (прикрепленную к FBO) в буфере кадров по умолчанию / display. Я могу сделать прямоугольник, но шрифты не отображаются. Я попробовал отладку, но пока не смог. Я должен делать это только в OpenGL ES 2.0.

Мой прямоугольник оранжевого цвета. Тексты / шрифты красного цвета. Я использую Freetype lib и вызов glTexImage2D для создания отдельных текстур для каждого шрифта. Когда я отрисовываю прямо в буфере кадров по умолчанию, я получаю оранжевый прямоугольник и красные шрифты успешно. Но когда я делаю это сначала за пределами экрана FBO, я получаю прямоугольник reddi sh и некоторые мелкие мелкие тексты (я полагаю). Я продолжаю отладку, но любой ввод будет полезен.

Примечание: я новичок в 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, связанный init.

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

1 Ответ

1 голос
/ 28 апреля 2020

Есть некоторые проблемы.

Включить Смешивание при визуализации текста:

DrawRect();

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

Но главная проблема - фрагментный шейдер. Фрагмент шейдера принимает альфа-канал текстуры, а цвет формирует униформу.

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

Это прекрасно работает для рендеринга четырехугольника и текста. Обратите внимание, что глифы хранятся в текстурах, где красный, зеленый и синий цвета равны нулю, а альфа-канал содержит маску глифа.

Вы используете тот же шейдер, чтобы переместить буфер кадров, который не будет работать при все, потому что для копирования кадрового буфера вам понадобится шейдер, который считывает цвета из текстуры (ваш шейдер получает его из униформы). Например:

gl_FragColor = texture2D(s_texture, texcoord);

Если вы хотите использовать 1 шейдер для всего рисунка, то создайте фрагментный шейдер, который использует альфа-канал от 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 в 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},

    // [...]
};
...