Использование шейдера в качестве режима наложения

Flash Player 10 и более поздних версий, Adobe AIR 1.5 и более поздних версий

Использование шейдера в качестве режима наложения очень похоже на применение других режимов наложения. Шейдер определяет внешний вид, полученный в результате визуального наложения двух экранных объектов. Чтобы использовать шейдер в качестве режима наложения, нужно назначить объект Shader свойству blendShader экранного объекта, который находится на переднем плане. Если задать свойству blendShader любое значение, кроме null , свойство blendMode экранного объекта автоматически получает значение BlendMode.SHADER . Следующий код демонстрирует использование шейдера в качестве режима наложения. Обратите внимание, что в этом примере есть экранный объект с именем foreground , который находится в списке отображения в том же контейнере, чтобы и другой экранный объект, и объект foreground пересекается с другим содержимым.

foreground.blendShader = myShader;

При использовании шейдера в качестве режима наложения необходимо определить не меньше двух значений ввода. Как показано в примере, код не задает значений ввода. Вместо этого, в качестве ввода шейдера автоматически используются два накладываемых изображения. Изображение, находящееся на первом плане, задается как второе значение ввода (Это экранный объект, к которому применяется режим наложения.) Фоновое изображение создается путем получения составного значения всех пикселов, находящихся за пределами ограничивающего прямоугольника изображения переднего плана. Это фоновое изображение задается как первое значение ввода. Если используется шейдер, который ожидает больше двух входных изображений, необходимо задать остальные значения.

Следующий код демонстрирует использование шейдера в качестве режима наложения. В этом примере используется режим наложения «Осветлить» на базе свечения. В результате наложения значение самого светлого пиксела любого из объединяемых объектов становится значением пиксела, отображаемого на экране.

Примечание. Код для этого примера написан Марио Клингеманном (Mario Klingemann). Мы благодарим Марио за предоставление этого кода. Другие работы и статьи Марио можно найти по адресу www.quasimondo.com .

Основной код ActionScript строится на двух методах.

  • init() : метод init() вызывается при загрузке приложения. В этом методе код загружает файл байт-кода шейдера.

  • onLoadComplete() : в методе onLoadComplete() код создает объект Shader с именем shader . Затем отрисовываются три объекта. Первый объект, backdrop , представляет собой темно-серый фон за объединяемыми объектами. Второй объект, backgroundShape представляет зеленый эллипс с заливкой градиентом. Третий объект, foregroundShape , представляет оранжевый эллипс с заливкой градиентом.

    Эллипс foregroundShape является объектом переднего плана для этого наложения. Фоновое изображение наложения состоит из части объекта backdrop и части объекта backgroundShape , которые попадают в область ограничивающего прямоугольника объекта foregroundShape . Объект foregroundShape находится перед всеми остальными объектами в списке отображения. На частично перекрывает объект backgroundShape и полностью перекрывает объект backdrop . Если не применяется режим наложения, в результате такого перекрытия оранжевый эллипс ( foregroundShape ) отображается полностью, а часть зеленого эллипса ( backgroundShape ) скрыта под ним.

    Однако при применении режима наложения более яркая часть зеленного эллипса «просвечивает» через оранжевый, так как она светлее перекрывающей его части объекта foregroundShape .

Ниже приводится код ActionScript для этого примера. Используйте этот класс в качестве основного класса приложения для проекта, созданного только на базе ActionScript в Flash Builder, или в качестве класса документа для FLA-файла в инструменте Flash Professional.

