Лайтмапы

```
***Основная статья***

```

## **Что такое лайтмап и для чего он нужен**

Лайтмап (Lightmap) представляет собой обычную текстуру, накладываемую на модель специфическим образом – цвета ее пикселей умножаются на цвета пикселей основной, диффузной текстуры (назовем ее базовой текстурой) – это простейший способ наложения **lightmap**, так называемый **modulate**, при нем на модели можно проявить только затененные участки. Далее будет описан еще один способ наложения лайтмап.

С помощью лайтмап можно имитировать освещение и затенение модели в отсутствие источников освещения. Однако главное достоинство лайтмап – это способность имитировать освещение реального мира (**GI**, **global illumination**), на расчет которого в пакетах 3d моделирования уходит значительное время (такие возможности есть в базовом наборе плагинов 3DSMAX, а также в **mentalray**, **vray** и т.п.). Ниже будет описан один из способов рендеринга лайтмап в 3DSMAX, а также настройка материалов для экспорта модели в движок игры.

## **Тестовая сцена и настройки рендера**

Для примера рендера **lightmap** настроим тестовую сцену. Создадим некоторый объект сложной формы, содержащей участки, в реальном мире подверженные скоплениям грязи и естественному самозатенению, т.е. выемки и вогнутые части. Для корректного рендера **lightmap** нужно, чтобы **Ambient** сцены был установлен в черный цвет (иначе не получится абсолютной тени). Цвет **background** нужно установить в белый. Также нам понадобится источник сферического света **SkyLight** (белый). Обращаю внимание на то, что сила блика должна быть 0, диффузный цвет – белый, а сам материал – 2-сторонний, чтобы при расчете теней замкнутые объемы (колонны, стволы пушек и т.п.) рендерились как сплошное тело, а не тонкая скорлупа.

Для того, чтобы получить **lightmap**, необходимо на ВСЁМ объекте выполнить развертку текстуры.

**Важно:**Если вы работаете с моделью техники, на которой не нужна отдельная текстура **lightmap**, а она может быть «вшита» в основную текстуру отдельным затеняющим слоем – нужно использовать уже имеющуюся развертку текстуры. Если же это – модель здания и т.п., использующая базовые текстуры «общего назначения» (неуникальные и применяемые в нескольких моделях), то для такой модели необходима развертка текстуры **lightmap** в отдельном текстурном канале.

Итак, мы имеем некоторую раскладку текстуры. В идеале все кластеры раскладки для **lightmap** – уникальные. Но одинаковые части модели могут быть положены на одно и то же место в раскладке. Ограничение следующее: части, одинаковые геометрически, но разные по освещенности, не должны накладываться друг на друга, иначе результат будет некорректным. Например, верх и низ кубика, лежащего на плоскости, должны лежать в разных местах раскладки, а вот боковые стороны могут быть совмещены, если нет разницы в освещении этих сторон.

Теперь собственно настройки рендера. Сначала нужно включить **LightTracer**, который рассчитает наше глобальное освещение. Обратите внимание на **rays/sample** – фактически кол-во фотонов на единицу площади текстуры: чем выше, тем чище освещенная поверхность и медленнее рендеринг, но на малых значениях (ниже 100) на равномерно освещенной поверхности возникнут пятна. Приемлемое качество достигается при **rays/sample** > 300. **Filter size** – это размер сглаживающего фильтра, устраняющего «ступеньки» и т.п. артефакты на готовой текстуре. Размер задается в пикселях. 3.0 вполне достаточно для хорошего качества текстуры **1024\*1024**. **Cone angle** – предельный угол отражения падающих лучей от поверхности объекта. Практика показывает, что угол больше 45 не дает визуального улучшения качества, но только замедляет расчет. **Bounces** – кол-во отражений света от поверхности. Если он равен 0, то объект будет освещен только падающими лучами от источника света, без расчета рефлексов от самого объекта. Чем выше этот параметр, тем больше отражений фотонов рассчитывается и тем больше время расчета (на каждую единицу **bounces** приходится время, равное полному расчету текстуры, так что нежелательно задавать его больше 2 – особого прироста качества не будет, только потеря времени). После выполненных операций нужно задать параметры расчета текстуры в меню **rendering/render to texture**.

**Важно:**Для расчета текстуры объект всегда должен быть выделен. В **general settings** нужно задать путь, по которому будет записана рассчитанная текстура **lightmap**.

