Fork me on GitHub
Not signed in (Sign In)
    • CommentAuthorTomAuger
    • CommentTimeJan 20th 2013 edited
     
    Using a PixelRenderer, it seems that alpha (such as set in a ColorInitializer, or in a Fade action) doesn't actually work, at least not the way I would expect.

    If each new particle has an alpha setting, one would expect that if we set clearBetweenFrames to false, particles that end up being drawn over a pixel that has already had a particle on it should add their colour to the existing colour of the pixel. That does not occur.

    In the example below, the center of the DiscZone should get progressively darker and darker as particles are drawn over top of pixels that have already had particles traverse them. Instead, the center of the zone mysteriously gets lighter! Almost as if the alpha is the alpha of the pixel (ie: on the Renderer), rather than the alpha of the particle.

    Please note: the examples below assume a white or light stage colour.


    renderer = new PixelRenderer( new Rectangle( 0, 0, stage.stageWidth, stage.stageHeight ) );
    renderer.clearBetweenFrames = false;
    emitter = new Emitter2D();

    emitter.counter = new Steady( 500 );

    emitter.addInitializer( new ColorInit( 0xff000000, 0xff000000 ) );
    emitter.addInitializer( new Position( new DiscZone( new Point( stage.stageWidth/2, stage.stageHeight/2 ), 50, 0 ) ) );
    emitter.addInitializer( new Lifetime( 5, 10 ) );
    emitter.addInitializer( new Velocity( new DiscZone( new Point( 0, 0 ), 2, 1 ) ) );

    emitter.addAction( new Move() );
    emitter.addAction( new Fade() );
    emitter.addAction( new Age() );

    renderer.addEmitter( emitter );
    addChild( renderer )

    emitter.start( );


    -----------

    In fact, for an even more obvious case: remove the Fade action, and add a ColorInitializer with alpha, like this:
    emitter.addInitializer( new ColorInit( 0x20000000, 0x20000000 ) );
    • CommentAuthorTomAuger
    • CommentTimeJan 22nd 2013
     
    I'm no longer 100% convinced that this is a bug, but rather an idiosyncrasy of the PixelRenderer. Still, I wonder whether it couldn't be improved. I'm noticing that you're using SetPixel32 to simply clobber whatever pixel was previously there. The alpha in the particle is not used as a blend amount, but rather is setting the opacity of that pixel against whatever might lie behind the Renderer DisplayObject.

    In my specific use case, I am more looking to draw on a flattened "canvas", so the following class addresses that need by providing an opaque BitmapData object that is filled with an opaque colour (white in this case). Then, the drawParticle method uses the alpha value of the particle as a blend value against the pixel colour that's already there.

    Here's the class:

    package renderers
    {
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.geom.Rectangle;
    import org.flintparticles.twoD.particles.Particle2D;
    import org.flintparticles.twoD.renderers.PixelRenderer;

    /**
    * ...
    * @author Tom Auger
    */
    public class OpaqueAlphaRenderer extends PixelRenderer
    {
    public function OpaqueAlphaRenderer(canvas:Rectangle)
    {
    super(canvas);

    }

    override protected function createBitmap():void
    {
    super.createBitmap();
    _bitmapData = new BitmapData( Math.ceil( _canvas.width ), Math.ceil( _canvas.height ), true );
    _bitmap.bitmapData = _bitmapData;
    }

    override protected function drawParticle( particle:Particle2D ):void
    {
    var colour:uint = _bitmapData.getPixel32( Math.round( particle.x - _canvas.x ), Math.round( particle.y - _canvas.y ) );
    var oa:uint = colour >>> 24;
    var or:uint = colour >>> 16 & 0xFF
    var og:uint = colour >>> 8 & 0xFF
    var ob:uint = colour & 0xFF

    var pa:uint = particle.color >>> 24;
    var alpha:Number = pa / 255;
    var pr:uint = particle.color >>> 16 & 0xFF
    var pg:uint = particle.color >>> 8 & 0xFF
    var pb:uint = particle.color & 0xFF

    var newR:uint = alpha * pr + ( 1 - alpha ) * or;
    var newG:uint = alpha * pg + ( 1 - alpha ) * og;
    var newB:uint = alpha * pb + ( 1 - alpha ) * ob;

    var newColour:uint = 255 << 24 | newR << 16 | newG << 8 | newB;

    _bitmapData.setPixel32( Math.round( particle.x - _canvas.x ), Math.round( particle.y - _canvas.y ), newColour );
    }

    }

    }
    • CommentAuthorTomAuger
    • CommentTimeJan 22nd 2013
     
    If anyone knows a faster way to combine the colours without first bitwise splitting them up, please post it!