package 
{ 
    import flash.display.BlendMode; 
    import flash.display.GradientType; 
    import flash.display.Graphics; 
    import flash.display.Shader; 
    import flash.display.Shape; 
    import flash.display.Sprite; 
    import flash.events.Event; 
    import flash.geom.Matrix; 
    import flash.net.URLLoader; 
    import flash.net.URLLoaderDataFormat; 
    import flash.net.URLRequest; 
     
    public class LumaLighten extends Sprite 
    { 
        private var shader:Shader; 
        private var loader:URLLoader; 
         
        public function LumaLighten() 
        { 
            init(); 
        } 
         
        private function init():void 
        { 
            loader = new URLLoader(); 
            loader.dataFormat = URLLoaderDataFormat.BINARY; 
            loader.addEventListener(Event.COMPLETE, onLoadComplete); 
            loader.load(new URLRequest("LumaLighten.pbj")); 
        } 
         
         
        private function onLoadComplete(event:Event):void 
        { 
            shader = new Shader(loader.data); 
             
            var backdrop:Shape = new Shape(); 
            var g0:Graphics = backdrop.graphics; 
            g0.beginFill(0x303030); 
            g0.drawRect(0, 0, 400, 200); 
            g0.endFill(); 
            addChild(backdrop); 
             
            var backgroundShape:Shape = new Shape(); 
            var g1:Graphics = backgroundShape.graphics; 
            var c1:Array = [0x336600, 0x80ff00]; 
            var a1:Array = [255, 255]; 
            var r1:Array = [100, 255]; 
            var m1:Matrix = new Matrix(); 
            m1.createGradientBox(300, 200); 
            g1.beginGradientFill(GradientType.LINEAR, c1, a1, r1, m1); 
            g1.drawEllipse(0, 0, 300, 200); 
            g1.endFill(); 
            addChild(backgroundShape); 
             
            var foregroundShape:Shape = new Shape(); 
            var g2:Graphics = foregroundShape.graphics; 
            var c2:Array = [0xff8000, 0x663300]; 
            var a2:Array = [255, 255]; 
            var r2:Array = [100, 255]; 
            var m2:Matrix = new Matrix(); 
            m2.createGradientBox(300, 200); 
            g2.beginGradientFill(GradientType.LINEAR, c2, a2, r2, m2); 
            g2.drawEllipse(100, 0, 300, 200); 
            g2.endFill(); 
            addChild(foregroundShape); 
             
            foregroundShape.blendShader = shader; 
            foregroundShape.blendMode = BlendMode.SHADER; 
        } 
    } 
}

Ниже представлен исходный код для ядра шейдера LumaLighten, который используется для создания файла байт-кода Pixel Bender с именем «LumaLighten.pbj».

<languageVersion : 1.0;> 
kernel LumaLighten 
< 
    namespace : "com.quasimondo.blendModes"; 
    vendor : "Quasimondo.com"; 
    version : 1; 
    description : "Luminance based lighten blend mode"; 
> 
{ 
    input image4 background; 
    input image4 foreground; 
 
    output pixel4 dst; 
     
    const float3 LUMA = float3(0.212671, 0.715160, 0.072169); 
 
    void evaluatePixel() 
    { 
        float4 a = sampleNearest(foreground, outCoord()); 
        float4 b = sampleNearest(background, outCoord()); 
        float luma_a = a.r * LUMA.r + a.g * LUMA.g + a.b * LUMA.b; 
        float luma_b = b.r * LUMA.r + b.g * LUMA.g + b.b * LUMA.b; 
         
        dst = luma_a > luma_b ? a : b; 
    } 
}

Дополнительные сведения об использовании режимов наложения см. в разделе Применение режимов смешивания .

Примечание. Когда программа шейдера Pixel Bender запускается в режиме наложения в Flash Player или AIR, функции сэмплинга и outCoord() ведут себя не так, как в других контекстах. В режиме наложения функция сэмплинга всегда возвращает текущий пиксел, вычисляемый шейдером. Например, нельзя добавить смещение в outCoord() с целью сэмплирования соседнего пиксела. Подобным образом, если функция outCoord() используется за пределами функции сэмплинга, ее координаты всегда равны 0. Поэтому, например, нельзя использовать положение пиксела с целью воздействия на совмещение накладываемых изображений.