Как работает освещение

216
6
19
Освещение [писалось под 1.8]

Исходная версия туториала
Мои остальные туториалы и переводы

Перевод довольно сложен, поэтому ошибок и некорректностей не избежать. О них, а так же о предложения по уроку, можно сообщить в ВК и в ЛС форума.​

Minecraft использует три модели освещения, в зависимости от того, что рендерится:
  1. Без освещения - в основном, для GUI
  2. Освещение предмета - использует модели освещения из OpenGL, которые применяются в рендере предметов, например, в слотах в инвентаре.
  3. Освещение мира - используется для определения яркости объектов в мире, в зависимости от близости источников света (света от неба и/или близлежащих святящихся объектов)

Освещение предмета
Освещение предмета включается и выключается через RenderHelper.disableStandardItemLighting() и .enableStandardItemLighting(). Эта модель освещения выбрана для создания трех-мерного отображения.

Освещение мира
Базовая модель освещения мира в Minecraft составлена из двух компонентов: Свет от неба и Свет от блоков. Каждая координата в мире имеет свое значение между 0-15 для Света от неба и так же значение между 0-15 для Света от блока.
  1. Свет от неба - это свет, который блок получает от неба, либо напрямую (если блок видит небо), либо косвенно (блок находится рядом с блоком, который видит небо).
  2. Свет от блока - это свет, который блок получает от других близлежащих источников света (факела, святящийся камень и т.п.).
Здесь можно узнать еще больше (англ).

World.computeLightValue() используется для вычисления Света от неба и Света от блока для каждого блока. Базовый концепт:
  1. Каждый блок имеет значение светопоглощения (.getLightOpacity()), которое определяет сколько света блок получает от шести соседей. Малое значение (например, 1) означает, что яркость освещения уменьшает на 1 от соседа, который освещает лучше всего, большое значение (например, 3) приводит к большей потери яркости освещения. Этот расчет применяется отдельно для Света от неба и Света от блоков.
  2. Некоторые блоки святятся (например, святящийся камень) - если заданная яркость освещения больше, чем яркость идущая от соседей блока, тогда свет от блока устанавливается в заданное значение.
  3. Если над блоком нет ничего или прозрачные блоки, тогда Свет от неба для него устанавливается на 15.
LightCalculation.png

Двумерный пример по распространению света от блока. Светопоглощение = 2. Свет от неба распространяется идентично.

Когда блок рендерится, значения Света от блока и Света от неба используются для установки яркости. Это происходит так:
  1. Значения Света от блока и Света от неба складываются в единый 32-битный Integer, например через Block.getMixedBrightnessForBlock(). Выше 16 битов содержатся значения Света от неба умноженные на 16, а ниже 16 битов содержатся значения для Света от блоков, умноженные на 16.
  2. worldRenderer.setBrightness() вызывается с значением "смешанной яркости", которое потом разделяется Тесселятором на 16-битные координаты ( [Свет от блоков, Свет от неба] ) и для текстуры вызывается Карта Освещения. (OpenGLHelper.lightmapTexUnit) - смотрите изображение ниже.
  3. Когда OpenGL рендерит стороны блоков, сначала он рисует начальную текстуру блока (OpenGLHelper.defaultTexUnit) и, как было ранее описано, после "собирает" конечную текстуру исходя из значения каждого текселя из Карты Освещения, т.е. из заданных значений координат [Свет от блоков, Свет от неба]. (Этот процесс называется Мультитекстурирование).

LightMap.png

Текстура Карты Освещения (OpenGLHelper.lightmapTexUnit), которая содержит в себе 16х16 текселей. Каждый тексел является сочетанием Света от блоков и Света от неба.

Почему Minecraft пошел именно таким путем? Есть две хорошие на то причины
  1. Рассматривание отдельно Света от блоков и Света от неба позволяет достичь более реалистичных эффектов освещения. Смотря на текстуру карты освещения можно увидеть что освещения блока строиться на красноватых/бурых цветах, хотя Свет от неба таковым не является. Это симулирует желтоватый свет, создаваемый (например) факелом.
  2. Карта освещения может быть легко обновлена для изменения освещения внутри сцены, например, в зависимости от времени суток; для создания мерцающего факела; или когда игрок пьет зелье ночного ведения. Обновление происходит через EntityRenderer.updateLightMap().

