使用Pixel Bender 和Shader Job来处理普通数据运算 [转]



虽然Pixel Bender主要是用来处理图形任务,但他还有一个强大的用法-处理普通数据(generic number crunching)。Pixel Bender核心和ActionScript在不同的进程中运行,你可以利用这个特点来避免界面的假死(无响应)。提高复杂运算的速度。例如,我们在处理一个很大规模的数据集合,需要对每个数据进行复杂的数学计算(3D,声音引擎等等)。你可以使用Pixel Bender kernal来处理这些数据,最后再将处理好的数据交给AS代码,效果好的甚至会超过优化的很好的AS代码。

下面是个非常简单的例子,Pixel Bender kernel接受一个数组,然后返回一个包含源数组的平方根的新数组。

CODE:

1. <languageVersion : 1.0;>
2. kernel NumberCruncher
3. <
4. namespace : "AIF";
5. vendor : "Ryan Taylor";
6. version : 1;
7. description : "Basic example of a generic number cruncher.";
8. >
9. {

10. input image1 src;
11. output pixel3 result;
12. void evaluatePixel()
13. {

14. pixel1 value = pixel1(sqrt(sample(src, outCoord())));
15. result = pixel3(value, 0.0, 0.0);
16. }
17. }

首先,注意结果是通过一个三元的pixel值返回回来的。当输出值低于三元的时候,目前版本的Pixel Bender工具,会抛出一个错误,并且拒绝生成字节码。Pixel Bender细则中描述是支持pixel1,pixel2,pixel3,pixel4输出的,所以这可能是一个Pixel Bender工具的bug。为了解决这个问题,我将后两个元素设置为0。同样,输入的类型必须为image1。 在AS段,需要如下处理:1.创建一个ByteArray对象,使用writeFloat方法来天津每个数据,确保endian设置为little endian。细则中虽说Vector.<Number>类型可以作为shader的输入数据,但是在使用这种方法的时候同样也出现了bug。2.创建一个Shader实例来接受Pixel Bender的字节码。宽度根据你的数据数组的长度来获取。在ByteArray中,你需要将数组长度除以4。高度你只需要设置为1。input必须为一个集合。3.创建一个ByteArray来储存shader计算的结果。同样确保endian为little endian。4.创建一个ShaderJob实例类接受shader,设置好输入,高度,宽度几个参数,添加一个"complete"的监听,等Shader计算结束后,来处理输出的ByteArray。然后你可以使用start方法来执行shader。这是as的代码示例:

1. package
2. {

3. import flash.display.Shader;
4. import flash.display.ShaderJob;
5. import flash.display.Sprite;
6. import flash.events.Event;
7. import flash.utils.ByteArray;
8. import flash.utils.Endian;
9. public class Main extends Sprite
10. {

11. protected var _shader:Shader;
12. protected var _shaderJob:ShaderJob;
13. protected var _input:ByteArray;
14. protected var _output:ByteArray;
15. [Embed(source="/../assets/filters/NumberCruncher.pbj", mimeType="application/octet-stream")]
16. protected var NumberCruncher:Class;
17. public function Main()
18. {

19. init();
20. }
21. protected function init():void
22. {

23. _input = new ByteArray();
24. _input.endian = Endian.LITTLE_ENDIAN;
25. _input.writeFloat(4);
26. _input.writeFloat(16);
27. _input.writeFloat(100);
28. _input.writeFloat(400);
29. _input.position = 0;
30. var width:int = _input.length >> 2;
31. var height:int = 1;
32. _shader = new Shader(new NumberCruncher());
33. _shader.data.src.width = width;
34. _shader.data.src.height = height;
35. _shader.data.src.input = _input;
36. _output = new ByteArray();
37. _output.endian = Endian.LITTLE_ENDIAN;
38. _shaderJob = new ShaderJob(_shader, _output, width, height);
39. _shaderJob.addEventListener(Event.COMPLETE, onShaderJobComplete, false, 0, true);
40. _shaderJob.start();
41. }
42. protected function onShaderJobComplete(event:Event):void
43. {

44. _output.position = 0;
45. var length:int = _output.length;
46. for(var i:int = 0; i < length; i += 4)
47. {

48. var output:Number = _output.readFloat();
49. if(i % 3 == 0)
50. trace("value -> " + output);
51. }
52. }
53. }
54. }

为了解决我早先提到的三通道输出的问题,我使用了取模的运算,在“onShaderJobComplete”方法中,最终结果是所有输入数字的平方根。

所以那是很好的。可以想象,等这些bug都消除以后,这江是个非常有用的东西。