distance[0] - dot(p, HalfSpaceO); distanced] = dot (p. HalfSpacel); distance[2] = dot(p. HalfSpace2): distance[3] = dotCp. Ha1fSpace3):
distance = smoothstep(-FWidth. FWidth. distance):
inorout +- dottdistance. vec4(1.0));
distance.^ = dotCp. HalfSpace4);
distance.у = StripeWidth - abs(p.z);
distance = smoothstep(-FWidth. FWidth. distance):
inorout -+= distance.x;
inorout - clamp(inorout, 0.0, 1.0):
surfColor = mix(Yellow, Red. inorout); Листинг 11.5 (продолжение)
surfColor = miх(surfColor. Blue, distance.у):
// norraal - точка на поверхности сферы (0.0.0) normal = р;
// Вычисление рассеянного освещения для каждого фрагмента intensity = 0.2; // ambient
intensity += 0.8 * clamp(dot(LightDir, normal}., 0.0, 1.0); surfColor *= intensity;
// Вычисления отраженнего освещения для каждого фрагмента intensity - clarapCdotCHVector, normal). 0.0. 1.0); intensity = pow(intensity. SpecularColor.a): surfColor += SpecilarColor * intensity:
gl_FragColor “ vec4 (surfColor. 1.0);
}
11.3. Сетка
Рассмотрим своего рода хитрость. Здесь будет показано, как не рисовать объект процедурно, В этом примере читатель увидит, как можно использовать команду di scard во фрагментном шейдере, чтобы получить интересные эффекты. Команда discard означает, что фрагмент будет отброшен и не попадет в буфер кадров вообще. Используем этот прием для рисования геометрических фигур с «дырками». Вершинный шейдер будет таким же, как вершинный шейдер полосок (см, раздел 11.1.1). Фрагментный шейдер приведен в листинге 11.6.
Листинг 11.6. Фрагментный шейдер для процедурного отбрасывания частей объекта
varying vee3 DIffuseColor: varying vec3 SpecularColor:
uniform vec2 Scale; uniform vec2 Threshold; uniform vec3 SurfaceColor:
void main (void)
{
float ss = fract(gl_TexCoord[0].s * Scale.s); float tt = fract(gl_TexCoard[0].t * Scale.t);
if ((ss > Threshold.s) && (tt > Threshold.t)) discard;
vec3 finalColor = SurfaceColor * DiffuseColor + SpecularColor; gl_FragColor = vec4 (finalColor, 1.0):
}
Отбрасываемая часть объекта определяется значениями 5 и t текстурных координат. Коэффициент масштаба применяется для того, чтобы определить частоту сетки. Затем вычисляется дробная часть отмасштабированного значения текетурных координат, чтобы в итоге получилось значение, принадлежащее диапазону [0,1]. Значения sh£ сравниваются с.заданным граничным значением. Если оба значения превышают граничное, фрагмент отбрасывается. В противном слу-яае вычисляется освещение и выполняется рендеринг фрагмента.
На цветном рис. 15 оба граничных значения были установлены в 0,13. Это означает, что больше чем три четверти фрагментов было отброшено! Получилась здырявая корова1».
1.4. Бугристая поверхность
Читатель уже видел процедурные шейдеры, которые меняют цвет (кирпичная стенка, полоски) и непрозрачность (сетка). Еще один интересный эффект можно получить, используя метод бугристой поверхности. Этот метод подразумевает изменение нормали поверхности перед наложением освещения. Изменение нормали может быть сделано алгоритмически, если накладывается какой-либо повторяющийся шаблон; можно просто добавлять шум к компонентам нормали, а можно брать значения из текстурной карты. Метод бугристой поверхности - эффективный способ сделать изображение более реалистичным, не увеличивая сложность геометрических фигур. Этот метод можно использовать для имитации деталей поверхности или ее неровностей.