カメラで物体の軌跡を追う。(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;
		}
	}
}