指定着色器参数值

某些着色器定义了参数值,着色器在创建其结果时会使用这些参数值。例如,更改图像亮度的着色器可能会指定一个亮度参数,该参数确定操作影响亮度的程度。根据着色器中的参数定义,着色器中定义的单个参数可能需要单个值或多个值。在 ActionScript 中,在着色器中定义的每个参数都由一个 ShaderParameter 对象表示。如识别着色器输入和参数中所述,ShaderParameter 对象是 Shader 对象的 data 属性中的 ShaderData 实例的属性。例如,假定着色器定义一个名为 brightness 的参数,并且该着色器由一个名为 myShader 的 Shader 对象表示。在这种情况下,可使用下面的标识符访问对应于 brightness 参数的 ShaderParameter:

myShader.data.brightness

若要为该参数设置一个(或多个)值,请创建包含这个值(或这些值)的 ActionScript 数组,并将该数组分配给 ShaderParameter 对象的 value 属性。value 属性定义为 Array 实例,是因为单个着色器参数可能需要多个值。即使着色器参数只需要一个值,也必须将该值包含在 Array 对象中才能将它分配给 ShaderParameter.value 属性。下面的代码演示如何将单个值设置为 value 属性:

myShader.data.brightness.value = [75];

如果着色器的 Pixel Bender 源代码为参数定义默认值,则在创建 Shader 对象时,会创建包含默认值的数组,并将其分配给 ShaderParameter 对象的 value 属性。将数组分配给 value 属性之后(包括该数组是默认数组的情况),可以通过更改数组元素的值来更改参数值。您不需要创建新数组并将它分配给 value 属性。

下面的示例演示如何在 ActionScript 中设置着色器的参数值。在此示例中,着色器定义一个名为 color 的参数。在 Pixel Bender 源代码中,color 参数声明为 float4 变量,这意味着该参数是包含四个浮点数的数组。在该示例中,color 参数值会连续更改,该参数每次更改时,都会使用着色器在屏幕上绘制一个有色的矩形。产生的结果是具有动画效果的颜色更改。

注: 此示例的代码由 Ryan Taylor 编写。感谢 Ryan 分享此示例。若要查看 Ryan 的个人资料并阅读他的文章,请访问 www.boostworthy.com/

这段 ActionScript 代码以下面三个方法为中心:

  • init():在 init() 方法中,代码加载包含着色器的 Pixel Bender 字节代码文件。加载文件后,调用 onLoadComplete() 方法。

  • onLoadComplete():在 onLoadComplete() 方法中,代码创建名为 shader 的 Shader 对象。同时还创建了 名为 texture 的 Sprite 实例。在 renderShader() 方法中,代码将着色器结果逐帧绘制在 texture 中。

  • onEnterFrame()onEnterFrame() 方法按每帧一次的频率进行调用,用于创建动画效果。在此方法中,代码将着色器参数值设置为新颜色,然后调用 renderShader() 方法将着色器结果绘制为矩形。

  • renderShader():在 renderShader() 方法中,代码调用 Graphics.beginShaderFill() 方法来指定着色器填充。然后,绘制一个矩形,该矩形的填充由着色器输出(生成的颜色)定义。有关以此方法使用着色器的详细信息,请参阅使用着色器作为绘制填充

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

package 
{ 
    import flash.display.Shader; 
    import flash.display.Sprite; 
    import flash.events.Event; 
    import flash.net.URLLoader; 
    import flash.net.URLLoaderDataFormat; 
    import flash.net.URLRequest; 
     
    public class ColorFilterExample extends Sprite 
    { 
        private const DELTA_OFFSET:Number = Math.PI * 0.5; 
        private var loader:URLLoader; 
        private var shader:Shader; 
        private var texture:Sprite; 
        private var delta:Number = 0; 
         
        public function ColorFilterExample() 
        { 
            init(); 
        } 
         
        private function init():void 
        { 
            loader = new URLLoader(); 
            loader.dataFormat = URLLoaderDataFormat.BINARY; 
            loader.addEventListener(Event.COMPLETE, onLoadComplete); 
            loader.load(new URLRequest("ColorFilter.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]; 
            texture = new Sprite(); 
             
            addChild(texture); 
             
            addEventListener(Event.ENTER_FRAME, onEnterFrame); 
        } 
        private function onEnterFrame(event:Event):void 
        { 
            shader.data.color.value[0] = 0.5 + Math.cos(delta - DELTA_OFFSET) * 0.5; 
            shader.data.color.value[1] = 0.5 + Math.cos(delta) * 0.5; 
            shader.data.color.value[2] = 0.5 + Math.cos(delta + DELTA_OFFSET) * 0.5; 
            // The alpha channel value (index 3) is set to 1 by the kernel's default 
            // value. This value doesn't need to change. 
             
            delta += 0.1; 
             
            renderShader(); 
        } 
         
        private function renderShader():void 
        { 
            texture:graphics.clear(); 
            texture.graphics.beginShaderFill(shader); 
            texture.graphics.drawRect(0, 0, stage.stageWidth, stage.stageHeight); 
            texture.graphics.endFill(); 
        } 
    } 
}

下面是 ColorFilter 着色器内核的源代码,用于创建“ColorFilter.pbj”Pixel Bender 字节代码文件:

<languageVersion : 1.0;> 
kernel ColorFilter 
< 
    namespace : "boostworthy::Example"; 
    vendor : "Ryan Taylor"; 
    version : 1; 
    description : "Creates an image where every pixel has the specified color value."; 
> 
{ 
    output pixel4 result; 
     
    parameter float4 color 
    < 
        minValue:float4(0, 0, 0, 0); 
        maxValue:float4(1, 1, 1, 1); 
        defaultValue:float4(0, 0, 0, 1); 
    >; 
     
    void evaluatePixel() 
    { 
        result = color; 
    } 
}

如果所使用的着色器的参数没有文档说明,则通过检查 ShaderParameter 对象的 type 属性,便可确定数组中必须包含的元素数量及其类型。type 属性指示着色器本身定义的参数数据类型。有关每个参数类型需要的元素数量和类型的列表,请参阅语言参考中的 ShaderParameter.value 属性列表。

每个 ShaderParameter 对象还有一个 index 属性,该属性指示参数在着色器参数顺序中的位置。除了这些属性之外,ShaderParameter 对象还可以具有包含由着色器创作者提供的元数据值的其它属性。例如,创作者可以指定元数据值,如参数的最小值、最大值和默认值。创作者所指定的所有元数据值都会作为动态属性添加到 ShaderParameter 对象中。若要检查这些属性,请使用 for..in 循环来循环访问 ShaderParameter 对象的动态属性,以识别其元数据。下面的示例演示如何使用 for..in 循环来识别 ShaderParameter 对象的元数据。每个元数据值都会添加到一个名为 metadata 的 Vector 实例。请注意,此示例假定已创建了一个名为 myShader 的 Shader 实例,并且该实例具有一个名为 brightness 的参数:

var brightness:ShaderParameter = myShader.data.brightness; 
var metadata:Vector.<String> = new Vector.<String>(); 
 
for (var prop:String in brightness) 
{ 
    if (brightness[prop] is String) 
    { 
        metadata[metadata.length] = brightness[prop]; 
    } 
} 
 
// do something with the metadata