LeapMotion #001 Starling

LeapMotion #001 Starling from Takepepe on Vimeo.

1ヶ月ぶりの投稿です。GW最終日、皆様いかがお過ごしですか?
今回の投稿は、個人的に今年最も気になるガジェット「LeapMotion」についてです。

・Leap Motion

LeapMotionは端末の上1m四方空間内で、1ミリ単位で指やツール(ペン等)を検知するセンサーです。
また、SDKレベルで数種類のジェスチャーを認識します。

つい先日、プレオーダーした人への発送延期がアナウンスされたばかりですが、
自分は3月末にプレオーダー、デベロッパー登録したところ、2週間ほどで手元に届きました。
発送延期の理由としては、完璧な状態として世に送り出したい、というような内容でした。
7月22日が発送予定日とされていますが、実際どうなるかはまだわかりませんね。

まだ日本語のリソースが少ない状態ですので、コード解説にはいる前に
DeveloperPortalの概要を写したものを交えて、簡単に解説したいと思います。

Frame

LeapMotionで値を取得するために使用するFrameオブジェクトの中には以下のものが含まれます。

・Lists of tracking data
Hands — すべての手
Pointables — Pointableオブジェクトとして、すべての指とツール
Fingers — すべての指
Tools — すべてのツール
Gestures — 開始、更新、終了のハンドラーを含むすべてのジェスチャー
・Frame motion
Rotation Axis — 回転軸を表現する方向ベクトル。
Rotation Angle — 回転軸(右手の法則を使用して)のまわりで右回りの回転角。
Rotation Matrix — 回転を表現するtransformマトリックス。
Scale Factor — 拡大縮小を表現するファクター。
Translation — 直線運動を表現するベクトル。

Hand model

手について様々な情報を提供します。2本の手を認識しますが、右手左手の識別はしていません。

・Hand attributes
Palm Position — Leapの起点から計測した手のひら中心座標
Palm Velocity — 秒速ミリメートル単位の、手のひらの移動速度
Palm Normal — 手のひらの中心から、下方へ指す垂直方向のベクトル
Direction — 手のひらの中心から、指へ向かうベクトル。
Sphere Center — 手の屈曲に適当な球体の中心。(手でボールを持っているような感じ)
Sphere Radius — 手の屈曲に適当な球体の半径。半径は手の形とともに変化します。
・Hand motion
Rotation Axis — 回転軸を表現する方向ベクトル。
Rotation Angle — 回転軸(右手の法則を使用して)のまわりで右回りの回転角。
Rotation Matrix —回転を表現するtransformマトリックス。
Scale Factor — 拡大縮小を表現するファクター。
Translation — 直線運動を表現するベクトル。
・Finger and Tool lists

検知した手に属する、指やツールの情報を取得できます。

Pointables — Pointableオブジェクトとして、すべての指とツール
Fingers — すべての指
Tools — すべてのツール

Finger and Tool models

Leapはその視界内の指およびツールの両方を検知するおよび追跡します。

Length — オブジェクト(手から先端に及ぶ)の可視部の長さ。
Width — オブジェクトの可視部の平均幅。
Direction — オブジェクト(つまり基礎から先端まで)と同じ方角に指すユニット方向ベクトル。
Tip Position — Leapの起点から計測した指先の座標
Tip Velocity — 秒速ミリメートル単位の、指先の移動速度

Gestures

Leapは特定の移動パターンをGesturesとして認識します。

Circle — 円をトレースする単一の指。
Swipe — 手の直線運動。
Key Tap — キーボード・キーを軽く打つかのような指の動作。
Screen Tap — コンピューター・スクリーンを軽く打つかのような指の動作。
開発環境について

現在サポートされている言語は、C++、C#、Objective-C、Java、Python、JavaScriptになります。
DevelperPortalでは前述の概要の他に、各フレームワークに対応したライブラリの配布、
ガイドライン、コミュニティ、アプリストア概要などが掲載されています。
Leapに興味があるかたは是非覗いてみてください。

・Leap Motion Developer Portal

LeapMotion × Adobe AIR Starling

今回作成したデモについての解説です。
AdobeAIRでStarlingのParticleSystemを使用して作成しています。

・Starling Framework
・Starling-Extension-Particle-System

StarlingはStage3Dを使用しているのでapp.xmlに以下の設定を忘れずにしましょう。

<renderMode>direct</renderMode>
<depthAndStencil>false</depthAndStencil>

LeapをActionScriptで使用するために、以下のライブラリと付属のC++SDKをラップしているANEを使用します。
導入方法については、下記ページの下部に書いてあるので、それぞれ開発環境にあったものを選んでください。
自分はFlashBuilder4.7でした。

・LeapMotionAS3

