Листинг 11.7. Вершинный шейдер для процедурного метода бугристой поверхности
varying vec3 LightDiг; varying vec3 EyeDir;
uniform vec3 LightPosition: attribute vec3 Tangent; void main(void)
{
EyeDir = vec3 (glJtodelViewMatrix * g1_Vertex);
glPosition = ftransformO: g1_TexCoord[0] = glMultiTexCoordO:
vec3 n = normalize(gl_NormlMatrix * gljtormal): vec3 t = normalizeCglJJormalMatrix * Tangent); vec3 b = cross(n. t):
vec3 v:
v.x - dotCLightPosition. t); v.y = dotCLightPosition. b): Листинг 11.7 {продолжение)
v.z = dotdightPosition. п):
LightDir = normal i ze(v);
v.x = dot(EyeDir, t); v.y = dotCEyeDir. b): v.z = dotfEyeDir. n):
EyeDi г - normalize(v):
}
11.4.3. Фрагментный шейдер
Фрагментный шейдер для метода бугристой поверхности приведен в листинге 11.8. Через uniform-переменные передаются некоторые характеристики шаблона бугорков, а именно: BumpDensity (количество бугорков в заданной области) и Вшр-Size (размеры бугорков). Также задаются характеристики самой поверхности: SurfaceCol or (основной цвет поверхности) и Specul arFactor (свойство рассеянного отражения поверхности).
Вычисляемые бугорки будут круглыми. Так как для вычисления расположения бугорков используются текстурные координаты, сначала нужно умножить входные текстурные координаты на значение density - от этого зависит количество бугорков на поверхности. Получив некую сетку, вычисляем бугорок в каждой ее ячейке. Компоненты вектора р вычисляются как расстояние от центра бугорка в направлениях хну. (Нам нужно всего лишь изменить нормаль в направлениях х и у. Значение г для преобразованной нормали всегда будет 1,0.) «Ложное расстояние*- d вычисляется возведершем в квадрат компонентов р и последующим их сложением. (Настоящее расстояние можно вычислить извлечением квадратного корня, но обычно это не требуется, если BumpSl ze является не абсолютным, а относительным значением.)
Чтобы правильно вычислить отражение позже, нужно предварительно нормализовать изменяющую нормаль. Эта нормаль должна быть единичным вектором, чтобы потом можно было выполнить операцию dot и получить точные значения косинуса для использования при вычислении освещения. Вектор нормализуется умножением каждого компонента нормали на l,0/sqrt(x2 + y2 + z2). При вычислении d часть необходимых данных уже получена (то есть х1 + у'1). Так как г вообще не меняется, мы знаем, что г2 всегда будет 1,0. Чтобы уменьшить количество вычислений, коэффициент нормализации в данном случае будет вычисляться по формуле l,0/sqrt(i + 1,0).
Далее сравниваем d с BumpSize, чтобы узнать, есть в данной точке бугорок или нет. Если нет, изменяющий вектор устанавливается в 0, а коэффициент нормализации - в 1,0. В следующих нескольких строках вычисляется освещение. Нормализованный изменяющий вектор умножается на коэффициент нормализации f. Рассеянное и зеркальное отражения вьгчисляются как обычно, за исключением того, что используются векторы освещения и обзора в локальном пространстве координат поверхности. Неплохие результаты получаются и без нормализации этих двух векторов, если значения их не будут сильно различаться от вершины к вершине.