Как реализовать пост-эффект Bloom во Flash

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

    Часть первая. Блюр



    Важное ограничение


    Прежде всего, стоит понимать, что расчёт этих пост-эффектов не может быть выполнен на видеокарте. Связано это с одним замечательным ограничением, за которое мы и любим GPU — одновременно рассчитывается цвет нескольких пикселей. Из-за этого, вы не сможете точно узнать цвет «соседнего» пиксела, так необходимого при реализации этих эффектов. Поэтому, рассчитывать окончательную картинку будем на CPU. Пост-эффекты позволяют значительно сгладить неровности и некрасивые рёбра трёхмерной графики, и значительно улучшает картинку. Скорость выполнения пост-эффекта целиком и полностью зависит от размеров view, соответственно наибольшее падение производительности будет наблюдаться при full-screen картинке. Так же, хочется упомянуть, что ни к какому конкретному движку эти эффекты не относятся и могут быть выполнены на любом изображении, с которого можно снять BitmapData. В данной статье будет рассматриваться применение размытия к картинке, полученной при помощи движка alternativa3d. Кто всё ещё читает — приглашаю под хабракат.

    Подготовка картинки


    В первую очередь, нам необходимо попросить видеокарту вернуть нам отрендеренную картинку в удобном для нас виде. Для этого, необходимо вызвать метод Context3D.drawToBitmapData(). Аргументом этот метод принимает объект типа BitmapData, обновляемый с каждым вызовом метода present() того же контекста. Если вы пользуетесь движком alternativa3d — необходимо просто выставить свойство renderToBitmap экземпляра View в true. Тогда отрендеренный bitmapData можно будет получить из свойства canvas того же экземпляра.

    private function itsRenderTime(e:Event):void { //No, dad, no!
    camera.view.renderToBitmap = true;
    camera.render(stage3d);
    realisePostEffect(camera.view.canvas);
    }


    Собственно размытие


    Общепринято использовать следующий алгоритм размытия изображения:

    1. Сначала мы уменьшаем полученную от рендерера картинку, чтобы уменьшить нагрузку на процессор — ему придётся выполнять одну и ту же довольно непростую операцию над каждым пикселом.
    2. Следующим действием нам нужно узнать усреднённый цвет каждого из соседних текущему пикселу и смешать его с цветом текущего в равных долях. Если используется «усиленное» размытие — узнаются цвета соседей соседей; влияние цвета таких пикселей обратно пропорционально расстоянию (возможно даже его квадрату, не вдавался в подробности) до них от текущего.
    3. Пункт 2 может быть повторён несколько раз для усиления качества размытия. Теоретически, он может быть выполнен произвольное количество раз, однако опытным путём наилучшее соотношение качество/производительность было установлено при выполнении второго пункта трижды. Умные статьи говорят, что таким образом достигается наибольшее приближение к размытию по Гауссу, но в этой статье подробностей вам не видать, так что просто поверьте на слово.
    4. Полученная размытая картинка снова растягивается до размеров отрендеренной, чтобы соответствовать.
    5. Размытая и отрендеренная картинка смешиваются с учётом [полу]прозрачности размытой.


    С пунктами 2 и 3 прекрасно справляется встроенный фильтр флеша под названием BlurFilter. 1 и 4 обеспечивается применением матрицы аффиных преобразований при вызове метода draw экземпляра bitmapData. Ну а пункт пятый легко реализовать настройкой параметров конструктора экземпляра ColorTransform. Остаётся только показать картинку на экране, с чем без посторонней помощи справляется добавленный к [ребёнку] Stage экземпляр View библиотеки альтернативы:

    private function realisePostEffect(canvas:BitmapData):void {
    var _scaling:int = 4 //Уменьшаем нагрузку на процессор в 16 (4*4) раз.
    var _power:int = 4 //Просим фильтр учитывать цвет соседей вплоть до четвёртого порядка
    var _alpha:Number = .5 //Размытая и отрендеренная картинки будут смешиваться в равных долях
    var _quality:int = 3 //Размытие каждого пиксела будет произведено трижды, во имя богини красоты текущей религии разработчика

    var _cT:ColorTransform = new ColorTransform(1, 1, 1, _alpha);
    var _bloomData:BitmapData = new BitmapData(canvas.width / _scaling, canvas.height / _scaling, true, 0);
    var matrix:Matrix = new Matrix();
    matrix.scale(1 / _scaling, 1 / _scaling);
    _bloomData.draw(canvas, matrix, _cT);
    _bloomData.applyFilter(_bloomData, _bloomData.rect, new Point(), new BlurFilter(_power, _power, _quality));
    matrix.invert();
    canvas.draw(_bloomData, matrix);
    }


    Изображение без пост-обработки и с ней:


    На этапе разработки бывает очень удобно вынести параметры _scaling, _power, _alpha и _quality в статическое свойство произвольного класса, чтобы менять их рантайм и настраивать картинку до тех пор, пока не будет достигнут желаемый баланс между красотой и производительностью. Либо позволить менять их непосредственно пользователю через меню настроек графики.

    Coming soon: HDR-эффект — высветление картинки и как пощупать буфера.
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 18

      +5
      Картинку бы ещё.
        0
        Добавил
          0
          По каким признакам можно понять, что это bloom? я вижу только простое размытие, может добавить пример с массивным источником света? И если быть дотошным, то на видеокарте можно сделать все что угодно, если не ограничиваться DirectX/OpenGl, а использовать CUDA и т д.
            0
            На видеокарте можно сделать что угодно, несомненно. Но я ограничился средой выполнения flash-player'а с её достоинствами и недостатками
              0
              Да даже CUDA использовать не надо. Всё отлично делается с использованием шейдеров, в которые можно просто передать нужную информацию.
                0
                Несомненно, можно сделать через шейдеры PixelBender. Однако, они используют GPU только в среде самого PixelBender. В среде выполнения FlashPlayer фильтрация bitmapData идёт на CPU, пока адоби не скажут иного
          0
          ИМХО, лучше использовать ADD для смешивания размытой текстуры с оригиналом, а если до этого ещё подтянуть яркость и контраст то получим что-то более похожее на ХДР:
          image
            0
            HDR делается отдельно, через комбинацию colorTransform. А для настоящего блума вообще необходимо ещё как минимум раз рендерить сцену. Расскажу как — в следующих двух частях статьи.
            0
            А почему не через Molehill? Там и процессор грузить не надо и шейдеры есть
              0
              Alternativa3d использует Molehill'овские шейдеры, но только для рендера 3d-сцены. Оконечное размытие выполняется над плоской картинкой. Для реализации «настоящего» Bloom через Glow помимо прочего необходимо будет ещё раз рендерить сцену (а точнее сцену, с некоторыми ограничениями). Это я расскажу в третьей части статьи.
                0
                для 2д они его не используют? тогда можно взять Starling например
                  0
                  Про старлинг услышал только от вас. Спасибо, посмотрю, попробую.
              0
              Спасибо за карму. Переместил в профильный блог.
                0
                Blur на видео карте возможен.
                Вот примеры:
                www.nulldesign.de/2011/12/07/nd2d-blur/
                и тут тоже
                wonderfl.net/c/r49o
                  0
                  Красиво. Обязательно потестирую такой вариант и возможно распишу.
                  А пока расскажу, как это можно сделать «в лоб», без подобных трюков.
                  0
                  Автор, с матчастью знаком?
                  image
                    0
                    Я знаю, чем Bloom отличается от Blur. Это вводная статья. Первая из трёх. Во второй будет применение HDR (эффекта которого вполне хватит, чтобы большинство отказалось от ресурсозатратного «настоящего» Bloom).
                    Спасибо за карму, надеюсь оправдать чуть позже следующей статьёй.
                      0
                      HDR никоим образом не заменяет Bloom и имеет гораздо большую «ресурсозатратность»

                  Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                  Самое читаемое