In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

3d light particles

press space to change color
Get Adobe Flash player
by YoupSolo 08 Apr 2015

    Talk

    bradfordsedito at 13 Apr 2015 22:28
    How would one do this or something similar with 3D particle formations utilizing an engine, particularly Away3D?
    bradfordsedito at 13 Apr 2015 22:28
    Some great code here by the way, nice work.
    YoupSolo at 26 Jul 2015 02:09
    sure, You get gpu accel using away3d
    Embed
/**
 * Copyright YoupSolo ( http://wonderfl.net/user/YoupSolo )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/gAN9
 */

package
{

    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.KeyboardEvent;
    import flash.filters.BitmapFilterQuality;
    import flash.filters.BlurFilter;
    import flash.geom.ColorTransform;
    import flash.geom.Point;
    import flash.utils.getTimer;
    
    [SWF(backgroundColor="0x0",frameRate="60",width="465",height="465")]
    public class Main extends Sprite
    {
        private const pi2:Number = Math.PI * 2;
        private var displayWidth:Number;
        private var displayHeight:Number;
        private var projCenterX:Number;
        private var projCenterY:Number;
        private var theta:Number;
        private var phi:Number;
        private var dphi:Number;
        private var dtheta:Number;
        private var fLen:Number;
        private var uMax:Number;
        private var dColor:uint;
        private var cost:Number;
        private var sint:Number;
        private var cosp:Number;
        private var sinp:Number;
        private var p:Particle3D;
        private var m:Number;
        private var numParticles:Number;
        private var bgColor:uint;
        private var blur:BlurFilter;
        private var origin:Point;
        private var darken:ColorTransform;
        private var picHolder:Sprite;
        private var displayBitmapData:BitmapData;        

        private var firstParticle:Particle3D;
        private var M11:Number;
        private var M12:Number;
        private var M31:Number;
        private var M32:Number;        

        private var level:Number;
        private var readColor:uint;
        private var levelInc:Number;        

        private var numT:Number;
        private var numS:Number;
        private var fadeRate:Number;
        private var maxLevelInc:Number;
        private var depth0:Number;
        private var level0:Number;
        private var depth1:Number;
        private var level1:Number;

        private var colorShift:Array = [16, 8, 0];
        private var csi:int = 0;

        public function Main()
        {
            if (stage)
                init();
            else
                addEventListener(Event.ADDED_TO_STAGE, init);
        }
        
        private function init(e:Event = null):void
        {
            removeEventListener(Event.ADDED_TO_STAGE, init);
            
            maxLevelInc = 20;
            level0 = 1;
            depth0 = -145;
            level1 = maxLevelInc;
            depth1 = 145;
            fadeRate = (maxLevelInc - 1) / (depth1 - depth0);

            displayWidth = 400;
            displayHeight = 400;
            projCenterX = displayWidth >> 1;
            projCenterY = displayHeight >> 1;
            
            theta = 3 * Math.PI / 2;
            phi = -Math.PI / 4;
            dphi = Math.PI / 208;
            dtheta = Math.PI / 177;

            fLen = 250;
            uMax = fLen - 2;
            
            origin = new Point();
            blur = new BlurFilter(4, 4);
            blur.quality = BitmapFilterQuality.MEDIUM;
            
            var darkenFactor:Number = 3/4;
            darken = new ColorTransform(darkenFactor, darkenFactor, darkenFactor);
            picHolder = new Sprite();
            
            picHolder.x = 40;
            picHolder.y = 40;

            displayBitmapData = new BitmapData(displayWidth, displayHeight, false, bgColor);
            picHolder.addChild( new Bitmap(displayBitmapData) );
            stage.addChild(picHolder);
            
            createParticles();
            stage.addEventListener(Event.ENTER_FRAME, _oef);
            stage.addEventListener(KeyboardEvent.KEY_UP, _onKeyUp );
        }

        private function _onKeyUp(e:KeyboardEvent):void 
        {
            csi = (csi + 1) % 3;
        }

        private function _oef(evt:Event):void
        {
            dphi = 0.015 * Math.cos(getTimer() * 0.000132);
            dtheta = 0.017 * Math.cos(getTimer() * 0.000244);
            phi = (phi + dphi) % pi2;
            theta = (theta + dtheta) % pi2;
            cost = Math.cos(theta);
            sint = Math.sin(theta);
            cosp = Math.cos(phi);
            sinp = Math.sin(phi);
            M11 = cost * sinp;
            M12 = sint * sinp;
            M31 = -cost * cosp;
            M32 = -sint * cosp;
            
            displayBitmapData.lock();
            displayBitmapData.colorTransform(displayBitmapData.rect, darken);
            displayBitmapData.applyFilter(displayBitmapData, displayBitmapData.rect, origin, blur);
            
            p = firstParticle;
            do
            {
                //Calculate rotated coordinates        
                p.u = M11 * p.x + M12 * p.y + cosp * p.z;
                p.v = -sint * p.x + cost * p.y;
                p.w = M31 * p.x + M32 * p.y + sinp * p.z;

                //Calculate viewplane projection coordinates
                m = fLen / (fLen - p.u);
                p.projX = p.v * m + projCenterX;
                p.projY = p.w * m + projCenterY;

                if ((p.projX > displayWidth) || (p.projX < 0) || (p.projY < 0) || (p.projY > displayHeight) || (p.u > uMax))
                {
                    p.onScreen = false;
                }
                else
                {
                    p.onScreen = true;
                }                

                if (p.onScreen)
                {
                    //we read the color in the position where we will place another particle:
                    readColor = displayBitmapData.getPixel(p.projX, p.projY);
                    //levelInc = expInt*Math.exp(expRate*p.u)
                    levelInc = fadeRate * (p.u - depth0) + 1;
                    
                    //clamp value of increase
                    levelInc = (levelInc > maxLevelInc) ? maxLevelInc : (levelInc < 0 ? 0 : levelInc);
                    level = (readColor >> colorShift[csi]) + levelInc;
                    
                    //we make sure that 'level' stays smaller than 255:
                    level = (level > 255) ? 255 : level;
                    dColor = level << colorShift[csi];
                    displayBitmapData.setPixel(p.projX, p.projY, dColor);
                }
                p = p.next;
            } while (p != null)

            displayBitmapData.unlock();
        }

        private function createParticles():void
        {
            var rad1:Number;
            var rad2:Number;
            var f1:Number;
            var f2:Number;
            var s:Number;
            var t:Number;
            var sMin:Number;
            var tMin:Number;
            var sMax:Number;
            var tMax:Number;
            var sInc:Number;
            var tInc:Number;            

            sMin = -Math.PI;
            sMax = Math.PI;
            tMin = -Math.PI;
            tMax = Math.PI;            

            //These are the number of divisions to use for the parameters
            numT = 150;
            numS = 500;    
            sInc = (sMax - sMin) / numS;
            tInc = (tMax - tMin) / numT;            

            var s0:Number;
            var t0:Number;          
            var sFuzz:Number = 0;
            var tFuzz:Number = 0;
            numParticles = numT * numS;
            var lastParticle:Particle3D;
            //note that in the loop below we only let i go up to numT-1 rather than numT, in order to
            //achieve a seamless periodic function.  In other words, the maximum t value is not PI, but
            //instead one incremental step smaller than PI.  We do a similar thing for the s parameter below.

            for (var i:int = 0; i < numT; i++)
            {
                t0 = tMin + tInc * i;
                for (var j:int = 0; j < numS; j++)
                {
                    s0 = sMin + sInc * j;
                    s = s0 + sFuzz * (Math.random() * 2 - 1);
                    t = t0 + tFuzz * (Math.random() * 2 - 1);
                    var thisParticle:Particle3D = new Particle3D(0x888888);
                    rad1 = 105;
                    rad2 = 27;
                    f1 = 0.5 * Math.sin(s * 5);
                    f2 = 0.5 * Math.cos(s * 5);
                    thisParticle.x = rad1 * Math.cos(s) + (1 + f1) * rad2 * Math.cos(t) * Math.cos(s);
                    thisParticle.y = rad1 * Math.sin(s) + (1 + f1) * rad2 * Math.cos(t) * Math.sin(s);
                    thisParticle.z = (1 + f2) * rad2 * Math.sin(t);
                    if ((i == 0) && (j == 0))
                    {
                        firstParticle = thisParticle;
                    }
                    else
                    {
                        lastParticle.next = thisParticle;
                    }
                    lastParticle = thisParticle;
                }
            }
        }
    }
}

