Deep Insider の Tutor コーナー
>>  Deep Insider は本サイトからスピンオフした姉妹サイトです。よろしく! 
Leap Motion実用サンプル(Visual Basic編)

Leap Motion実用サンプル(Visual Basic編)

Leap Motionでパーティクルを使用して軌跡に無数の円や画像を表示する

2013年9月18日

さまざまな色の粒子(パーティクル)が、Leap Motionによる手の指の動きに合わせて飛び散りながら追従するサンプル・アプリを作ってみよう。

  • このエントリーをはてなブックマークに追加

前書き

 今回のパーティクルのサンプルは、MSDNの「パーティクル効果のデモ」でダウンロードできるサンプルに、筆者独自のアレンジを加えたものである。
  ただし、パーティクル処理に関しては全てDLL化しているため、クラス・ライブラリの内容を見たい方はサンプルをダウンロードして見てほしい。

 今回は、パーティクルを使った2つのサンプルを紹介する。各種色の付いた円が、空中タッチした位置に無数に表示されるパーティクルのサンプルと、無数の画像が、空中タッチした位置に表示されるパーティクルのサンプルの2つだ。まずは、円のパーティクルから紹介しよう。

まずWPFプロジェクトを作成しよう

 Leap MotionのアプリはWPFで作成する。

 これには、Visual Studio 2012(以下、VS 2012)のIDEを起動して、メニューバーから[ファイル]-[新規作成]-[プロジェクト]と選択して、それにより表示される[新しいプロジェクト]ダイアログで「Visual Basic」のテンプレートから「WPF アプリケーション」を選択する(Leap Motionは、.NET Framework 3.5と4.0に対応している。しかし、.NET Framework 4.5でも動作する。今回のアプリは全て.NET Framework 4.5で作成している。しかし、あくまでも対応しているのは、.NET Framework 3.5と4.0だ。心配な方は、.NET Framework 4.0で作成すると安心だろう)。[名前]欄には、ここでは「ParticleLeapMotion」と指定する。

 WPFの基本的な作成手順は、第1回と同じ手順となるので、説明を割愛する。具体的な手順は、第1回の「参照の追加」「プロジェクトのルートに「LeapCSharp.dll」と「Leapd.dll」を追加する」「プロパティを設定する」を参考にしてほしい。「参照の追加」においては、第1回と異なる部分のみ記述した。

参照の追加

 実行に必要なアセンブリをプロジェクト内で管理しやすいように、[ソリューション エクスプローラー]内でプロジェクト項目の直下に「Lib」フォルダーを作成し、その中に、今回使用するパーティクルに関するClassLibrary1.dllファイルを置いておこう(ClassLibrary1.dllファイル自体は、サンプルをダウンロードしたうえで、「sampler_04/ClassLibrary1/ClassLibrary1/bin/Debug/ClassLibrary1.dll」ファイルを使えばよい)。そして、これへの参照設定を追加しておく。

今回のLeap Motionアプリについて

 今回のアプリは、パーティクル(Particle)を使ったアプリだ。Particleとは「分子」とか「粒子」とかいう意味であり、このアプリは、タッチした位置に、無数のさまざまな色の入り混じった円が「粒子」のように表示され、タッチ・ポイントの動きに合わせて、無数の円も追従して動くというものだ(次の画面を参照)。

タッチ・ポイントに追従して無数の円が移動している

 この画面では小さくて見づらいが、さまざまな色で表示されているのは、無数の円だ。ここでは、指5本で円を表示させているが、もちろんLeap Motionの機能としては1~10本までの指で表示することもできる。しかしこのプログラムでは、1~5本の指のみを認識するようにしているので、5本以上の指で円を表示することはできない。

画面のレイアウト(MainWindow.xaml)

ビューポートの設定

 名前が「World」の<Viewport3D>要素(=2Dレイアウト境界内に含まれている3Dコンテンツをレンダリングする要素。以降、Viewport3D)を配置し、その子要素として「<Viewport3D.Camera>」というプロパティ要素(詳細後述)を配置する。その子要素として、<OrthographicCamera>要素(詳細後述)を配置する。

カメラの設定

 <Viewport3D.Camera>プロパティ要素は、Viewport3Dの3Dコンテンツを、Viewport3Dの2Dサーフェイスに投影するカメラ・オブジェクトを設定する要素だ。

 <OrthographicCamera>要素は、正投影カメラを表す。Positionプロパティには、ワールド座標でのカメラの位置を設定する。LookDirectionプロパティには、ワールド座標でカメラが向いている方向を定義するVector3D構造体のデータを設定する。UpDirectionプロパティには、カメラの上向き方向を定義するVector3Dデータを設定する。これらの各プロパティには、Vector3D構造体の「x,y,z」の値を指定する。

