2011年1月14日金曜日

Unity3D事始め

ゲームエンジン「Unity3D」入門のための覚え書き。
たまに聞かれるのでまとめてみました。
FlashからUnity3Dに移行したい人向けです。

■環境を整える

・Unity:
 Basicは無料。Proは1500ドル。(機能比較表
 Proにすると影シェーダ、ビデオ再生、スプラッシュ変更などの機能が使える。
 その他、UIが黒ベースになって少しリッチな気分に。

 iPhone、Androidアプリを作りたい場合は、別途ライセンスがいる。
 iPhoneアプリを書き出すにはMac OSX snowleopard以上が必要。

・モデリングツール:
 Unityが対応しているソフトはMaya / 3DSMax / Blender / Cheetah3D。
 Blenderは無料で使えるのでオススメ。
 2.5になってUIが一新されてとっつきやすくなった。

 Mac版のみだが、Cheetah3Dも比較的安くてシンプルなUIで入門としては良さそう。
 ただ、うちの環境ではUnityにモデルを読み込むと軸が90度回転してしまう。
 (なにか設定がいる?)

・画像加工ソフト:
 PhotoShop。psdデータを直接Unityに読み込めます。

・スクリプトエディタ
 デフォルトのエディタはコードヒントが出ないので、他のエディタを使う。
 C#で開発するならUnity3.1にバンドルされているMonoDevelopがオススメ。

  jsで開発するならUnityDevelopFlashDevelopを改造したもの。
 ただし、Windows版のみ。
 Flasherならjsで始めると覚える事が少なくて楽チン。

 ただ、UnityにMonoDevelopがバンドルされているので、
 今後はC#に移行するのが良いかもしれない。


■覚えておくと便利なポイント

 ・Unityでは日本語を含んだパスはNG
  (最初、デスクトップに置いたサンプルファイルが開かなくて、ハマりました。。。)
 ・単位は1unit = 1mとして作る
 ・Fキーが異常に便利。選択したオブジェクトをフォーカスしてくれる
 ・Asset Storeが凄い
  (UnityのWindowメニュー> Asset Storeからアクセス)
 ・Unity3.0以前のデータを読み込むには最適化が必要
  (Unity2.6では問題なく動いていたものを3.0で開くとエラーが出ることがある)


■Flashから移行する時のポイント

 ・Hierarchy view =レイヤーパネル、Animation view = タイムラインパネル
 ・psdデータは直接読み込める
 ・jsだとActionScriptライク
 ・WindowsユーザーはUnityDevelop必須
 ・スクリプトはMonoBehaviorを継承している
 ・GameObject = DisplayObject、Prefabs = MovieClip、TextMesh = TextFieldと理解
 ・trace() = Debug.log()もしくは print()
 ・iTweenが便利。Tweenerみたいなもの
 ・スクリプト-オブジェクトの参照方法
 ・スクリプト-GameObject生成方法


■Unity関連リンク

 ・ドキュメント日本語化プロジェクト
  http://ws.cis.sojo-u.ac.jp/~izumi/Unity_Documentation_jp/Documentation.html
 ・コミュニティwiki
  http://www.unifycommunity.com/wiki/index.php?title=Main_Page
 ・フォーラム
  http://answers.unity3d.com/
 ・チュートリアル集
  http://www.design3.com/unity/
 ・スクリプトリファレンス
  http://unity3d.com/support/documentation/ScriptReference/20_class_hierarchy.html

2011年1月11日火曜日

MonoDevelop(Unity) for Macの日本語文字化けを直す

最近、3Dを扱うインタラクティブデモを作成するのにUnityを使い始めています。まだノウハウが無く、四苦八苦しながら学習している状態ですが…

このUnityですが、インストールするとMonoDevelopというエディタがついてきます。
MonoDevelopを起動すると、そのままの状態だとウェルカムスクリーン等、GUI上の日本語が文字化けしてしまいます。

Unityにバンドルされていない、普通のMonoDevelopであれば、/Library/Frameworks以下のファイルを変更すると直るようなのですが、UnityにバンドルされているMonoDevelopだけだと当該フォルダが生成されません。
参考サイト:[Mac][.NET]Mac OS X LeopardにMonoDevelopを入れたら文字化け、の対処法

代わりに、アプリのパッケージ内にそれに該当するものを持っているようです。
「パッケージの内容を表示」から見る事が出来ます。


普通のMonoDevelopと同じようなファイル構成になっているので、上記サイトを参考に日本語化を試した所うまくいかず…

どうやらGTKというツールキットを使用しているようなので、以下を参考にgtkrcファイル内のfont-nameというプロパティを変更してみました。
参考サイト:GIMPやInkscapeの文字化け対策


Contents/Frameworks/Mono.framework/Versions/Current/etc/gtk-2.0/gtkrc
を変更していきます。

font = "Lucida Grande 12"
の下に
font_name ="Hiragino Kaku Gothic Pro 10"

を追加します。
最後の数字は使用するフォントサイズのようなので、見やすいサイズに変更してください。
他の部分は変更しなくても良いようです。


これを保存し、MonoDevelopを起動するとウェルカムスクリーンが日本語化されている事が確認出来ると思います。


エディタの設定はこれで完了したので、後はfukusinさんに聞きながらちびちびやっていこうかな。

2011年1月10日月曜日

SCPluginを利用してGoogle Code(https)からチェックアウトする

会社で協同作業をする時は、Subversionをよく使います。導入してから、最新ファイルの共有とバージョン管理が格段に楽になりました。
SVNのクライアントと言えばTortoiseSVNが有名ですが、僕の作業環境はMacなので、Mac版のTortoiseSVNとも言えるSCPluginを使用しています。

現在公開しているSDLibraryもSVNを使用してGoogle Codeに公開しています。これをチェックアウトする場合、read-onlyであればhttpで問題ないのですが、編集しようとするとhttpsでの接続を要求されます。ですが、SCPluginからhttps接続でチェックアウトしようとしたら証明書エラーが出てしまいました。エラー内容は以下。
(画像は再現のために、適当なSSLを使用したサイトからチェックアウトしています)

OPTIONS of 'URL': Server certificate verification failed: issuer is not trusted(URL)
URLには接続先のアドレス(https://〜)が入ります

証明書のエラーという事でちょっとはまってしまったのですが、SCPluginのフォーラムにこの問題に対する解決策がありました。

http://scplugin.tigris.org/ds/viewMessage.do?dsForumId=1525&dsMessageId=2405274

かなり詳細に書かれているのですが、対処方法だけ抜粋すると

1.Terminalを開く
2."svn ls チェックアウトしたいリポジトリのアドレス"と入力、リターン。
3.証明書を認証するかどうかのプロンプトが出る(下記参照)
4."p"と入力、リターン(常に信頼)


となります。
一度承認が済めば、後はSCPluginから操作が可能になります。

2011年1月6日木曜日

[Kinectハック] SD_KinectIOをFlashで受ける

[Kinectハック] SD_KinectIO とりあえず公開でKinectからFlashへスケルトン情報を送るプログラムを公開していますが、それをFlashで受けるためのサンプルとライブラリも併せて作ってみました。



先のエントリでは人物のスケルトンモデルを表示するだけのデモを動かしていましたが、それと以前のオブジェクト移動のデモを合体させたサンプルを作成しています。

SD_KinectIOからは

"ユーザーID","部位ID","状態","x座標","y座標","z座標" (Null)

(例)
1,1,add,100.223,600.032,1534,302
1,1,update,140.344,632.323,1523,324
1,1,remove,0,0,0

ユーザーID:1~10
部位ID:1~24
状態:add,update,remove


というフォーマットで信号が送られてきます。

今回はスケルトン情報からFlash上にスケルトンモデルを表示させたいのですが、各ユーザーの各パーツがバラバラに送信されてくるので、それをFlashの方でユーザーごとにまとめてやる必要があります。
IDとパーツとの対応づけや、それを各ユーザーに割り振る処理は中々面倒そうだったので、今回もライブラリとしてまとめました。Google Code上のライブラリを更新していて、com.sdtech.kinect以下がそれに該当します。

・kinectパッケージ
・kinect.usersパッケージ

ひとまず、各オブジェクトをコンストラクタでインスタンス化していきます。


public function Main():void{
//
//ポインタ生成
mp=new MultiPointer(-1 , false);
mp.simulate=true;
mp.registerDefaultCursor(HandCursor);
addChild(mp);
//
//ボーン描画用
kmu=new KinectMultiUser();
kmu.mouseEnabled=kmu.mouseChildren=false;
addChild(kmu);
//
//FieldOfView設定
fov.addEventListener(Event.ENTER_FRAME , getFOV);
//
//接続開始
connect_btn.addEventListener(MouseEvent.CLICK , connectStart);
//
}


スケルトンモデルとボーン描画用のクラスのKinectMultiUserをインスタンス化し、以前も使用したPointerパッケージを組み合わせて使うため、同じようにインスタンス化します。また、3DのFieldOfViewを動的に変更出来るようにスライダーに、接続先を動的に変更出来るようにボタンにイベントを貼付けています。


private function connectStart(e:MouseEvent):void{
//
kc=new KinectConnector();
kc.addEventListener(Event.CONNECT , connectComplete);
kc.addEventListener(KinectEvent.RECEIVE , receiveKinectData);
kc.connect(ip.text , int(port.text));
//
}


接続ボタンが押されたら、SD_KinectIOに接続に行きます。受け取るデータは単なるプレーンテキストなのでXMLSocketで受け取っても問題ないのですが、今後特殊な仕様が追加される事を考えて、ここではKinectConnectorを使用しています。イベントリスナも専用の物を使用していますが、結局DataEvent.DATAと同じ処理になっているので、実はDataEvent.DATAを使用しても問題なかったりします。


private function receiveKinectData(e:KinectEvent):void{
//
//受け取ったデータをパースし、ボーンを描画
kmu.parseData(e.data);
//
for(var i:int=0 ; i<kmu.users ; i++){
//
//ユーザーを取得
var ku:KinectUser=kmu.getUserById(i);
if(!ku)continue;
//
//両手を取得
for(var n:int=0 ; n<2 ; n++){
//
//一意のIDを作成
var pointer_id:int=int(String(i+1)+(n+1));
//
var parts:KinectUserParts;
if(n==0){
parts=ku.getPartsById(KinectUserParts.R_HAND);
}else{
parts=ku.getPartsById(KinectUserParts.L_HAND);
}
//
if(!parts){
mp.lost(0,0,pointer_id);
continue;
}
//
//グローバル座標に変換
var p:Point=ku.local3DToGlobal(new Vector3D(parts.x , parts.y , parts.z));
//
//ポインタ認識
mp.detect(p.x,p.y , pointer_id);
//ポインタを動かす
mp.move(p.x,p.y,pointer_id);
if(parts.z>1500){
mp.down(p.x,p.y,pointer_id);
}else{
mp.up(p.x,p.y,pointer_id);
}
//
}
//
}
//
//
}


データを受け取ったらボーンを描画しますが、KinectMultiUserにはサーバーから受け取ったデータを渡すと自動的にボーンを描画してくれるparseDataというメソッドが実装されているので、ボーン描画部分はその一行で済んでいます。
内部的には、受け取ったデータをパースしてユーザーIDを取得し、まだ存在しなかったらユーザー追加、存在したらデータ更新、という何の変哲も無い処理になっています。

肝心のボーン描画部分は一行で済んでしまっていますが(笑)、これでFlash上にスケルトンモデルを描画する事が出来ました。

さて、ここから以前のようにオブジェクトを動かせるようにしていきます。


for(var i:int=0 ; i<kmu.users ; i++){
//
//ユーザーを取得
var ku:KinectUser=kmu.getUserById(i);
if(!ku)continue;
//
//両手を取得
for(var n:int=0 ; n<2 ; n++){
//
//一意のIDを作成
var pointer_id:int=int(String(i+1)+(n+1));
//
var parts:KinectUserParts;
if(n==0){
parts=ku.getPartsById(KinectUserParts.R_HAND);
}else{
parts=ku.getPartsById(KinectUserParts.L_HAND);
}
//
if(!parts){
mp.lost(0,0,pointer_id);
continue;
}
//
//グローバル座標に変換
var p:Point=ku.local3DToGlobal(new Vector3D(parts.x , parts.y , parts.z));
//
//ポインタ認識
mp.detect(p.x,p.y , pointer_id);
//ポインタを動かす
mp.move(p.x,p.y,pointer_id);
if(parts.z<1500){
mp.down(p.x,p.y,pointer_id);
}else{
mp.up(p.x,p.y,pointer_id);
}
//
}
//
}


まず、KinectMultiUserのusersプロパティで現在認識されている最大のユーザー数を取得し、各KinectUserインスタンスへの参照を取得します。各ユーザーの両手を認識したいので、さらにfor文で両手分処理を繰り返します。繰り返し処理の中は以前のエントリとほぼ同じですが、x,y座標は各ユーザーの両手の座標を使用したいので、各パーツ(KinectUserParts)の座標を使用します。また、今回はx,yに加えてz座標も加味する必要があるので、座標変換の時にlocalToGlobalでなくlocal3DToGlobaを使用しています。

これで、スケルトンモデル+オブジェクト操作で、スケルトンがオブジェクトを操作しているようなデモができました。
オブジェクトの操作について、現在は奥行きでDOWN/UPを判断していますが、手のひらの開閉が取れればもっと自然で良いんですけどね。C++は専門外なので、解析するにしても時間がかかりそうです…

ソースをダウンロード