2016-09-10 2 views
-1

Я создал 8x8 пиксельные растровые буквы, чтобы визуализировать их с помощью OpenGL, но иногда, в зависимости от масштабирования, я получаю странные артефакты, как показано ниже на изображении. Фильтрация текстур устанавливается на ближайший пиксель. Это похоже на проблему округления, но как может быть, если линия абсолютно горизонтальная.Артефакты с текстурой рендеринга с горизонтальными и вертикальными линиями с OpenGL

Left original 8x8, middle scaled to 18x18, right scaled to 54x54.

левый оригинальный 8x8, средний масштабируется до 18x18, правильно масштабируется до 54x54.

Данные вершин являются беззнаковыми байтами в формате (x-offset, y-offset, letter). Вот полный код:

вершинные шейдеры:

#version 330 core 

layout(location = 0) in uvec3 Data; 

uniform float ratio; 
uniform float font_size; 

out float letter; 

void main() 
{ 
    letter = Data.z; 

    vec2 position = vec2(float(Data.x)/ratio, Data.y) * font_size - 1.0f; 
    position.y = -position.y; 

    gl_Position = vec4(position, 0.0f, 1.0f); 
} 

геометрия шейдеры:

#version 330 core 

layout (points) in; 
layout (triangle_strip, max_vertices = 4) out; 

uniform float ratio; 
uniform float font_size; 

out vec3 texture_coord; 

in float letter[]; 

void main() 
{ 
// TODO: pre-calculate 
    float width = font_size/ratio; 
    float height = -font_size; 

    texture_coord = vec3(0.0f, 0.0f, letter[0]); 
    gl_Position = gl_in[0].gl_Position + vec4(0.0f, height, 0.0f, 0.0f); 
    EmitVertex(); 

    texture_coord = vec3(1.0f, 0.0f, letter[0]); 
    gl_Position = gl_in[0].gl_Position + vec4(width, height, 0.0f, 0.0f); 
    EmitVertex(); 

    texture_coord = vec3(0.0f, 1.0f, letter[0]); 
    gl_Position = gl_in[0].gl_Position + vec4(0.0f, 0.0f, 0.0f, 0.0f); 
    EmitVertex(); 

    texture_coord = vec3(1.0f, 1.0f, letter[0]); 
    gl_Position = gl_in[0].gl_Position + vec4(width, 0.0f, 0.0f, 0.0f); 
    EmitVertex(); 

    EndPrimitive(); 
} 

пиксельный шейдер:

#version 330 core 

in vec3 texture_coord; 

uniform sampler2DArray font_texture_array; 

out vec4 output_color; 

void main() 
{ 
    output_color = texture(font_texture_array, texture_coord); 
} 
+1

Как это сделать? Пожалуйста, предоставьте код – pleluron

ответ

0

Ну, при использовании ближайших фильтраций, вы увидите таким если ваше местоположение образца очень близко к границе между двумя текселями. И так как tex-координаты должны быть интерполированы отдельно для каждого фрагмента, который вы рисуете, небольшие числовые погрешности приведут к прыжкам между этими двумя текселями.

При рисовании текстуры 8x8 к 18x18 пикселей большой прямоугольник, и ваш прямоугольник идеально выровнены с putput пикселя растра, вы почти гарантированно вызвать такое поведение:

Глядя на Текселем coodinates тогда покажет что для самого нижнего выходного пикселя текстурные координаты будут интерполированы до 1/(2 * 18) = 1/36. Переход на один пиксель добавит 1/18 = 2/36 к координате t. Так что для пятого ряда снизу это будет 9/36.

Итак, для текстуры 8x8 текселя, которую вы отбираете, вы на самом деле выполняете выборку в ненормализованных координатах текселя (9/36) * 8 == 2.0. Это как раз граница между второй и третьей строками вашей текстуры. Так как координаты текстуры для каждого фрагмента интерполируются барицентрической интерполяцией между tex-координатами, назначенными трем вершинам из треугольника, могут быть небольшие неточности. И даже малейшая возможная неточность, представляемая в формате с плавающей запятой, приведет к перевороту между двумя текселями в этом случае.

Я думаю, что ваш подход просто не хорош. Масштабирование растровых шрифтов всегда проблематично (возможно, помимо интегральных масштабных коэффициентов). Если вы хотите красиво выглядящие масштабируемые текстурные шрифты, я рекомендую посмотреть на signed distance fields. Это довольно простая и мощная техника, и есть tools available to generate the necessary distance field textures.

Если вы ищете быстрый хак, вы также можете просто компенсировать выходной прямоугольник. В основном вы должны следить за смещением в [-0,5,0,5] пикселей (так что во время растеризации не генерируются разные фрагменты, и вы должны убедиться, что все потенциальные места выборки никогда не будут находиться близко к целому числу, поэтому смещение будет зависеть от фактического масштабного коэффициента.

+0

Я вижу, я полностью забыл, что в GPU используется барицентрическая система координат, и интерполяция может привести к этим ошибкам округления. – user1146657