カメラで物体の軌跡を追う。(Line3D, SpringCamera、Effect)
今回は主にSpringCameraとLine3Dを使って流星の動きをカメラが追いかけていくようなFlashを作ってみました。
作品はこちら
スクリーンセーバー化もしてみたので使いたい方はこちら
Flashのスクリーンセーバー化のやり方はこちら。
- プログラムの流れ
1.SpringCameraの設定
SpringCameraとはターゲットに指定した物体を自動で追っていくカメラ。
2.球が進む座標の計算(軌跡はローレンツアトラクタ)
3.球を移動
4.球が進んだ部分に線を引く
5.球の周りにパーティクルを発生
6.パーティクルの位置を更新
7.2〜6を繰り返し実行
色の変化はFrocessingを使ってHSV色空間でやっています。
以下にコードを載せておきます。
package { import __AS3__.vec.Vector; import flash.events.Event; import flash.filters.*; import frocessing.color.ColorHSV; import org.papervision3d.cameras.*; import org.papervision3d.core.geom.Lines3D; import org.papervision3d.core.geom.renderables.Line3D; import org.papervision3d.materials.ColorMaterial; import org.papervision3d.materials.special.LineMaterial; import org.papervision3d.objects.primitives.*; import org.papervision3d.view.BasicView; [SWF(backgroundColor=0x000000)] public class Papervision_Line3D_rainbow extends BasicView { //カメラが追う球 private var sphere:Sphere; //描く線 private var line:Lines3D; //ここを変更すると描かれる線が変わる private var A:Number = 5.0, B:Number = 25.0, C:Number = 8.0/3.0, D:Number = 0.01; //向かう座標 private var xx:Number, yy:Number, zz:Number; //RGB->HSB変換用の変数 private var hsv:ColorHSV; private var glow:GlowFilter; //Planeを格納するためのVector private var particles:Vector.<Plane>; public function Papervision_Line3D_rainbow() { super(stage.stageWidth, stage.stageHeight, true, false, CameraType.SPRING); //初期化 hsv = new ColorHSV(0, 1, 1); glow = new GlowFilter(0, 1, 8, 8, 2); particles = new Vector.<Plane>(); xx = yy = zz = 1; //球の生成 sphere = new Sphere(new ColorMaterial(0xffffff), 3); sphere.x = sphere.y = sphere.z = 1; scene.addChild(sphere); //フィルターを有効にする sphere.useOwnContainer = true; sphere.filters = [new BlurFilter(8,8,4), glow]; //カメラが追うものを球に設定 camera.target = sphere; //各パラメータの設定 SpringCamera3D(camera).mass = 20; //勢い SpringCamera3D(camera).damping = 30; //摩擦 SpringCamera3D(camera).stiffness = 8; //動きの固さ //線をまとめて管理するクラス。 //第一引数はMaterialだが線一本ずつ個別に設定するのでnull line = new Lines3D(null); scene.addChild(line); //レンダリング開始 startRendering(); addEventListener(Event.ENTER_FRAME, onFrame); } private function onFrame(event:Event):void{ //from var preX:Number = sphere.x; var preY:Number = sphere.y; var preZ:Number = sphere.z; //進む距離 var dx:Number, dy:Number, dz:Number; dx = A*(yy-xx); dy = xx * (B - zz) - yy; dz = xx * yy - C * zz; //to xx += D*dx; yy += D*dy; zz += D*dz; sphere.x = xx*20; sphere.y = yy*20; sphere.z = zz*20; //線を描画 line.addNewLine(2, preX, preY, preZ, sphere.x, sphere.y, sphere.z); //HSV->RGBの変換 var color:uint = hsv.toRGB().value; //glowフィルターの色変更 glow.color = color; //線の色を変更 (line.lines[line.lines.length-1] as Line3D).material = new LineMaterial(color); //球から出るパーティクルの生成 for(var j:int = 0; j < 3; j++){ //Planeの生成 var mat:ColorMaterial = new ColorMaterial(color); mat.doubleSided = true; var p:Plane = new Plane(mat, 1, 1); //球の位置に発生 p.x = sphere.x; p.y = sphere.y; p.z = sphere.z; //Filterを有効にする p.useOwnContainer = true; p.filters = [new BlurFilter(4,4,2)]; //速度の設定 p.extra = {vx:Math.random()*6-3, vy:Math.random()*6-3, vz:Math.random()*6-3}; scene.addChild(p); particles.push(p); } var i:int = particles.length; //パーティクルの管理 while(i--){ p = particles[i]; //位置の更新 p.x += p.extra.vx; p.y += p.extra.vy; p.z += p.extra.vz; //透明にする p.material.fillAlpha -= 0.05; //透明になったら消去 if(p.material.fillAlpha <= 0){ particles.splice(i,1); scene.removeChild(p); p = null; } } i = line.lines.length; //線を徐々に透明にしていく while(i--){ var l:Line3D = line.lines[i]; l.material.lineAlpha -= 0.0015; if(l.material.lineAlpha <= 0) line.removeLine(l); l = null; } //色を徐々に変化させる hsv.h += 1; } } }