光源の設定

 次に、<Viewport3D.Children>プロパティ要素(=<ModelVisual3D>要素のコレクションを指定するためのプロパティ)内に、<ModelVisual3D>要素(=3Dモデルを格納するVisualオブジェクト)を配置し、子要素とし、<ModelVisual3D.Content>プロパティ要素(=Visualオブジェクトの内容)を配置する。その子要素として、「WorldModels」という名前の<Model3DGroup>要素(=複数の3Dモデルを1グループにまとめたもの。以降、Model3DGroup)を配置し、その子要素として「<AmbientLight Color="White"/>」(=対象オブジェクトの形状に関係なく、オブジェクトに一様に光を適用する光源オブジェクト)を配置する。これらの定義により、画面に表示される円の光源は白色になるが、ここのColorプロパティ値の色名を変えると光源の色も変わる。例えば「Color="Red"」と指定すると、光源の色が赤になり円の色も全て赤みがかって見えるようになる。

InkPresenterコントロールの配置

 最後に、最前面に「paintCanvas」という名前のInkPresenterコントロールを配置する。

 書き出されるXAMLコードは次のリストのようになる。

XAML
<Window x:Class="MainWindow"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  Title="MainWindow" Background="Black" Width="1920" Height="1080" BorderThickness="0.0" WindowState="Maximized">
  <Grid>
    <Viewport3D Name="World">

      <Viewport3D.Camera>
        <OrthographicCamera Position="0,0,32" LookDirection="0,0,-32" UpDirection="0,1,0" Width="128" />
      </Viewport3D.Camera>

      <Viewport3D.Children>
        <ModelVisual3D>
          <ModelVisual3D.Content>
            <Model3DGroup x:Name="WorldModels">
              <AmbientLight Color="White"/>
            </Model3DGroup>
          </ModelVisual3D.Content>
        </ModelVisual3D>
      </Viewport3D.Children>

    </Viewport3D>

    <InkPresenter Name="paintCanvas"/>
  </Grid>
</Window>
XAMLデザイン後に書き出されたMainWindow.xamlファイルのコード

プログラム・コード(MainWindow.xaml.vb)

 では次に、プログラム・コード(MainWindows.xaml.vbファイル)を見ていこう。

 プログラム・コードも、タッチ処理以外は第1回と基本的に同じ内容となるので、説明を割愛する。まずは第1回の「名前空間の読み込み」「メンバー変数の宣言」「MainWindow_Loadedメソッドの処理」「Updateメソッドの処理」の開発手順を参考にタッチ処理の前までを実装してほしい。相違点として、下記の3点を修正してほしい。

  (1)まずParticleを扱うために、「ClassLibrary1.ParticleSample」名前空間を読み込む
   (2)「Private myParticle As New ClassLibrary1.ParticleSample.ParticleSystem(1000, Colors.White)」メンバー変数を宣言する(=表示される円の最大個数(この例では「1000」)と色(この例では「Colors.White」。何色を指定しても構わない。何色を指定しても円の色に関係はない)で初期化された、ParticleSystemクラス(ClassLibrary1.ParticleSample名前空間)の新規インスタンスを格納するmyParticleメンバー変数を宣言する)
   (3)第1回のリスト3にある「Private Message As String」と「Private Index As Integer」の行は削除する。

MainWindow_Loadedメソッドの処理

 MainWindowが読み込まれたときの処理を実装する。

 パーティクルの肝となるParticleSystemManagerクラス(ClassLibrary1.ParticleSample名前空間)の新しいインスタンスを生成し、myParticleメンバー変数のpmフィールドに代入する。

 myParticleメンバー変数のAddParticleメソッド(=パーティクルを表示させるメソッド)を呼び出して、XAMLコード内で定義しておいた「WorldModels」という名前のModel3DGroupを指定する。

 ~以下は第1回目と同じ処理の解説になるので割愛する。~

 具体的には次のようなコードになる。

Visual Basic
Private Sub MainWindow_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded

  ' ParticleのDLLから、新しいParticleSystemManagerのインスタンスを作成する
  ' PaticleNewメソッドにXAML内の[WorldModels]を指定する
  myParticle.pm = New ParticleSystemManager()
  myParticle.AddPaticle(WorldModels)

  ……第1回目と同じ処理のため割愛……

End Sub
MainWindowが読み込まれたときの処理(MainWindow.xaml.vb)

 第1回でも説明したが、Leap Motionのタッチ処理について簡単に説明しておこう。

 次の図に示すように、Leap Motionでは手前側が「ホバー状態(hovering)」、奥側が「タッチ状態(touching)」を表す。空間の範囲は前後「1」~「-1」となっている。

