将Freetype字形渲染为OpenGL(3.3+)纹理会导致带有伪影的重复纹理

时间:2014-09-08 12:43:09

标签: c++ opengl textures glsl freetype2

我只是试图将从Freetype加载的字形(字母Ě)作为位图图片显示在整个窗口上拉伸的OpenGL纹理上。结果在这里:

OpenGL + Freetype

要获得此结果,我必须将极大的FT_Set_Pixel_Sizes设置为450,否则生成的图像看起来会更糟。

我正在使用M.M.的GLSLShader loader class。 Mobeen,GLEW,SDL2和GLM。

着色器/ shader.vert

#version 330 core
layout(location=0) in vec4 vVertex; //object space vertex
out vec2 vUV;   // texture coordinates for texture lookup in the fragment shader

void main()
{
    gl_Position = vec4(vVertex.xy,0,1);
    vUV = vVertex.zw; // texture coordinate
}

着色器/ shader.frag

#version 330 core
layout (location=0) out vec4 vFragColor;
smooth in vec2 vUV;
uniform sampler2D textureMap;

void main()
{                                              
    vFragColor = texture(textureMap, vUV);
}

的main.cpp

#include <glew.h>
#include <glm/glm.hpp>

#include "SDL2/SDL.h"
#include "SDL2/SDL_opengl.h"

#include <ft2build.h>
#include FT_FREETYPE_H    

#include "GLSLShader.h" // https://github.com/bagobor/opengl33_dev_cookbook_2013/blob/master/Chapter3/src/GLSLShader.h

//shader reference
GLSLShader shader;

//vertex array and vertex buffer object IDs
GLuint vaoID;
GLuint vboVerticesID;
GLuint vboIndicesID;

//texture ID
GLuint textureID;

//quad vertices and indices
glm::vec4 vertices[4];
GLushort indices[6];

int main( int argc, const char* argv[] )
{
    if( SDL_Init( SDL_INIT_EVERYTHING ) == -1 ) return EXIT_FAILURE;

    SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, 3 );
    SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, 2 );
    SDL_GL_SetAttribute( SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE );
    SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
    SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 24 );

    SDL_Window* window = SDL_CreateWindow( "OpenGL + Freetype",
                                           SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
                                           1024, 768,
                                           SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN );

    SDL_GLContext glcontext = SDL_GL_CreateContext( window );

    if( glcontext == nullptr ) return EXIT_FAILURE;

    glewExperimental = GL_TRUE;

    if( glewInit() != GLEW_OK ) return EXIT_FAILURE;

    SDL_GL_SetSwapInterval( 1 );

    shader.LoadFromFile( GL_VERTEX_SHADER, "shaders/shader.vert" );
    shader.LoadFromFile( GL_FRAGMENT_SHADER, "shaders/shader.frag" );

    //compile and link shader
    shader.CreateAndLinkProgram();
    shader.Use();
        shader.AddAttribute( "vVertex" );
        shader.AddUniform( "textureMap" );
        glUniform1i( shader( "textureMap" ), 0 );
    shader.UnUse();

    //setup quad geometry
    vertices[0] = glm::vec4( -1.0, -1.0, 0, 1 );
    vertices[1] = glm::vec4( 1.0, 1.0, 1, 0 );
    vertices[2] = glm::vec4( 1.0, -1.0, 1, 1 );
    vertices[3] = glm::vec4( -1.0, 1.0, 0, 0 );

    //fill quad indices array
    GLushort* id = &indices[0];
    *id++ = 0;
    *id++ = 1;
    *id++ = 2;
    *id++ = 0;
    *id++ = 1;
    *id++ = 3;

    glGenVertexArrays( 1, &vaoID );
    glGenBuffers( 1, &vboVerticesID );
    glGenBuffers( 1, &vboIndicesID );

    glBindVertexArray( vaoID );

    glBindBuffer( GL_ARRAY_BUFFER, vboVerticesID );
    glBufferData( GL_ARRAY_BUFFER, sizeof( vertices ), &vertices[0], GL_DYNAMIC_DRAW );

    glEnableVertexAttribArray( shader["vVertex"] );
    glVertexAttribPointer( shader["vVertex"], sizeof( shader["vVertex"] ), GL_FLOAT, GL_FALSE, 0, 0 );

    glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, vboIndicesID );
    glBufferData( GL_ELEMENT_ARRAY_BUFFER, sizeof( indices ), &indices[0], GL_STATIC_DRAW );

    glGenTextures( 1, &textureID );
    glActiveTexture( GL_TEXTURE0 );
    glBindTexture( GL_TEXTURE_2D, textureID );

    glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
    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 );

    FT_Library  library;
    FT_Face     face;

    bool error = FT_Init_FreeType( &library );

    if( error ) return EXIT_FAILURE;

    error = FT_New_Face( library,
                         "dejavu.ttf",
                         0,
                         &face );

    if( error ) return EXIT_FAILURE;

    error = FT_Set_Pixel_Sizes( face, 0, 16 );

    if( error ) return EXIT_FAILURE;

    FT_Set_Pixel_Sizes( face, 0, 450 );

    FT_UInt glyph_index = FT_Get_Char_Index( face, 282 ); // letter Ě

    error = FT_Load_Glyph( face, glyph_index, FT_LOAD_DEFAULT );

    if( error ) return EXIT_FAILURE;

    error = FT_Render_Glyph( face->glyph, FT_RENDER_MODE_NORMAL );

    if( error ) return EXIT_FAILURE;

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

    bool running = true;
    while( running )
    {
        SDL_Event e;

        if( SDL_PollEvent( &e ) )
        {
            switch( e.type )
            {
                case SDL_QUIT:
                    running = false;
                    break;
                default:
                    break;
            }
        }

        glClearColor( 1, 1, 1, 1 );
        glClear( GL_COLOR_BUFFER_BIT );

        shader.Use(); // bind shader
            glDrawElements( GL_TRIANGLES, sizeof( indices ), GL_UNSIGNED_SHORT, 0 );
        shader.UnUse(); // unbind shader

        SDL_GL_SwapWindow( window );
    }

    return 0;
}

1 个答案:

答案 0 :(得分:3)

FT_RENDER_MODE_NORMAL results in a single-channel bitmap, not RGB:

  

FT_RENDER_MODE_NORMAL这是默认的渲染模式;它对应于8位抗锯齿位图。

GL_RED来电中format代替glTexImage2D()尝试GL_RGB

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