This page will contain a detailed reference about fragment filters in the future. At the moment, it is just a placeholder.
Here's the simplest possible filter: a filter that displays the object in exactly the way it was rendered in the first place.
public class IdentityFilter extends FragmentFilter { private var mShaderProgram:Program3D; public function IdentityFilter() { super(); } public override function dispose():void { if (mShaderProgram) mShaderProgram.dispose(); super.dispose(); } protected override function createPrograms():void { var fragmentProgramCode:String = "tex oc, v0, fs0 <2d, clamp, linear, mipnone>"; // just forward texture color mShaderProgram = assembleAgal(fragmentProgramCode); } protected override function activate(pass:int, context:Context3D, texture:Texture):void { // already set by super class: // // vertex constants 0-3: mvpMatrix (3D) // vertex attribute 0: vertex position (FLOAT_2) // vertex attribute 1: texture coordinates (FLOAT_2) // texture 0: input texture context.setProgram(mShaderProgram); } }
This one does a little more: it converts a colored object into its grayscale version, using specific quantifiers for each color.
public class GrayscaleFilter extends FragmentFilter { private var mQuantifiers:Vector.<Number>; private var mShaderProgram:Program3D; public function GrayscaleFilter(red:Number=0.299, green:Number=0.587, blue:Number=0.114) { mQuantifiers = new <Number>[red, green, blue, 0.0]; } public override function dispose():void { if (mShaderProgram) mShaderProgram.dispose(); super.dispose(); } protected override function createPrograms():void { var fragmentProgramCode:String = "tex ft0, v0, fs0 <2d, clamp, linear, mipnone> \n" + // read texture color "dp3 ft0.xyz, ft0.xyz, fc0.xyz \n" + // dot product color with quantifiers "mov oc, ft0 \n"; // output color mShaderProgram = assembleAgal(fragmentProgramCode); } protected override function activate(pass:int, context:Context3D, texture:Texture):void { context.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT, 0, mQuantifiers, 1); context.setProgram(mShaderProgram); } }
And another one: an InverseFilter.
public class InverseFilter extends FragmentFilter { private var mShaderProgram:Program3D; private var mOnes:Vector.<Number> = new <Number>[1.0, 1.0, 1.0, 1.0]; private var mMinColor:Vector.<Number> = new <Number>[0, 0, 0, 0.0001]; public function InverseFilter() { super(); } public override function dispose():void { if (mShaderProgram) mShaderProgram.dispose(); super.dispose(); } protected override function createPrograms():void { // One might expect that we could just subtract the RGB values from 1, right? // The problem is that the input arrives with premultiplied alpha values, and the // output is expected in the same form. So we first have to restore the original RGB // values, subtract them from one, and then multiply with the original alpha again. var fragmentProgramCode:String = "tex ft0, v0, fs0 <2d, clamp, linear, mipnone> \n" + // read texture color "max ft0, ft0, fc1 \n" + // avoid division through zero in next step "div ft0.xyz, ft0.xyz, ft0.www \n" + // restore original (non-PMA) RGB values "sub ft0.xyz, fc0.xyz, ft0.xyz \n" + // subtract rgb values from '1' "mul ft0.xyz, ft0.xyz, ft0.www \n" + // multiply with alpha again (PMA) "mov oc, ft0 \n"; // copy to output mShaderProgram = assembleAgal(fragmentProgramCode); } protected override function activate(pass:int, context:Context3D, texture:Texture):void { context.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT, 0, mOnes, 1); context.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT, 1, mMinColor, 1); context.setProgram(mShaderProgram); } }
Those filters are no longer a part of Starling, because you can achieve all three effects with the more flexible “ColorMatrixFilter” class.