Leap Motionのタッチ検出イメージ(Leap Motion SDKのAPIドキュメントから引用)
Leap Motionのタッチ検出イメージ(Leap Motion SDKのAPIドキュメントから引用)

 今回のパーティクルのサンプルでは、ホバー時、タッチ時といった判別は行っていない。どんな状態のときにでもパーティクルが表示されるようにしている。ただし、タッチ・ポイントの色は「Blue」としている。

 まず、画面に表示された指の個数を取得して、メンバー変数「FingersCount」に格納しておく。

 画面上に指が1~5本表示されている場合は、メンバー変数「x」に「touchPoint.X」の値を、メンバー変数「y」に「touchPoint.Y」の値を格納する。下記に示すコードで「- 970」とマイナス指定している数値は、タッチした位置と円の表示位置を調整するための値だ。「0.05」を乗算しているのは、そのままのtouchPoint.XプロパティとtouchPoint.Yプロパティの値では、値が大きくなりすぎるとパーティクルが表示されないためである。この辺りの数値は、筆者がいろいろ試してみて独自に導き出した値であるため、この値にした理由自体は特にない。また、「0.05」の値は「0.09」~「0.1」までの範囲の値なら、どんな値を指定してもいいようだ。

 メンバー変数「myParticle」のParticlePositionメソッド(後述)に、メンバー変数「x」と「y」の値を指定する。これで、無数の各種色の付いた円が、おおよそタッチした位置に表示され、軌跡に追従して移動するようになる。

 ParticlePositionメソッドは、指定したX/Y座標にパーティクルが追従するメソッドだ。その引数に「0, 0」と指定すると、タッチ・ポイントには関係なく次の画面のように、各種色の付いた円が画面全体を駆け巡る。

「ParticlePosition(0, 0)」と指定すると、タッチ・ポイントに関係なく、各種色の付いた円が画面全体を駆け巡る

 具体的には下記のコードのようになる。

Visual Basic
Private Sub Update(sender As Object, e As EventArgs)

  ……コード略……

  touchIndicator.Color = Colors.Blue
  FingersCount = leap.Frame.Fingers.Count

  If FingersCount = 1 OrElse FingersCount = 2 OrElse FingersCount = 3 OrElse FingersCount = 4 OrElse FingersCount = 5 Then

    ' メンバー変数「x」に「touchPoint.X」の値を、メンバー変数「y」に「touchPoint.Y」の値を格納する。
    ' 「-970」とマイナス指定している数値は、タッチした位置と円の表示位置を調整するための値だ。
    ' 「0.05」を乗算しているのは、そのままの値では、値が大きくなりすぎて、パーティクルが表示されないためである
    x = (touchPoint.X - 970) * 0.05
    y = (touchPoint.Y - 520) * 0.05

    ' ParticlePositionメソッドにメンバー変数「x」と「y」の値を指定する
    myParticle.ParticlePosition(x, y)
  End If

  ……コード略……

End Sub
Leap Motionのタッチ処理(MainWindow.xaml.vb)

 今回はもう1つサンプルを作成してみよう。次も、同じパーティクルの処理だが、円の代わりに画像を表示させてみる。

円の代わりに画像を表示させるサンプル・アプリ

 次もWPFで作成する。プロジェクト名は「ImageParticleLeapMotion」とする。

 以下、先のサンプルと異なるのは、[参照の追加]で「ImageParticleClassLibrary.dll」ファイルを参照していることだ。ImageParticleClassLibrary.dllファイル自体は、サンプルをダウンロードしたうえで、「sampler_04/ ImageParticleClassLibrary/ImageParticleClassLibrary/bin/Debug/ImageParticleClassLibrary.dll」ファイルを使えばよい。

JPEG画像を配置する

 今回のアプリの実行に関しては、アプリを動作させる以前に、「C:\ ParticleImage」というフォルダーを手動で作成して、そのフォルダー内に1枚のJPEG画像を配置する。画像のサイズは640×480がよい。フォルダー内に配置する画像は、必ず拡張子が「.jpg」の画像に限られる。PNG画像は読み込まないので気を付けてほしい。何枚の画像を配置してもいいが、読み込むのはタイムスタンプの新しい1枚の画像だけだ。事前にフォルダーや画像がないとエラーになるので、注意してほしい。

今回のLeap Motionアプリについて

 今回のアプリも、Particleを使ったアプリだ。タッチした位置に無数の画像が粒子のように表示され、タッチ・ポイントの動きに合わせて、無数の画像も追従して動くというアプリだ(次の画面を参照)。

タッチ・ポイントに追従して無数の画像が移動している

