Hollow Horizon

Hollow Horizon 

A Certain Developer of a Certain Engine 🙃

128subscribers

81posts

goals3
20 of 25 paid subscribers
Такое количество подписчиков позволяет мне регулярно работать и обновлять движок. А также иногда вкладываться в дизайн и удобство движка.
1 of 3

Рендеринг Minecraft, Фреймбуферы, Шейдеры

Сегодня у нас пост в котором, я немного расскажу о рендеринге в игре целиком, а также разберу один интересный эффект из одного мода. 
Постараюсь обойтись без сложных терминов, да и в целом пост обзорный, т.е. это не гайд, как сделать крутой эффект, но зато у Вас вероятно отпадёт большинство вопросов, вроде "Почему какие-то моды не работают с шейдерпаками".

Как работает рендеринг в Minecraft?

Я начну разбор сразу с Sodium+Iris, чтобы было понятно как работает рендеринг с шейдерпаками. Для начала напомню, Шейдеры это не Шейдерпаки, очень часто люди это путают! Говорить "Я играю в майнкрафт с шейдерами", это всё равно что говорить "Я играю в майнкрафт с текстурами", вместо "Я играю в майнкрафт с текстурпаками".
Короче говоря, шейдер - это программа, которая что-то рисует или обрабатывает на видеокарте, а шейдерпак - это набор этих самых шейдеров, которые использует тот же Iris или Optifine.
Рассмотрим процесс отрисовки этого кадра из шейдерпака Complementary Reimagined:
Начинается всё с рисования теней. Игра создаёт вот такую текстуру:
Тут у вас вероятно возникла куча вопросов:
1) Что это такое? - Это карта теней, представьте себе камеру, которая стоит на месте солнца и смотрит на вас. Он нужен, чтобы позднее определить, в какую сторону направлены тени и где их видно (то есть участки, которые не видно на этой текстуре - тени, они будут темнее в финальном кадре)
То есть своего рода снимок со спутника)
2) Почему он круглый? - Обычно для оптимизации шейдерпаки делают снимок не всего мира, а лишь некоторого участка вокруг игрока, то в некотором радиусе от него, чтобы не рисовать лишнего, что игрок всё равно не увидит.
3) Что это за синие участки, и вообще почему всё тёмное/чёрно-белое? - Если выкрутить яркость и присмотреться внимательно, то можно заметить на этом рисунке листву, которая светлее того же дёрна. То есть объекты ближе к камере более белые, а те, что дальше - более чёрные. Это позволяет понять приблизительное расстояние до объектов, тем самым на финальном кадре определить на какой именно поверхности будет тень. Синие фрагменты есть не во всех шейдерпаках, конкретно сейчас это вода, обычно её игнорируют, но иногда могут вот так обрабатывать для разных эффектов, вроде теней под водой или бликов.
Ну и ещё эта текстура обычно рендерится в меньшем размере, чем финальный кадр (меньше, чем окно игры), потому что делать полную карту теней, это будет съедать куда больше ресурсов, а итоговые тени потом просто размывают (во многих пакетах её можно настраивать, можете сами в этом убедиться :D) 
Далее обычно идёт скайбокс:
Обычно их сразу делят на дневной и ночной, и целиком рендерят шейдерами. В отличии от ресурспаков, которые часто его добавляют просто как куб с текстурами на внутренних гранях. Сделано это потому что те же звёзды на небе проще нарисовать шейдером, чем добавлять 8к/16к текстуру, к тому же шейдер проще анимировать.
После чего уже идёт сам рендеринг мира. Происходит он одновременно в 4 текстуры.
Albedo (Цвет)
Вообще зависит от реализации шейдера, тут, в Complementary, можно сразу заметить тени и в целом освещение (некоторые грани блоков темнее/светлее других), но нету тумана и пост-обработки. Но суть тут конкретно в том, чтобы передать цвет каждого объекта.
Normal (Нормали/Наклон)
Тут уже можно отчётливо заметить разные грани, грубо говоря, они помогают разработчику шейдерпака определить в какую сторону направлен каждый пиксель на картинке, условно: сиреневый - север, зелёный - верх, красноватый - восток и т.п. Это нужно, чтобы понять в какую сторону отражается свет от объекта (все ведь помнят, чему равен угол падения и угол отражения из физики?)
Specular (Материал/Отражение)
Это уже текстура отвечающая за свойства материала, например, чтобы от железного блока отражался мир. Обычно тут есть чёткий стандарт, который используют большинство PBR ресурспаков:
  • Красный - более гладкие блоки, чем больше красного тем больше гладкости.
  • Зеленый - металличность, чем больше зеленого - больше процент отражения.
  • Синий - шершавость, обычно отвечает за логику отражения света во время дождя (т.е. чтобы прям лужи было видно или капающий дождь на поверхности лужи)
  • Канал прозрачности - зависит от тестурпака, обычно отвечает за параметр emissive, это когда у эндермена в темноте глаза светятся, также можно сделать, например, с рудами.
Depth (Глубина)
Тут почти ничего не видно, разве что пару блоков снизу по центру, уже упоминал ранее - это глубина, где тёмные объекты - ближе к камере, а светлые дальше от неё. Нужно, чтобы можно было определить глобальные координаты для каждого пикселя на экране (это делается через матрицу modelView
Ну а после этого за дело берётся последний шейдер-композитор, который объединяет эти 4 картинки в одну, например, берёт координаты пикселя, сравнивает их с картой тени (1 пункт, который мы обсуждали), если не находит там его, то рисует тень (если прям упрощённо), в зависимости от Depth-текстуры рисует тень (если пиксель дальше определённого расстояния, то делает его более серым, иначе не трогает) и другие эффекты, в зависимости от того, что захочет разработчик шейдерпака.
Ну и в результате получается то, что было на 1 картинке - финальный вариант.
Я тут не стал вдаваться в подробности той же отрисовки чанков или сущностей, как это всё дело оптимизирует Sodium, и как в это вмешивается Iris, да и думаю Вы это вряд ли переживёте)

