forked from: flash on 2011-7-23
/**
* Copyright yonatan ( http://wonderfl.net/user/yonatan )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/thba
*/
// forked from yonatan's flash on 2011-7-23
package {
import flash.geom.PerspectiveProjection;
import flash.geom.Vector3D;
import flash.geom.Matrix3D;
import flash.geom.Utils3D;
import flash.geom.ColorTransform;
import flash.events.Event;
import flash.display.*;
import flash.utils.*;
import flash.filters.*;
import net.hires.debug.Stats;
public class Main extends Sprite {
public static const NUM_TRANSFORMS:int = 4;
public static const NUM_PARTICLES:int = 100000;
public static const WARMUP:int = 100;
private var transforms:Vector.<Matrix3D> = new Vector.<Matrix3D>;
private var probabilities:Vector.<Number> = new Vector.<Number>;
private var particles:Vector.<Number> = new Vector.<Number>;
private var projected:Vector.<Number> = new Vector.<Number>;
private var proj:PerspectiveProjection = new PerspectiveProjection;
private var w:uint, h:uint;
private var points:Vector.<Vector3D> = new Vector.<Vector3D>;
private var p:Vector3D = new Vector3D;
private var depthBmd:BitmapData;
private var screenBmd:BitmapData;
private var ssao:BitmapData;
private var screenBmp:Bitmap = new Bitmap(screenBmd);
private var blur:BlurFilter = new BlurFilter(12,12);
private var colt:ColorTransform = new ColorTransform(-8, -8, -8, 1, 255, 255, 255, 0);
public function Main() {
w = stage.stageWidth/2;
h = stage.stageHeight/2;
depthBmd = new BitmapData(w, h, false, 0);
screenBmd = new BitmapData(w, h, false, 0);
ssao = new BitmapData(w, h, false, 0);
proj.focalLength = 45;
addChild(screenBmp = new Bitmap(screenBmd));
screenBmp.scaleX = screenBmp.scaleY = 2;
//addChild(new Bitmap(ssao));
addChild(new Stats);
createTransforms(NUM_TRANSFORMS);
createParticles(WARMUP, NUM_PARTICLES);
//render();
addEventListener("enterFrame", render);
//stage.addEventListener("click", function(e:*):void {
setInterval(change, 8000);
function change():void {
createTransforms(NUM_TRANSFORMS);
createParticles(WARMUP, NUM_PARTICLES);
}
}
private function rnd():Number {
return (Math.random() + Math.random() + Math.random())/3;
}
private function createTransforms(cnt:int):void {
transforms.length = probabilities.length = 0;
var volumes:Array = new Array;
var totalVolume:Number = 0;
for(var i:int=0; i<cnt; i++) {
var mtx:Matrix3D = new Matrix3D;
var sx:Number = Math.random()*2-1, sy:Number = Math.random()*2-1, sz:Number = Math.random()*2-1;
volumes[i] = Math.abs(sx*sy*sz);
totalVolume += volumes[i];
mtx.prependScale(sx, sy, sz);
mtx.prependRotation(Math.random()*360, Vector3D.X_AXIS);
mtx.prependRotation(Math.random()*360, Vector3D.Y_AXIS);
mtx.prependTranslation(0.5-rnd(), 0.5-rnd(), 0.5-rnd());
transforms[i] = mtx;
}
for(i=0; i<cnt; i++) probabilities[i] = volumes[i] / totalVolume;
}
private function randomTransform():Matrix3D {
var r:Number = Math.random();
var v:Number = 0;
var i:int=0, last:int = transforms.length-1;
while(i<last) {
v += probabilities[i];
if(v>r) break;
i++;
}
return transforms[i];
}
private function createParticles(warmup:int, cnt:int):void {
particles.length = 0;
var p:Vector3D = new Vector3D;
for(var i:int=-warmup; i<cnt; i++) {
var mtx:Matrix3D = randomTransform();
p = mtx.transformVector(p);
if(i>=0) particles.push(p.x, p.y, p.z);
}
projected.length = particles.length;
//proj.toMatrix3D().transformVectors(particles, projected);
}
private function render(...args):void {
screenBmd.lock(); depthBmd.lock(); ssao.lock();
var mtx:Matrix3D = proj.toMatrix3D();
mtx.identity();
mtx.appendRotation(getTimer()/20, Vector3D.Y_AXIS);
mtx.appendRotation(getTimer()/22, Vector3D.X_AXIS);
mtx.appendScale(4,4,4);
mtx.appendTranslation(0,0,30);
mtx.append(proj.toMatrix3D());
mtx.appendTranslation(w/2, h/2, 0);
mtx.transformVectors(particles, projected);
screenBmd.fillRect(screenBmd.rect, 0);
depthBmd.fillRect(screenBmd.rect, 0);
//Utils3D.projectVectors(proj.toMatrix3D(), particles, projected, null);
var minz:Number = +Infinity;
var maxz:Number = -Infinity;
for(var i:int=0, l:int = particles.length; i<l;) {
var x:Number = projected[i++];
var y:Number = projected[i++];
var z:Number = projected[i++]*40 - 1000;
//if(z<0)z=0;
var c:uint = z<0 ? 0 : (z<256 ? int(z)*0x10101 : 0xffffff);
//if(z<minz) minz = z;
//if(z>maxz) maxz = z;
var oc:uint = depthBmd.getPixel(x, y);
if(oc<c) depthBmd.setPixel(x, y, c);
oc = screenBmd.getPixel(x, y);
c = oc + 0x202020;
screenBmd.setPixel(x, y, c < 0xffffff ? c : 0xffffff);
}
ssao.applyFilter(depthBmd, depthBmd.rect, depthBmd.rect.topLeft, blur);
ssao.draw(depthBmd, null, null, "subtract");
ssao.threshold(depthBmd, depthBmd.rect, depthBmd.rect.topLeft, "==", 0, 0, 255);
//screenBmd.fillRect(screenBmd.rect, 0xffffff);
//screenBmd.draw(depthBmd);
screenBmd.draw(new Bitmap(ssao), null, colt, "multiply");
screenBmd.unlock(); depthBmd.unlock(); ssao.unlock();
//Wonderfl.log(minz + " " + maxz);
}
}
}