Starling ‘God Ray’ Filter
While cruising the internet today looking for interesting things to try out, I ran across this fun little GPU Gem about creating a post-process volumetric lighting effect. With a little bit of work I quickly ported it over to an AGAL shader (you can see it on Wonderfl here). Then I figured what the hell, why not make it into a Starling filter.
I should say right off the bat that this won’t work in ‘baseline constrained’ mode (i.e. no mobile apps), but if you’re working on a web or desktop project, this filter will give you an effect like this.
The entire filter is below. Enjoy.
/**
* Copyright (c) 2013 Devon O. Wolfgang
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package starling.filters
{
import flash.display3D.Context3D;
import flash.display3D.Context3DBlendFactor;
import flash.display3D.Context3DProgramType;
import flash.display3D.Program3D;
import starling.textures.Texture;
/**
* Creates a 'God Rays' / fake volumetric light filter effect. Only use with Context3DProfile.BASELINE (not compatible with constrained profile)
* @author Devon O.
*/
public class GodRaysFilter extends FragmentFilter
{
private var shaderProgram:Program3D;
private var numSteps:int;
// lightx, lighty
private var lightPos:Vector.<Number> = Vector.<Number>( [ .5, .5, 1, 1 ]);
// numsamples, density, numsamples * density, 1 / numsamples * density
private var values1:Vector.<Number> = Vector.<Number>( [ 1, 1, 1, 1 ]);
// weight, decay, exposure
private var values2:Vector.<Number> = Vector.<Number>( [ 1, 1, 1, 1 ]);
private var _lightX:Number = 0;
private var _lightY:Number = 0;
private var _weight:Number = .50;
private var _decay:Number = .87;
private var _exposure:Number = .35;
private var _density:Number = 2.0;
public function GodRaysFilter(numSteps:int = 30)
{
this.numSteps = numSteps;
}
public override function dispose():void
{
if (this.shaderProgram) this.shaderProgram.dispose();
super.dispose();
}
protected override function createPrograms():void
{
var frag:String = "";
// Calculate vector from pixel to light source in screen space.
frag += "sub ft0.xy, v0.xy, fc0.xy \n";
// Divide by number of samples and scale by control factor.
frag += "mul ft0.xy, ft0.xy, fc1.ww \n";
// Store initial sample.
frag += "tex ft1, v0, fs0 <2d, clamp, linear, mipnone> \n";
// Set up illumination decay factor.
frag += "mov ft2.x, fc0.w \n";
// Store the texcoords
frag += "mov ft4.xy, v0.xy \n";
for (var i:int = 0; i < this.numSteps; i++)
{
// Step sample location along ray.
frag += "sub ft4.xy, ft4.xy, ft0.xy \n";
// Retrieve sample at new location.
frag += "tex ft3, ft4.xy, fs0 <2d, clamp, linear, mipnone> \n";
// Apply sample attenuation scale/decay factors.
frag += "mul ft2.y, ft2.x, fc2.x \n";
frag += "mul ft3.xyz, ft3.xyz, ft2.yyy \n";
// Accumulate combined color.
frag += "add ft1.xyz, ft1.xyz, ft3.xyz \n";
// Update exponential decay factor.
frag += "mul ft2.x, ft2.x, fc2.y \n";
}
// Output final color with a further scale control factor.
frag += "mul ft1.xyz, ft1.xyz, fc2.zzz \n";
frag += "mov oc, ft1";
this.shaderProgram = assembleAgal(frag);
}
protected override function activate(pass:int, context:Context3D, texture:Texture):void
{
// light position
this.lightPos[0] = this._lightX / texture.width;
this.lightPos[1] = this._lightY / texture.height;
// numsamples, density, numsamples * density, 1 / numsamples * density
this.values1[0] = this.numSteps;
this.values1[1] = this._density;
this.values1[2] = this.numSteps * values1[1];
this.values1[3] = 1 / values1[2];
// weight, decay, exposure
this.values2[0] = this._weight;
this.values2[1] = this._decay;
this.values2[2] = this._exposure;
context.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT, 0, this.lightPos, 1 );
context.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT, 1, this.values1, 1 );
context.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT, 2, this.values2, 1 );
context.setProgram(this.shaderProgram);
}
public function set lightX(value:Number):void { this._lightX = value; }
public function get lightX():Number { return this._lightX; }
public function set lightY(value:Number):void { this._lightY = value; }
public function get lightY():Number { return this._lightY; }
public function set decay(value:Number):void { this._decay = value; }
public function get decay():Number { return this._decay; }
public function set exposure(value:Number):void { this._exposure = value; }
public function get exposure():Number { return this._exposure; }
public function set weight(value:Number):void { this._weight = value; }
public function get weight():Number { return this._weight; }
public function set density(value:Number):void { this._density = value; }
public function get density():Number { return this._density; }
标签:function,frag,效果,Number,GodRay,Starling,._,var,public From: https://blog.51cto.com/kenkao/5991723