Эффекты освещения, зависящие от сторон
В добавление к описанному выше по-блочному освещению, Minecraft использует некоторые дополнительные расчеты для каждой стороны блока, чтобы улучшить реализм освещения.
1 - Яркость освещения, зависящая от направления стороны
Этот метод рендерит 6 сторон с разной интенсивностью света в зависимости от того, на какую сторону света направлена сторона блока:
  1. Верхняя сторона (Y поз.) - полная интенсивность
  2. Нижняя сторона (отриц. Y поз.) - 50%-ая интенсивность
  3. Стороны по Z-координате (Z поз., отриц. Z поз. = Юг, Север) - 80% интенсивности
  4. Стороны по X-координате (x поз., отриц. X поз. = Восток, Запад) - 60% интенсивности
BlockShadeOnOff.png

Яркость освещения, зависящая от направления стороны: слева (выключено), справа (включено).

Это освещение применяет для каждой стороны через worldRenderer.setColorOpaque(); когда текстура рендерится это значение умножается на значение цвета (в случае на картинке на значение серого цвета).

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

На освещение стороны так же влияет смесь яркости от [Свет от блоков, Свет от неба] по стандартному способу. Диаграмма снизу описывает все шаги.

Lighting.png

Схема, которая описывает как Minecraft накладывает эффекты освещения;

2 - Ambient Occlusion
Ambient Occlusion - это метод для расчета количества попадающего на блок солнечного света исходя из ближайщих блоков. Полное введение в тему того, как это работает в Minecraft здесь (англ). Если кратко, для каждого вертекса вычисляется интенсивность света исходя из трех смежных блоков плюс тот, который касается сторон. В примере ниже для обведенного красным вертекса есть три белого блока плюс блок, располагающийся на верхней стороне (не отображается). Если все эти три блока прозрачны, тогда интенсивность света "Ambient Occlusion" будет равна 1.0. Каждый непрозрачный блок уменьшает свет, полученный вертексом - если все 4 блока непрозрачны. (Есть некоторые детали на счет того, будет ли учитываться соседний блок или нет, но вам можно знать только основное). OpenGL накладывает сглаживание, когда рисует сторону, поэтому эффект света выглядит гладким на стороне между вертексами.

Ambient_Occlusion.png

Алгоритм Ambient Occlusion.

Немного дополнительной информации
Настоящий процесс мультитекстуринга немного сложней приведенного выше. Он настраиваться двумя функциями в RenderLivingEntity - сейчас называется func_177092_a и func_177091_f, но это может измениться в будущем. Мультитекстурирование устанавливается тремя слоями и они эти слои изменяются в зависимости от того, рендер чего происходит.

Для нормального рендера мира func_177091_f работает так:
Слой 0 - умножает текстуру модели на цвет и альфу.
Слой 1 - умножает карту освещения на конечный Слой 0, одновременно на цвет и альфу.
Слой 2 - не используется.

Для рендера существ func_177091_f работает так:
Вызывается перед рендером частей существа, только для того, чтобы изменить цвет, когда существу наносится урон (т.е. устанавливает красный цвет существу, когда наносится урон).

Слой 0 - умножает текстуру модели на необходимый цвет, альфа перезаписывается текстурой модели.
Слой 1 - Слой 0 смешивается с необходимым цветом, используя необходимую альфу (т.е. 50%-ая альфа с красным цветом дает нам 50:50 смесь слоя 0 и красного цвета).
Слой 2 - карта освещения умножается на RGB текстуру, игнорируя альфу карты освещения.

OpenGLHelper.GL_TEXTURE2 используется на одном из слоев просто как муляж, чтобы дать еще один слой для мультитекстурирования.
 
Последнее редактирование:
476
9
39
Переведи Ambient Occlusion! Очень интересно)
 
5,018
47
783
запилил бы кто нибудь гайд по своей системе освещения :\
 
5,018
47
783
Зачем тебе это?
И разные цвета света. И разная сила. И разные вариации. И разные направленности - узкий, круглый, квадратный, овальный, звездочкой, рассеяный, куполообразный...
 
476
9
39
Сверху