ActionScript 3.0 , AIR , FLEXからCocoa, OpenGL
24 Dec
このエントリはOpenNI Advent Calendar 2011 : ATNDの12月24日分です!!

最近話題になっている、ゲームの開発環境のUnity3Dというものがあり、OpenNIのサイトからUnity3Dで使うためのUnityWrapperをダウンロードできます。

Unity3D ( http://unity3d.com/unity/ ) とはゲーム開発ツールであり、WindowsとMacのどちらでも開発する事が可能です。
IDEがあるのでステージの画面を見ながら次々とオブジェクトを配置するだけでゲームの世界を簡単に作る事ができます。
プログラムはJavascriptとC#(mono)で書く事ができるのでweb開発者や.NETの開発者にも取っ付きやすいのではないでしょうか。
MacでもC#で記述する事ができます。
また、一人でグラフィックやサウンドやモデリング、プログラムを行うのは大変ですが、Unity3DではAsset Storeというものが用意されており、これを利用する事で必要な素材を入手する事ができるので気軽にゲーム開発を進める事ができます。
無料版と有料版があり、無料版では制限はいくつかありますが、WindowsとMacで実行できますし、有料版にアップグレードする事でAndroidやiOSに対応させる事も可能です。
詳しいライセンスなどはUnity3Dのサイト( http://unity3d.com/unity/licenses )か、「強火で進め」さまのサイトが詳しいです。( http://d.hatena.ne.jp/nakamura001/20110710/1310292561 )
それでは、Unityをダウンロードしましょう。
http://unity3d.com/unity/download/より、Unityをダウンロードし、流れに沿ってインストールしてください。
インストール後、先ほどOpenNIのサイトからダウンロードしたファイル(Unity OpenNI toolkit 0.9.7.1.unitypackage )をダブルクリックしImport Packageより一式をunityにインポートします。
importが完了すると、Projectタブにこのようなファイル群が表示されます。

OpenNI/Sample Scenes以下にすぐに試せるようなサンプルシーンが入っていますのでダブルクリックしてシーンを開き、三角の再生ボタンを押して次々と試してみるとUnity3D+OpenNIの可能性を試せると思います。

私はライブなどで使ったりしていますが、骨格をちゃんと映していれば問題なく現場でも使えます。今のUnityWrapperだと全身映す前提のコードになっているので、上半身だけ認識などに変更する事でより柔軟なアプリケーションが開発できます。
ではそれぞれのサンプルのキャプチャやサンプル動画をのせておきます。
せっかくなのでスケルトンをサンタにかえてみましたよ。サンタ気分で小さく踊ってみました。
あ、サンタのデータはAsset Storeで購入可能ですよ!
※この記事は、下記の環境で確認しました。
| OpenNI | 1.5.2.7 |
| NITE | 1.5.2.7 |
| Unity3D | 3.4.2f3 |
24 Dec
このエントリはOpenNI Advent Calendar 2011 : ATNDの12月23日分です!!

OpenframeworksでOpenNIの連携について書きます。
Openframeworks ( http://www.openframeworks.cc/ )(以下、oF)とは、メディアアート界隈で使われている描画や動画の扱いやプログラムの書き方がprocessingっぽく作られている、クロスプラットフォームで動作するC++のフレームワークです。
oFはたくさんの有志により様々なアドオンが配布されており、それを使うとソケットやOSC、OpenCVなどの機能を簡単に使う事ができます。
oFで使えるKinect関連のアドオンがいくつか、下記のものがあります。
・ofxKinect: ( https://github.com/ofTheo/ofxKinect )
→深度情報とRGBが取得できます。スケルトンの取得機能はありません。
・ofxOpenNI:( https://github.com/gameoverhack/ofxOpenNI )
→OpenNIをoFで使えるように作ったもの。
ただ、OpenNI自体バージョンアップが早い事もあるので今回は普通のOpenNIをoFで使う方法を紹介します。
oFのWebサイトから必要なファイルをダウンロードします。私の場合はMacなのでosxバージョンをダウンロードします。
http://www.openframeworks.cc/download/
ダウンロードしたファイルを解凍すると下記のフォルダ構成になっています。
では、oFの基本を理解するために EmptyExampleをみてみます。
testApp.cppをみてみましょう。
はじめに定義されているメソッドの実装を進めて開発を進めます。
基本的にはこれらを使うのですが、マウスやキーボードのユーザー入力にも対応しています。
今回はとにかく簡単に使えるようになる事を考えて説明します。
まず、OpenNIのIncludeとLibフォルダをプロジェクト直下に”OpenNI”というフォルダを作成し、そこに移動します。
次にプロジェクトにヘッダー参照パスとライブラリパスの設定をします。
プロジェクト設定の “Build Settings” → “Search Paths”の
Header Search Pathsに以下を設定します。
“$(SRCROOT)/../OpenNI/Include
Library Search Pathsに以下を設定します。
“$(SRCROOT)/../OpenNI/Lib
※設定後、自動的に別の項目に変更される場合がありますが、ビルドが通れば問題はありません。
私の環境では、
HEADER_SEARCH_PATHS_QUOTED_FOR_TARGET_1
LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_1
の項目が追加されていました。
さて、それではOpenNIのコードを書いてみましょう。NiSimpleViewerをパク、、いやもとにして、深度情報を表示させてみましょう。
表示にはoFTextureクラスを使い、テクスチャとして表示させます。
今回は簡単に移植するため、NiSimpleViewerからコピペする事にします。
まず、
testApp.hに下記を追加します。
#include <XnCppWrapper.h> using namespace xn;
//--------------------------------------------------------------------------- // Defines //--------------------------------------------------------------------------- #define SAMPLE_XML_PATH "../../../data/SamplesConfig.xml" #define DISPLAY_MODE_DEPTH 2 #define DEFAULT_DISPLAY_MODE DISPLAY_MODE_DEPTH #define MAX_DEPTH 10000
SamplesConfig.xmlはbin/data/以下に設置したため、
SAMPLE_XML_PATHを変更しています。
——-
testApp.cppに”Globals”の内容をもとに移植します。
//--------------------------------------------------------------------------- // Globals //--------------------------------------------------------------------------- float g_pDepthHist[MAX_DEPTH]; XnRGB24Pixel* g_pTexMap = NULL; unsigned int g_nTexMapX = 0; unsigned int g_nTexMapY = 0; unsigned int g_nViewState = DEFAULT_DISPLAY_MODE; Context g_context; ScriptNode g_scriptNode; DepthGenerator g_depth; DepthMetaData g_depthMD;
——–
NiSimpleViewerのmain関数が初期化に関する内容なので、setupに移植します。
XnStatus rc;
EnumerationErrors errors;
rc = g_context.InitFromXmlFile(SAMPLE_XML_PATH, g_scriptNode, &errors);
if (rc == XN_STATUS_NO_NODE_PRESENT)
{
XnChar strError[1024];
errors.ToString(strError, 1024);
printf("%s\n", strError);
return ;
}
else if (rc != XN_STATUS_OK)
{
printf("Open failed: %s\n", xnGetStatusString(rc));
return;
}
rc = g_context.FindExistingNode(XN_NODE_TYPE_DEPTH, g_depth);
if (rc != XN_STATUS_OK)
{
printf("No depth node exists! Check your XML.");
return;
}
g_depth.GetMetaData(g_depthMD);
// Texture map init
g_nTexMapX = (((unsigned short)(g_depthMD.FullXRes()-1) / 512) + 1) * 512;
g_nTexMapY = (((unsigned short)(g_depthMD.FullYRes()-1) / 512) + 1) * 512;
g_pTexMap = (XnRGB24Pixel*)malloc(g_nTexMapX * g_nTexMapY * sizeof(XnRGB24Pixel));
——-
setup関数の最後にofTextureクラスとofTextureで表示させるためのunsigned char*のデータをを初期化します。
pixels = (unsigned char*)malloc(640*480*3*sizeof(unsigned char)); tex.allocate(640, 480, GL_RGB);
——-
OpenNIでのデータを更新する処理をupdateに移植します。
XnStatus rc = XN_STATUS_OK;
// Read a new frame
rc = g_context.WaitAnyUpdateAll();
if (rc != XN_STATUS_OK)
{
printf("Read failed: %s\n", xnGetStatusString(rc));
return;
}
g_depth.GetMetaData(g_depthMD);
//g_image.GetMetaData(g_imageMD);
const XnDepthPixel* pDepth = g_depthMD.Data();
// Calculate the accumulative histogram (the yellow display...)
xnOSMemSet(g_pDepthHist, 0, MAX_DEPTH*sizeof(float));
unsigned int nNumberOfPoints = 0;
for (XnUInt y = 0; y < g_depthMD.YRes(); ++y)
{
for (XnUInt x = 0; x < g_depthMD.XRes(); ++x, ++pDepth)
{
if (*pDepth != 0)
{
g_pDepthHist[*pDepth]++;
nNumberOfPoints++;
}
}
}
for (int nIndex=1; nIndex<MAX_DEPTH; nIndex++)
{
g_pDepthHist[nIndex] += g_pDepthHist[nIndex-1];
}
if (nNumberOfPoints)
{
for (int nIndex=1; nIndex<MAX_DEPTH; nIndex++)
{
g_pDepthHist[nIndex] = (unsigned int)(256 * (1.0f - (g_pDepthHist[nIndex] / nNumberOfPoints)));
}
}
xnOSMemSet(g_pTexMap, 0, g_nTexMapX*g_nTexMapY*sizeof(XnRGB24Pixel));
// check if we need to draw depth frame to texture
const XnDepthPixel* pDepthRow = g_depthMD.Data();
XnRGB24Pixel* pTexRow = g_pTexMap + g_depthMD.YOffset() * g_nTexMapX;
for (XnUInt y = 0; y < g_depthMD.YRes(); ++y)
{
const XnDepthPixel* pDepth = pDepthRow;
XnRGB24Pixel* pTex = pTexRow + g_depthMD.XOffset();
for (XnUInt x = 0; x < g_depthMD.XRes(); ++x, ++pDepth, ++pTex)
{
int idx = (x + y * g_depthMD.XRes()) * 3;
if (*pDepth != 0)
{
int nHistValue = g_pDepthHist[*pDepth];
pixels[idx] = nHistValue;
pixels[idx+1] = nHistValue;
pixels[idx+2] = nHistValue;
}
else
{
pixels[idx] = 0;
pixels[idx+1] = 0;
pixels[idx+2] = 0;
}
}
pDepthRow += g_depthMD.XRes();
pTexRow += g_nTexMapX;
}
tex.loadData(pixels, 640, 480, GL_RGB);
ofTextureのloadDataメソッドを使い、深度データをテクスチャとして読み込ませます。
——
最後にdrawメソッドにofTexetureのdrawを使って実際に描画します。
引数は、x座標、y座標、幅、高さを示しています。
—–
これでビルドすると表示できるようになります。
たくさんの警告はありますが、ライブラリ内部的なものもあるので無視する事にします。

ファイル一式をこちらにアップしましたのでダウンロードして試してみてください。
https://github.com/mmlemon/OpenNI_Advent_oFSample
※OpenNIは1.4.0.2、oFは007で記述しています。
15 Nov
iOSアプリの開発で、adlantisの広告を入れて試すにはlibz.dylibが必要なのですが、プロジェクトにファイルを追加するのを横着して、間違ってsdk4.3のものを追加してしまった後、ビルドするとわけのわからないエラーが出て、どれだけ戻してもエラーが解消されなかったのですが、下記の画像のように Library Search Pathsに赤枠の”DeviceSupport/4.3.5″が追加されていることが原因でした。
これが現行のsdkと衝突して問題を起こしていたのかな?

この赤枠の参照を外すと無事動作するようになりました。
5 Sep
時間が空いてしまいました。
さて、今回はCSS3アニメーションをjavascriptで設定、制御する例を残しておきます。
CSS3アニメーションはSafari(Windowsは未検証)、Mobile SafariではプロパティによってはGPUで動作するため、通常のアニメーションと比較すると非常に滑らかに動作します。
例えば矩形を動かしてみましょう。
css3アニメーションサンプル(webkit用) – jsdo.it – share JavaScript, HTML5 and CSS
idがrectであるdivをアニメーションさせています。
@-webkit-keyframes rectanimation
{
0%{
-webkit-transform: translate(0px, 0px) scale(0.5);
}
30%{
-webkit-transform: translate(300px, 200px) scale(2);
}
100%{
-webkit-transform: translate(300px, 100px) scale(1.0);
}
}
#rect
{
background-color: #f00;
width: 100px;
height: 100px;
-webkit-animation-name: rectanimation;
-webkit-animation-duration: 1400ms;
-webkit-animation-iteration-count: 100;
-webkit-animation-timing-funciton: ease-in-out;
}
では、これと同じコードをjsで書いてみましょう。せっかくなので、onclickでアニメーションを起動させてみましょう。
基本的には通常のcss->jsのルールと同様です。
CSS3アニメーション(javascriptで制御) – jsdo.it – share JavaScript, HTML5 and CSS
var tar = document.getElementById("rect");
tar.style.webkitAnimationName = kfname;
tar.style.webkitAnimationDuration = "1400ms";
tar.style.webkitAnimationIterationCount = 100;
tar.style.webkitAnimationTimingFunction = "ease-in-out";
1 Jul
タイトルの通りなんですが、会社を退職し、再びフリーランスとして活動することになりましたのでご報告致します。
先日までおよそ3年半、会社員としてつとめさせていただき、そのときはまだまだ力不足で御迷惑をかける事もありましたし、自分なりに悩んだり苦労したりという事もありました。
ただ、結果的には控えめというか、「おれはすごい」なんて思える性格ではない僕でも少しは成長もできたのではないかと思っています。
また、仕事の面では今まで想像もつかなかったような面白い仕事を沢山経験させていただきました。
おかげさまで今までだったらただビックリするだけの様な新しいものをみて憧れだけじゃなく実装方法や技術の活かし方まで意識できるようになりました。
また、性格を理解していただいて仕事しやすいように進めていただいた皆様にも感謝しております。
今後は人が触りたくなる、体験したくなるようなアプリって何だろう?という事を考えつつ作って行ければと考えています。
皆様今後ともよろしくお願いします。
※お仕事絶賛募集中です!よろしくお願いします1
17 May
OpenGLでは画像をテクスチャとしてマッピングする事が多々あるとは思うのですが、やり方を残しておきます。
なお、これはC++のプロジェクトを使った場合で、Cocoaは使えない状況を想定しています。
画像の読み込みには、OpenCVを使いました。ただし、IplImageはRGBではなく、BGRの順番で色データを格納しているので注意が必要です。
// IplImageとして画像をロード
IplImage* image = cvLoadImage("/events/mo1.png");
int w = image->width;
int h = image->height;
int channels = image->nChannels;
GLubyte* imageData = (GLubyte*)malloc(w*h*channels);
for(int i = 0; i < w*h*channels; i+=channels)
{
imageData[i] = image->imageData[i+2]; // R
imageData[i+1] = image->imageData[i+1]; // G
imageData[i+2] = image->imageData[i]; // B
if(channels > 3)
{
imageData[i+3] = image->imageData[i+3]; // Aが存在する場合
}
}
以上で画像データをOpenGLで使える形式に読み込む事ができました。
次に、テキスチャとしてバインドします。
// テキスチャの生成
glGenTextures(1, &g_imageTex);
// テキスチャと変数をバインド(関連付け)
glBindTexture(GL_TEXTURE_2D, g_imageTex);
// 各種フィルタの設定
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
// 実際のテキスチャを設定
glTexImage2D(GL_TEXTURE_2D, // テキスチャの種類。
0, // level: 解像度が単一の場合は0
GL_RGB, // どの成分が画像のテクセルに使用されているか
w, h, // サイズ
0, // border: 境界の幅
GL_RGB, // 描画フォーマット
GL_UNSIGNED_BYTE, // データの型
imageData // 実際のデータ
);
実際にテキスチャを表示させる処理。(display関数内部)
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glEnable(GL_TEXTURE_2D);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
//glBindTexture(GL_TEXTURE_2D, texName);
glBindTexture(GL_TEXTURE_2D, g_imageTex);
glBegin(GL_QUADS);
// OpenGLの座標とテキスチャの座標をマッピングする
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 0.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, -1.0f, 0.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, -1.0f, 0.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, 1.0f, 0.0f);
glEnd();
glFlush();
glDisable(GL_TEXTURE_2D);
13 Jul
連続Postですみません。
最近WordPress上でアップデートが可能になってとても便利だな〜なんてのんびり喜んでいたのですが、google analysisのプラグインの設定が消えてしまう、という問題が起こりました。
実際このサイトは誰が見ているんだろう、という位なのでpvとかあまり意識していなかったのですが、ある日を境にアクセス数が0になってたので、さすがにこれはおかしいと思い調べてみると、UA-00000-0というような値になってしまっていました。。。。
メニュー下部のここをクリックして設定を確認してみるとよいと思います。
1 Jul
かなり投稿回数が少なくなってしまっているブログですが、つい先日までは本業で時間をいっぱいいっぱい使ってて、全く動けない状態でした。
だけど、これからは時間ができたのでiPhone開発合宿の予定を再調整したいです。http://123.writeboard.com/8464cc38ec43064f5 pass:ipdc09
とてもありがたいことに今月は結構休みを頂けることになったので、この間にflashとiPhoneの一人合宿?も行って成長しないと!
1 May
自分への備忘録的なメモです。
iPhoneアプリ開発で、sqliteに対してFMDataBaseを使う場合、
select : executeQuery
他(delete, update, create table, insert..) : extecuteUpdate
です。
さっき間違って使っていて、[db close]しようとするとそこでロックしたような状態で動かなくなってしまいました。
1 May
結構前になってしまうのですが、4/18-4/19の2日間、湯河原にてiPhoneアプリ開発合宿#2を行いました。
メンバーは、kara_dさん、gnueさん、allnightappsさん、kirara_397さんと僕(mmlemon)の5名で、幹事はkara_dさんでした。
宿泊先近辺はこんな感じです。

宿泊地の岩本旅館。とても風情のあるところでした。


今回は当然ですが、ネット(e-mobile)が使える環境でした。
今回も各自自分の作りたいアプリを作るという形式で、実際にアプリを作られて操作感などをテストされていた方、ウェブと連携させるアプリを作られている方で、サーバー側のロジックを作られた方、またはiPhone OS 3.0の機能について技術調査されていた方、これから作ろうとするアプリのコンセプトを考えるかた、と本当に一人一人がいろんな事をやっていて日頃一人で開発している時はあまり意識していなかったところに気づかされることもあり、大変有意義な時間を過ごす事ができました。
僕はというと、最近どはまりしていたところがあったのですが、allnightappsさん、gnueさんの力を借りて簡単に解決できました。
やっぱりこうやって同じところに集まって合宿することは明日からも頑張ろう!という良い刺激にもなるし、合宿の日までに或る程度形にしないといけない!と自分を追い込むこともできるので、これからも続けたいな、と思いました。
で、月も変わった事ですので、第三回の予定を立てようと思います。
http://123.writeboard.com/8464cc38ec43064f5/v/show/6745677
pass: ipdc09
です。
ご興味もたれた方はtwitterのアカウントなどご連絡先などを添えて追記して下さい。
あるいは、twitterで@mmlemonまでDMいただければと思います。