Как я могу сделать воду темнее с глубиной, как в Minecraft?


24

В Minecraft, когда вы смотрите на воду, чем глубже вы видите, тем темнее становится. Кто-нибудь знает, как кодировать что-то подобное?

Minecraft с эффектом Minecraft с эффектом

похожая игра без эффекта похожая игра без эффекта


18
Разве это не сделано автоматически, поскольку материал водного куба полупрозрачен?
Пек

Я так не думаю. Я добавил картинку без эффекта для сравнения.
Ксавье

2
Может быть, это эффект добавок, применяемый только к кубикам воды? Опять же, это должно быть легко, так как материал полупрозрачен.
Пек

1
Вы также можете изменить цвет ящиков в зависимости от глубины.
Ali1S232

Ответы:


51

Существуют два основных подхода к освещению воды в зависимости от глубины:

Воксельный-Lighting

Minecraft использует воксельное освещение, которое распространяет свет на соседние кубы, уменьшая яркость в зависимости от типа блока. Темные океаны являются побочным эффектом этой системы.

Вода блокирует солнечный свет и уменьшает свет на 3 уровня на блок (вместо 1 уровня по умолчанию), что означает, что яркость в океане для каждого расстояния от поверхности составляет:

0 (surface): 15 (direct sunlight)
1:           12
2:            9
3:            6
4:            3
5 and below:  0 (darkness)

Источник: Minecraft Wiki - Light

Затенение, основанное на расстоянии

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

Прямой расчет

Если у вас плоская поверхность, вы можете легко рассчитать расстояние, которое свет проходит в воде, если вы передадите нормаль поверхности от водоема \ VEC {п}и точечное произведение этого нормаля и положение поверхности sв геометрический шейдер.

Эффективное расстояние воды

\ max (\ left (s - \ vec {n} \ cdot \ vec {p} \ right), 0) \ cdot \ left (1 + \ tan (\ alpha) \ right)

где \ VEC {р}- положение вершины и альфаугол между направлением света под поверхностью и поверхностью воды, перпендикулярным массе воды.

На закате альфатолько достигает чуть менее 50 °, потому что свет преломляется при входе в воду.
Вот запись в блоге с хорошим объяснением: Цифровая камера: полное внутреннее отражение
Еще одна запись с более подробной информацией: Цифровая камера: закон преломления Снелла

Если вы используете карту высот на поверхности, параллельной воде, \ left (s - \ vec {n} \ cdot \ vec {p} \ right)становится \ левый (с - ч \ правый). Правильный коэффициент равен 1, если солнце находится прямо над поверхностью воды.
С точечным источником света вы должны рассчитать альфадля каждой вершины, основываясь на относительном положении источника света.

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

Плюсы:

  • Быстро и точно

Минусы:

  • Работает только для плоских водных поверхностей или только для света сверху, так как обычно учитывается только одна поверхность. (Сочетание шероховатой поверхности и наклонного света может в некоторой степени работать при картировании параллакса.)
  • Нет каустики

Shadow Mapping

Если вы визуализируете поверхность воды на отдельной карте глубины (как видно из источника света), вы можете использовать эту текстуру глубины, чтобы вычислить расстояние, которое свет проходит в воде, прежде чем ударить по поверхности.
Для этого вы проецируете каждую вершину в проекцию вида источника света в вершинном шейдере и выполняете поиск текстуры в пиксельном шейдере.

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

Плюсы:

  • Работает с относительно сложной геометрией воды, если только она не перекрывает себя. *
  • Можно использовать практически для любого частично прозрачного объема.

Минусы:

  • Медленнее, чем прямой расчет.
  • Требуется дополнительный VRAM для карты глубины.
  • Не на 100% точный.

* Вы можете определить количество воды перед ближайшей твердой поверхностью, посчитав глубину от POV света следующим образом:

  1. Отобразите твердую геометрию в вашей сцене как обычно. Для каждого фрагмента вы добавляете значение глубины к результирующей текстуре.
  2. Рендеринг передних граней воды без обновления буфера глубины и вычитания глубины фрагментов из результата.
  3. Визуализируйте задние грани таким же образом, но добавьте глубину фрагмента к результату.

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

Трассировка лучей

Трассировка лучей - безусловно, самое точное, но и самое дорогое решение для рендеринга прозрачных объемов. Есть два способа сделать это: 1. Отслеживание от дна океана к поверхности и 2. Отслеживание от источника света к воде. Несколько лучей необходимы для каждой точки на полу, чтобы рассчитать яркость.

Плюсы:

  • Работает правильно с каждой геометрией.
  • Правильная каустика!

Минусы:

  • Медленный!

Дополнительные эффекты

Есть еще несколько вещей, которые необходимо учитывать при рендеринге воды:

Туман

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

Если наблюдатель погружен в воду , вы можете просто визуализировать туман на основе окончательного результата буфера глубины. Цвет тумана, но не его плотность, должен меняться с удалением наблюдателя от поверхности! (Minecraft использует только эту часть эффекта.)

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

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

