Рендеринг глифа Freetype в текстуру OpenGL (3.3+) приводит к повторной текстуре с артефактами

Я просто пытался отобразить глиф (букву Ě), загруженный из Freetype, в виде растрового изображения на текстуру OpenGL, растянутую по всему окну. Результат здесь:

OpenGL + Freetype

Чтобы достичь этого результата, мне пришлось установить очень большие FT_Set_Pixel_Sizes на 450, иначе результирующее изображение выглядит еще хуже.

я использую Класс загрузчика GLSLShader М.М. 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;
}

3

Решение

FT_RENDER_MODE_NORMAL в результате получается одноканальное растровое изображение, а не 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
);
3

Другие решения


По вопросам рекламы [email protected]