The Book of Shaders by Patricio Gonzalez Vivo & Jen Lowe

日本語 - 中文版 - 한국어 - Español - Français - Italiano - Deutsch - Русский - English


Алгоритмическое рисование

Формообразующие функции

Эта глава могла бы называться «Урок с забором от мистера Мияги». Ранее мы отобразили нормализованные координаты x и y в красный и зелёный цветовые каналы. По сути, мы сделали функцию, которая принимает двумерный вектор (x и y) и возвращает четырёхмерный вектор (r, g, b и а). Но прежде чем мы погрузимся глубже в трансформацию данных между измерениями, не помешает начать с более простых вещей. То есть с понимания способов конструирования одномерных функций. Чем больше времени и энергии вы потратите на освоение этого материала, тем сильнее будет ваше шейдерное карате.

Парень-каратист (1984)

Следующий код будет нашим забором. В нём мы визуализируем нормированное значение координаты x (st.x) двумя способами: с помощью яркости (обратите внимание на градиент от чёрного к белому) и путём построения зелёной линии поверх (в этом случае значение x записывается напрямую в y). Вы можете пока не вникать в функцию построения графика. Она будет детально рассмотрена далее.

На заметку: Конструктор типа vec3 «понимает», что вы хотите присвоить одно и то же значение всем трём каналам, а vec4 понимает, что четырёхмерный вектор нужно собрать из трёхмерного вектора и одного числа. Это число в данном случае отвечает за альфа канал, или прозрачность. Примеры этого поведения вы можете видеть в строках 20 и 26.

Этот код - это ваш забор; важно видеть и понимать его. Вы раз за разом будете возвращаться в пространство между 0.0 и 1.0. Вы изучите искусство смешивания и формирования линий.

Такое отображение один-в-один между x и y (или яркостью) называется линейной интерполяцией. Начиная с этого момента, мы можем использовать математические функции для придания формы линии. Например, мы можем возвести x в пятую степень, чтобы получить кривую линию.

Интересно, правда? Попробуйте различные степени в 22 строке, например 20.0, 2.0, 1.0, 0.0, 0.2 и 0.02. Понимание соотношения между числом и его степенью будет очень полезным. Использование математических функций такого типа даст вам мощное выразительное средство, позволяющее тонко управлять потоком значений.

pow() - одна из многих встроенных функций языка GLSL. Большинство из них ускорены на аппаратном уровне, а значит при их правильном и осмотрительном использовании ваш код станет быстрее.

Замените функцию степени в строке 22 на какую-нибудь другую. Попробуйте exp(), log() и sqrt(). Некоторые из этих функций более интересны при использовании числа Пи. В восьмой строке я определил макрос, заменяющий любое упоминание PI на 3.14159265359.

Step и Smoothstep

В GLSL так же есть несколько уникальных функций интерполяции с аппаратным ускорением.

Функция step() (ступенька) принимает два параметра. Первый параметр задаёт значение порога, а второй - точку, в которой мы хотим вычислить функцию. В любой точке до порога функция возвращает 0.0, а в любой точке после него - 1.0.

Попробуйте изменить значение порога в 20 строке в следующем коде.

Ещё одна уникальная функция называется smoothstep() (гладкая ступенька). Эта функция гладко интерполирует аргумент в интервале между двумя заданными числами. Первые два параметра задают начало и конец переходного интервала, а третий - точку, в которой нужно интерполировать.

В строке 12 приведённого выше кода мы используем smoothstep для рисования зелёной линии в функции plot(). Для каждой точки вдоль оси x эта функция делает всплеск при нужно значении y. Как? Через соединение двух smoothstep(). Рассмотрите следующую функцию, вставьте её вместо строки 20 в коде выше и вообразите, что это вертикальный разрез. Фон выглядит как линия, не так ли?

float y = smoothstep(0.2,0.5,st.x) - smoothstep(0.5,0.8,st.x);

Синус и косинус

Синус и косинус - ваши лучшие друзья, когда вы используете математику для анимации, построения фигур или смешивания значений.

Эти две базовые тригонометрические функции при построении кругов удобны, как швейцарский армейский нож, и обычно они используются в паре. Очень важно знать как они себя ведут и какими способами могут быть скомбинированны. Вкратце, они принимают угол в радианах и возвращают координаты x (косинус) и y (синус) точки на окружности единичного радиуса. Тот факт, что они возвращают нормализованные значения (между -1 и 1) и при этом являются достаточно гладкими, делает их незаменимым инструментом.

Описать все взаимоотношения между кругами и тригонометрическими функциями довольно трудно, но анимация выше отлично их демонстрирует.

Внимательно присмотритесь к этой синусоидальной волне. Обратите внимание на плавное изменение значения y между -1 и 1. Как мы видели в примере со временем в предыдущем параграфе, это ритмичное поведение синуса sin() можно использовать в анимациях. Если вы читаете этот пример в браузере, вы можете поизменять формулу выше и пронаблюдать как изменяется волна. Не забывайте ставить точку с запятой в конце строки.

Попробуйте проделать следующие действия и посмотрите что происходит:

Другие полезные функции

В конце предыдущего упражнения мы затронули несколько новых функций. Теперь давайте поэкспериментируем. Попробуйте раскомментировать строки в коде ниже по одной. Запомните эти функции и изучите их поведение. Возможно, вы спросите, зачем это нужно? Быстрый поиск в google по запросу «generative art» даст ответ. Помните, что пока мы осваиваем перемещение в одном измерении, вверх и вниз. Но скоро мы перейдём к двум, трём и даже четырём измерениям!

Anthony Mattox (2009)

Продвинутые функции

Голан Левин написал отличный учебник по более сложным функциям, которые могут понадобиться. Начните собирать вашу собственную библиотеку полезных кусочков кода с портирования этих функций на GLSL.

Подобно поварам, собирающим специи и экзотические ингридиенты, цифровые художники уделяют особое внимание работе над своими собственными формообразующими функциями.

Иниго Квилес собрал хорошую коллекцию полезных функций. После прочтения статьи посмотрите на реализацию этих функций на GLSL. Обратите внимание на незначительность потребовавшихся изменений. Например, пришлось использовать точку в числах с плавающей точкой и заменить функций из C на их GLSL-аналоги: pow() вместо powf() и т.п.

Для поддержания вашего вдохновения, посмотрите на элегантный пример использования одномерных функций, написанный автором Danguafer на ShaderToy.

В следующей главе мы сделаем ещё один шаг. Сначала мы посмешиваем цвета, а затем перейдём к рисованию фигур.

Упражнение

Рассмотрите таблицу с формулами, созданную автором Kynd. Он комбинирует функции и их свойства, чтобы контролировать значения между 0.0 и 1.0. Попробуйте воспроизвести эти функции самостоятельно. Помните, что чем больше вы тренируетесь, тем сильнее станет ваше карате.

Kynd - www.flickr.com/photos/kynd/9546075099/ (2013)

Инструментарий

Здесь собраны ссылки на инструменты, которые упростят визуализацию одномерных функций.

Grapher в OS X (2004)

Иниго Квилес - GraphToy (2010)

Тоби Шахман - Shadershop (2014)