셰이더를 블렌드 모드로 사용

Flash Player 10 이상, Adobe AIR 1.5 이상

셰이더를 블렌드 모드로 사용하는 방법은 다른 블렌드 모드를 사용하는 방법과 비슷합니다. 셰이더는 두 개의 표시 객체를 시각적으로 함께 블렌드하여 생성되는 모양을 정의합니다. 셰이더를 블렌드 모드로 사용하려면 전경 표시 객체의 blendShader 속성에 Shader 객체를 할당합니다. blendShader 속성에 null 이외의 값을 할당하면 자동으로 표시 객체의 blendMode 속성이 BlendMode.SHADER로 설정됩니다. 다음 샘플에서는 셰이더를 블렌드 모드로 사용하는 방법을 보여 줍니다. 이 예제에서는 다른 표시 내용과 동일한 표시 목록 상의 부모에 foreground라는 표시 객체가 포함되어 있는 것으로 가정합니다. 이때 foreground는 다른 내용에 겹쳐 표시됩니다.

foreground.blendShader = myShader;

셰이더를 블렌드 모드로 사용하는 경우 셰이더는 적어도 두 개의 입력을 사용하여 정의해야 합니다. 예제와 같이 코드에서 입력 값을 설정하지 마십시오. 대신 두 개의 블렌드된 이미지가 자동으로 셰이더 입력으로 사용됩니다. 전경 이미지는 두 번째 이미지로 설정됩니다. 이 이미지는 블렌드 모드가 적용된 표시 객체입니다. 배경 이미지는 전경 이미지의 경계 상자 뒤에 있는 모든 픽셀을 합성하여 만들어집니다. 이 배경 이미지는 첫 번째 입력 이미지로 설정됩니다. 세 개 이상의 입력이 필요한 셰이더를 사용하는 경우에는 처음 두 개 외의 입력을 위한 값을 제공합니다.

다음 예제에서는 셰이더를 블렌드 모드로 사용하는 방법을 보여 줍니다. 이 예제에서는 광도를 기준으로 하는 lighten 블렌드 모드를 사용합니다. 블렌드 후에는 블렌드된 객체 중 하나에서 가장 밝은 픽셀 값이 표시되는 픽셀이 됩니다.

참고: 이 예제의 코드는 Mario Klingemann에 의해 작성되었습니다. 이 예제를 공유해 주신 Mario 씨께 감사드립니다. Mario의 작업과 그가 쓴 내용은 www.quasimondo.com/에서 보다 자세히 보고 읽을 수 있습니다.

중요한 ActionScript 코드는 다음 두 가지 메서드를 중심으로 합니다.

  • init(): init() 메서드는 응용 프로그램이 로드될 때 호출됩니다. 이 메서드의 코드에서는 셰이더 바이트코드 파일을 로드합니다.

  • onLoadComplete(): onLoadComplete() 메서드의 코드에서는 shader라는 Shader 객체를 만듭니다. 그런 다음 세 개의 객체를 그립니다. 첫 번째 객체인 backdrop은 블렌딩된 객체 뒤의 진한 회색 배경입니다. 두 번째 객체인 backgroundShape는 녹색 그래디언트 타원입니다. 세 번째 객체인 foregroundShape는 주황색 그래디언트 타원입니다.

    foregroundShape 타원은 블렌드의 전경 객체입니다. 블렌드의 배경 이미지는 foregroundShape 객체의 경계 상자와 겹치는 backdrop 부분 및 backgroundShape 부분으로 구성됩니다. foregroundShape 객체는 표시 목록에서 가장 앞에 있는 객체입니다. 이 객체는 backgroundShape와 부분적으로 겹치고 backdrop과 완전히 겹칩니다. 이 겹침으로 인해 블렌드 모드가 적용되지 않은 경우 주황색 타원(foregroundShape)은 완전히 표시되며 녹색 타원(backgroundShape)은 일부가 숨겨집니다.

    그러나 블렌드 모드가 적용된 경우에는 녹색 타원의 밝은 부분이 겹치는 foregroundShape 부분보다 밝으므로 이 부분이 표시됩니다.

다음은 이 예제에 대한 ActionScript 코드입니다. 이 클래스는 Flash Builder에서 ActionScript 전용 프로젝트의 기본 응용 프로그램 클래스로 사용하거나 Flash Professional에서 FLA 파일의 문서 클래스로 사용합니다.

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 셰이더 커널에 대한 소스 코드이며, "LumaLighten.pbj" Pixel Bender 바이트코드 파일을 만드는 데 사용됩니다.

<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으로 계산됩니다. 예를 들어 픽셀의 위치를 사용하여 블렌딩된 이미지의 결합 방법에 영향을 줄 수 없습니다.