Значения Bri ckPct. х и Bri ckPct. у можно вычислить приложением, чтобы получить ширину промежутков между кирпичами в обоих направлениях, основываясь на соотношении высоты ряда и ширины столбца; эти значения можно выбирать и произвольно.
Остается только вычислить окончательное значение цвета и сохранить его в особой переменной д! _/гадСо1 or:
color “ mixtMortarColor. BrickColor, useBrick.x * useBrick.y): color *= Lightlntensity;
gl_Frag.Color = vec4 (color. 1.0):
}
Рис. 6.3, Периодическая функция шага для горизонтального компонента шаблона кирпичной стены
Здесь цвет фрагмента вычисляется и сохраняется в локальной переменной col or. Встроенная функция mi х используется для выбора цвета кирпича или промежутка в зависимости от результата useBrick.х * useBrick.у. Так как useBrick.х и useBri ck. у могут иметь значения только 0 или 1,0, цвет кирпича можно получить, только если оба значения - 1,0, а иначе в результате получится цвет промежутка.
Затем вычисленное значение умножается на интенсивность освещения, и результат сохраняется в локальной переменной col ог. Эта переменная - типа vec3, a gl_FragColor определен как vec4, так что окончательное значение цвета будет получено с помощью конструктора. Он добавит четвертый компонент (прозрачность), равный 1,0, и занесет результат во встроенную переменную gl_FragCo1 or. Весь исходный код фрагментного шейдера приведен в листинге 6.2.
Листинг 6.2. Исходный код фрагментного шейдера кирпичной стены
uniform vec3 BrickColor, MortarColor; uniform vec2 BrickSize; uniform vee2 BrickPct:
varying vec? MCposition; varying float Lightlntensity:
void main(void)
{
vec3 color;
vec2 position. useBrick:
position = MCposition / BrickSize:
if (fract(position.y * 0.5) > 0.5) position.x +- 0.5;
position = fract(position);
useBrick = step(position. BrickPct);
eolor = mixCMortarCalor. BrickColor. useBrick.x * useBrick.y).; color *= LightIntensity; gl_FragColor = vec4 (color. 1.0);
'I
При сравнении этого шейдера с вершинным шейдером из предыдущего примера видно, что основные возможности языка шейдеров OpeijGL, использованные в них, почти одинаковы. Оба шейдера используют функцию Tain, некоторые umform-переменныс, некоторые локальные переменные, выражения; встроенные ..функции вызываются одинаково; конструкторы используются одинаково и т. д. Небольшие различия заключаются в следующем: а) вершинный шейдер работает .свстроенными атрибутами gl_Vertex и gl_Normal; б) вершинный шейдер пишет во встроенную переменную gl_Position, в то время как фрагментный шейдер пишет во встроенную переменную gl FragCol or; в) varying-переменные устанавливаются в вершинном шейдере и считываются фрагмеитным шейдером.
Код приложения, в котором создаются и используются эти шейдеры, приведен в разделе 7.11 после описания API языка шейдеров OpenGL. Результат рендеринга нескольких простых объектов показан на рис. 6.4 (см. также цветной рис. 25).
Рис. 6.4. Плоский многоугольник, шар и тор, рендеринг которых выполнялся шейдерами кирпичной стенки
6.4. Замечания
В приведенном решении задачи есть несколько подводных камней, из-за которых оно может использоваться только в самых простых случаях. Так как шаблон кирпичной стены вычисляется с использованием модельных координат заданного объекта, видимые размеры кирпичей зависят от размера объекта в модельных координатах. Некоторые объекты в результате будут выглядеть хорошо, но для других созданные нами кирпичики будут либо слишком большими, либо слишком маленькими. Чтобы избежать этого, для вершинного шейдера нужно задать параметр - uniform-переменную, в соответствии со значением которой шаблон будет масштабироваться по отношению к модельным координатам. Приложение могло бы предоставлять пользователю возможность самому задавать масштаб для того, чтобы кирпичный рисунок выглядел хорошо на любом объекте.