package { import flash.events.Event; import flash.events.MouseEvent; import flash.filters.BlurFilter; import idv.cjcat.stardust.common.clocks.SteadyClock; import idv.cjcat.stardust.threeD.papervision3d.renderers.PV3DDisplayObject3DRenderer; import org.papervision3d.core.effects.view.ReflectionView; import org.papervision3d.objects.DisplayObject3D; /** * @see http://clockmaker.jp/blog/2008/08/papervision3d_focus_blur/ * @see http://wonderfl.net/code/d22f0f92eb9390b6f6ef84b808ab923f2e467137 * @author paq89 */ [SWF(width=465, height=465, backgroundColor=0x001122, frameRate=60)] public class Main extends ReflectionView { private var _container:DisplayObject3D; private var _emitter:PlaneEmitter; private var _particlesList:Array = []; private var _blurFilter:Array = []; /** * コンストラクタ */ public function Main():void { if (stage) init(); else addEventListener(Event.ADDED_TO_STAGE, init); } /** * ... */ private function init():void { // PV3D _container = new DisplayObject3D(); scene.addChild(_container); opaqueBackground = 0x001122; // カメラ camera.zoom = 2; camera.focus = 200; // 反射のアルファ viewportReflection.alpha = 0.5; // 軽量化のため、フィルターをあらかじめ作っておく for (var i:int = 0; i < 20; i++) { _blurFilter[i] = new BlurFilter(i, i, 1); } // パーティクルシステムの構築 _emitter = new PlaneEmitter(new SteadyClock(0.1), _particlesList); var renderer:PV3DDisplayObject3DRenderer = new PV3DDisplayObject3DRenderer(_container); renderer.addEmitter(_emitter); // イベントリスナー addEventListener(Event.ENTER_FRAME, onEnterFrame); stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove); } /** * エンターフレームイベント */ private function onEnterFrame(e:Event):void { // エミッター更新 _emitter.step(); // Papervision3Dのレンダリング singleRender(); // 被写界深度 setBlur(); } /** * マウスの位置に合わせてカメラを移動 */ private function onMouseMove(e:MouseEvent):void { camera.x += (2000 * Math.sin(mouseX / stage.stageWidth * 360 * Math.PI / 180) - camera.x) * .1; camera.z += (2000 * Math.cos(mouseX / stage.stageWidth * 360 * Math.PI / 180) - camera.z) * .1; camera.y += (2000 * mouseY / stage.stageHeight - camera.y) * .1; } /** * 被写界深度 */ private function setBlur():void { var len:int = _particlesList.length; for (var i:int = 0; i < len; i++) { var o:DisplayObject3D = _particlesList[i]; if (!o.visible) o.visible = true; // 距離の算出 var deg:Number = Math.abs(calcPointDistanceFromCamera(o) - 2000); // ぼかしの適用値 var blurVal:int = Math.min(20, deg * 0.008 << 1 ) >> 0;; if (blurVal > 19) blurVal = 19; var blurFilter:BlurFilter = _blurFilter[blurVal]; // フィルター適用 o.filters = [blurFilter]; } } /** * カメラからの距離を算出します * @param obj 計測したいオブジェクト * @return カメラからの距離(3D空間内のpx値) */ private function calcPointDistanceFromCamera(obj:DisplayObject3D):Number { var vecX:Number = obj.sceneX - camera.x; var vecY:Number = obj.sceneY - camera.y; var vecZ:Number = obj.sceneZ - camera.z; return Math.sqrt((vecX * vecX) + (vecY * vecY) + (vecZ * vecZ)); } } } //------------------------------------------------------------------------------------------------ import frocessing.color.ColorHSV; import idv.cjcat.stardust.common.actions.Age; import idv.cjcat.stardust.common.actions.CompositeAction; import idv.cjcat.stardust.common.actions.DeathLife; import idv.cjcat.stardust.common.actions.ScaleCurve; import idv.cjcat.stardust.common.clocks.Clock; import idv.cjcat.stardust.common.initializers.Life; import idv.cjcat.stardust.common.initializers.Scale; import idv.cjcat.stardust.common.math.UniformRandom; import idv.cjcat.stardust.threeD.actions.Deflect3D; import idv.cjcat.stardust.threeD.actions.Gravity3D; import idv.cjcat.stardust.threeD.actions.Move3D; import idv.cjcat.stardust.threeD.actions.Spin3D; import idv.cjcat.stardust.threeD.deflectors.PlaneDeflector; import idv.cjcat.stardust.threeD.emitters.Emitter3D; import idv.cjcat.stardust.threeD.fields.UniformField3D; import idv.cjcat.stardust.threeD.initializers.DisplayObjectClass3D; import idv.cjcat.stardust.threeD.initializers.Omega3D; import idv.cjcat.stardust.threeD.initializers.Position3D; import idv.cjcat.stardust.threeD.initializers.Rotation3D; import idv.cjcat.stardust.threeD.initializers.Velocity3D; import idv.cjcat.stardust.threeD.zones.SinglePoint3D; import idv.cjcat.stardust.threeD.zones.SphereCap; import org.papervision3d.core.proto.MaterialObject3D; import org.papervision3d.materials.WireframeMaterial; import org.papervision3d.objects.primitives.Plane; //------------------------------------------------------------------------------------------------ /** * プレーンをひたすら出し続けるEmitter * * @author paq89 */ class PlaneEmitter extends Emitter3D { public function PlaneEmitter(clock:Clock, particlesList:Array) { super(clock); var doc3D:DisplayObjectClass3D = new DisplayObjectClass3D(); doc3D.displayObjectClass = PlaneParticle; doc3D.constructorParams = [null, 100, 100, 1, 1, particlesList]; var cap:SphereCap = new SphereCap(0, 0, 0, 50, 50, 15); cap.rotationX = 180; var rotationRand:UniformRandom = new UniformRandom(0, 180); var omegaRand:UniformRandom = new UniformRandom(0, 4); // パーティクルの属性を定義 addInitializer(doc3D); addInitializer(new Life(new UniformRandom(200, 0))); addInitializer(new Scale(new UniformRandom(1, 1.2))); addInitializer(new Position3D(new SinglePoint3D(0, 0, 0))); addInitializer(new Velocity3D(cap)); addInitializer(new Rotation3D(rotationRand, rotationRand, rotationRand)); addInitializer(new Omega3D(omegaRand, omegaRand, omegaRand)); // 重力を定義 var field:UniformField3D = new UniformField3D(0, -1, 0); var gravity:Gravity3D = new Gravity3D(); gravity.addField(field); // デフレクトを定義 var deflect:Deflect3D = new Deflect3D(); deflect.addDeflector(new PlaneDeflector(0, 90, 0, 0, 1, 0)); // パーティクルのアクションを定義 addAction(gravity); addAction(deflect); addAction(new Age()); addAction(new DeathLife()); addAction(new Move3D()); addAction(new Spin3D()); addAction(new ScaleCurve(5, 20)); } } class PlaneParticle extends Plane { static private var col:int = 180; public function PlaneParticle(material:MaterialObject3D = null, width:Number = 0, height:Number = 0, segmentsW:Number = 0, segmentsH:Number = 0, particlesList:Array = null):void { var color:ColorHSV = new ColorHSV(col += 2, 0.8); // マテリアルを作成 var mat:WireframeMaterial = new WireframeMaterial(color.value); mat.doubleSided = true; super(mat, width, height, segmentsW, segmentsH); useOwnContainer = true; if (particlesList){ particlesList.push(this); visible = false;} } } [Stardust][PV3D] Depth of field