Starlingを使用したパーティクルのデモはClockmakerさんにゃあプロジェクトさんが充実していますので、
そちらを参考にさせていただきました。

FL001.as

package {
	
	import flash.display.Sprite;
	import flash.display.StageAlign;
	import flash.display.StageDisplayState;
	import flash.display.StageScaleMode;
	import flash.events.KeyboardEvent;
	import starling.core.Starling;
	
	[SWF(backgroundColor="#00164a", width="1440", height="900", frameRate="60")]
	
	public class FL001 extends Sprite {
		
		private var starling:Starling;
		
		public function FL001() {
			
			stage.align = StageAlign.TOP_LEFT;
			stage.scaleMode = StageScaleMode.NO_SCALE;
			stage.addEventListener(KeyboardEvent.KEY_DOWN,onKeyDown);
			
			starling = new Starling(MainView, stage);
			starling.start();
			
		}
		
		private function onKeyDown(e:KeyboardEvent):void {
			
			if(stage.displayState == StageDisplayState.NORMAL){
				stage.displayState = StageDisplayState.FULL_SCREEN;
			} else {
				stage.displayState = StageDisplayState.NORMAL
			}
			
		}
		
		
	}
}

MainView.as

package {
	
	import flash.geom.Rectangle;
	import starling.core.Starling;
	import starling.display.Sprite;
	import starling.events.Event;
	import starling.events.ResizeEvent;
	import starling.extensions.ParticleDesignerPS;
	import starling.textures.Texture;
	import com.leapmotion.leap.LeapMotion;
	import com.leapmotion.leap.Pointable;
	import com.leapmotion.leap.events.LeapEvent;
	
	internal class MainView extends Sprite { 
		
		// 事前に「online particle editor」で.pexファイルとtexture.pngを用意しておきます
		// http://onebyonedesign.com/flash/particleeditor/
		
		[Embed(source = "assets/particle.pex", mimeType = "application/octet-stream")]
		private static var ParticleData:Class;
		
		[Embed(source = "assets/texture.png")]
		private static var ParticleImage:Class;
		
		private var particles:Vector.<ParticleDesignerPS>;		
		private var count:int = 10;
		private var leap:LeapMotion;
		
		public function MainView() {
			addEventListener(Event.ADDED_TO_STAGE, onAddStage);
		}
		
		private function onAddStage(e:Event):void {
			
			setParticles();
			leap = new LeapMotion();
			leap.controller.addEventListener( LeapEvent.LEAPMOTION_FRAME, onLeapFrame );
			stage.addEventListener(ResizeEvent.RESIZE, onResizeStage);
			
		}
		
		private function setParticles():void{
			
			particles = new Vector.<ParticleDesignerPS>(10);
			for(var i:int = 0; i<count ; i++){
				particles[i] = new ParticleDesignerPS( XML(new ParticleData()), Texture.fromBitmap(new ParticleImage()));
				particles[i].startSize = 100;
				particles[i].endSize = 100;
				particles[i].speed = 0;
				particles[i].start();
				Starling.juggler.add(particles[i]);
				addChild(particles[i]);
			}
			
		}
		
		private function onResizeStage(e:ResizeEvent):void {
			
			Starling.current.viewPort = new Rectangle(0, 0, e.width, e.height);
			stage.stageWidth = e.width;
			stage.stageHeight = e.height;
			
		}
		
		private function onLeapFrame(e:LeapEvent):void {
			
			var max:int = e.frame.pointables.length;
			for(var i:int = 0; i<count ; i++){
				if( i < max ){
					var pointable:Pointable = e.frame.pointables[i];
					particles[i].emitterX = (pointable.tipPosition.x)*3+stage.stageWidth/2;
					particles[i].emitterY = (pointable.tipPosition.y)*-3+stage.stageHeight;
					particles[i].gravityX = pointable.tipVelocity.x*-5;
					particles[i].gravityY = pointable.tipVelocity.y*5;
					particles[i].maxNumParticles = 50;
				}else{
					particles[i].maxNumParticles = 1;
				}
			}
			
		}
		
	}
}

1ヶ月いじった上で得た感想(というかぶちあたっている壁)です。

  1. 指がLeapに向かって垂直に重なると検知できない。
  2. 細かなUI操作に向いていない
  3. ジェスチャーはそのままでは利用しづらい

あくまで、現状公開されているSDKとライブラリを使用した上での感想です。
概要を読む限りではワクワクするばかりですが、ちゃんとアプリケーションに落とし込むためには
上記の問題をカバーしたフレームワークが必要だなと思いました。

今回の投稿はさらっと紹介しただけになってしまったので、
次回はちょっとしたフレームワークと何か面白いネタで投稿できればいいなー。