Как работают эффекты применяемые на мир целиком?

Я думаю, теперь понять, как работает подобный эффект станет проще.
По сути у вас есть точка центра, от которой должны расходится волны. Для того чтобы они были в 3D, а не 2D (поверх экрана) используется эта самая Depth-текстура, а сами лучи строятся примерно по такому алгоритму:
  1. Ты "выстреливаешь" луч из камеры через пиксель на картинке.
  2. Ты спрашиваешь математическую формулу: "Какое расстояние от текущей точки луча до моей сферы"
  3. Допустим, формула говорит: "5 метров".
  4. Ты смело пропускаешь этот пиксель.
  5. Повторяешь вопрос для каждого пикселя. Если расстояние стало почти нулевым - значит, луч "ударился" о поверхность объекта! Пора красить пиксель в цвет энергии.
В данный момент проблема лишь одна - ты хочешь сделать такой эффект, а разработчик шейдерпака уже прописал все свои эффекты. Что делать? - Вариантов не много:
  • Переписать сам шейдерпак и добавить туда эффект.
  • После отрисовки финального кадра воспользоваться его сохранённой копией, её можно найти в фреймбуфере (это объект, который как раз и хранит те 4 текстуры, что мы обсуждали ранее), то есть мы берём, рисуем новый прямоугольник размером с экран прямо поверх мира, взяв за основу финальный кадр и Depth-текстуру из буфера и с их помощью рисуешь то, что тебе надо. Это и есть - пост-шейдеры, их может быть много и каждый может использовать результат предыдущего.
Единственный минус - тебе доступна не вся информация и вообще, по факту разработчики шейдерпаков плевать хотели, что ты там за фичу хотел написать и могут вообще не использовать некоторые из тех 4 текстур (хотя текстуру глубины обычно используют все шейдеры...). Но вот, к примеру я год назад, хотел целиком перенести отрисовку npc на движок Kool, но не смог разобраться с тенями, потому что Kool и Шейдерпаки не смогли определиться, где именно в мире будет находиться нпс. Например, взять ту же карту теней, как помните она округлая, есть шейдерпак, делающий подомное не только для теней, но и для мира в целом:
И вот представьте, Kool рендерит npc на одних координатах, а шейдерпак такой говорит: "Да плевал я на совместимость, лучше изогну тени для оптимизации", а Холлоу потом неделю сидит в RenderDoc и ругается, не понимая, куда делась тень от npc и почему она на соседней горе, а не возле npc.
В общем методика рабочая для всяких эффектов и партиклов, но есть ряд ограничений, если ты хочешь сделать что-то своё уникальное, как я год назад)
Очень интересный пост сам по себе. Многое стало понятным, хоть такие же аспекты встречаются в игровых движках, ты объяснил намного интереснее. А насчет отрисовки чанков и сущностей я бы точно послушал)
Но вот еще интересно послушать твое мнение насчет узкого горлышка Майнкрафта - долбежки в 1 поток, выскажи пожалуйста либо отдельный пост об этом со своим мнением, или просто небольшой ответ. Типо что в целом думаешь об этом, какие пути и костыли искать, а вдруг есть идея схитрить?🤔
Axel Encore, А, ответил немного ниже)
Насчёт отрисовки чанков, там и я понимаю всё поверхностно, так что пока сомневаюсь, что есть смысл об этом писать. А насчёт сущностей, там особо ничего нового, просто можно дополнить, что есть несколько подходов для рисования в эти самые текстуры из поста.
А насчёт серверов, по факту майн многопоточный, те же чанки подготавливаются для отрисовки в многопоточном режиме, да и рендеринг и серверная часть работают в отдельных потоках. Узким горлышком тут обычно называют сам подход к обновлению чанков на сервере. Представь себе 100 игроков, и все они одновременно прогружают свою зону чанков в мире. Это всё происходит в одном потоке. Но разделить это на несколько потоков не безопасно, т.к. это может поломать другие моды (условно захочет какой-нибудь мод собрать всех мобов рядом с игроками, а из-за того, что ты их раскидал по разным потокам возникнут конфликты или гонки данных), так что тут разве что или самому ядро и моды переписывать, или ждать, пока это сделают Mojang.
Hollow Horizon, о, мерси, применю
Hollow Horizon, А вообще кстати на старых версиях уже давно применяется довольно интересная практика: У каждого игрока свой мир, обычно даже скайблок. А также есть общие миры, куда игроки иногда делают вылазки. И таких миров может быть под 150 и все они висят в Docker контейнерах и могут распределяться на несколько процессов, а иногда и машин, зависит от бюджетов
Subscription levels4

Передовой Хеллоу-Вордер

$0.71 per month
Приобретя эту подписку Вы сможете получить доступ к большинству постов и некоторым бета-версиям мода. Кроме того, Вам станет доступен канал для подписчиков в Discord, где я часто делюсь своими мыслями и наработками.
+ chat

Продвинутый Скриптописец

$3.6 per month
Эта подписка уже открывает посты дороже, чаще всего это доступ к всяким глобальным обновлениям, объяснениям различных сложных механик и прочих фишек мода, о которых большинству не известно. 
+ chat

Магистр Kotlin

$14.1 per month
Это уже довольно солидная цена для подписки, так что с ней у вас будет больший приоритет на голосованиях и вашим идеям и предложениям будет уделено больше внимания :)
+ chat

Верховный Спонсор

$71 per month
Интересно, зачем нужна эта подписка?
+ chat
Go up