package { import flash.display.*; import flash.events.*; import flash.filters.*; import flash.geom.*; import flash.utils.*; import org.papervision3d.cameras.*; import org.papervision3d.view.*; import org.papervision3d.materials.*; import org.papervision3d.objects.*; import org.papervision3d.objects.primitives.* import caurina.transitions.Tweener; [SWF(width = "720", height = "480", frameRate = "30", backgroundColor = "#001122")] public class Main extends BasicView { // const vars static private const SNOW_PLACE_RANGE :int = 1500; static private const SNOW_MAX_DEPTH :int = 64; static private const FOCUS_POSITION :int = 2000; // 3d vars private var list :Array = []; private var blurs :Array = []; [Embed(source = "snow.png")] private var BitmapSnow:Class; /** * Constructor */ public function Main() { stage.quality = StageQuality.LOW; //camera camera.focus = 500; camera.zoom = 2; camera.x = 0; camera.y = -1000; camera.z = 0; // create blur field material for (var i:int = 0; i < SNOW_MAX_DEPTH; i++) { // create circle graphics var snow:Sprite = new Sprite(); snow.addChild(new BitmapSnow()); // ぼかしの適用値 var blurFilter:BlurFilter = new BlurFilter(i, i, 3); // 明度の適用値 var b:Number = (SNOW_MAX_DEPTH - i) / SNOW_MAX_DEPTH; var blightnessArr:Array = [ 1 - 0.2 * b, 0, 0, 0, 0, 0, 1 - 0.1 * b, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0.5 + 0.5 * b, 0 ]; var blightnessFilter:ColorMatrixFilter = new ColorMatrixFilter(blightnessArr); // add Fileter snow.filters = [blightnessFilter , blurFilter]; // copy bitmapdata var bitmapData:BitmapData = new BitmapData(100, 100, true, 0x00000000); bitmapData.draw(snow); // create material from bitmapdata var mat:BitmapMaterial = new BitmapMaterial(bitmapData); // save blurs.push(mat); } // partcle create interval var timer:Timer = new Timer(10); timer.addEventListener(TimerEvent.TIMER, timerHandler); timer.start(); // arrange blur addEventListener(Event.ENTER_FRAME, enterFrameHandler); // render startRendering(); } /** * partcle create interval * @param e */ private function timerHandler(e:TimerEvent):void { // crarete 3d plane var o:Plane = new Plane(blurs[SNOW_MAX_DEPTH - 1], 100, 100, 1, 1); // 3d plane position o.x = SNOW_PLACE_RANGE * Math.random() - SNOW_PLACE_RANGE / 2; o.y = 4000; o.z = SNOW_PLACE_RANGE * Math.random() - SNOW_PLACE_RANGE / 2; o.rotationX = -90; // 3d plane motion Tweener.addTween(o , { y : -1000, time : 5, transition : "easeInSine", onCompleteParams : [o], onComplete : onCompleteHandler }); // save and display scene.addChild(o); list.push(o); } /** * 3d plane remove handler * @param snow */ private function onCompleteHandler(p:Plane):void { var len:uint = list.length; for (var i:int; i < len; i++ ) { if (list[i] == p) { list.splice(i, 1); break; } } scene.removeChild(p); } /** * 被写界深度表現のチェック * @param event */ private function enterFrameHandler(event:Event):void { // マウスのインタラクティブ camera.x += ((mouseX / stage.stageWidth * 500)- 250 - camera.x) * .1; camera.z += ((mouseY / stage.stageHeight * 750)- camera.z) * .1; // 被写界深度フィルターの適用 var len:uint = list.length; for (var i:int = 0; i < len; i++) { if(list[i] == null) continue; var o:DisplayObject3D = list[i] as DisplayObject3D; // 距離の算出 var f:Number = calcPointDistanceFromCamera(o) - FOCUS_POSITION; var deg:Number = (f ^ (f >> 31)) - (f >> 31); // Math.abs(f)と同等 // ぼかしの適用値 var blurVal:int = Math.min(SNOW_MAX_DEPTH - 1, deg * .01 << 1 ); //ココの調整が絶妙 // ぼかしマテリアルを入れ替え o.material = blurs[blurVal]; } } /** * カメラからの距離を算出します * @param obj 計測したいオブジェクト * @return カメラからの距離(3D空間内のpx値) */ private function calcPointDistanceFromCamera(obj:DisplayObject3D):Number { var vecX:Number = obj.x - camera.x; var vecY:Number = obj.y - camera.y; var vecZ:Number = obj.z - camera.z; return Math.sqrt((vecX * vecX) + (vecY * vecY) + (vecZ * vecZ)); } } }