виньетирование ведьмак 3 что это
Небольшая шпаргалка по видео настройкам Ведьмака 3.
Хочу помочь тем у кого такое же железо как и на моём дескстопе. Сам потратил более двух часов на поиск оптимальных настроек и чтобы сберечь ваше время предлагаю эту информацию к ознакомлению. Сразу оговорюсь: настраивал игру на максимальную «красотищу», но и чтобы производительность не падала ниже 30 fps (ибо это последний порог, когда человеческий глаз начинает замечать подтормаживание). Короче: дамы и господа графадрочеры (я с вами!), тема для вас!
феррум: процессор — Intel Core i5-3470 @3.20 @3.60; ОЗУ 8 Гб.; видеокарта GeForce GTX 760 (zotac amp! edition 2Гб., разогнана аппаратно производителем до максимума); HDD — честно, даже уже и не помню:) какой-то стандартный (не ssd) шпиндельный накопитель в пол терабайта.
И так настройки — настройки видео —
постобработка: (продолжительные танцы с бубном в этой опиции утвердили во мнении, что если что-то из включенного здесь и влияет на уменьшение производительности, то не так критично. Поэтому включать что-то или отключать дело ваших сугубо личных предпочтений.)
1 размытие при движении: выкл.
2 размытие: выкл.
3 сглаживание: вкл.
4 свечение: вкл.
5 повышенная чёткость: вкл.
6 рассеянное затемнение: HBAO+ (понижение до SSAO даёт минимальное преимущество максимум в 5 fps, поэтому я посчитал, что им не стоит жертвовать).
7 глубина кадра: выкл.
8 хроматическая аберрация: выкл. (честно сказать опция ну очень на любителя))) и совсем не жрёт производительность.
9 виньетирование: выкл. (так и не понял что она меняет. Вроде как должна затенять углы экрана, но я этого не заметил).
10 световые шахты: вкл. (на всякий случай:-) уж больно название мудрёное, наверно и в правду что-то со светом хорошее делает))).
В этой закладке всё. Отдельно хочется отметить работу программистов из CD Projekt RED и CD Projekt RED Krakw в том, что не свели все настройки постобработки к банальным вкл./выкл. (как это сейчас принято), а разложили всё по полочкам, что позволило мне отключить ненавистные размытия и глубину кадра. Следующая закладка:
общее:
1 вертикальная синхронизация: вкл.
2 кадров в секунду: 60
3 разрешение: 1920х1080
4 режим экрана: полный экран
5 NVIDIA HairWorks: выкл. (это не про мою видеокарту. к сожалению. надеюсь — «пока»).
6 число персонажей на экране: запредельное
7 качество теней: запредельное
8 качество рельефа: запредельное
9 качество воды: запредельное
10 качество травы: запредельное
11 качество текстур: запредельное
12 дальность видимости растительности: низкая (хотелось бы отдельно остановиться на этой опции: производительность она жрёт, как бык помои! но если вы находитесь в густом лесу или в деревне/городе она по моему и не нужна совсем. Отключение её даёт существенный прирост кадро-секундофф и с этим, естественно, ухудшение качество изображения — где-то в далёком-далёко в километре от ведьмака. Это меня, как графодрочера не может не печалить. Но! Я заметил, что играя в «Ведьмака» (по крайней мере на начальном этапе) смотрю в основном на мини-карту и себе под ноги, даже редко замечая волков в десяти метрах от себя. Картинка и так до того насыщена, что устремлять взор куда то в даль просто не хочется (если конечно ты не стоишь на краю утёса и не любуешься на заходящее солнце))). Поэтому переступив через себя я отключил эту опцию, чтобы не жертвовать остальными более влияющими на «красотищу» опциями).
13 качество детализации: запредельное
14 аппаратный курсор: (не знаю что это такое, т.к. играю на джойстике)
Это всё. Понятное дело, что ни о каких 60 fps говорить не приходится (да и не очень я от этого страдаю, привык к консольным играм наверное). Такие настройки позволяют моему железу вытягивать игру до 40 fps в населённых пунктах и не позволяют падать ниже 30 в лесу. Кстати! Это первая игра на моём долгом геймерском веку которая начинает работать быстрее в окружении толпы людей и зданий, и замедляется в окружении деревьев и кустарников! шок!
Попробуйте, поэкспериментируйте. Надеюсь эта информация кому нибудь поможет.
Руководство по тонкой настройке графики Witcher 3: Wild Hunt
Разработчики поступили очень щедро (если не сказать великодушно), разрешив игрокам самостоятельно улучшать качество графики Witcher 3: Wild Hunt, редактируя файл конфигурации графики игры. Однако эта статья будет полезна не только энтузиастам, но и тем, у кого тормозит The Witcher 3: Wild Hunt, ведь графику можно как улучшить, так и ухудшить, отключив некоторые настройки и обеспечив себе приемлемый FPS.
Содержание
Что такое файл конфигурации графики Witcher 3: Wild Hunt
Это файл, в котором прописаны почти все параметры графики, называется он user.settings и хранится в папке «Мои ДокументыThe Witcher 3».
Прежде чем вносить какие-либо изменения, обязательно сначала настройте параметры графики в самой игре, затем сделайте резервную копию файла user.settings. Открыть данный файл можно при помощи блокнота или текстового редактора Notepad++, после чего спокойно вносите изменения в те значения, которые мы описали ниже.
Зафиксировать результат можно не просто сохранив файл user.settings в блокноте или редакторе Notepad ++, а выбрав затем в его свойствах параметр «только для чтения», чтобы предотвратить переопределение графических характеристик самой игрой. Это позволит вам наслаждаться визуальными эффектами, отличными от предусмотренных разработчиками.
Увеличиваем качество детализации в Witcher 3
В нашей опорной статье мы писали о том, что «качество детализации» регулирует количество крови, видимость брызг крови и частей тел, которые, как правило, возникают во время очередного кровавого замеса, а также дистанцию, с которой они начинают отрисовываться.
В файле конфигурации можно дополнительно увеличить количество этих элементов графики и увеличить дистанцию для отрисовки. Для этого нужно найти следующий код:
Стоит помнить, что данные параметры, как и сама графическая настройка «качество детализации», не поддаются точному исследованию и не оказывают значимого влияния на качество графики, так что даже после целого ряда экспериментов вы можете не найти изменений.
Увеличиваем дальность видимости растительности в Witcher 3
Один из самых ресурсоемких параметров игры в конфигурационном файле содержит такие настройки, которых нет в игровом меню — вы сможете увеличить дальность прорисовки растительности и всех сопутствующих элементов.
За количество видимых на горизонте деревьев отвечает параметр MaxVisibilityDepth:
В большинстве случаев вы можете спокойно увеличить эти параметры, выставив, например:
Увеличиваем качество и плотность травы в Witcher 3
Для этого находим в файле user.settings следующий код:
Из интерактивных сравнений выше хорошо видно, что GrassDistanceScale добавляет листву по всей долине, а вот на противоположном склоне горы параметр перестает действовать, поскольку попадает в лимит.
Значение «3» обеспечивает достаточно качественное улучшение общего впечатления от графики, при этом производительность уменьшается незначительно, а вот значение «6» практически убивает производительность даже на двух Titan X, хотя при разрешении ниже FullHD вы вполне сможете увидеть и 60 FPS, вопрос только в том, устроят ли вас прущие из всех щелей ветки.
Уменьшение этого значения с 0.075 до 0.001 практически не ухудшило производительность:
Увеличиваем количество частиц в Witcher 3
Опытным путем игроки определили, что если в разделе [Budget] поиграть с параметром cvMaxAllowedParticlesCount, то можно несколько увеличить количество частиц в кадре, продуцируемых системой частиц RED Engine.
Трудно сказать, насколько именно нужно увеличивать этот параметр, поскольку нет возможности провести тестирование в одинаковых условиях, однако мы рекомендуем вам попробовать его изменить.
Улучшаем качество теней в Witcher 3
Как упоминалось в нашей первой статье, качество теней напрямую регулирует визуальное качество, однако через игровое меню изменить его так гибко, как через файл конфигурации, невозможно.
Только начав правку файла user.settings можно не только улучшить или ухудшить графику Witcher 3, выйдя далеко за пределы значений «Низкое» или «Запредельное» качество, но и провести определенную оптимизацию.
Например, можно изменить размеры теней, отдаваемых растительностью, и хотя этот графический элемент сильно связан с параметром «дальность видимости растительности» (рассмотрено выше), но его можно изменить, пользуясь следующим твиком:
Переходим в раздел [Rendering/SpeedTree], находим код
Теперь перейдем к разбору общих настроек теней. Следующий список настроек раздела [Rendering] позволит вам изменить игровые настройки самых разных теней:
Начнем с параметра CascadeShadowDistanceScale0, который мы подняли с 1 до 2, а затем до 4:
В заключение данного параграфа отметим, что если вы измените в сторону увеличения все значения настроек теней, то можете довести игру до неиграбельного состояния из-за низкого FPS — то есть кадров будет меньше 30 в секунду, что не комфортно.
Чтобы избежать этого сначала подберите значения для теней на близкой и средней дистанции CascadeShadowDistanceScale0 и CascadeShadowDistanceScale1, соответственно без значительной потери FPS, а затем уже двигайте CascadeShadowDistanceScale2, CascadeShadowQuality и CascadeShadowmapSize.
Увеличиваем качество и количество текстур в Witcher 3
В нашей основной статье мы писали, что движку RED Engine достаточно 2 ГБ видеопамяти для загрузки текстур высокого качества. Если поставить «запредельное» качество текстур, то потребуется видеокарта с большим объемом видеопамяти, но фишка в том, что эти текстуры не будут использованы для отрисовки кадра в полном объеме.
Чтобы увеличить количество текстур «в работе», зайдите в раздел [Rendering], найдите параметр:
В том же разделе можно покрутить следующие настройки:
Реверс-инжиниринг рендеринга «Ведьмака 3»
Недавно я начал разбираться с рендерингом «Ведьмака 3». В этой игре есть потрясающие приёмы рендеринга. Кроме того, она великолепна с точки зрения сюжета/музыки/геймплея.
В этой статье я расскажу о решениях, использованных для рендеринга The Witcher 3. Она не будет такой всеобъемлющей, как анализ графики GTA V Адриана Корреже, по крайней мере, пока.
Мы начнём с реверс-инжиниринга тональной коррекции.
Часть 1: тональная коррекция
В большинстве современных AAA-игр одним из этапов рендеринга обязательно является тональная коррекция.
Напомню вам, что в реальной жизни существует довольно широкий диапазон яркости, в то время как у экранов компьютеров очень ограничен (8 бит на пиксель, что даёт нам 0-255). Именно здесь на помощь приходит тональная коррекция (tonemapping), позволяющая уместить в ограниченный интервал освещения более широкий. Обычно в этом процессе присутствуют два источника данных: HDR-изображение с плавающей запятой, значения цветов которого превышают 1.0, и средняя освещённость сцены (последнюю можно вычислить несколькими способами, даже с учётом адаптации глаза для имитации поведения человеческих глаз, но здесь это неважно).
Следующий (и последний) этап заключается в получении выдержки, вычислении цвета с выдержкой и его обработка с помощью кривой тональной коррекции. И здесь всё становится довольно запутанным, потому что появляются новые концепции, такие как «точка белого» (white point) и «средний серый цвет» (middle gray). Есть как минимум несколько популярных кривых, и некоторые из них рассматриваются в статье Мэтта Петтинео «A Closer Look at Tone Mapping».
Честно говоря, у меня всегда возникали проблемы с правильной реализацией тональной коррекции в собственном коде. В сети есть по крайней мере несколько различных примеров, которые оказались мне полезны… в какой-то степени. Некоторые из них учитывают HDR-яркость/точку белого/средний серый цвет, другие нет — поэтому они не особо помогают. Мне хотелось найти «проверенную в боях» реализацию.
Мы будем работать в RenderDoc с захватом этого кадра одного из основных квестов Новиграда. Все настройки поставлены на максимум:
Немного поискав, я нашёл вызов отрисовки для тональной коррекции! Как я упоминал выше, есть буфер HDR-цветов (текстура номер 0, полное разрешение) и средняя яркость сцены (текстура номер 1, 1×1, с плавающей точкой, вычисленная ранее compute-шейдером).
Давайте взглянем на ассемблерный код пиксельного шейдера:
Здесь стоит заметить несколько моментов. Во-первых, загруженная яркость не обязательно должна равняться использованной, потому что она ограничивается (вызовы max/min) в пределах выбранных художниками значений (из буфера констант). Это удобно, потому что позволяет избежать слишком высокой или низкой выдержки сцены. Этот ход кажется довольно банальным, но раньше я никогда такого не делал. Во-вторых — тот, кто знаком с кривыми тональной коррекции, мгновенно узнают это значение «11.2», ведь по сути это значение точки белого из кривой тональной коррекции Uncharted2 Джона Хейбла.
Параметры A-F загружаются из cbuffer.
Так, у нас есть ещё три параметра: cb3_v16.x, cb3_v16.y, cb3_v16.z. Мы можем исследовать их значения:
Я считаю, что «x» — это некий «масштаб белого» или среднего серого цвета, потому что он умножается на 11.2 (строка 4), а после этого используется как числитель в вычислении настройки выдержки (строка 10).
«y» — я назвал его «множителем числителя u2», и скоро вы увидите, почему.
«z» — «параметр возведения в степень», потому что он используется в тройке log/mul/exp (по сути — при возведении в степень).
Но относитесь к этим названиям переменных с долей скептицизма!
cb3_v4.yz — значения min/max допустимой яркости,
cb3_v7.xyz — параметры A-C кривой Uncharted2,
cb3_v8.xyz — параметры D-F кривой Uncharted2.
Теперь приступим к сложному — напишем HLSL-шейдер, который даст нам точно такой же ассемблерный код.
Это может быть очень трудно, и чем длиннее шейдер, тем сложнее задача. К счастью, какое-то время назад я написал инструмент, позволяющий быстро просматривать hlsl->asm.
Леди и джентльмены… приветствуйте D3DShaderDisassembler!
Поэкспериментировав с кодом, я получил готовый HLSL тональной коррекции The Witcher 3:
Скриншот из моей утилиты, чтобы это подтвердить:
Полагаю, это достаточно точная реализация тональной коррекции TW3, по крайней мере, с точки зрения ассемблерного кода. Я уже применил его в своём фреймворке и он работает отлично!
Я сказал «достаточно», потому что понятия не имею, почему denominator в ToneMapU2Func становится максимальным при нуле. При делении на 0 должно ведь получаться undefined?
На этом можно было бы закончить, но почти случайно я обнаружил в этом кадре ещё один вариант шейдера тональной коррекции TW3, используемый для красивого заката (интересно, что он применяется при минимальных настройках графики!)
Давайте его проверим. Для начала ассемблерный код шейдера:
Поначалу код может выглядеть пугающе, но на самом деле не всё так плохо. После краткого анализа можно заметить, что тут есть два вызова функции Uncharted2 с различными наборами входных данных (A-F, min/max яркость. ). Такого решения я раньше не встречал.
То есть по сути у нас есть два набора контрольных параметров, мы вычисляем два цвета с тональной коррекцией, а в конце интерполируем их. Умное решение!
Часть 2: адаптация глаза
Вторая часть будет гораздо проще.
В первой части я показал, как в TW3 выполняется тональная коррекция. Объясняя теоретические основы, я вкратце упомянул адаптацию глаза. И знаете что? В этой части я расскажу о том, как реализуется эта адаптация глаза.
Но постойте, что же такое адаптация глаза и зачем она нам нужна? Википедия знает о ней всё, но я объясню: представьте, что вы находитесь в тёмной комнате (вспомним Life is Strange) или в пещере, и выходите наружу, где светло. Например, основным источником освещения может быть солнце.
В темноте наши зрачки расширены, чтобы через них к сетчатке попало больше света. Когда становится светло, наши зрачки уменьшаются и иногда мы закрываем глаза, потому что это «больно».
Это изменение не происходит мгновенно. Глаз должен адаптироваться к изменениям яркости. Именно поэтому мы выполняем адаптацию глаза при рендеринге в реальном времени.
Хороший пример того, когда заметно отсутствие адаптации глаза — это HDRToneMappingCS11 из DirectX SDK. Резкие смены средней яркости довольно неприятны и неестественны.
Давайте приступим! Ради последовательности мы будем анализировать тот же кадр из Новиграда.
Теперь мы углубимся в захват кадра программой RenderDoc. Адаптация глаза обычно выполняется прямо перед тональной коррекцией, и «Ведьмак 3» в этом не исключение.
Посмотрим на состояние пиксельного шейдера:
У нас есть два источника входных данных — 2 текстуры, R32_FLOAT, 1×1 (один пиксель). texture0 содержит среднюю яркость сцены из предыдущего кадра. texture1 содержит среднюю яркость сцены из текущего кадра (вычисленную непосредственно перед этим compute-шейдером — я пометил это синим цветом).
Вполне ожидаемо, что есть одни выходные данные — R32_FLOAT, 1×1. Давайте посмотрим на пиксельный шейдер.
Ого, какой простой! Всего 7 строк ассемблерного кода. Что здесь происходит? Объясню каждую строку:
0) Получаем среднюю яркость текущего кадра.
1) Получаем среднюю яркость предыдущего кадра.
2) Выполняем проверку: текущая яркость меньше или равна яркости предыдущего кадра?
Если да, то яркость снижается, если нет, то яркость увеличивается.
3) Вычисляем разность: difference = currentLum — previousLum.
4) Эта условная пересылка (movc) назначает коэффициент скорости из буфера констант. В зависимости от результата проверки из строки 2 может быть назначено два различных значения. Это умный ход, ведь так можно получить разные скорости адаптации и для снижения, и для повышения яркости. Но в исследуемом кадре оба значения одинаковы и изменяются в пределах от 0.11 до 0.3.
5) Окончательное вычисление адаптированной яркости: adaptedLuminance = speedFactor * difference + previousLuminance.
6) Конец шейдера
Это реализуется в HLSL довольно просто:
Эти строки дают нам такой же ассемблерный код. Я бы только предложил заменить тип выводимых данных с float4 на float. Нет нужды в бессмысленной трате полосы пропускания. Вот так в Witcher 3 реализована адаптация глаза. Довольно просто, правда?
PS. Огромное спасибо Балдуру Карлссону (Twitter: @baldurk ) за RenderDoc. Программа просто отличная.
Часть 3: хроматическая аберрация
Хроматическая аберрация — это эффект, в основном встречающийся у дешёвых объективов. Он возникает, потому что объективы имеют разный коэффициент преломления для разных длин видимого света. В результате него появляется видимое искажение. Однако оно нравится не всем. К счастью, в Witcher 3 этот эффект очень малозаметен, а потому не раздражает при игровом процессе (меня, по крайней мере). Но при желании его можно отключить.
Давайте внимательно посмотрим на пример сцены с хроматической аберрацией и без неё:
Хроматическая аберрация включена
Хроматическая аберрация отключена
Вы замечаете какие-нибудь отличия рядом с краями? Я тоже нет. Давайте попробуем другую сцену:
Хроматическая аберрация включена. Заметьте небольшое «красное» искажение в обозначенной области.
Ага, намного лучше! Здесь контраст между тёмными и светлыми областями сильнее, и в углу мы видим небольшое искажение. Как видно, этот эффект очень слаб. Тем не менее, мне было интересно, как он реализован. Давайте перейдём к самой любопытной части: к коду!
Первое, что нужно сделать — это найти нужный вызов отрисовки с пиксельным шейдером. На самом деле хроматическая аберрация является частью большого пиксельного шейдера «финальной постобработки», которая состоит из хроматической аберрации, виньетирования и гамма-коррекции. Всё это находится внутри одного пиксельного шейдера. Давайте внимательнее приглядимся к ассемблерному коду пиксельного шейдера:
И к значениям cbuffer:
Так, попробуем понять, что здесь происходит. По сути, cb3_v17.xy является центром хроматической аберрации, поэтому первые строки вычисляют 2d-вектор из координат текселов (cb3_v17.zw = величина, обратная размеру вьюпорта) до «центра хроматической аберрации» и его длину, затем выполняет другие вычисления, проверку и ветвление. При применении хроматической аберрации мы вычисляем смещения с использованием неких значений из буфера констант и искажаем каналы R и G. В общем случае, чем ближе к краям экрана, тем сильнее эффект. Довольно интересна строка 10, потому что она заставляет пиксели «придвинуться ближе», особенно когда мы преувеличиваем аберрацию. С удовольствием поделюсь с вами моей реализацией эффекта. Как обычно, воспринимайте названия переменных с (солидной) долей скептицизма. И учтите, что эффект применяется до гамма-коррекции.
Я добавил «fChromaticAberrationIntensity», чтобы увеличить размер смещения, а значит и силу эффекта, как следует из названия (TW3 = 1.0). Intensity = 40:
Вот и всё! Надеюсь, вам понравилась эта часть.
Часть 4: виньетирование
Виньетирование — один из самых распространённых эффектов постобработки, используемых в играх. Он популярен и в фотосъёмке. Немного затенённые углы могут создавать красивый эффект. Существует несколько типов виньетирования. Например, в Unreal Engine 4 используется естественный. Но вернёмся к The Witcher 3. Нажмите сюда, чтобы увидеть интерактивное сравнение кадров с виньетированием и без него. Сравнение взято из руководства NVIDIA по производительности The Witcher 3.
Скриншот из «Ведьмака 3» со включенным виньетированием.
Заметьте, что верхний левый угол (небо) не так затенён, как другие части изображения. Позже мы вернёмся к этому.
Во первых, существует незначительное различие между виньетированием, использованным в оригинальной версии «Ведьмака 3» (которая была выпущена 19 мая 2015 года) и в «Ведьмак 3: Кровь и вино». В первой «обратный градиент» вычисляется внутри пиксельного шейдера, а в последней он заранее вычисляется в 2D-текстуру размером 256×256:
Текстура 256×256, используемая как «обратный градиент» в дополнении «Кровь и вино».
Я буду использовать шейдер из «Крови и вина» (отличная игра, кстати). Как и в большинстве других игр, виньетирование «Ведьмака 3» вычисляется в пиксельном шейдере финальной постобработки. Взглянем на ассемблерный код:
Интересно! Похоже, что для вычисления виньетирования используется и гамма (строка 46), и линейные пространства (строка 51). В строке 48 мы сэмплируем текстуру «обратного градиента». cb3[9].xyz не связан с виньетированием. В каждом проверенном кадре ему присваивается значение float3(1.0, 1.0, 1.0), то есть он, вероятно, является финальным фильтром, используемым в эффектах постепенно затемнения/осветления экрана (fade-in / fade-out). Для виньетирования в TW3 есть три основных параметра:
Типичная маска виньетирования
Но с помощью весов (строка 52) можно получать очень интересные результаты:
Маска виньетирования TW3, вычисленная с использованием весов
Веса близки к 1.0. Посмотрите на данные буфера констант одного кадра из «Крови и вина» (магического мира с радугой): вот почему на яркие пиксели упомянутого выше неба не повлияло виньетирование.
Вот моя реализация виньетирования TW3 на HLSL.
GammaToLinear = pow(color, 2.2)
Надеюсь, вам понравилось. Также можете попробовать мой HLSLexplorer, который очень помог мне в понимании ассемблерного кода HLSL.
Как и раньше, воспринимайте названия переменных с долей скептицизма — шейдеры TW3 обработаны D3DStripShader, поэтому я по сути почти ничего о них не знаю, мне остаётся только гадать. Кроме того, я не несу никакой ответственности за урон, нанесённый вашему оборудованию этим шейдером 😉
Бонус: вычисление градиента
В выпущенном в 2015 году «Ведьмаке 3» обратный градиент вычислялся в пиксельном шейдере, а не использовалось сэмплирование заранее вычисленной текстуры. Взглянем на ассемблерный код:
К счастью для нас, он довольно прост. На HLSL он будет выглядеть примерно так:
То есть мы просто вычисляем расстояние от центра до текстела, творим с ним некую магию (умножение, saturate. ), а затем… вычисляем многочлен! Потрясающе.
Часть 5: эффект опьянения
Давайте посмотрим, как в игре «Ведьмак 3: Дикая охота» реализован эффект опьянения. Если вы в неё ещё не играли, то бросайте всё, покупайте и играйте посмотрите видео:
Сначала мы видим двоящееся и кружащееся изображение, часто возникающее, когда выпьешь в реальной жизни. Чем дальше пиксель от центра изображения, тем сильнее эффект вращения. Я намеренно выложил второе видео с ночью, потому что можно чётко увидеть это вращение на звёздах (видите 8 отдельных точек?)
Вторая часть эффекта опьянения, возможно, не сразу заметная, — это небольшое изменение зума. Оно заметно рядом с центром.
Наверно очевидно, что этот эффект является типичной постобработкой (пиксельным шейдером). Однако не таким очевидным может быть его расположение в конвейере рендеринга. Оказывается, эффект опьянения применяется сразу после тональной коррекции и прямо перед motion blur («пьяное» изображение является входными данными для motion blur).
Давайте начнём игры с ассемблерным кодом:
Здесь использованы два отдельных буфера констант. Давайте проверим их значения:
Нам интересны некоторые из них:
Мы начнём с первых строк:
Строку 0 я называю «коэффициентом зума», и скоро вы поймёте, почему. Сразу после неё (строка 1), мы вычисляем «смещения поворота». Это просто входная пара данных sin/cos, умноженная на 0.05.
Строки 2-4: сначала мы вычисляем вектор из центра эффекта до UV-координат текстуры. Затем мы вычисляем квадрат расстояния (3) и простое расстояние (4) (от центра до тексела)
Текстурные координаты с зумом
Давайте рассмотрим следующий ассемблерный код:
Поскольку они упакованы таким образом, мы можем проанализировать только одну пару float.
Для начала, r0.yz являются «смещениями поворота», r1.z — это расстояние от центра до тексела, r1.xy — это вектор от центра до тексела, r0.x — это «коэффициент зума».
Чтобы понять это, примем пока, что zoomFactor = 1.0, то есть можно записать следующее:
Аналогично для r3.xy:
Отлично. То есть в данный момент у нас по сути есть текущая TextureUV (texel) ± смещения поворота, но что насчёт zoomFactor? Посмотрите на строку 0. По сути, zoomFactor = 1.0 — 0.1 * drunkAmount. Для максимального drunkAmount значение zoomFactor должно быть равно 0.9, а текстурные координаты с зумом вычисляются теперь так:
Возможно, более интуитивно понятным будет такое объяснение: это просто линейная интерполяция на какой-то коэффициент между нормализованными текстурными координатами и центром. Это «приближенное зумом» изображение. Чтобы понять это, лучше всего поэкспериментировать со значениями. Вот ссылка на Shadertoy, где можно посмотреть эффект в действии.
Смещение текстурных координат
Весь фрагмент на ассемблерном коде:
создаёт некий градиент, назовём его «маской интенсивности смещения». На самом деле, он даёт два значения. Первое в r0.w (мы используем его позже) и второе, в 5 раз сильнее, в r0.x (строка 15). Последнее на самом деле служит в качестве множителя размера текселов, поэтому влияет на силу смещения.
Сэмплирование, связанное с вращением
Далее выполняется серия сэмплирования текстур. На самом деле используются 2 серии на 8 выборок, по одной на каждую «сторону». На HLSL можно записать это следующим образом:
Хитрость в том, что мы прибавляем к baseTexcoordsA/B дополнительное смещение, лежащее на единичной окружности, умноженное на упомянутую ранее «интенсивность смещения текстурных координат». Чем дальше от центра находится пиксель, тем больше радиус окружности вокруг пикселя — мы сэмплируем его 8 раз, что хорошо заметно на звёздах. Значения pointsAroundPixel (кратные 45 градусам):
Сэмплирование, связанное с зумом
Вторая часть эффекта опьянения в The Witcher 3 — это зум с приближением и отдалением. Давайте посмотрим на выполняющий эту задачу ассемблерный код:
Мы видим, что здесь есть три отдельных вызова текстуры, то есть три разные координаты текстур. Давайте проанализируем, как из них вычисляются текстурные координаты. Но сначала покажем входные данные для этой части:
Пара слов о входных данных. Мы вычисляем смещение в текселах (например, 8.0 * размер тексела), которое затем прибавляется к базовым uv-координатам. Амплитуда просто колеблется в интервале от 0.98 и 1.02, чтобы придать ощущение зума, как и zoomFactor в части, выполняющей вращение.
Давайте начнём с первой пары — r1.xy (строка 61)
Давайте проверим вторую пару — r3.xy (строка 62)
Давайте проверим третью пару — r0.xy (строки 63-64)
Все три запроса текстур складываются вместе, и результат хранится в регистре r1. Стоит заметить, что этот пиксельный шейдер использует сэмплер с ограниченной адресацией.
Соединяем всё вместе
Итак, на данный момент у нас есть результат вращения в регистре r2 и три сложенных запроса зума в регистре r1. Давайте посмотрим на последние строки ассемблерного кода:
О дополнительных входных данных: r0.w берётся из строки 7, это наша маска интенсивности, а cb3[0].y — это величина эффекта опьянения.
Давайте разберёмся, как это работает. Мой первый подход заключался в «брутфорсе»:
Но какого чёрта, никто так не пишет шейдеры. Я взял карандаш с бумагой и написал такую формулу:
Где t = effectAmount * intensityMask
Итак, у нас получается:
И мы приходим к следующему:
Да, эта часть статьи оказалась очень подробной, но мы наконец-то закончили! Лично я научился кое-чему в процессе написания, надеюсь, и вы тоже!
Если вам интересно, полные исходники на HLSL выложены здесь. Я проверил их своим HLSLexplorer, и хотя нет прямых соответствий один в один с исходным шейдером, различия так малы (на одну строку меньше), что я могу с уверенностью сказать, что он работает. Спасибо за прочтение!