ここで表示される画像は、「C:\ ParticleImage」フォルダー内に配置したJPEG画像だ。

 「画面のレイアウト」の解説については、先のサンプルとほとんど同じため、そちらを参照してほしい。異なる点は、<Window>要素のBackgroundプロパティに「Blue」を指定して、背景色を「青」としているところだ。

 プログラム・コード(MainWindows.xaml.vbファイル)についても、基本的に先のサンプルと同じ内容となるので、説明を割愛する。異なる点は、下記の3点だ。

  (1)名前空間の読み込みに、まずParticleを扱うために、「ImageParticleClassLibrary.ParticleSample」名前空間を読み込む(先の「ClassLibrary1.ParticleSample」名前空間と異なる点に注意)
   (2)「Private myParticle As New ClassLibrary1.ParticleSample.ParticleSystem(1000, Colors.White)」を、「Private myParticle As New ImageParticleClassLibrary.ParticleSample.ParticleSystem(1000, Colors.Yellow)」に書き換える
   (3)「myParticle.AddPaticle(WorldModels)」を、「myParticle.AddImagePaticle(WorldModels)」に書き換える

 これだけで、以下は先のサンプルとまったく同じ処理と解説なので。割愛させていただく。

 このサンプルでも、「ParticlePosition(0,0)」を指定できる。無数の画像がタッチ・ポイントに関係なく、画面を駆け巡る。

 本稿の2つのサンプルのコードは、下記のリンク先よりダウンロードできる*1

  • *1サンプルをダウンロードして動かす場合は、「LeapCSharp.NET4.0.dll」や「LeapCSharp.dll」、「Leap.dll」を読者自身のフォルダー内にあるDLLファイルに指定し直さなければ動かない可能性があるので、動かない場合は再指定していただきたい。
      今回の場合は、2番目のサンプルに関しては、「C:\ ParticleImage」フォルダーを作成して、JPEG画像を必ず配置してから実行することを忘れないようにしてほしい。

 今回はこれで終わりだ。パーティクルを使ったアプリは、ある程度数学的知識が豊富でないと作りにくい。今回は、パーティクルの部分のみDLLで提供しているので、大変に簡潔なコードになった。ダウンロードされるサンプルには、DLLの基になったクラス・ライブラリも同梱しているので、興味のある方は、のぞいて勉強してみるといいだろう。

 正直、筆者はこのクラス・ライブラリの内容を100%理解しているとはいいにくいのだが、自分で分かる範囲に修正を加えて、今回のようなアプリに完成させた。皆さんもクラス・ライブラリを改変して、自分なりのパーティクルのアプリを作ってみてはいかがだろうか? けっこう楽しい作業になると思う。

 次回はLeap MotionでBing Mapsを扱った処理を紹介する。Leap Motionを使って、選択された住所の位置にズームインして、該当する位置にピンを立てるアプリだ。Bing Mapsの拡大/縮小も実装している。普通の地図アプリだが、それと異なる点は全ての処理をLeap Motionで処理する点だ。こういったアプリではWin32 APIの利用が不可欠だ。お楽しみに!

 では、また次回の記事でお会いしよう。

※以下では、本稿の前後を合わせて5回分(第1回~第5回)のみ表示しています。
 連載の全タイトルを参照するには、[この記事の連載 INDEX]を参照してください。

Leap Motion実用サンプル(Visual Basic編)
1. オブジェクト(Button)をLeap Motionでタッチして背景色を変化させる

Leap Motionの動くサンプルを実際に作ってみる連載スタート。今回はLeap Motionのタッチ操作で背景色を変化させるWPFアプリをVBで開発する。

Leap Motion実用サンプル(Visual Basic編)
2. Leap MotionによるWPFアプリ上のオブジェクトの移動

Leap Motionの動くサンプルを実際に作ってみる。今回はWPFの画面上に配置したオブジェクトを、Leap Motionによる操作で移動させるアプリを作成。

Leap Motion実用サンプル(Visual Basic編)
3. Leap Motionによる、WPFアプリ上に動的に作成したオブジェクトのイベント処理

Leap Motionの動くサンプルを実際に作ってみる。今回はWPFの画面上に動的に作成したオブジェクトを、Leap Motionによる操作でアニメーションさせるアプリを作成。

Leap Motion実用サンプル(Visual Basic編)
4. 【現在、表示中】≫ Leap Motionでパーティクルを使用して軌跡に無数の円や画像を表示する

さまざまな色の粒子(パーティクル)が、Leap Motionによる手の指の動きに合わせて飛び散りながら追従するサンプル・アプリを作ってみよう。

Leap Motion実用サンプル(Visual Basic編)
5. Leap MotionでBing Mapsを扱う

リスト内に表示された住所項目をLeap Motionによりタッチすることで、Web上のサービス「Bing Maps」での地図検索を行うサンプル・アプリを作ってみよう。

サイトからのお知らせ

Twitterでつぶやこう!