Параметр **padding** отвечает за следующее: каждый кластер раскладки окружается «бордюром» шириной в указанное кол-во пикселей (для текстуры 1024\*1024 достаточно 8, для меньшей – от 4 до 6). Для чего это нужно? При отдалении от объекта, когда включаются mip-уровни текстуры, работает фильтрация пикселей и значение цвета каждого из них усредняется по определенной области соседей. При этом, если цвет текстуры внутри кластера сильно отличается от фона текстуры (а это практически всегда), границы кластеров проявятся в виде темных или светлых полос. **Padding** как раз устраняет эту проблему. **Projection mapping** нужно выключить.

В **Mapping coordinates** нужно указать, что необходимо использовать существующую раскладку и указать текстурный канал, из которого брать эту раскладку. Далее по кнопке **Add** задается рендер компонента «**complete map**», указывается имя и расширение текстуры **lightmap**, которая будет записана по указанному ранее пути. Также задается размер текстуры (она всегда квадратная, но при необходимости можно в **photoshop** изменить пропорции, главное рендерить с размером, равным наибольшей стороне текстуры). Если в сцене присутствуют дополнительные источники света, отбрасывающие тень, нужно включить флажок «**shadows**».

## **Требования к раскладке текстуры**

* Вся раскладка **обязательно** должна быть в пределах U=0..1, V=0..1 (кластера за пределами текстурного поля не допускаются).
* Рендерить **lightmap** нужно только с использованием белого материала, как это было в тестовой сцене.
* Если на модели не предполагается использование **lightmap** отдельной текстурой (это любая техника и солдаты), можно рассчитанную текстуру использовать просто как отдельный слой, накладываемый в **photoshop** с помощью **multiply**. Таким образом, не нужно вручную вырисовывать собственные тени объекта, что значительно ускорит работу и при этом эффективно выразит объем модели.
* Раскладка должна выполняться на весь объект целиком, т.е. до разбиения объекта на функциональные части (двери, стены, колеса и т.п.). Таким образом, если создается модель здания, то еще до разрезания стен на куски должна быть выполнена развертка под **lightmap**. В этой раскладке должны участвовать только те фрагменты модели, на которые **lightmap** будет использован. Не нужно занимать место на раскладке под окна и двери, на текстуре которых все равно вручную прорисовывается затенение. Также на **lightmap** не нужно рендерить места разломов стен.
* Для оптимального использования **lightmap** на моделях зданий желательно выполнять раскладку на несколько домов сразу. При правильной раскладке на 3-4 дома вполне может хватить **lightmap** размером 512\*512. Только с одним условием, что набор таких домов будет как можно более полно использован на одной карте.
* **Lightmap** может использоваться как для чистого затенения, так и для имитации световых пятен. Для этого нужно будет поменять настройки **ligth** **tracer** и способ наложения **lightmap** в материале модели. Также в сцену вводятся источники света в нужных местах. В настройках **light** **tracer** нужно задать **global** **multiplier** = 0.5 (вместо 1.0) и **background** **color** в **environment** должен быть средне-серым (128,128,128). Если рассчитывается такой **lightmap** для модели техники, то соответствующий слой в **photoshop** нужно наносить не как **multiply**, а как **overlay**. Хотя более точный результат получится, если сдублировать этот слой, и одну копию наносить как **darken**, а вторую как **screen**, при этом модифицировав **curves** слоя **screen** так, чтобы серый цвет (128) превратился в черный.
* Раскладывать базовую текстуру и **lightmap** нужно, руководствуясь следующим принципом: если на модель не предполагается выполнять LOD или если LOD выполняется «вручную», то базовая текстура остается в **explicit** **channel** **#1**, а **lightmap** – в **#2**. Если же на модель с **lightmap** предполагается создание LOD при помощи модификатора **multires**, то **lightmap** лучше раскладывать в канале **#1**, потому как **multires** портит раскладку остальных текстурных каналов, а базовая текстура накладывается обычно более простым способом (**planar**, **box**), чем **lightmap**.

## **Создание lightmap для готовых и разрезанных на части моделей**

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

Итак, пусть нам требуется внедрить лайтмап в готовую модель дома. Последовательность подготовки такая:

