varying vec2 MCposition; varying float Lightlntensity;
Idefine Integral (x, p. notp) ((floor(x)*(p)) + max(fract(x)-(notp), 0.0)) void main(void)
{
vec2 position, fw. useBrick; vec3 color;
// Определение координат в шаблоне кирпичной стенки position = MCposition / BrickSize:
// Каждая следующая строка сдвигается на половину кирпича if (fract(position.у * 0.5) > 0.5) position.х += 0.5:
// Вычисление размера фильтра fw = fwidth(position):
// Фильтрация с помощью интеграции двухмерного импульса // в шаблоне кирпичной стенки по ширине и высоте фильтра
useBrick = (Integral(position + fw, BrickPct. MortarPct) -Integral(position, BrickPct, MortarPct)) / fw;
// Определение окончательного цвета
color = mix(MortarColor, BrickColor, useBrick.x * useBrick.y): color *= Lightlntensity; gl_FragColor = vec4 (color, 1.0);
}
4.5. Отбрасывание частот
Для некоторых функций рассмотренный в предыдущих разделах способ вычислений не подходит, и тут можно попробовать другой метод, называемый отбрасывание частот. Для замены конкретного значения функции в случае излишней ширины фильтра используется среднее значение функции. Это удобно для функций, среднее значение которых уже известно, например синуса и функции шума.
4.5.1. Фрагментный шейдер шахматной оски со сглаживанием
Рисунок шахматной доски - удобный критерий проверки качества метода сглаживания (рис. 14.9). В листинге 14.3 приведен фрагментный шейдер для процедурного рисования шахматной доски со сглаживанием. Вершинный шейдер всего лишь преобразует координаты вершин и передает текстурные координаты. Приложение передает значения двух цветов шахматной доски, среднее значение этих двух цветов (приложение может вычислить его один раз и передать через uniform-переменную, чтобы не вычислять в шейдере для каждого фрагмента) и частоту чередования клеток.
Рис. 14.9. Шаблон шахматной доски. Рендеринг выполнен с помощью шейдера шахматной доски со сглаживанием. Слева ширина фильтра выставляется в 0, и получаются неровности. Справа ширина фильтра вычисляется функцией fwidth
Фрагментный шейдер вычисляет размер фильтра, а затем выполняет гладкое интерполирование между соседними клетками доски. Если фильтр слишком широкий (переменный параметр изменяется слишком быстро, чтобы можно было правильно использовать фильтр), подставляется среднее значение. Даже если во фрагментном шейдере есть условное выражение, все равно выполняется гладкое интерполирование между вычисленным и средним значениями цвета.
Листинг 14.3. Исходный код шейдера шахматной доски со сглаживанием
uniform vec3 Colorl: uniform vec3 Colог2: uniform vec3 AvgColor; uniform float Frequency:
varying vec2 TexCoord; void main(void)
{
vec3 color:
// Определение ширины проекции одного пиксела в пространстве s-t vec2 fw = fwidth(TexCoord):
// Определение степени размытости vec2 fuzz = fw * Frequency * 2.0;
float fuzzMax = max(fuzz.s, fuzz.t);
// Определение координат шаблона шахматной доски vec2 checkPos = fract(TexCoord * Frequency):
if (fuzzMax <0.5)
{
// Если ширина фильтра слишком маленькая, вычисляется цвет шаблона vec2 р = smoothstep(vec2 (0.5), fuzz + vec2 (0.5), checkPos) +