Текстурирование спрайтов с помощью (dis)placement map

:


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

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

Суть в том, что в изучаемой мной игре есть большое количество анимированных спрайтов человечков (как я изначально считал — заранее отрендеренных). Человечки разные (по-разному одетые, разных цветов и т.п.).

Но посмотрев ресурсы, я увидел очень интересную штуку. Я увидел странного вида отрендеренные картинки:

А также, различные текстуры такого вида:

С текстурой все понятно. Но что за ерунда на первой картинке? Логика подсказывала, что это — какого-то рода карта искажений текстуры. Сначала я думал про какие-то искривления и карту нормалей… Но потом в голову пришла простая идея — displacement map. Это когда в картинке зашифрованы координаты сдвигов. Например, в красном канале — сдвиг по «x», а в синем — по «y».

Раскидав ее по каналам, я получил это:

И практически сразу все понял. Сразу видно, что синий канал — это явно альфа-канал.

Посмотрев на зеленый канал и увидев на нем явный вертикальный градиент, стало очевидно, что в нем зашифрована y-координата. Ну, а красному не оставалось быть ничем иным, как иксом.

Поползав «пипеткой» по картинке, подозрения подтвердились еще и тем, что каждая и R и G компонент менялась в диапазоне 0..127, в то время как картинка текстуры как раз и была размером 128х128 пикселей.

Довольно быстро я набросал код, который делал следующее для каждого пикселя:

color = map.getPixel(x, y);
tX = color.R;
tY = color.G;
alpha = color.B;
textureColor = texture.getPixel(tX, tY);
dest.setPixel(x, y, textureColor, alpha);

В результате получил почти то, что вижу в исходном проекте. Текстурированные фазы анимации человечка:

Правда, механизм не совсем displacement (в случает дисплейсмента речь идет об относительных изменениях наложения текстуры). Здесь скорее нужно назвать просто «placement map». :)

Можно еще накидать алгоритм сглаживания и использования соседних точек на текстуре — и все будет вообще шоколадно.

Стоит отметить, что во флэше есть встроенный механизм DisplacementMapFilter, но он не подошел, т.к. он работает с относительными координатами (как, в прочем, и положено дисплейсменту). Т.е. в нашем случае он бы делал
textureColor = texture.getPixel(x+tX, y+tY);

Итого.


Мне очень понравилась технология. Она позволяет получить кучу разноскиновых объектов высокого качества не применяя технологий 3D рендеринга и при этом иметь простую смену этих самых скинов.

Уже планирую использовать это в своем проекте.

Вопрос.


Остается только вопрос — с помощью какого софта можно получить вот такие текстуры, и что самое главное — рендер подобных карт искажений???

Был бы очень признателен хабрасообществу, если бы кто-нибудь поделился Знанием.

P.S.


Уже после публикации, понял, как можно получить подобный рендер даже без каких-то специальных плагинов и т.п.:
  1. Берем нашу модельку, делаем UV-развертку.
  2. Заливаем текстуру UV-развертки специальным градиентом, где R-компонента будет соответствовать координате «x», а G — координате «y».
  3. Ставим B-компоненту по всей текстуре в максимум.
  4. Рендерим получившуюся вещь без учета света, отражений и т.п., на черном фоне.
В результате получим искомый результат. X/y будут в R/G, а альфа автоматом попадет в «B», т.к. где наш объект будет прозрачным — там будет просвечивать цвет фона (черный), в остальных же местах — «B» будет браться из текстуры (255).

PS: Про экспорт альфа-канала в синий цвет помог додумать хабраюзер xanep.