class Point3D
{
    public var x:Number;
    public var y:Number;
    public var z:Number;
    
    private var outputPoint:Point3D;

    public function Point3D(x1:Number = 0, y1:Number = 0, z1:Number = 0)
    {
        this.x = x1;
        this.y = y1;
        this.z = z1;
    }

    public function clone():Point3D
    {
        outputPoint = new Point3D();
        outputPoint.x = this.x;
        outputPoint.y = this.y;
        outputPoint.z = this.z;
        return outputPoint;
    }

}


class Particle3D extends Point3D
{
    public var next:Particle3D;
    public var prev:Particle3D;   

    public var onScreen:Boolean;
    public var vel:Point3D = new Point3D();
    public var accel:Point3D = new Point3D();

    public var lastX:Number;
    public var lastY:Number;
    public var lastZ:Number;    

    public var projX:Number;
    public var projY:Number;

    public var u:Number;
    public var v:Number;
    public var w:Number;

    public var picX:Number;
    public var picY:Number;
    public var dest:Array;   

    public var color:uint;
    public var red:Number;
    public var green:Number;
    public var blue:Number;
    public var lum:Number;
    public var alpha:Number;

    public var initColor:uint;
    public var initRed:Number;
    public var initGreen:Number;
    public var initBlue:Number;
    public var initLum:Number;

    public var destColor:uint;
    public var destRed:Number;
    public var destGreen:Number;
    public var destBlue:Number;

    public var destLum:Number;
    public var colorChanging:Boolean;

    function Particle3D(thisColor:uint = 0xFFFFFFFF)
    {
        this.dest = [];
        this.color = thisColor;
        this.red = getRed(thisColor);
        this.green = getGreen(thisColor);
        this.blue = getBlue(thisColor);
        this.alpha = getAlpha(thisColor);
        this.lum = 0.2126 * this.red + 0.7152 * this.green + 0.0722 * this.blue;
        this.colorChanging = false;
        this.onScreen = true;
    }

    public function setColor(thisColor:uint):void
    {
        this.color = thisColor;
        this.red = getRed(thisColor);
        this.green = getGreen(thisColor);
        this.blue = getBlue(thisColor);
        this.alpha = getAlpha(thisColor);
        this.lum = 0.2126 * this.red + 0.7152 * this.green + 0.0722 * this.blue;
    }

    public function getAlpha(c:Number):Number
    {
        return Number((c >> 24) & 0xFF);
    }
    

    public function getRed(c:Number):Number
    {
        return Number((c >> 16) & 0xFF);
    }    

    public function getGreen(c:Number):Number
    {
        return Number((c >> 8) & 0xFF);
    }

    public function getBlue(c:Number):Number
    {
        return Number(c & 0xFF);
    }
}