[1.7.10] Мини-инвентарь/процессинг/рецепт (пример кода).
И код был написан за ночь. По-этому не ждите от этого кода, что-то грандиозного.
—
(github.com) «Fabrication for Example» общие lang и текстуры
—-
(github.com) «Fabrication for Example» code «0»
Два слота, просто сделан как инвентарь, просто как начало заготовки.
—-
(github.com) «Fabrication for Example» code «1»
Производство каждый тик, проверяет первый слот на наличии нужного предмета для производства другого предмета во второй слот, если он пустой. Сторона сверху для входного слота, остальные стороны извлекаю предмет из второго слота. Эм.. Ну, типа не совсем правильно объяснил, ну ладно.
—-
(github.com) «Fabrication for Example» code «2a»
Девять входных слотов и один выходной слот. Верхняя сторона для входных слотов, остальные стороны для выходного слота.
—-
(github.com) «Fabrication for Example» code «2b»
По одному входному и выходному слоту, данная машина уже имеет время, сколько будет изготовляться предмет. Причём из входного слота сразу-же забирается предмет. В случаи разбивания блока, тот предмет который был взят для производства, будет исчезнут.
—-
(github.com) «Fabrication for Example» code «3»
Девять входных и один выходной слот, тоже как процессинг (их по разному могут называть) машинка.
—-
(github.com) «Fabrication for Example» code «3c»
Девять входных и девять выходных. Здесь выходные слоты просто как инвентарь. И в данной машинке уже будет результаты множество разных предметов.
—-
Машинки у которых один входной слот, в этот слот и по Shift-клику не положить.
Машинки у которых девять входных слотов, имеет определённый порядок для крафта и по Shift-клику или просто положить можно (не зависимо от рецепта для входных слотов).
Выходные слоты не были заблокированы на видео для данного тестирования, просто не ждать пока забьются выходные слоты, просто намерено их забить, и видеть, что будет если они забьются.
Возможно, потом добавлю комментариев в коде.
—-
Я не утверждаю, что этот код будет правильным. Я просто показываю код, который я-бы написал.
Последнее редактирование: 15 Май 2018
Ну, как-то так. Я тоже могу ошибаться. Я пишу на 1.7.10.
Что такое процессинг
Чем же он уникален и отличен от классических подходов в психологии?
Термин «процессинг» возник от слова процесс. В нашей психике постоянно происходят всякие процессы — в мыслях, чувствах, теле. Это могут быть наши переживания, наши восприятия, различные эмоции и ощущения, наши фантазии, убеждения, решения и тому подобное. Эти процессы могут быть осознаваемыми и управляемыми, а могут и неосознаваемыми и от того неуправляемые, потому что управлять можно только тем, что осознается нами. Процессинг- это применение техник для вывода неосознаваемых процессов в осознаваемые в результате чего увеличиваются способности человека и его свобода.
Отличия процессинга от психологии
И в чем же отличие процессинга от академической психологии? Заключается оно в подходах к решению проблем. В процессинге происходит исследование внутреннего мира конкретного человека, его уникальной психики, без попыток сопоставлять его с готовыми моделями представлений о психике и проработке по готовым шаблонам. В процессинге мы ищем понимание как у конкретного человека это работает, как лично у него включаются и как выключаются его процессы.
Приходит человек с какими-то смутными переживаниями, что-то его гложет, с каким-то нерешенными вопросом и процессор безоценочно, с помощью специальных вопросов начинает прояснять ту область жизни прояснителя, где у него нет ясности, направляя внимание как луч света в темную комнату и благодаря чему происходит повышение осознанности. И тогда он сам, без подсказок и советов, может принять решение как ему действовать и в каком направлении идти.
В процессинге нет интепритаций, готовых ответов и готовых рецептов, потому что психика каждого человека уникальна, несмотря на кажущееся сходство. У каждого человека своя внутренняя Вселенная и взять и загнать его в определенную модель можно лишь с искажением его сути. Это то самое прокрустово ложе — отрезать лишние выпирающие части или растянуть до размера формы то, чего не хватает.
В процессинге нет гипноза, внушений, манипуляций с сознанием. Здесь только работа с внутренним пространством конкретного человека, с помощью задавания чистый вопросов.
С точки зрения процессинга, мы не знаем какие внутренние законы у конкретного уникального человека. И мы вместе с ним исследуем его внутренний мир и благодаря этому происходит магия. Магия трансформации благодаря лучшему пониманию себя и повышению уровня осознанности. И я не перестаю удивляться магии процессинга, когда часто благодаря всего одной сессии, иногда нескольким, происходит внутреннее преображение человека. Меняется состояние, которое он мог носить с собой много лет! И при этом, я вижу множество людей, ходящим к психологам иногда годами, которые знают причины почему у них все в жизни происходит, но при этом так ничего не изменившими в своей жизни. Потому что «доверительные беседы» с психологом хоть и приносят облегчение, но часто являются недостаточными, чтобы подняться на новый уровень осознания. Как говорил Эйнштейн: «Чтобы решать проблему, нужно подняться на уровень выше того, на котором она была создана». И процессинг с этой задачей справляется идеально. Поэтому я использую этот подход, потому что он позволяет распутывать клубки давних проблем и получать результаты в довольно быстрые сроки .
Как добавить Natural Language Processing в Minecraft
Создание хороших примеров по использованию NLP инструментария — не самая простая задача. Они получаются или слишком простыми, так что читателям кажется, что в реальных проектах не стоит даже использовать какие-то внешние системы для решения таких простых NLP задач, а можно и даже желательно все написать самому, или, если постараться сделать примеры более жизненными, их бизнес логика становится чрезмерно сложной и отвлекает внимание от NLP части.
Появление этого примера, использование NLP в Minecraft, оказалось самым естественным в истории проекта на данный момент. Запрос на его разработку возник у настоящих и самых преданных пользователей — детей одного из разработчиков, которым показалось сложным и даже скорее просто ненужным запоминать формат некоторых команд новой для них игры.
Формулировка задачи — необходимо создать систему, переводящую запросы с естественного языка в команды формата игры Minecraft. Для простоты сразу было наложено ограничение — пример не должен являться полноценной системой, покрывать все возможные команды и т.д., а быть просто шаблоном для разработки.
Системы для сопряжения
Итак нам нужно состыковать две большие системы: 1. игру Minecraft и 2. диалоговую NLP систему на базе Apache NLPCraft.
1. Для разработчика приложений Minecraft это:
- игровое клиентское приложение и
- сервер с возможностью добавления модификаций.
В нашем случае мы будем работать с серверными модификациями.
2. NLP приложения построенные на базе Apache NLPCraft состоят из трех модулей:
- NLP Server, выполняющий стандартный для всех моделей NLP процессинг.
- клиентские NLP модели, загруженные в Probe.
- клиентское бизнес приложение, общающееся через REST с NLP Server.
Общая архитектура
Итоговая архитектура будет выглядеть следующим образом:
- В режиме сетевой игры пользовательские запросы на естественном языке с клиентского приложения Minecraft отправляются на Minecraft Server.
- NLPCraft mod, загруженный в Minecraft сервер, перехватывает эти запросы и перенаправляет их на NLPCraft Server. То есть mod в данном случае является клиентским приложением Apache NLPCraft системы.
- NLPCraft Server выполняет начальную обработку запроса и пересылает разобранный запрос на Probe с загруженной в него Minecraft NLP моделью.
- На Probe запрос окончательно разбирается, в Minecraft NLP модели находится соответствующий ему интент, в колбеке которого изначальный запрос пользователя транслируется в команду Minecraft.
- Probe возвращает результат обратно на NLPCraft Server, который в свою очередь возвращает ответ на Minecraft Server mod, который уже использует эту сконвертированную команду для передачи в Minecraft Server Engine вместо изначальной.
Звучит чуть запутано, но на самом деле все очень просто 🙂
Таким образом от нас требуется:
- Создать NLP модель для перевода запросов на естественном языке в команды понятные Minecraft серверу.
- Запрограммировать Minecraft mod, то есть NLPcraft клиент.
В зависимости от поставленных целей над первой задачей вы можете провести достаточно продолжительное время. Вам придется отлаживать правильность вашей модели, расширять список поддерживаемых Minecraft команд, развивать точность распознавания запросов и т.д. Все зависит от того, что вы в итоге планируете получить. Просто запустить существующие примеры — задача максимум на пару часов, создание же собственного коммерческого NLP транслятора команд потребует от вас гораздо больших усилий.
Вторая задача по созданию mod должна быть решена один раз, и этот mod будет использован для работы с NLP моделью любой сложности, которую вы уже можете далее развивать.
Minecraft mod
Основная логика nlpcraft-minecraft mod написанного на java приведена ниже:
@SubscribeEvent public void onCommandEvent(CommandEvent event) < String cmd = event.getParseResults().getReader().getString(); String convCmd = '/' + askProbe(cmd).state.resBody; event.setCanceled(true); server.getCommandManager().handleCommand( server.getCommandSource(), convCmd ); >
- Сначала мы перехватываем запрос на естественном языке, поступивший на Minecraft Server от пользователя.
- Далее пересылаем запрос на NLPCraft Server, который после обработки и коммуникаций с моделью на Probe возвращает разобранную и переведенную в формат Minecraft Server команду.
- Полученную сконвертированную команду мы направляем в Minecraft Server Engine вместо изначальной.
Запрос “make a box of sand with the size of 2, 10 meters in front of me” переведется в команду “/execute at @p positioned ~0 ~0 ~10 rotated 0 0 run fill ^-1 ^0 ^-1 ^0 ^0 ^0 minecraft:sand”.
Метод askProbe это обычный REST вызов к NLP server.
private NCResponse askProbe(String txt) throws Exception < AskParams params = new AskParams(); params.mdlId = "nlpcraft.minecraft.ex"; params.txt = txt.startsWith("/") ? txt.substring(1) : txt; if (this.token == null) this.token = signin(); params.acsTok = this.token; return post("ask/sync", GSON.toJson(params), NCResponse.class); >
В методе post реализована логика отправки http запроса, опустим ее. Опущен также также ряд несущественных для понимания общих принципов работы деталей, но основная логика данного mod думаю ясна.
- Полный код mod для обзора доступен по ссылке.
- Собирать его удобнее через основной проект (потребуется gradle)
- Если хочется попробовать в деле только описанную ниже NLP часть, а с mod неохота даже возиться — мы собрали его под java 8, вот ссылка на jar, просто поместите его папку mods инсталлированного Minecraft Server. По ссылке приведено описание процесса инсталляции и конфигурации.
Minecraft NLP Model
Вторая и более важная часть нашей работы — это создание NLP модели, ответственной за перевод запросов с естественного языка в формат команд Minecraft Server.
В примере поддерживаются всего четыре Minecraft команды, то есть сконфигурированы четыре интента Apache NLPCraft.
Ниже разберем самую простую команду — команду установки времени. Весь процесс работы с системой расписан подробно в статье по ссылке.
1. Определим элементы, которые мы должны найти в тексте для этого типа запроса. Для работы с командой выставления времени нам потребуется определить два элемента: тип команды и значение времени. В примере используется встроенный механизм определения элементов — через модель синонимов, но при желании, для поиска элементов, необходимых для разбора пользовательского запроса, вы можете воспользоваться и нейросетями.
Определим элемент “time:action“, тип команды:
- id: time:action synonyms: - " "
Определим несколько элементов группы “time”:
. - id: afternoon groups: - time synonyms: - " <afternoon|noon|midday>" - id: evening groups: - time synonyms: - " " .
2. Создадим интент для данной команды:
intents: - "intent=timeIntent term=? term(arg)="
В нем мы указали, что для срабатывания интента timeIntent в запросе должны встретиться следующие элементы: один опциональный с идентификатором “time:action” и один обязательный группы “time”.
3. Напишем колбек для данного интента:
@NCIntentRef("timeIntent") @NCIntentSample( "set time to evening", "now is evening", "night", "it's midnight" ) fun onTimeMatch( ctx: NCIntentMatch, @NCIntentTerm("arg") tok: NCToken ): NCResult < checkAmbiguous(ctx) val time: Int = when (tok.id) < "morning" ->23000 "day" -> 1000 "afternoon" -> 6000 "evening" -> 12000 "night" -> 12000 "midnight" -> 18000 else -> null > ?: throw NCException("Invalid token id") return NCResult.text("time set $time") >
- NCIntentRef — имя интента.
- NCIntentSample — примеры текстовых запросов, использующиеся в частности в процессе автоматического тестирования модели.
- Колбек onTimeMatch извлекает данные из элемента группы “time”, переводит их в числовые значения формата Minecraft и формирует в итоге готовую к использованию Minecraft команду.
Так, например, пользовательский запрос “set time to the evening” будет преобразован в Minecraft команду “time set 12000”. Таким образом конечный пользователь избавлен от необходимости запоминать формат команд Minecraft и может управлять процессом игры на естественном языке.
Модель создана на языке kotlin, но это может быть java или любой другой java based язык программирования, такой как scala, groovy и т.д.
На старт
Итак все готово, проверим работоспособность всех модулей на одном компьютере.
- Запускам Apache NLPCraft Server.
- Запускаем Apache NLPCraft Probe с Minecraft Example моделью.
- Запускаем Minecraft Server с добавленным модом.
- Запускам игру, выбираем сетевую версию, настраиваемся на localhost.
- Вводим команду “set the day”, см. первый скрин, левый нижний угол.
- Экран посветлел!
Probe выдал разобранный запрос:
И информацию о сработавшем интенте:
Minecraft сервер отреагировал логом:
[NCMinecraftExampleMod]: Command ‘/set the day’ was converted to ‘/time set 1000’
Все отработало как мы и ожидали.
Полный код примера доступен по ссылке.
Заключение
Пример получился не самым простым по архитектуре, достаточно скромным по функционалу, но как мне кажется удачно демонстрирующим возможности применения NLP технологий в довольно неожиданных областях. Надеюсь он окажется полезен при начале работы с системой, так как показывает использование всех модулей и элементов проекта Apache NLPCraft во вполне реальных условиях.
- Программирование
- Разработка игр
- API
- Apache
- Natural Language Processing
Руководство начинающего программиста графических шейдеров
Умение писать графические шейдеры открывает перед вами всю мощь современных GPU, которые сегодня уже содержат в себе тысячи ядер, способных выполнять ваш код быстро и параллельно. Программирование шейдеров требует несколько иного взгляда на некоторые вещи, но открывающийся потенциал стоит некоторых затрат времени на его изучение.
Практически каждая современная графическая сцена являет собой результат работы некоторого кода, написанного специально для GPU — от реалистичных эффектов освещения в новейших ААА-играх до 2D-эффектов и симуляции жидкости.
Сцена в Minecraft до и после применения нескольких шейдеров.
Цель этой инструкции
Программирование шейдеров иногда кажется загадочной черной магией. Тут и там можно встретить отдельные куски кода шейдеров, которые обещают вам невероятные эффекты и, возможно, вправду способны их обеспечить — но при этом совершенно не объясняют, что именно они делают и как добиваются столь впечатляющих результатов. Данная статья попробует закрыть этот пробел. Я сфокусируюсь на базовых вещах и терминах, касающихся написания и понимания шейдерного кода, так что впоследствии вы сами сможете менять код шейдеров, комбинировать их или писать свои собственные с нуля.
Что такое шейдер?
Шейдер — это просто программа, которая запускается на одном из графических ядер и говорит видеокарте, как нужно отрисовать каждый пиксель. Программы называются «шейдерами», поскольку они часто используются для контроля эффектов освещения и затенения («shading»). Но, конечно, нет никаких причин ограничиваться только этими эффектами.
Шейдеры пишутся на специальном языке программирования. Не беспокойтесь, вам не нужно прямо сейчас идти и изучать с нуля новый язык программирования. Мы будем использовать GLSL (OpenGL Shading Language), который имеет С-подобный синтаксис. Существуют и другие языки программирования шейдеров под различные платформы, но, поскольку их конечной целью является всё тот же запуск кода на GPU, они имеют достаточно схожие принципы.
Данная статья будет рассказывать лишь о так называемых пиксельных (или фрагментных) шейдерах. Если вам стало интересно, а какие они бывают ещё — вам следует почитать о графическом конвейере (например, в OpenGL Wiki).
Поехали!
Для наших экспериментов мы воспользуемся ShaderToy. Это позволит вам взять и начать писать шейдерный код здесь и сейчас, не откладывая это дело на потом из-за необходимости устанавливать какие-то определённые инструменты или SDK. Единственное, что вам необходимо — это браузер с поддержкой WebGL. Создавать аккаунт на ShaderToy не обязательно (только, если вы захотите сохранить там свой код).
Заметка: ShaderToy сейчас в стадии беты, так что на момент прочтения вами этой статьи некоторые нюансы его UI могут измениться.
Итак, нажимаем кнопку New в правом углу, что приведёт к созданию нового шейдера:
Маленькая чёрная стрелка под кодом компилирует и запускает шейдер.
Что здесь происходит?
Я сейчас объясню, как работает шейдер, ровно одним предложением. Вы готовы? Вот оно. Единственным предназначением шейдера является вернуть четыре числа: r, g, b и a.
Это всё, что может и должен сделать шейдер.
Функция, которую вы видите выше, запускается для каждого пикселя на экране. И для каждого из них она возвращает четыре вышеуказанных числа, которые и становятся цветом данного пикселя. Так работают Пиксельные Шейдеры (иногда также называемые фрагментными).
Итак, теперь у нас есть достаточно знаний для того, чтобы, например, залить весь экран чистым красным цветом. Значения каждой из компонент rgba (red, green, blue и «alpha» — то есть «прозрачность») может быть в диапазоне от 0 до 1, так что в нашем случае мы просто вернем r,g,b,a = 1,0,0,1. ShaderToy ожидает финальный цвет пикселя в переменной fragColor.
void mainImage( out vec4 fragColor, in vec2 fragCoord )
Мои поздравления! Это ваш первый работающий шейдер!
Мини-задание: сможете залить весь экран серым цветом?
vec4 — это просто тип данных, так что мы можем объявить наш цвет как переменную:
void mainImage( out vec4 fragColor, in vec2 fragCoord )
Данный пример не слишком захватывающий. У нас есть мощь сотен или тысяч вычислительных ядер, способных работать эффективно и параллельно, а мы из это пушки стреляем по воробьям, заливая весь экран одним цветом.
Давайте хотя бы нарисуем градиент. Для этого, как вы можете догадаться, нам нужно знать позицию текущего пикселя на экране.
Входные параметры шейдера
Каждый пиксельный шейдер имеет в своём распоряжении несколько полезных переменных. В нашем случае наиболее полезной будет fragCoord, которая содержит координаты x и y (а также z, если нужно будет работать в 3D) текущего пикселя. Для начала попробуем закрасить все пиксели в левой половине экрана в черный цвет, а в правой — в красный:
void mainImage( out vec4 fragColor, in vec2 fragCoord ) < vec2 xy = fragCoord.xy; // координаты текущего пикселя vec4 solidRed = vec4(0,0.0,0.0,1.0);// чёрный цвет if(xy.x >300.0)/ некоторое число, мы не знаем реального размера экрана solidRed.r = 1.0;// красный цвет > fragColor = solidRed; >
Заметка: для доступа к компонентам переменных типа vec4 вы можете использовать obj.x, obj.y, obj.z, obj.w или obj.r, obj.g, obj.b, obj.a. Это эквивалентные записи. Таким способом мы получаем возможность именовать компоненты vec4 в зависимости от того, чем они являются в каждом конкретном случае.
Вы уже видите проблему с кодом выше? Попробуйте нажать кнопку перехода в полноэкранный режим. Пропорции красной и черной частей экрана изменятся (в зависимости от размера вашего экрана). Для того, чтобы закрасить ровно половину экрана, нам нужно знать его размер. Размер экрана не является встроенной переменной, поскольку это нечто, что программист приложения контролирует сам. В нашем случае это ответственность разработчиков ShaderToy.
Если что-то не является встроенной переменной, вы можете переслать эту информацию от CPU (основного кода вашего приложения) к GPU (вашему шейдеру). ShaderToy делает это за вас. Вы можете просмотреть все доступные шейдеру переменные во вкладке Shader Inputs. В GLSL они называются uniform-переменными.
Давайте исправим наш код таким образом, чтобы он корректно определял середину экрана. Для этого нам понадобится uniform-переменная iResolution:
void mainImage( out vec4 fragColor, in vec2 fragCoord ) < vec2 xy = fragCoord.xy; // координаты текущего пикселя xy.x = xy.x / iResolution.x; // делим на разрешение экрана xy.y = xy.y / iResolution.y; // теперь х будет равен 0 для самого левого пикселя и 1 для самого правого vec4 solidRed = vec4(0,0.0,0.0,1.0); // чёрный цвет if(xy.x >0.5) < solidRed.r = 1.0; // красный цвет >fragColor = solidRed; >
Теперь даже при увеличении окна предпросмотра (или переходе в полноэкранный режим) мы получим поделенный ровно пополам черно-красный прямоугольник.
От разделения экрана к градиенту
Изменить наш код для получения градиентной заливки достаточно просто. Компоненты цветов могут быть в пределах от 0 до 1, и наши координаты тоже теперь представлены в том же диапазоне.
void mainImage( out vec4 fragColor, in vec2 fragCoord ) < vec2 xy = fragCoord.xy; // координаты текущего пикселя xy.x = xy.x / iResolution.x; // делим на разрешение экрана xy.y = xy.y / iResolution.y; // теперь х будет равен 0 для самого левого пикселя и 1 для самого правого vec4 solidRed = vec4(0,0.0,0.0,1.0); // чёрный цвет solidRed.r = xy.x; // устанавливаем красную компоненту цвета в нормализированное значение х fragColor = solidRed; >
Мини-задание: попробуете сами сделать вертикальный градиент? Диагональный? Как на счёт перехода между более чем двумя цветами?
Если вы не пропустили вышеуказанное задание с вертикальным градиентом, то уже знаете, что верхний левый угол имеет координаты (0;1), а не (0;0), как можно было бы предположить. Это важно, запомните это.
Рисование изображений
Развлекаться с заливкой цветом, конечно, забавно, но, если мы хотим реализовать какой-нибудь по-настоящему захватывающий эффект, наш шейдер должен быть способен принимать на вход картинку и изменять её. Таким образом мы можем написать шейдер, который может влиять, например, на отрисовку всего кадра в игре (реализовать эффекты движения жидкостей или выполнять цветокоррекцию) или наоборот, выполнять лишь отдельные операции для некоторых объектов сцены (например, реализовать часть системы освещения).
Если бы мы писали шейдеры на какой-нибудь обычной платформе, то должны были бы передать изображение шейдеру как uniform-переменную (таким же образом, как передавалось разрешение экрана). ShaderToy делает это за нас. Есть четыре входных канала внизу:
Кликните на канале iChannel0 и выберите любую текстуру (изображение). Теперь у вас есть картинка, которая будет передана вашему шейдеру. Но есть одна проблема: функции DrawImage() у нас нет. Вы ведь помните — всё, что может сделать шейдер, это вернуть значение rgba для одного пикселя.
Итак, если мы можем лишь вернуть значение цвета, то как же нам отрисовать картинку на экране? Мы должны как-то соотнести пиксель в картинке с пикселем, для которого был вызван шейдер:
Мы можем сделать это с помощью функции texture(textureData,coordinates), которая принимает на вход текстуру и координаты (x, y), а возвращает цвет текстуры в данной точке в виде переменной типа vec4.
Вы можете соотнести пиксели текстуры и экрана как-угодно. Можно, например, растянуть текстуру на четверть экрана или нарисовать лишь её часть. В нашем случае мы всего лишь хотим увидеть оригинальное изображение:
void mainImage( out vec4 fragColor, in vec2 fragCoord ) < vec2 xy = fragCoord.xy / iResolution.xy; // сжимаем в одну линию vec4 texColor = texture(iChannel0,xy); // берём пиксель с координатами (x;y) из канала iChannel0 fragColor = texColor; // устанавливаем цвет пикселя на экране >
И вот она, наша картинка!
Теперь, когда вы умеете вытягивать данные из текстуры, вы можете манипулировать ими как захотите. Вы можете растянуть или сжать изображение, поиграть с его цветами.
Давайте добавим сюда уже известный нам градиент:
texColor.b = xy.x;
Поздравляю, вы только что написали свой первый пост-процессинг эффект!
Мини-задание: сможете ли вы написать шейдер, который преобразует входную картинку в черно-белое изображение?
Заметьте, хотя мы используем статическую картинку, то, что вы видите на экране рендерится в реальном времени, много раз в секунду. Вы можете убедиться в этом, заменив во входном канале статическую картинку на видео (просто кликните на канале iChannel0 и выберите видео).
Добавляем немного движения
До этого момента все наши эффекты были статические. Мы можем делать намного более интересные вещи, используя входные параметры, предоставляемые нам разработчиками ShaderToy. iGlobalTime это постоянно увеличивающаяся переменная — мы можем использовать её в качестве основы для переодических эффектов. Давайте попробуем поиграть с цветами:
void mainImage( out vec4 fragColor, in vec2 fragCoord ) < vec2 xy = fragCoord.xy / iResolution.xy; // сжимаем в одну линию vec4 texColor = texture(iChannel0,xy); // берём пиксель с координатами (x;y) из канала iChannel0 texColor.r *= abs(sin(iGlobalTime)); texColor.g *= abs(cos(iGlobalTime)); texColor.b *= abs(sin(iGlobalTime) * cos(iGlobalTime)); fragColor = texColor; // устанавливаем цвет пикселя на экране >
В GLSL есть встроенные функции синуса и косинуса (да и много других полезных). Компоненты цвета не должны быть негативными, так что мы используем функцию abs.
Мини-задание: можете ли вы сделать шейдер, который будет периодически плавно делаеть картинку черно-белой, а потом снова полноцветной?
Отладка шейдеров
При написании обычных программ вы, возможно, использовали возможность отладочного вывода или логирования, но для шейдеров это не очень-то возможно. Вы можете найти какие-то отладочные средства под вашу конкретную платформу, но в общем случае лучше всего представить нужное вам значение в виде некоторой графической информации, которую вы можете увидеть в выводе невооруженным взглядом.
Заключение
Мы рассмотрели лишь базовые средства разработки шейдеров, но вы уже можете экспериментировать с ними и пробовать делать что-то своё. Просмотрите доступные на ShaderToy эффекты и попробуйте понять (или самостоятельно воспроизвести) какие-то из них.
Одна из (многих) вещей, которые я не упомянул в данной статье, это вершинные шейдеры (Vertex Shaders). Они пишутся на том же языке, но запускаются не для пикселей, а для вершин, возвращая, соответственно, новую позицию вершины и её цвет. Вершинные шейдеры занимаются, например, отображением 3D-сцены на экран.
Последнее мини-задание: сможете ли вы написать шейдер, который заменит зелёный фон (есть в некоторых видео на ShaderToy) на другую картинку или видео?
Вот и всё, что я хотел рассказать в данной статье. В следующих я попробую рассказать о системах освещения, симуляции жидкостей и разработке шейдеров под конкретные платформы.
- Блог компании Инфопульс Украина
- Разработка игр
- GPGPU
- Обработка изображений
- WebGL