`

Pixel Bender 浅尝

 
阅读更多

来自:http://chaimzane.iteye.com/blog/344488

 

Adobe Pixel Bender 是一种编程语言,用于创建或操作图像内容。您可以使用 Pixel Bender 创建一个内核(在本文档中亦称之为着色器)。着色器定义了一个可对图像的每个像素单独执行的单一函数。对该函数的每次调用都将得到图像中该像素坐标处的输出颜色。可通过指定输入图像和参数值来自定义该操作。在着色器的单次执行中,输入值和参数值是不变的。唯一发生变化的是像素(其颜色是函数调用的结果)的坐标。

对多个输出像素坐标调用着色器函数时,将尽可能采用并行方式。这样会改进着色器性能,提供高性能的处理能力。

在 Flash Player 和 Adobe AIR 中,使用着色器可轻松创建三种类型的效果:

  • 绘制填充

  • 混合模式

  • 滤镜

着色器也可以按独立模式执行。使用独立模式时,将直接访问着色器的结果,而非预先指定着色器的用途。结果可以按图像数据或者二进制或数值数据的形式访问。该数据完全不必是图像数据。这样一来,您可以为着色器输入一组数据。着色器将处理该数据,然后您可以访问着色器返回的结果数据。

 

以下是您可能会在 ActionScript 中使用滤镜完成的任务:

  • 将着色器加载到正在运行的 SWF 应用程序中,或者在编译时嵌入着色器并在运行时访问它。

  • 访问着色器元数据

  • 为着色器标识并指定输入值(通常为图像)

  • 为着色器标识并指定参数值

  • 着色器有以下几种使用方法:

    • 用于绘制填充

    • 用于混合模式

    • 用作滤镜

    • 按独立模式使用

  • 内核:对于 Pixel Bender 而言,内核指的就是着色器。通过 Pixel Bender,您的代码定义了一个内核,它定义了可对图像的每个像素单独执行的单一函数。

  • Pixel Bender 字节代码:编译 Pixel Bender 内核时,会将其转换为 Pixel Bender 字节代码。Flash Player 或 Adobe AIR 在运行时访问并执行字节代码。

  • Pixel Bender 语言:用于创建 Pixel Bender 内核的编程语言。

  • Pixel Bender 工具包:用于依据 Pixel Bender 源代码创建 Pixel Bender 字节代码文件的应用程序。您可以使用该工具包编写、测试和编译 Pixel Bender 源代码。

  • 着色器:在本文档中,着色器是指采用 Pixel Bender 语言编写的一组功能。着色器的代码会创建视觉效果或执行计算。在任一情况下,着色器都返回一组数据(通常为图像的像素)。着色器对每个数据点执行相同的操作,唯一的区别在于输出像素的坐标不同。

    着色器不是用 ActionScript 编写的。它用 Pixel Bender 语言编写,并编译为 Pixel Bender 字节代码。着色器可在编译时嵌入 SWF 文件,也可在运行时作为外部文件加载。无论采用上述哪一种方式,都要在 ActionScript 中访问着色器,方法是先创建一个 Shader 对象,然后将其链接到着色器字节代码。

  • 着色器输入:一种复杂的输入,通常为位图图像数据,该数据提供给着色器供其计算之用。对于着色器中定义的每个输入变量,着色器的整个执行过程都使用单一变量值(即,一个图像或一组二进制数据)。

  • 着色器参数:提供给着色器供其计算之用的单一值(或限定的值集合)。着色器的每次执行中都会定义各个参数值,该值在着色器的整个执行过程中保持不变。

 

首先去下个Pixel BenerToolkit 。界面如下:

 


 

图2为,代码编辑区:

看一下,Kernel Language 的语法结构:

 

Java代码 复制代码 收藏代码
  1.   <languageVersion : 1.0;>   
  2.      
  3.   kernel DoNothing   <SPAN style="COLOR: #ff0000">头信息   
  4. </SPAN>   
  5.   
  6.   <   
  7.       namespace: "Adobe::Example";   
  8.       vendor: "Adobe examples";   
  9.       version: 1;   
  10.       description: "A shader that does nothing, but does it well."; <SPAN style="COLOR: #ff0000">版本信息   
  11. </SPAN>   
  12.   
  13.   >   
  14.   {   
  15.       input image4 src; <SPAN style="COLOR: #ff0000">输入图片源</SPAN>   
  16.   
  17.   
  18.      
  19.       output pixel4 dst; <SPAN style="COLOR: #ff0000">输出</SPAN>   
  20.   
  21.   
  22.          
  23.       parameter float3 color <SPAN style="COLOR: #ff0000">定义一个float4,输入参数</SPAN>   
  24.   
  25.   
  26.       <   
  27.           description: "......................";   
  28.       >;   
  29.          
  30.       parameter float alpha   
  31.       <   
  32.           description: "......................";   
  33.       >;   
  34.      
  35.       void evaluatePixel()<SPAN style="COLOR: #ff0000"> kernel </SPAN>   
  36.   
  37. <SPAN style="COLOR: #ff0000">的像素计算   
  38. </SPAN>   
  39.   
  40.       {   
  41.           dst = sampleNearest(src, outCoord());   
  42.           dst.rgb = color;   
  43.           dst.a = alpha;   
  44.       }   
  45.   }   
  46.     
  <languageVersion : 1.0;>
  
  kernel DoNothing   头信息


  <
      namespace: "Adobe::Example";
      vendor: "Adobe examples";
      version: 1;
      description: "A shader that does nothing, but does it well."; 版本信息


  >
  {
      input image4 src; 输入图片源


  
      output pixel4 dst; 输出


      
      parameter float3 color 定义一个float4,输入参数


      <
          description: "......................";
      >;
      
      parameter float alpha
      <
          description: "......................";
      >;
  
      void evaluatePixel() kernel 

的像素计算


      {
          dst = sampleNearest(src, outCoord());
          dst.rgb = color;
          dst.a = alpha;
      }
  }
  

 

在 ActionScript 中使用 Pixel Bender 着色器的第一步是在 ActionScript 代码中访问着色器。因为着色器是用 Adobe Pixel Bender 工具包创建并以 Pixel Bender 语言编写的,所以不能在 ActionScript 中直接访问。您需要创建 Shader 类的一个实例,用于向 ActionScript 表示 Pixel Bender 着色器。通过 Shader 对象可以查明着色器的有关信息,如着色器是否需要参数或输入图像值。将 Shader 对象传递给其它对象即可实际使用着色器。例如,若要将着色器用作滤镜,可将 Shader 对象分配给 ShaderFilter 对象的shader属性。若要将着色器用作绘制填充,可将 Shader 对象作为参数传递给Graphics.beginShaderFill()方法。

ActionScript 代码可以通过两种方式访问由 Adobe Pixel Bender 工具包创建的着色器(.pbj 文件):

在运行时加载:可以使用 URLLoader 对象将着色器文件作为外部资源进行加载。这种方法类似于加载外部资源(如文本文件)。下面的示例演示如何在运行时加载着色器字节码文件并将其链接到一个 Shader 实例:

 

Java代码 复制代码 收藏代码
  1. var loader:URLLoader = new URLLoader();    
  2. loader.dataFormat = URLLoaderDataFormat.BINARY;    
  3. loader.addEventListener(Event.COMPLETE, onLoadComplete);    
  4. loader.load(new URLRequest("myShader.pbj"));    
  5.     
  6. var shader:Shader;    
  7.     
  8. function onLoadComplete(event:Event):void {    
  9.     // Create a new shader and set the loaded data as its bytecode    
  10.     shader = new Shader();    
  11.     shader.byteCode = loader.data;    
  12.         
  13.     // You can also pass the bytecode to the Shader() constructor like this:    
  14.     // shader = new Shader(loader.data);    
  15.         
  16.      // do something with the shader    
  17. }  
var loader:URLLoader = new URLLoader(); 
loader.dataFormat = URLLoaderDataFormat.BINARY; 
loader.addEventListener(Event.COMPLETE, onLoadComplete); 
loader.load(new URLRequest("myShader.pbj")); 
 
var shader:Shader; 
 
function onLoadComplete(event:Event):void { 
    // Create a new shader and set the loaded data as its bytecode 
    shader = new Shader(); 
    shader.byteCode = loader.data; 
     
    // You can also pass the bytecode to the Shader() constructor like this: 
    // shader = new Shader(loader.data); 
     
     // do something with the shader 
}

 

   嵌入在 SWF 文件中:使用[Embed]元数据标签可以在编译时将着色器文件嵌入在 SWF 文件中。只有在使用 Flex SDK 编译 SWF 文件时,[Embed]元数据标签才可用。[Embed]标签的source参数指向着色器文件,其mimeType参数为"application/octet-stream"

,如此例中所示:

 

Java代码 复制代码 收藏代码
  1. [Embed(source="myShader.pbj", mimeType="application/octet-stream")]    
  2. var MyShaderClass:Class;    
  3.     
  4. // ...    
  5.     
  6. // create a shader and set the embedded shader as its bytecode    
  7. var shaderShader = new Shader();    
  8. shader.byteCode = new MyShaderClass();    
  9.     
  10. // You can also pass the bytecode to the Shader() constructor like this:    
  11. // var shader:Shader = new Shader(new MyShaderClass());    
  12.     
  13. // do something with the shader  
[Embed(source="myShader.pbj", mimeType="application/octet-stream")] 
var MyShaderClass:Class; 
 
// ... 
 
// create a shader and set the embedded shader as its bytecode 
var shaderShader = new Shader(); 
shader.byteCode = new MyShaderClass(); 
 
// You can also pass the bytecode to the Shader() constructor like this: 
// var shader:Shader = new Shader(new MyShaderClass()); 
 
// do something with the shader

 

在任何一种情况下,都可以将原始着色器字节码(URLLoader.data属性或[Embed]数据类的实例)链接到 Shader 实例。如以上示例所示,可以通过两种方式将字节码分配给 Shader 实例。可以将着色器字节代码作为参数传递到Shader()构造函数。或者,可以将其设置为 Shader 实例的byteCode属性。

在创建 Pixel Bender 着色器并将其链接到 Shader 对象后,即可使用着色器以多种方式创建效果。您可以将着色器用作滤镜、混合模式、位图填充,也可以用于位图或其它数据的独立处理。您还可以使用 Shader 对象的data

属性访问着色器的元数据、指定输入图像以及设置参数值。

 

使用着色器作为绘制填充

在使用着色器创建绘制填充时,您将使用绘图 API 方法来创建矢量形状。正如使用绘图 API 可将任何位图图像用作位图填充一样,着色器的输出将用于填充该形状。若要创建着色器填充,可在代码中开始绘制形状的位置处,调用 Graphics 对象的beginShaderFill()方法。将 Shader 对象作为第一个参数传递给beginShaderFill()

方法,如以下清单所示:

 

Java代码 复制代码 收藏代码
  1. var canvas:Sprite = new Sprite();    
  2. canvas.graphics.beginShaderFill(myShader);    
  3. canvas.graphics.drawRect(1010150150);    
  4. canvas.graphics.endFill();    
  5. // add canvas  
var canvas:Sprite = new Sprite(); 
canvas.graphics.beginShaderFill(myShader); 
canvas.graphics.drawRect(10, 10, 150, 150); 
canvas.graphics.endFill(); 
// add canvas

 


 

Java代码 复制代码 收藏代码
  1. <languageVersion : 1.0;>    
  2. kernel ThreePointGradient    
  3. <    
  4.     namespace : "Petri Leskinen::Example";    
  5.     vendor : "Petri Leskinen";    
  6.     version : 1;    
  7.     description : "Creates a gradient fill using three specified points and colors.";    
  8. >    
  9. {    
  10.     parameter float2 point1 // coordinates of the first point    
  11.     <    
  12.         minValue:float2(00);    
  13.         maxValue:float2(40004000);    
  14.         defaultValue:float2(00);    
  15.     >;    
  16.         
  17.     parameter float4 color1 // color at the first point, opaque red by default    
  18.     <    
  19.         defaultValue:float4(1.00.00.01.0);    
  20.     >;    
  21.         
  22.     parameter float2 point2 // coordinates of the second point    
  23.     <    
  24.         minValue:float2(00);    
  25.         maxValue:float2(40004000);    
  26.         defaultValue:float2(0500);    
  27.     >;    
  28.         
  29.     parameter float4 color2 // color at the second point, opaque green by default    
  30.     <    
  31.         defaultValue:float4(0.01.00.01.0);    
  32.     >;    
  33.         
  34.     parameter float2 point3 // coordinates of the third point    
  35.     <    
  36.         minValue:float2(00);    
  37.         maxValue:float2(40004000);    
  38.         defaultValue:float2(0500);    
  39.     >;    
  40.         
  41.     parameter float4 color3 // color at the third point, opaque blue by default    
  42.     <    
  43.         defaultValue:float4(0.00.01.01.0);    
  44.     >;    
  45.         
  46.     output pixel4 dst;    
  47.         
  48.     void evaluatePixel()    
  49.     {    
  50.         float2 d2 = point2 - point1;    
  51.         float2 d3 = point3 - point1;    
  52.             
  53.         // transformation to a new coordinate system    
  54.         // transforms point 1 to origin, point2 to (1, 0), and point3 to (0, 1)    
  55.         float2x2 mtrx = float2x2(d3.y, -d2.y, -d3.x, d2.x) / (d2.x * d3.y - d3.x * d2.y);    
  56.         float2 pNew = mtrx * (outCoord() - point1);    
  57.             
  58.         // repeat the edge colors on the outside    
  59.         pNew.xy = clamp(pNew.xy, 0.01.0); // set the range to 0.0 ... 1.0    
  60.             
  61.         // interpolating the output color or alpha value    
  62.         dst = mix(mix(color1, color2, pNew.x), color3, pNew.y);    
  63.     }    
  64. }  
<languageVersion : 1.0;> 
kernel ThreePointGradient 
< 
    namespace : "Petri Leskinen::Example"; 
    vendor : "Petri Leskinen"; 
    version : 1; 
    description : "Creates a gradient fill using three specified points and colors."; 
> 
{ 
    parameter float2 point1 // coordinates of the first point 
    < 
        minValue:float2(0, 0); 
        maxValue:float2(4000, 4000); 
        defaultValue:float2(0, 0); 
    >; 
     
    parameter float4 color1 // color at the first point, opaque red by default 
    < 
        defaultValue:float4(1.0, 0.0, 0.0, 1.0); 
    >; 
     
    parameter float2 point2 // coordinates of the second point 
    < 
        minValue:float2(0, 0); 
        maxValue:float2(4000, 4000); 
        defaultValue:float2(0, 500); 
    >; 
     
    parameter float4 color2 // color at the second point, opaque green by default 
    < 
        defaultValue:float4(0.0, 1.0, 0.0, 1.0); 
    >; 
     
    parameter float2 point3 // coordinates of the third point 
    < 
        minValue:float2(0, 0); 
        maxValue:float2(4000, 4000); 
        defaultValue:float2(0, 500); 
    >; 
     
    parameter float4 color3 // color at the third point, opaque blue by default 
    < 
        defaultValue:float4(0.0, 0.0, 1.0, 1.0); 
    >; 
     
    output pixel4 dst; 
     
    void evaluatePixel() 
    { 
        float2 d2 = point2 - point1; 
        float2 d3 = point3 - point1; 
         
        // transformation to a new coordinate system 
        // transforms point 1 to origin, point2 to (1, 0), and point3 to (0, 1) 
        float2x2 mtrx = float2x2(d3.y, -d2.y, -d3.x, d2.x) / (d2.x * d3.y - d3.x * d2.y); 
        float2 pNew = mtrx * (outCoord() - point1); 
         
        // repeat the edge colors on the outside 
        pNew.xy = clamp(pNew.xy, 0.0, 1.0); // set the range to 0.0 ... 1.0 
         
        // interpolating the output color or alpha value 
        dst = mix(mix(color1, color2, pNew.x), color3, pNew.y); 
    } 
}

 

 

Java代码 复制代码 收藏代码
  1. package    
  2. {    
  3.     import flash.display.Shader;    
  4.     import flash.display.Sprite;    
  5.     import flash.events.Event;    
  6.     import flash.geom.Point;    
  7.     import flash.net.URLLoader;    
  8.     import flash.net.URLLoaderDataFormat;    
  9.     import flash.net.URLRequest;    
  10.         
  11.     public class ThreePointGradient extends Sprite    
  12.     {    
  13.         private var canvas:Sprite;    
  14.         private var shader:Shader;    
  15.         private var loader:URLLoader;    
  16.             
  17.         private var topMiddle:Point;    
  18.         private var bottomLeft:Point;    
  19.         private var bottomRight:Point;    
  20.             
  21.         private var colorAngle:Number = 0.0;    
  22.         private const d120:Number = 120 / 180 * Math.PI; // 120 degrees in radians    
  23.             
  24.             
  25.         public function ThreePointGradient()    
  26.         {    
  27.             init();    
  28.         }    
  29.             
  30.         private function init():void    
  31.         {    
  32.             canvas = new Sprite();    
  33.             addChild(canvas);    
  34.                 
  35.             var size:int = 400;    
  36.             topMiddle = new Point(size / 210);    
  37.             bottomLeft = new Point(0, size - 10);    
  38.             bottomRight = new Point(size, size - 10);    
  39.                 
  40.             loader = new URLLoader();    
  41.             loader.dataFormat = URLLoaderDataFormat.BINARY;    
  42.             loader.addEventListener(Event.COMPLETE, onLoadComplete);    
  43.             loader.load(new URLRequest("ThreePointGradient.pbj"));    
  44.         }    
  45.             
  46.         private function onLoadComplete(event:Event):void    
  47.         {    
  48.             shader = new Shader(loader.data);    
  49.                 
  50.             shader.data.point1.value = [topMiddle.x, topMiddle,y];    
  51.             shader.data.point2.value = [bottomLeft.x, bottomLeft.y];    
  52.             shader.data.point3.value = [bottomRight.x, bottomRight.y];    
  53.                 
  54.             addEventListener.Event.ENTER_FRAME, updateShaderFill);    
  55.         }    
  56.             
  57.         private function updateShaderFill(event:Event):void    
  58.         {    
  59.             colorAngle += .06;    
  60.                 
  61.             var c1:Number = 1 / 3 + 2 / 3 * Math.cos(colorAngle);    
  62.             var c2:Number = 1 / 3 + 2 / 3 * Math.cos(colorAngle + d120);    
  63.             var c3:Number = 1 / 3 + 2 / 3 * Math.cos(colorAngle - d120;    
  64.                 
  65.             shader.data.color1.value = [c1, c2, c3, 1.0];    
  66.             shader.data.color2.value = [c3, c1, c2, 1.0];    
  67.             shader.data.color3.value = [c2, c3, c1, 1.0];    
  68.                 
  69.             canvas.graphics.clear();    
  70.             canvas.graphics.beginShaderFill(shader);    
  71.                 
  72.             canvas.graphics.moveTo(topMiddle.x, topMiddle.y);    
  73.             canvas.graphics.lineTo(bottomLeft.x, bottomLeft.y);    
  74.             canvas.graphics.lineTo(bottomRight.x, bottomLeft.y);    
  75.                 
  76.             canvas.graphics.endFill();    
  77.         }    
  78.     }    
  79. }  
package 
{ 
    import flash.display.Shader; 
    import flash.display.Sprite; 
    import flash.events.Event; 
    import flash.geom.Point; 
    import flash.net.URLLoader; 
    import flash.net.URLLoaderDataFormat; 
    import flash.net.URLRequest; 
     
    public class ThreePointGradient extends Sprite 
    { 
        private var canvas:Sprite; 
        private var shader:Shader; 
        private var loader:URLLoader; 
         
        private var topMiddle:Point; 
        private var bottomLeft:Point; 
        private var bottomRight:Point; 
         
        private var colorAngle:Number = 0.0; 
        private const d120:Number = 120 / 180 * Math.PI; // 120 degrees in radians 
         
         
        public function ThreePointGradient() 
        { 
            init(); 
        } 
         
        private function init():void 
        { 
            canvas = new Sprite(); 
            addChild(canvas); 
             
            var size:int = 400; 
            topMiddle = new Point(size / 2, 10); 
            bottomLeft = new Point(0, size - 10); 
            bottomRight = new Point(size, size - 10); 
             
            loader = new URLLoader(); 
            loader.dataFormat = URLLoaderDataFormat.BINARY; 
            loader.addEventListener(Event.COMPLETE, onLoadComplete); 
            loader.load(new URLRequest("ThreePointGradient.pbj")); 
        } 
         
        private function onLoadComplete(event:Event):void 
        { 
            shader = new Shader(loader.data); 
             
            shader.data.point1.value = [topMiddle.x, topMiddle,y]; 
            shader.data.point2.value = [bottomLeft.x, bottomLeft.y]; 
            shader.data.point3.value = [bottomRight.x, bottomRight.y]; 
             
            addEventListener.Event.ENTER_FRAME, updateShaderFill); 
        } 
         
        private function updateShaderFill(event:Event):void 
        { 
            colorAngle += .06; 
             
            var c1:Number = 1 / 3 + 2 / 3 * Math.cos(colorAngle); 
            var c2:Number = 1 / 3 + 2 / 3 * Math.cos(colorAngle + d120); 
            var c3:Number = 1 / 3 + 2 / 3 * Math.cos(colorAngle - d120; 
             
            shader.data.color1.value = [c1, c2, c3, 1.0]; 
            shader.data.color2.value = [c3, c1, c2, 1.0]; 
            shader.data.color3.value = [c2, c3, c1, 1.0]; 
             
            canvas.graphics.clear(); 
            canvas.graphics.beginShaderFill(shader); 
             
            canvas.graphics.moveTo(topMiddle.x, topMiddle.y); 
            canvas.graphics.lineTo(bottomLeft.x, bottomLeft.y); 
            canvas.graphics.lineTo(bottomRight.x, bottomLeft.y); 
             
            canvas.graphics.endFill(); 
        } 
    } 
}

 

使用着色器作为混合模式

 

使用着色器作为混和模式与使用其它混和模式类似。着色器定义的外观取决于将两个显示对象混和在一起的视觉效果。若要将着色器用于混和模式,请将 Shader 对象指派给前景显示对象的blendShader属性。如果为blendShader属性指定非null值,显示对象的blendMode属性将自动设置为BlendMode.SHADER。下面的清单演示如何使用着色器作为混和模式。注意,此示例假定存在名为foreground的显示对象。该对象与其它显示内容包含在显示列表的同一父级中,而foreground

与其它内容重叠:

 

foreground.blendShader = myShader;

 

使用着色器作为混和模式时,着色器必须由至少两个输入定义。如示例所示,您未在代码中设置输入值。而是将两个混和后的图像自动用作着色器的输入。前景图像设置为第二个图像。(此显示对象便是要对其应用混和模式的对象。)背景图像由前景图像边框后的所有像素组合而成。背景图像设置为第一个输入图像。如果所用着色器要求两个以上的输入,则还需为前两个之外的其它输入提供值。

下面的示例演示如何使用着色器作为混和模式。此示例使用基于亮度的加亮混和模式。混和的结果是以任一混和对象中最亮的像素值显示该像素。

注: 此示例的代码由 Mario Klingemann 编写。感谢 Mario 分享此示例。若要查看 Mario 的更多作品及阅读他的文章,请访问 www.quasimondo.com/

这段重要的 ActionScript 代码用到下面两个方法:

  • init():应用程序加载时调用init()方法。在此方法中,代码加载着色器字节代码文件。

  • onLoadComplete():在onLoadComplete()方法中,代码创建名为shader的 Shader 对象。然后绘制三个对象。第一个对象backdrop是混和对象后的深灰色背景。第二个对象backgroundShape是绿色渐变椭圆。第三个对象foregroundShape是橙色渐变椭圆。

    foregroundShape椭圆是混和的前景对象。混和的背景图像由部分backdrop和部分backgroundShape构成,并叠加了foregroundShape对象的边框。foregroundShape对象是位于显示列表最前面的对象。它与backgroundShape部分重叠,与backdrop全部重叠。由于上述重叠的存在,如果不应用混和模式,橙色椭圆 (foregroundShape) 将全部显示,并遮盖住绿色椭圆 (backgroundShape) 的一部分:

 

Java代码 复制代码 收藏代码
  1. <languageVersion : 1.0;>    
  2. kernel LumaLighten    
  3. <    
  4.     namespace : "com.quasimondo.blendModes";    
  5.     vendor : "Quasimondo.com";    
  6.     version : 1;    
  7.     description : "Luminance based lighten blend mode";    
  8. >    
  9. {    
  10.     input image4 background;    
  11.     input image4 foreground;    
  12.     
  13.     output pixel4 dst;    
  14.         
  15.     const float3 LUMA = float3(0.2126710.7151600.072169);    
  16.     
  17.     void evaluatePixel()    
  18.     {    
  19.         float4 a = sampleNearest(foreground, outCoord());    
  20.         float4 b = sampleNearest(background, outCoord());    
  21.         float luma_a = a.r * LUMA.r + a.g * LUMA.g + a.b * LUMA.b;    
  22.         float luma_b = b.r * LUMA.r + b.g * LUMA.g + b.b * LUMA.b;    
  23.             
  24.         dst = luma_a > luma_b ? a : b;    
  25.     }    
  26. }  
<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; 
    } 
}

 

Java代码 复制代码 收藏代码
  1. package    
  2. {    
  3.     import flash.display.BlendMode;    
  4.     import flash.display.GradientType;    
  5.     import flash.display.Graphics;    
  6.     import flash.display.Shader;    
  7.     import flash.display.Shape;    
  8.     import flash.display.Sprite;    
  9.     import flash.events.Event;    
  10.     import flash.geom.Matrix;    
  11.     import flash.net.URLLoader;    
  12.     import flash.net.URLLoaderDataFormat;    
  13.     import flash.net.URLRequest;    
  14.         
  15.     public class LumaLighten extends Sprite    
  16.     {    
  17.         private var shader:Shader;    
  18.         private var loader:URLLoader;    
  19.             
  20.         public function LumaLighten()    
  21.         {    
  22.             init();    
  23.         }    
  24.             
  25.         private function init():void    
  26.         {    
  27.             loader = new URLLoader();    
  28.             loader.dataFormat = URLLoaderDataFormat.BINARY;    
  29.             loader.addEventListener(Event.COMPLETE, onLoadComplete);    
  30.             loader.load(new URLRequest("LumaLighten.pbj"));    
  31.         }    
  32.             
  33.             
  34.         private function onLoadComplete(event:Event):void    
  35.         {    
  36.             shader = new Shader(loader.data);    
  37.                 
  38.             var backdrop:Shape = new Shape();    
  39.             var g0:Graphics = backdrop.graphics;    
  40.             g0.beginFill(0x303030);    
  41.             g0.drawRect(00400200);    
  42.             g0.endFill();    
  43.             addChild(backdrop);    
  44.                 
  45.             var backgroundShape:Shape = new Shape();    
  46.             var g1:Graphics = backgroundShape.graphics;    
  47.             var c1:Array = [0x3366000x80ff00];    
  48.             var a1:Array = [255255];    
  49.             var r1:Array = [100255];    
  50.             var m1:Matrix = new Matrix();    
  51.             m1.createGradientBox(300200);    
  52.             g1.beginGradientFill(GradientType.LINEAR, c1, a1, r1, m1);    
  53.             g1.drawEllipse(00300200);    
  54.             g1.endFill();    
  55.             addChild(backgroundShape);    
  56.                 
  57.             var foregroundShape:Shape = new Shape();    
  58.             var g2:Graphics = foregroundShape.graphics;    
  59.             var c2:Array = [0xff80000x663300];    
  60.             var a2:Array = [255255];    
  61.             var r2:Array = [100255];    
  62.             var m2:Matrix = new Matrix();    
  63.             m2.createGradientBox(300200);    
  64.             g2.beginGradientFill(GradientType.LINEAR, c2, a2, r2, m2);    
  65.             g2.drawEllipse(1000300200);    
  66.             g2.endFill();    
  67.             addChild(foregroundShape);    
  68.                 
  69.             foregroundShape.blendShader = shader;    
  70.             foregroundShape.blendMode = BlendMode.SHADER;    
  71.         }    
  72.     }    
  73. }  
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; 
        } 
    } 
}

 

 

 

<!----> <!----> <!---->
<!---->

使用着色器作为滤镜

<!----> <!---->
 
<!---->

使用着色器作为滤镜与在 ActionScript 中使用任何其它滤镜类似。使用着色器作为滤镜时,过滤出的图像(显示对象或 BitmapData 对象)将传递给着色器。着色器使用输入图像来创建滤镜输出,该输出通常为原始图像经过修改的版本。如果过滤出的对象是显示对象,着色器输出将显示在屏幕上,代替过滤出的显示对象。如果过滤出的对象是 BitmapData 对象,着色器输出将成为 BitmapData 对象的内容,并调用该对象的applyFilter()方法。

若要使用着色器作为滤镜,您首先要创建 Shader 对象,如加载或嵌入着色器 中所述。接下来,您需要创建链接到该 Shader 对象的 ShaderFilter 对象。ShaderFilter 对象便是将应用到所过滤对象的滤镜。将滤镜应用于对象的方式与应用任何滤镜的方式相同。将其传递给显示对象的filters属性,或者对 BitmapData 对象调用applyFilter()方法。例如,下面的代码创建 ShaderFilter 对象,并将此滤镜应用到名为homeButton的显示对象。

var myFilter:ShaderFilter = new ShaderFilter(myShader); 
homeButton.filters = [myFilter];

在使用着色器作为滤镜时,着色器必须由至少一个输入定义。如示例所示,您未在代码中设置输入值。而是将过滤出的显示对象或 BitmapData 对象设置为输入图像。如果所用着色器要求一个以上的输入,则还需为第一个之外的其它输入提供值。

在某些情况下,滤镜会改变原始图像的尺寸。例如,典型的投影效果会添加额外的像素,这些像素组成为图像添加的阴影。在使用改变图像尺寸的着色器时,需设置leftExtensionrightExtensiontopExtensionbottomExtension属性,指明所需图像尺寸变化量。

下面的示例演示如何使用着色器作为滤镜。此示例中的滤镜将反转图像红绿蓝三色通道的值。其结果为该图像的“负片”版本。

注: 此示例使用的着色器为 Pixel Bender 工具包中附带的 invertRGB.pbk Pixel Bender 内核。您可以从 Pixel Bender 工具包安装目录中加载此内核的源代码。编译源代码,然后将字节代码文件保存到源代码所在的目录。

这段重要的 ActionScript 代码用到下面两个方法:

  • init():应用程序加载时调用init()方法。在此方法中,代码加载着色器字节代码文件。

  • onLoadComplete():在onLoadComplete()方法中,代码创建名为shader的 Shader 对象。然后创建并绘制名为target的对象的内容。target对象是填充有线性渐变色的矩形:左边是红色,中间是黄绿色,右边是淡蓝色。未过滤的对象看上去是这样:

    应用了滤镜后,颜色反转,矩形变成这样:

此示例使用的着色器为 Pixel Bender 工具包中附带的“invertRGB.pbk”Pixel Bender 范例内核。源代码位于 Pixel Bender 工具包安装目录的“invertRGB.pbk”文件中。编译源代码,然后以文件名“invertRGB.pbj”将字节代码文件保存在 ActionScript 源代码所在的目录中。

下面是此示例的 ActionScript 代码。使用此类作为 Flex 中仅包含 ActionScript 项目的主应用程序类,或者作为 Flash 创作工具中 FLA 文件的文档类:

package 
{ 
    import flash.display.GradientType; 
    import flash.display.Graphics; 
    import flash.display.Shader; 
    import flash.display.Shape; 
    import flash.display.Sprite; 
    import flash.filters.ShaderFilter; 
    import flash.events.Event; 
    import flash.geom.Matrix; 
    import flash.net.URLLoader; 
    import flash.net.URLLoaderDataFormat; 
    import flash.net.URLRequest; 
     
    public class InvertRGB extends Sprite 
    { 
        private var shader:Shader; 
        private var loader:URLLoader; 
         
        public function InvertRGB() 
        { 
            init(); 
        } 
         
        private function init():void 
        { 
            loader = new URLLoader(); 
            loader.dataFormat = URLLoaderDataFormat.BINARY; 
            loader.addEventListener(Event.COMPLETE, onLoadComplete); 
            loader.load(new URLRequest("invertRGB.pbj")); 
        } 
         
         
        private function onLoadComplete(event:Event):void 
        { 
            shader = new Shader(loader.data); 
             
            var target:Shape = new Shape(); 
            addChild(target); 
             
            var g:Graphics = target.graphics; 
            var c:Array = [0x990000, 0x445500, 0x007799]; 
            var a:Array = [255, 255, 255]; 
            var r:Array = [0, 127, 255]; 
            var m:Matrix = new Matrix(); 
            m.createGradientBox(w, h); 
            g.beginGradientFill(GradientType.LINEAR, c, a, r, m); 
            g.drawRect(10, 10, w, h); 
            g.endFill(); 
             
            var invertFilter:ShaderFilter = new ShaderFilter(shader); 
            target.filters = [invertFilter]; 
        } 
    } 
}

有关应用滤镜的详细信息,请参阅创建和应用滤镜

 
<!---->

使用着色器作为滤镜

使用着色器作为滤镜与在 ActionScript 中使用任何其它滤镜类似。使用着色器作为滤镜时,过滤出的图像(显示对象或 BitmapData 对象)将传递给着色器。着色器使用输入图像来创建滤镜输出,该输出通常为原始图像经过修改的版本。如果过滤出的对象是显示对象,着色器输出将显示在屏幕上,代替过滤出的显示对象。如果过滤出的对象是 BitmapData 对象,着色器输出将成为 BitmapData 对象的内容,并调用该对象的applyFilter()方法。

若要使用着色器作为滤镜,您首先要创建 Shader 对象,如加载或嵌入着色器 中所述。接下来,您需要创建链接到该 Shader 对象的 ShaderFilter 对象。ShaderFilter 对象便是将应用到所过滤对象的滤镜。将滤镜应用于对象的方式与应用任何滤镜的方式相同。将其传递给显示对象的filters属性,或者对 BitmapData 对象调用applyFilter()方法。例如,下面的代码创建 ShaderFilter 对象,并将此滤镜应用到名为homeButton的显示对象。

 

 

Java代码 复制代码 收藏代码
  1. var myFilter:ShaderFilter = new ShaderFilter(myShader);    
  2. homeButton.filters = [myFilter];  
var myFilter:ShaderFilter = new ShaderFilter(myShader); 
homeButton.filters = [myFilter];

 

在使用着色器作为滤镜时,着色器必须由至少一个输入定义。如示例所示,您未在代码中设置输入值。而是将过滤出的显示对象或 BitmapData 对象设置为输入图像。如果所用着色器要求一个以上的输入,则还需为第一个之外的其它输入提供值。

在某些情况下,滤镜会改变原始图像的尺寸。例如,典型的投影效果会添加额外的像素,这些像素组成为图像添加的阴影。在使用改变图像尺寸的着色器时,需设置leftExtensionrightExtensiontopExtensionbottomExtension属性,指明所需图像尺寸变化量。

下面的示例演示如何使用着色器作为滤镜。此示例中的滤镜将反转图像红绿蓝三色通道的值。其结果为该图像的“负片”版本。

注: 此示例使用的着色器为 Pixel Bender 工具包中附带的 invertRGB.pbk Pixel Bender 内核。您可以从 Pixel Bender 工具包安装目录中加载此内核的源代码。编译源代码,然后将字节代码文件保存到源代码所在的目录。

这段重要的 ActionScript 代码用到下面两个方法:

  • init():应用程序加载时调用init()方法。在此方法中,代码加载着色器字节代码文件。

  • onLoadComplete():在onLoadComplete()方法中,代码创建名为shader的 Shader 对象。然后创建并绘制名为target的对象的内容。target对象是填充有线性渐变色的矩形:左边是红色,中间是黄绿色,右边是淡蓝色。未过滤的对象看上去是这样:


应用了滤镜后,颜色反转,矩形变成这样:

 


 

 

在独立模式下使用着色器

 

在独立模式下使用着色器时,着色器处理的运行独立于其输出结果的用途。指定要执行的着色器、设置输入值和参数值,及指定用于放置结果数据的对象。在以下两种情形中,可以考虑以独立模式使用着色器:

  • 处理非图像数据:在独立模式下,您可以选择将任意二进制数据或数值数据(而非位图图像数据)传递给着色器。除位图图像数据外,您还可以选择将着色器结果以二进制数据或数值数据的形式返回。

  • 背景处理:以独立模式运行着色器时,着色器默认为异步运行。这表示,在您的应用程序继续运行的同时,着色器以后台方式运行,并在其处理结束时通知您的代码。您可以使用运行耗时的着色器,它在运行时不会导致应用程序用户界面或其它处理响应迟缓。

使用 ShaderJob 对象以独立模式执行着色器。首先创建 ShaderJob 对象,并将其链接到代表要执行的着色器的 Shader 对象:

 

 

Java代码 复制代码 收藏代码
  1. var job:ShaderJob = new ShaderJob(myShader);  
var job:ShaderJob = new ShaderJob(myShader);

 接下来,设置着色器需要的所有输入值或参数值。如果着色器在后台运行,还需要为 ShaderJob 对象的

complete

 

事件注册一个侦听器。着色器完成其处理时,将调用该侦听器

 

 

Java代码 复制代码 收藏代码
  1. function completeHandler(event:ShaderEvent):void    
  2. {    
  3.     // do something with the shader result    
  4. }    
  5.     
  6. job.addEventListener(ShaderEvent.COMPLETE, completeHandler);  
function completeHandler(event:ShaderEvent):void 
{ 
    // do something with the shader result 
} 
 
job.addEventListener(ShaderEvent.COMPLETE, completeHandler);

 

接下来,创建着色器操作完成时,向其中写入操作结果的对象。将该对象指派给 ShaderJob 对象的target

属性:

 

 

Java代码 复制代码 收藏代码
  1. var jobResult:BitmapData = new BitmapData(10075);    
  2. job.target = jobResult;  
var jobResult:BitmapData = new BitmapData(100, 75); 
job.target = jobResult;

 

 

如果使用 ShaderJob 执行图像处理,则为target属性指派一个 BitmapData 实例。如果要处理二进制数据或数值数据,则指派 ByteArray 对象或 Vector.<Number> 实例给target属性。在该情形下,您必须设置 ShaderJob 对象的widthheight属性,以指定输出到target对象的数据量。

注: 您可以一步完成 ShaderJob 对象shadertargetwidthheight属性的设置,方法是将相应的参数传递给ShaderJob()构造函数,如:var job:ShaderJob = new ShaderJob(myShader, myTarget, myWidth, myHeight);

准备好执行着色器时,调用 ShaderJob 对象的start() 方法:

job.start();

默认情况下,调用start()导致 ShaderJob 以异步方式执行。在这种情况下,程序立即继续执行下一行代码,而不等待着色器完成处理。着色器操作完成时,ShaderJob 对象调用其complete事件的侦听器,通知它们操作已完成。在此(即complete事件侦听器代码中),target对象获得着色器操作结果。

注: 也可以不使用target属性对象,直接从传递给侦听器方法的事件对象处取得着色器结果。该事件对象是一个 ShaderEvent 实例。根据设置为target属性的对象的数据类型,ShaderEvent 对象有三个可用于访问结果的属性:ShaderEvent.bitmapDataShaderEvent.byteArrayShaderEvent.vector

或者,可以将true参数传递给start()方法。在该情形下,着色器操作将同步执行。所有代码(包括与用户界面及所有其它事件的交互)在着色器执行时暂停。着色器完成处理后,target对象包含着色器结果,程序继续执行下一行代码。

job.start(true);
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics