You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
thebookofshaders/09/README-ru.md

14 KiB

Узоры

Шейдерные программы исполняются попиксельно, поэтому вне зависимости от количества повторений фигуры объём вычислений не изменяется. Это значит, что фрагментные шейдеры хорошо справляются с повторяющимися узорами.

Нина Вормердам - Проект IMPRINT (2013)

В этой главе мы собираемся применить весь ранее изученный материал, и повторить это в изображении несколько раз. Как и в предыдущих главах, наша стратегия будет основана на умножении пространственных координат (между 0.0 и 1.0), так чтобы фигуры, которые мы рисуем между 0.0 и 1.0 повторялись несколько раз, образуя решётку.

«Регулярная решётка - это то, с чем человеческой интуиции и изобретательности проще всего работать. Повторяющиеся элементы вступают в контраст с хаосом мироздания и создают ощущение порядка. Люди всегда старались украсить и разнообразить окружающее пространство с помощю повторяющихся элементов. Это прослеживается от доисторических узоров на керамике до геометрических мозаик римских бань.» 10 PRINT, Издательство MIT, (2013)

Для начала давайте вспомним функцию fract(). Она возвращает дробную часть числа, то есть работает как взятие остатка от деления на единицу (mod(x,1.0)). Другими словами, fract() возвращает число справа от точки. Переменная с нормализованными координатами (st) уже пробегает значения от 0.0 до 1.0, поэтому нет смысла делать что-то вроде:

void main(){
	vec2 st = gl_FragCoord.xy/u_resolution;
	vec3 color = vec3(0.0);
    st = fract(st);
	color = vec3(st,0.0);
	gl_FragColor = vec4(color,1.0);
}

Но если мы увеличим масштаб нормализованной системы координат, скажем, в три раза, то получится три отрезка линейной интерполяции между 0.0 и 1.0: между 0 и 1, между 1 и 2, и наконец между 2 и 3.

Теперь давайте нарисуем что-нибудь в каждом подпространстве, раскомментировав строку 27. Соотношение сторон при этом не изменится и фигуры не будут искажены, ибо мы умножаем по обеим осям.

Для более полного понимания попробуйте выполнить следующее:

  • Поумножайте пространственные координаты на различные числа. Поэкспериментируйте с дробными числами и с различными множителями для x и y.

  • Сделайте функцию создания узоров, пригодную для повторного использования.

  • Разделите пространство на 3 строки и 3 столбца. Придумайте как узнать в какой строке и каком столбце находится текущий поток, и изменяйте фигуру в зависимости от этого. Нарисуйте игру в крестики-нолики.

Применение матриц к узорам

Каждая клетка решётки является уменьшенной версией нормализованной системы координат, которую мы использовали ранее, поэтому мы можем применить к этим клеткам матричные преобразования переноса, поворота и масштаба.

  • Придумайте интересные анимации для этого узора. Анимируйте цвет, форму и движение. Сделайте три различных анимации.

  • Создайте более сложные узоры, совмещая разные формы.

Векторный шотландский узор от Kavalenkava

Узоры со сдвигом

Давайте сымитируем кирпичную стену. Каждый ряд кирпичей в стене смещён на полкирпича по оси x относительно предыдущего ряда. Как это сделать?

Для начала нам нужно узнать чётность номера строки, над которой работает данный поток. Таким образом мы сможем понять, нужно ли делать сдвиг по x в этой строке.

Чтобы определить чётность строки, используем взятие по модулю 2.0 с помощью функции mod(), и сравним результат с единицей. Посмотрите на формулы ниже и раскомментируйте две последние строки.

Как видите, мы могли бы использовать тернарный оператор для сравнения значения по модулю 2.0 с единицей, но того же эффекта можно достичь с помощью step(), которая работает быстрее. Почему? Хотя мы и не знаем как графические карты оптимизирует код, безопаснее будет предположить что встроенные функции работает быстрее, чем не встроенные. Если у вас есть возможность использовать встроенную функцию - используйте!

Теперь у нас есть формула вычисления чётности и мы можем сдвинуть нечётные строки для создания эффекта кирпичной стены. В 14 строке следующего кода мы используем эту формулу для «обнаружения» нечётных строк. Как видите, для чётных строк функция возвращает 0.0, что при умножении на сдвиг 0.5 так же даёт 0.0, а значит чётные строки не сдвигаются. В нечётных же строках 0.5 умножается на 1.0, поэтому в них пространство сдвигается на 0.5 по оси x.

Теперь попробуйте раскомментировать строку 32. Это сделает соотношение сторон похожим на соотношение сторон кирпича. А раскомментировав 40 строку вы увидите отображение координат в красный и зелёный цвета.

  • Попробуйте анимировать этот пример, изменяя сдвиг в зависимости от времени.

  • Создайте ещё одну анимацию, где чётные строки движутся налево, а нечётные - направо.

  • Можете ли вы повторить такой же эффект для столбцов?

  • Сделайте сдвиг по x и y одновременно, чтобы получить что-то вроде этого:

Плитка Труше

Теперь, когда мы научились определять чётность строки и столбца для каждой клетки, мы можем многократно использовать один и тот же элемент в зависимости от его расположения. Рассмотрим плитку Труше, где один элемент дизайна может быть представлен четырьмя различными способами:

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

Обратите особое внимание на функцию rotateTilePattern(), которая разделяет пространство на четыре части и задаёт угол поворота каждой из них.

  • Закомментируйте, раскомментируйте и продублируйте строки с 69 по 72, чтобы скомпоновать новые изображения.

  • Замените чёрно-белый треугольник на какой-нибудь другой элемент, например полукруг, повернутые квадраты или линии.

  • Напишите другие узоры с элементами, повёрнутыми в зависимости от их расположения.

  • Создайте узор, элементы которого меняют другие свойства в зависимости от расположения.

  • Придумайте ещё какое-нибудь изображение (не обязательно повторяющийся узор), в котором можно применить принципы из этой главы, например, Гексаграммы И цзин.

Создавайте свои собственные правила

Создание процедурных узоров - это умственное упражнение по поиску минимальных повторно используемых элементов. Это древняя практика. Мы, как биологический вид, издавна использовали узоры для украшения тканей, пола и границ объектов: вспомните извилистые узоры древней Греции или решётчатые узоры из Китая. Магия повторений и вариаций всегда захватывала наше воображение. Рассмотрите декоративные узоры и обратите внимание как художники и дизайнеры балансируют между предсказуемостью порядка и внезапностью изменчивости хаоса. От арабских геометрических узоров и до бесподобных африканских тканей раскинулась целая вселенная узоров, среди которых есть что изучить.

Франц Сейлс Мейер - Учебник орнамента (1920)

Этой главой мы заканчиваем раздел об алгоритмическом рисовании. В следующих главах мы привнесём в шейдеры немного энтропии для создания генеративного дизайна.