DLL化するサンプルプログラム

DLL化するサンプルとして,Kinect を使って距離画像を取得し,最もセンサに近い点Pの
座標を求めるプログラムを作成した.
点Pのカメラ座標系での座標値を CameraSpacePoint 型のグローバル変数
p_nearest に保持する.

(余談)
CameraSpacePoint 構造体は Kinect.h で定義されている.
Visual Studio のエディタであれば,CameraSpacePoint の上にポインタを
置いて右クリックし,「定義をここに表示」を選択すると,構造体の
メンバを見ることができ,便利である.
(余談終わり)

ソースコード: 05a-nearest.zip

スレッド化

DLL化する前に,Kinectからのデータ取得とその処理部分をスレッド化する.
スレッド化しないと,情報を要求されてから計測や処理を実行することになり,
値を返すまでに時間がかかり,かつ,その間呼び出し元の処理も停止するため
実用的ではない.

またスレッド化されたメインループを終了させる関数や,
最近点のX座標,Y座標,Z座標を返す関数

float GetNearestPointX(void);
float GetNearestPointY(void);
float GetNearestPointZ(void);

を用意する.
本当は p_nearest へのアクセスに排他制御が必要だし,
スレッドで使用する変数は構造体にまとめてポインタで渡すべきなのだが,
後で考えることにする.

まず冒頭に,

#include <process.h>

を追加する.
次に,

int main(int argc, char **argv)

を,

unsigned int __stdcall KinectMain(void *p)

に変える.
またこの関数末尾の return 0; の前に,

_endthreadex(0);

を追加する.

main関数として,とりあえずスレッドを起動するだけのものを記述する.

int main(int argc, char **argv)
{
  _beginthreadex(nullptr, 0, KinectMain, nullptr, 0, nullptr);

  while (1);

  return 0;
}

とりあえずこれでほぼ同じように動く.

その他,いくつか変更点があるのだが,ちょっと解説は置いておいて,
さしあたり動くソースコードを以下に置く.

ソースコード: 05b-nearest-thread.zip

DLL化する.

DLLの作成方法と,そのUnityからの呼び出しについては, http://qiita.com/imura/items/39334a02bb77bdef9e91 を参照.

プロジェクト nearest-thread-dll を作成し,おおむね以下の処理を行う.

  1. nearest-thread-dll.cpp の中に,Main.cpp の内容(main関数以外)を入れる.
  2. 外部から呼び出す関数に NEARESTTHREADDLL_API を付ける.
  3. nearest-thread-dll.h の中に,ヘッダ部分 #include と #pragma を入れる.
  4. プロトタイプ宣言を書く.extern “C” {} でかこむことを忘れない.
extern "C" {
NEARESTTHREADDLL_API float GetNearestPointX(void);
NEARESTTHREADDLL_API float GetNearestPointY(void);
NEARESTTHREADDLL_API float GetNearestPointZ(void);
NEARESTTHREADDLL_API void StartKinect(void);
NEARESTTHREADDLL_API void StopKinect(void);
}

これでDLLが作成できる.

以下にソースコードを置いておく.

ソースコード: 05c-nearest-thread-dll.zip

Unityから呼び出すC#スクリプトの例.これを適当なGameObjectに設定すると,Kinectに向かって手を突き出すとその先端の位置に合わせて物体が動く.

using UnityEngine;
using System.Collections;
using System.Runtime.InteropServices;

public class CubeBehavior : MonoBehaviour {

	[DllImport ("nearest-thread-dll")] private static extern float GetNearestPointX();
	[DllImport ("nearest-thread-dll")] private static extern float GetNearestPointY();
	[DllImport ("nearest-thread-dll")] private static extern float GetNearestPointZ();
	[DllImport ("nearest-thread-dll")] private static extern void StartKinect();
	[DllImport ("nearest-thread-dll")] private static extern void StopKinect();

	// Use this for initialization
	void Start () {
		StartKinect ();
	}
	
	// Update is called once per frame
	void Update () {
		const float scale = 10.0f;
		transform.position = new Vector3 (GetNearestPointX () * scale,
		                                  GetNearestPointY () * scale,
		                                  GetNearestPointZ () * scale);
	}

	void OnDestroy () {
		StopKinect ();
	}
}