Поддельные каустики

Если вы используете бесшовную мозаичную 3D-текстуру вместо надписи для искусственной каустики, вы можете избежать растяжения вертикальных поверхностей. Сила рассеянного света у поверхности варьируется в трех измерениях, поэтому использование 2D-текстуры обычно приводит к растяжению где-то в сцене. Вы можете смоделировать изменение углов освещения, проецируя положения вершин пола в другую систему координат.

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

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

Цветовой градиент

Цвета разбросаны по-разному, поэтому светлый цвет должен меняться с увеличением глубины. Это также предотвращает появление крутых кромок, например, если пляж пересекает поверхность воды.

Угол падения

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


6

Я считаю, что эффект освещения неба в Майнкрафте прямо вниз - вещи затеняются тем, что находится над ними, независимо от того, где солнце. Затем применяется локальное освещение от факелов и т. Д. С эффектом спада - чем дальше от источника света, тем меньше света получает куб.

Если сделать это таким образом, каждый слой воды будет кумулятивно затенять слой под ним, так что каждый становится все темнее. Листва деревьев обеспечивает такой оттенок, однако он не является кумулятивным. Вы получаете тот же оттенок под деревом, будь то 1 или 100 кубиков листвы.

Один из признаков того, что этот метод используется, заключается в том, что вода не темнеет, когда находится дальше от зрителя, - только когда вы спускаетесь. Да, эффект тумана срабатывает на расстоянии, но не эффект темноты воды.

Таким образом, основная формула для расчета освещения будет выглядеть примерно так в псевдокоде ...

light_on_cube = 1.0
for each cube above target cube, from lowest to highest {
   if cube being examined is tree foliage
      light_on_cube = 0.5
   else if cube being examined is water
      light_on_cube = light_on_cube - 0.1
   else if cube being examined is solid 
      light_on_cube = 0
}

Это не идеально для расчета освещения под выступами или в пещерах, так как при использовании этого метода было бы совершенно темно под выступом. Но можно добавить как локальные источники света (факелы, огни и т. Д.), Так и трактовать освещенные солнцем блоки в качестве источников света. Нечто подобное может сделать это ...

  1. Рассчитайте свет от солнца прямо сверху (через псевдокод выше) для каждого куба.
  2. Если у куба есть источник света, считайте его полностью освещенным (1.0)
  3. Если куб не получает солнца непосредственно сверху, дайте ему немного света, основываясь на том, как далеко он находится от полностью освещенного куба. Ближе означает больше света, дальше - меньше (до нуля).

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


1
Да, я уверен, что это билет. Я сделал нечто подобное в моей игре.
MichaelHouse

Кстати, я только что добавил ваш блог в свой список читателей Google Byte56 - блоги разработчиков FTW!
Тим Холт

О, почему спасибо. Все еще не по теме этого вопроса, но я только что прочитал ваш блог о классе профессора Бейли. Я был в этом классе в прошлом году! Я вполне уверен, что вы дали эту презентацию и в прошлом году. Я думал, что твое имя было знакомо. Маленький мир :)
MichaelHouse

3

Возможно, я неправильно понимаю вопрос, но почему вы не можете просто изменить цвет блоков в зависимости от их глубины?

Если у вас есть глубина d (в блоках, начиная с 0), то разумным уравнением для яркости будет:

L = (1- т ) е - кд + м

Код: L = (1.0 - m) * exp(-k * d) + m;

k контролирует, насколько быстро становится темнее (выше = быстрее). Разумное значение будет 0,5.
m - минимальная яркость, которую вы хотите.
L варьируется от 0 до 1.

Если вы не знаете, как изменить цвет блоков в любом графическом API, который вы используете, задайте это как отдельный вопрос (с указанием того, какой API вы используете, и используете ли вы шейдеры или нет).


Я просто не думал об этом. Просто из любопытства, откуда у тебя это уравнение?
Ксавье

1
@Xavier: я только что сделал это. e^-kdБит просто экспоненциальный спад, который является стандартной функцией для вещей , которые постепенно стремятся к нулю в течение некоторого значения (глубины). Умножение на (1-m)и сложение mпросто для масштабирования и смещения затухания так, чтобы оно заканчивалось как минимум, mно все равно начиналось с 1. en.wikipedia.org/wiki/Exponential_decay
Питер Александр

Дело в том, что блоки более глубокого оттенка будут видны, только если блоки имеют альфа-цвета; в этом случае нет необходимости менять цвет блока, альфа создаст эффект автоматически.
Джонатан Коннелл

@Jonathan: Вы не визуализируете водные блоки, вы визуализируете блоки на морском дне с затемнением цвета, а затем просто получаете один альфа-слой на поверхности воды.
Питер Александр

@ Питер Александр Хорошо, я предположил, что в этих играх блочного типа даже вода была сделана из блоков.
Джонатан Коннелл
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.