1. Создаем копию сцены с нашей моделью.
2. Все лишние объекты, которые не экспортируются и служат вспомогательными (чаще всего они оказываются скрытыми в сцене) - удаляем.
3. Выделяем все служебные объекты (объемы, точки привязки эффектов и т.п.) и **скрываем** их – они будут только мешать.
4. Выделяем все объекты, на которых лайтмапы не будет (окна, двери, плакаты и т.п. геометрия) и **скрываем** их тоже.
5. Выделяем все объекты и делаем **group** - **open**. **Важно:** Должны остаться только те части модели, на которых нужно рассчитать лайтмап и те объекты, на которых лайтмап не нужен, но они должны отбрасывать тень (например, водосточные трубы) – такие вспомогательные объекты выделяем, двигаем весь набор далеко в сторону, на целое и легко запоминающееся число единиц (например 100) и замораживаем, чтобы не выделить их при работе. Смещение нужно для удобства, чтобы в дальнейшем выполнить разборку модели на исходные части и чтобы эти самые исходные части не мешали нам при расчете освещения.
6. Обязательно «чистим» редактор материалов – заполняем его пустыми материалами (например с помощью скрипта **BlurScript**->**ClearMedit** или вручную), выделяем все оставшиеся в сцене объекты и в редактор материалов вытаскиваем материалы с выделенного набора – **get** **from** **selected**  (НЕ из всей сцены **get** **from** **scene**). Если модель выполнялась аккуратно, то количество материалов не создаст проблемы. Если же при изготовлении модели образовалось много мультиматериалов, придется очень тщательно поработать над их чисткой. Это один из самых длительных процессов при подготовке модели к нанесению лайтмапы, и как показывает практика, готовые модели часто страдают подобным хаотическим набором мультиматериалов.
7. Выносим в редактор материалов все (сколько поместится в максимальное кол-во ячеек, мультиматериалы с одинаковой структурой. Пример: **material#7876** [**mtl#1, mtl#5**], **material#9865** [**mtl#1, mtl#5**], **material#0978** [**mtl#1, mtl#5**] и т.п. После этого выделяем первый из таких материалов в редакторе и нажимаем на кнопку **select** **by material** . В появившемся списке будут выделены те объекты, на которых текущий материал. Закрываем это окно и выделяем в редакторе второй мультиматериал. Повторяем **select by material**, теперь выделяем предложенные объекты и назначаем им первый мультиматериал из набора одинаковых. Потом выделяем третий мультиматериал, выделяем его объекты и назначаем им первый мультиматериал. Повторяем операцию до тех пор, пока у нас не останется одна копия мультиматериала с данной структурой.
8. Снова чистим редактор материалов. Те же вышеуказанные операции проделываем с остальными одинаковыми мультиматериалами, пока не останется набор из нескольких мультиматериалов с разной структурой. Для удобства можно выбрать материалы у которых одинаковый набор дочерних материалов, но разный их порядок и, поменяв в модели идентификаторы материалов, привести такие наборы к одному мультиматериалу.
9. Итак у нас в редакторе материалов имеется некоторый набор (в удачном случае не более 10) материалов, назначенных частям модели, над которыми нам предстоит работать. Если в имеющихся в редакторе мультиматериалах повторяется какой-либо дочерний материал (например **material#1245** [**mtl#1,mtl#5**], **material#1872** [**mtl#1,mtl#3**],......) то такой материал нужно вынести (**drag-and-drop**) в неиспользуемую ячейку редактора материалов, затем выделить мультиматериал, где этот материал (**mtl#1**) присутствует и из скопированной ячейки «втащить» в соответствующий слот мультиматериала (**material#1245**). На запрос **instance or copy** ответить **instance**. Это нужно для того, чтобы у нас не было в сцене одинаковых материалов в нескольких независимых копиях (недоработка 3DSMAX – в сцене могут быть одинаковые материалы с одинаковыми именами, но являющиеся разными сущностями)
10. Выделяем все обрабатываемые объекты и делаем с них копию (не instance). Двигаем весь набор на ту же дистанцию, куда ранее сместили вспомогательные объекты. После этого выделяем оригиналы и замораживаем их.
11. По очереди выбираем каждый из обрабатываемых кусков и удаляем (**detach**) из них те полигоны, на которых лайтмапы не будет (места разломов, решетки и т.п.) Отделенные части именуем так, чтобы легко было потом узнать, откуда они и скрываем их (**hide**).
12. Если в оставшихся частях есть материалы, которые будут иметь лайтпам, но эти материалы также принадлежат объектам без лайтмапы, то следует сделать копии таких материалов (копии будут содержать лайтмап, исходники – нет) и назвать такие копии по-другому.
13. У нас остались только те части, на которых будет рассчитываться лайтмап. В редакторе материалов выделяем неиспользуемый слот, создаем в нем материал с клетчатой текстурой в канале **#2** для контроля развертки текстурных координат лайтмапы. Назначаем этот материал всем оставшимся объектам.

Итак, мы завершили подготовку модели к созданию лайтмапы. Теперь непосредственно сам процесс:

1. Для каждой части создаем раскладку второго канала текстурных координат так, чтобы масштаб наложения на разных кусках совпадал – это легко проконтролировать визуально по клетчатой текстуре временного материала. Следует помнить, что кластеры раскладки каждой части для удобства нужно разносить подальше от места раскладки соседних частей – так удобнее будет впоследствии работать с объединенным в один **mesh** набором объектов.
2. После обработки всех частей нужно приаттачить все части друг к другу, создав один объект без сшивания вертексов и переназначения идентификаторов материалов. Желательно после этого сделать **Reset** **XForm**, сколлапсировать стек модификаторов и при выворачивании модели наизнанку инвертировать ее нормали.
3. На получившемся объекте выполняем укладку кластеров текстурной развертки так, чтобы получить приемлемое и оптимальное их расположение.
4. Далее выполняем операции, чтобы получить собственно лайтмап. Проверяем полученную текстуру и при необходимости вносим изменения в раскладку.
5. Создаем копию (не instance) объекта, с которого была сделана лайтмапа и копию скрываем (она может нам позже пригодиться при перерасчете лайтмапы).
6. Размораживаем все вспомогательные объекты (трубы и т.п.), которые были заморожены, двигаем назад к их исходному местоположению (на те самые 100 единиц). Теперь выделяем наш объект и начинаем разбирать его на части:
	* Отделяем фрагмент, соответствующий исходной модели и делаем **detach**.
	* После этого **unhide** тот набор полигонов, который был ранее оторван от данного фрагмента (например полоса разлома стены).
	* Затем назначаем отделенному куску тот материал, который назначен исходной части.
	* Аттачим к полученному объекту вышеуказанный набор полигонов и двигаем весь объект обратно к исходному месту. При назначениях материала и присоединении геометрии не должно появляться предупреждений об изменение **mtl id**. Если это произошло – значит что-то сделали не так, нарушили последовательность действий.
	* Выделяем иходный фрагмент, превращаем его в **editable** **mesh**, выбираем под-объекты **face** и снимаем выделение со всех полигонов. После этого добавляем модификатор **Delete** **Mesh**, потом **Edit** **Mesh** и аттачим к получившемуся пустому месту наш заново собранный экземпляр данного фрагмента с лайтмапой, который уже установлен на нужное место.
	* Повторяем набор операций до тех пор, пока весь объект с лайтмапой не будет разобран на части и возвращен в исходные позиции.
7. U**nhide** **all**, **unfreeze** **all**. Выделяем все и делаем **group** - **close**. Скрываем копию объекта, на котором считалась лайтмапа и источник света – сейчас это должны быть единственные вспомогательные объекты в сцене.
8. В редакторе материалов выбираем те материалы, на которых присутствует лайтмапа, настраиваем их. Очень желательно вынести текстуру лайтмапы в **common/model**, чтобы не пришлось потом это делать вручную.
9. Экспортируем модель.

## **Экспорт lightmap**

Для того, чтобы можно было увидеть **lightmap** в игре, нужно в каждом материале, для которого предполагается применять **lightmap**, в качестве текстуры диффузного канала задать **RGB** **Multiply** вместо **Bitmap**. При этом в **Color#1** нужно указать базовую текстуру с тем каналом, в котором выполнена ее раскладка (например, **explicit channel #2**) и в **Color#2** указать текстуру **lightmap** со своим текстурным каналом (например, **explicit channel #1**). В поле **alpha from** обязательно должна быть указана **map#1** (т.е. базовая текстура). Для того, чтобы использовать **lightmap** с тенями и освещением, нужно выставить флажок **modulate2x** **lightmap** в оболочке материала **eclipsemtl**.

После этого модель экспортируется и в материале, использующем **lightmap**, будет записано примерно следующее:

```
{material multiply
    {diffuse "имя-базовой-текстуры"
        {AlphaChannel 0}
    }
    {diffuse1 "имя-текстуры-lightmap"
        {AlphaChannel 0}
    }
    {tile}
}

```