Реализация освещения на ActionScript 3

Итак, давно обещанный пост про реализацию освещения в My Little Princess. Сперва я рассмотрю пробные варианты, ну и в конце будет тот, который вошёл в релиз. Вполне возможно, что я где-то повернул в неправильную сторону, так что обсуждение приветствуется. Да, использовался движок Flixel, но описываемые техники не содержат жёсткой привязки к нему.

Для реализации самого первого способа нам понадобится такая вот текстура:

Она используется как маска. Назовём её для определённости «mask».

Принцип работы достаточно простой:

  1. Генерируем текстуру размером с экран. Назовём её «darkness».;
  2. Устанавливаем ей режим блендинга «multiply»;
  3. Заполняем цветом 0xFF000000. (чёрные непрозрачный. первый компонент — альфа канал);
  4. Накладываем darkness на отрендеренное изображения, рисуем поверх текстуру mask. Получаем дырку в darkness;

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

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

А уж если источников света было несколько, то FPS легко падал до 10.

Итак. Этот вариант пришлось отбросить. Следующей стоящей идеей была попиксельная пост обработка изображения. Я так и не смог найти код, который за неё отвечает. Почему то его не оказалось в репозитории, но идея ещё проще чем в предыдущем варианте. Просто берём массив пикселей после рендеринга основной картинки и изменяем яркость точек. Я предполагал? что работа с памятью будет медленной, но не думал что настолько. Она очень медленная.

После гугления я узнал о технологии Pixel Bender. Вот оно, спасение, подумал я. Если коротко, то это что-то вроде шейдеров для flash. На деле она оказалась ещё более тормознутой чем работа с массивом пикселей. Сейчас я не вспомню насколько, но достаточно для того, чтобы забыть про бендера раз и навсегда. И зачем её придумали вообще?

Итак, теперь финальный вариант. Я уже понял что множественных источников освещения мне не видать и решил сделать просто один быстрый. Для его реализации используется вот такая вот текстура:

Она просто накладывается серединой примерно на принцессу и растягивается до нужных размеров. Белый цвет на самом деле не белый. На текстуре градиентно изменяется альфа канал. На незаполненное пространство накладывается «darkness». Казалось бы — способ похож на самый первый, но тем не менее он быстрее. Правда, не очень сильно. По сути отличается только отсутствием блендинга и множественных источников.

Вот такие вот приключения. Всех проблем можно было бы избежать, если делать игру в меньшем разрешении или создавать арт заранее с расчётом на апскейл. Так, кстати говоря, делает автор Flixel. Надо будет попробовать рисовать 2D через новое API для работы с 3D ускорением. По идее оно должно дать существенный прирост и позволить забыть об описываемых тормозах.

  • спасибо, очень интересно такое почитать :)