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

使用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都消除以后,这江是个非常有用的东西。

你可能感兴趣的:(job)