アンドロイドでARのSDKを使ってみる
SATCH
SATCHをダウンロードしてインストール
Satch Studioを使ってコンテンツ作成
アプリ生成用の環境構築
サンプルアプリ生成
新規アプリ生成
New
AR Viewer Library for Android (satch_Android_jp.zip)が更新されました。
最新版の更新はこちらから
(ユーザー登録が必要です)
使用するには、ユーザー登録が必要です。
有償版と無償版があります、無償版ではアプリにスプラッシュとウォーターマークが表示されるようです。
結論から言うと、デプロイ時にエラーが発生し、まだ原因が特定できていません。
ログインページから新規登録ができます。
1:SATCHをダウンロードしてインストール
SATCH Developer site
Android用に2つダウンロードします。
AR Viewer Library for Android
Authoring Tool (SATCH Studio)
ダウンロード後、satch_Authoring_Tool_jp.zipを解凍して、SatchStudioSetup.exeを起動してインストールします。
以下のような画面になったら、ユーザー登録に設定した、IDとパスワードを入力して、Activateします。
インストールできたら、メニュのTotal immersionの中の「SatchStudio.exe」で起動。
2:Satch Studioを使ってコンテンツ作成
基本的な流れは、SATCHのDeveloper siteの開発ガイドを見れば、問題なくできます。
ただ、初めての場合、とまどう部分もあるので、その辺をフォローしてみます。
1.3.1で出てくる「Outliner(アウトライナー)」
1.3.2で出てくる「Object editor(オブジェクト・エディター)」
1.4の6で出てくる「Calibrate(キャリブレート)」
説明の流れでは、この場合カメラはPauseの状態のままですが、この場合うまくいきません。
リセットボタンを押しておく必要があります。
1.5.1で出てくる「Solution Explorer(ソリューション・エクスプローラー)」
1.7.2で出てくる「3Dビュー(ビューポート・ウィンドウ)へとドラッグ&ドロップ」
Satch Studioでは、コンテンツはこういう感じになります。
ターゲット(flyer)を見る角度が変わると、DemoRobotのスケールや角度も変わります、面白い。
ちなみに、コンテンツ作成の最終成果物は「シナリオ」と呼ばれる一連のファイル群です。
このシナリオを使って、アプリを作成します。
追記(2012/05/17)
SATCHで使える3Dモデルの作成は、3dsMaxかMayaだけだと思ってましたので自作はGive Upって感じでした。
(どっちもバカ高い、50万くらいする...)
でも、どうもマニュアルを読むと、D'Fusionのオブジェクト・レンダリングエンジンはOgreみたい。
で、Ogreモデルを作って、それを取り込めばいい....らしいのです。3dsMaxやMayaではなく、Google SketchUpで3Dモデルを
作成し、それをOgreモデルでexportできるプラグインがあるようだ.....。
要調査!
結果(2012/05/30)
どうやらいけるっぽいです。
ここを参照
SketchUpのモデルをSATCHで使う
3:アプリ生成用の環境構築
環境構築の仕方は
ここ「PhoneGapでネイティブアプリ」
に書いておいたままでいいようです。
さらに、Targetのパッケージはすべてインストールするようにしたほうが無難です(入らないものもありますが)。で、Accept all。
4・1:サンプルアプリ生成
まず、サンプルを使ってみます。
SATCH Developer siteのサンプルにある「Views」です。
ここでは、Google Mapsも使用されるので、まずEclipseのSDK Managerで Targetに「Google APi」のパッケージがインストールされているか
チェックしてください。
次に、GoogleのAPIキーを取得しておく必要があります。
取得方法はこのページを参照。
例えば、Windows XPの場合。
debug.keystoreを使いますが、場所は「C:¥Documents and Settings¥<ユーザー名>¥.android¥debug.keystore」です。
DOS窓(コンソール)で、Javaのkeytool.exeを使います。パスが通っていない場合は、JREのインストール先のbinフォルダに移動してください。
コンソールで以下のコマンドを実行。
>keytool -list -keystore "C:¥Documents and Settings¥<ユーザー名>¥.android¥debug.keystore"
パスワードを聞いてきますが、無視していいです。
例えば、「94:1E:43:49:87:73:BB:E6:A6:88:D7:20:F1:8E:B5:98」のようなものが表示されますが、これがMD5 Fingerprint です。
で、次にこのページに移動して、
下のほうにある空欄にFingerprintを入力して、「Generate API Key」ボタンをクリックすればいいです。
後は、サンプルの解説にあるとおりでいけます。
結果は、こんな感じ。
この状態でスマホを振ると色が変わります。
このソースを参考にして、自分のアプリを作ってみましょう。
4・2:新規アプリ生成
SATCHのDeveloper siteで公開されている、一番シンプルなアプリを作ってみます。
サンプルのオリジナルコードのままでは動かないと思います(多分)、ちょっと変更が必要。
(1)Eclipseを起動して、プロジェクトを新規に作成
File -> New -> Other
Android -> Android Project
プロジェクト名は「Tutorial」。
Project Name -> Tutorial
Build Target -> Android 2.3.3
Package Name -> com.kddi.satch.tutorial
プロジェクトの"assets"フォルダにScenarioフォルダーを作成、その中に作成済みのScenario_aフォルダーをコピー。
前にダウンロードした、AR Viewer Library for Android (satch_Android_jp.zip)を解凍。
プロジェクトに"libs"フォルダを作成し、satch.jarをコピー。
"libs"フォルダ内に"armeabi"フォルダを作成し、libsatchAnrdoid.soとlibtiAndroidAR2.soをコピー。
プロジェクトをRefresh。
satch.jarを右クリックしてビルドパスを通します。
Build Path -> Add to Build Path
(2)AndroidManifest.xmlを編集
<Activityに以下を追加
android:screenOrientation="landscape"
android:configChanges="orientation|keyboard|keyboardHidden"
</application>の下に以下を追加
<!-- 画像解像度を設定します -->
<supports-screens
android:anyDensity="false"
android:normalScreens="true"
android:largeScreens="true"
android:smallScreens="true"
android:resizeable="true">
</supports-screens>
<!-- カメラ機能、ライセンス認証で利用するパーミッションを許可します -->
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!-- オートフォーカスを設定します -->
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-sdk android:minSdkVersion="7" />
(3)プロジェクトにパッケージを追加
File -> New -> Package
Name -> com.kddi.satch.tutorialactivity
このパッケージに、抽象クラスを作成。
com.kddi.satch.tutorialactivityを選んで、
File -> New -> Class
Name ->TutorialActivity_simple
Modifiers -> Public/abstract
コードはサンプルのまま、以下の通り。
【TutorialActivity_simple.java】
package com.kddi.satch.tutorialactivity;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Bundle;
import android.os.Handler;
import android.view.KeyEvent;
import android.view.View;
import android.widget.FrameLayout;
import com.kddi.satch.LoadScenarioStatus;
import com.kddi.satch.ARViewer;
public abstract class TutorialActivity_simple extends Activity {
protected abstract String getSampleScenarioName();
protected abstract String getSampleLogTag();
protected boolean _isInitializedCorrectly;
protected ARViewer _kddiComponent;
protected FrameLayout _frameLayout;
public void resetMembers(){
_isInitializedCorrectly = false;
_frameLayout = null;
_kddiComponent = null;
}
private static final int DIALOG_EXIT = 0;
public void initComponent(){
_isInitializedCorrectly = false;
_kddiComponent = new ARViewer(this);
// This FrameLayout must be empty (but initialized) when you pass it to the kddiComponent.initialize() method.
_frameLayout = new FrameLayout(this);
_kddiComponent.initialize(_frameLayout);
_isInitializedCorrectly = true;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Add null to AR Viewer Library compornent's reference.
resetMembers();
}
@Override
public void onRestart() {
super.onRestart();
}
@Override
public void onStart() {
super.onStart();
// Create AR Viewer Library compornent.
initComponent();
postInitComponent();
initContentView();
if (_isInitializedCorrectly) {
// Do authorize and madia is loaded.
// You must call loadScenario() method.
loadScenario();
}
}
@Override
public void onResume(){
super.onResume();
if (_isInitializedCorrectly) {
// GL context is recreated and media is reloaded.
_kddiComponent.onResume();
reservePlayScenario();
}
}
@Override
public void onPause() {
// When the activity is paused the GL context is destroyed, so all media is unloaded.
if (_isInitializedCorrectly) {
cancelReservePlayScenario();
if (_kddiComponent.checkLoadScenarioStatus() == LoadScenarioStatus.COMPLETE) {
_kddiComponent.pauseScenario();
}
_kddiComponent.onPause();
}
super.onPause();
}
@Override
public void onStop() {
releaseContentView();
// Destroy AR Viewer Library Objects.
if (_isInitializedCorrectly){
_kddiComponent.terminate();
_kddiComponent = null;
_frameLayout = null;
}
super.onStop();
}
@Override
public void onDestroy() {
// Destroy AR Viewer Library Objects.
if (_isInitializedCorrectly){
_frameLayout = null;
_kddiComponent = null;
}
super.onDestroy();
resetMembers(); // forced clean
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent msg){
switch(keyCode){
case android.view.KeyEvent.KEYCODE_BACK :
showDialog( DIALOG_EXIT );
return true;
}
return false;
}
public void postInitComponent(){
// override this if you need to do some special handling on the component after standard initialization
if (_isInitializedCorrectly) {
_kddiComponent.activateAutoFocusOnDownEvent(true);
}
}
public void initContentView(){
// override this if you need to do some special handling on the component after standard initialization
if (_isInitializedCorrectly) {
// you'll probably use some other UI object as the content view that itself will embed the component's frame layout -- here you can change all this
// by default, the frame layout containing DFusion will be the activity content view
setContentView(_frameLayout);
}
}
public void releaseContentView(){
// override this if you need to do some special handling on the component after standard initialization
if (_isInitializedCorrectly) {
// do here the release of the your UI instances (if customized)
}
}
public void loadScenario(){
ApplicationInfo appInfo = null;
PackageManager packMgmr = getApplicationContext().getPackageManager();
try {
appInfo = packMgmr.getApplicationInfo(getPackageName(), 0);
} catch (NameNotFoundException e) {
e.printStackTrace();
throw new RuntimeException("Unable to locate assets, aborting...");
}
String dpdfile = appInfo.sourceDir + getSampleScenarioName();
_kddiComponent.loadScenario(dpdfile);
}
// Set polling rate for loading the media.
private final int REPEAT_INTERVAL = 100;
private Handler handler = new Handler();
private Runnable runnable = null;
//
private void reservePlayScenario(){
if (runnable == null){
runnable = new Runnable(){
@Override
public void run(){
LoadScenarioStatus status = _kddiComponent.checkLoadScenarioStatus();
if (status == LoadScenarioStatus.CANCEL){
// cancel(appli suspend)
}else if (status == LoadScenarioStatus.COMPLETE){
// Ready to play scenario
_frameLayout.setVisibility(View.VISIBLE);
_kddiComponent.playScenario();
}else if (
status == LoadScenarioStatus.ERROR_NETWORK_UNUSABLE ||
// faild to load a media becase of no network connection.
status == LoadScenarioStatus.ERROR_NETWORK ||
// faild to load a media becase of network error.
status == LoadScenarioStatus.ERROR_SOFTWAREKEY ||
// faild to load a media becase software key has not be found on server.
status == LoadScenarioStatus.ERROR_CONTENT_STOPPED ||
// faild to load a media becase content has stopped.
status == LoadScenarioStatus.ERROR_SERVER ||
// faild to load a media becase of server error.
status == LoadScenarioStatus.ERROR_ETC
// faild to load a media becase of another error.
){
// error
}else{
handler.postDelayed(this, REPEAT_INTERVAL);
}
}
};
handler.postDelayed(runnable, REPEAT_INTERVAL);
}
}
//
private void cancelReservePlayScenario(){
if (handler != null && runnable != null){
handler.removeCallbacks(runnable);
runnable = null;
}
}
protected Dialog onCreateDialog(int id) {
Dialog dialog;
switch(id) {
case DIALOG_EXIT:
{
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage(
"Really want to quit the sample?"
)
.setCancelable(true)
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
finish();
}})
.setNegativeButton("No", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
}});
dialog = builder.create();
break;
}
default:
dialog = null;
}
return dialog;
}
}
既存のTutorialActivity.javaを上の抽象クラスを継承するコードに書き換えます。
下の赤字の部分が変更点です。
sample.dpdは作成時、小文字のファイル名になっている...と思います。
【TutorialActivity.java】
package com.kddi.satch.tutorial;
import com.kddi.satch.tutorialactivity.TutorialActivity_simple;
public class TutorialActivity extends TutorialActivity_simple{
private static final String THIS_CLASS_SHORT_NAME = TutorialActivity.class.getName().replace("com.kddi.satch.tutorial.", "");
private static final String THIS_LOGTAG = THIS_CLASS_SHORT_NAME;
// Set AR scenario file path.
private static final String SCENARIO_NAME = "/assets/Scenario/Scenario_a/sample.dpd";
protected String getSampleScenarioName() { return SCENARIO_NAME; }
protected String getSampleLogTag() { return THIS_LOGTAG; }
@Override
public void postInitComponent(){
super.postInitComponent();
}
}
(4)アプリを登録する
コーディングは以上ですが、このままでは動きません。
実機で動かそうとすると以下のようなライセンス・エラーになります。
SATCH Developer siteのマイページに移動。
New(2012/09/19)
レギュレーションが変わりましたので修正しておきます。
新規の場合、アプリ追加ボタンをクリックします。
最低限、必要な項目は以下の通り。
●対象OS
Android/iOS
●アプリ名称
適当に
●公開範囲
とりあえずは非公開
●アプリアID
マイページに戻って、「コンテンツ一覧」をクリックします。
「コンテンツ追加」ボタンをクリックします。
アプリ名称を確認して、コンテンツ名称を記入して、署名ファイルを選びます。
sample.dpd.dfkファイルです。
登録ボタンをクリックすると、署名ファイルのダウンロード画面が出てきます。
ファイルをダウンロードして、assets/Scenario/Scenario_a/sample.dpd.dfkに上書きしてください。
以上でアプリ生成完了。
こんな、感じです。
サンプルのトラッキング画像は印刷すると、A4に収まるサイズですが、カメラは60cm位の距離でも検出できるようです。
それ以上離れると難しいみたい。一度検出すれば、かなり離れていてもトラックできますが、一度ロストするとダメみたい。
再度接近して検出し直しましょう。
動作確認:docomo Xperia acro
別途、1000円札検出もやってみました。
TOP
metaioのMobile SDKを使ってみる
このウォーターマークが結構大きいようで、製品アプリを作ろうとする場合は邪魔になります。
まあ、ここでは製品アプリをつくる気はないので無償版を使います(有償版だと結構なお値段しますです..はいTT)。
Mobile SDKのページ
SDKをダウンロードしましょう...と思ったのですが、最初はどこにあるか戸惑います。
ダウンロード用のリンクが見当たらない。
あれこれ探してようやく分かりました。まず「Free Full Version」のボタンをクリック。
Dear Customers.....というダイアログが出ます。
で、このダイアログをスクロールダウンして最後まで行くと、メールアドレスを入れるフィールドと「Agree」のボタンがあります。
メールアドレスを入れて、Agreeをクリックすると、ダウンロードリンクの書かれたメールが送られます。
これをクリックするとダウンロードが開始されます。
57MBくらいの結構なサイズのファイルです。
Under construction
Next
junaioを使ったアルファチャンネル入り動画の再生をやってみる....予定。
TOP
QUALCOMMのVuForiaを使ってみる
まあ、そこに至るまでの顛末をレポートします。
QUALCOMMのVuForiaを使用するには、
Eclipse + Android SDK + ADT + Cygwin(Windowsの場合) + Android NDKの環境が必要。
環境構築の仕方は
ここ「PhoneGapでネイティブアプリ」
と
ここ「アンドロイドでOpenCV(特徴点検出)」
に書いておきました。
VuForiaもSATCHと同じで、ユーザー登録が必要です。
SDKのページから新規登録ができます。
右上の「Register」ボタンをクリックしてパスワード取得。
IDはメールアドレスになります。
「vuforia-sdk-android-1-5-9.exe」と「vuforia-unity-android-1-5-10.exe」をダウンロード。
vuforia-sdk-android-1-5-9.exeをダブルクリックしてインストール。
デフォルトでは、「C:¥Development¥Android」の中にインストールされます。
サンプルを使ってみます。
「C:¥Development¥Android\vuforia-sdk-android-1-5-9¥samples」にあります。
まず、適当なプロジェクトをNDKでビルドします。
CygwinのTerminalを起動。
例:
$cd /cygdrive/c/Development/Android/vuforia-sdk-android-1-5-9/samples/ImageTargets
$ndk-build
Eclipseを起動して、「ImageTargets」をインポート。
ImageTargetsを右クリック-->Properties-->Android-->Android 2.3.3をtargetにする。
mageTargetsを右クリック-->Android Tools-->Fix Project Properties
genフォルダーが作成されます。
以下のようなエラーがでる...はず。
Unbound classpath variable: 'QCAR_SDK_ROOT/build/java/QCAR/QCAR.jar' in project 'ImageTargets' ImageTargets
再度、ImageTargetsを右クリック-->Properties-->Java Build Path-->Libraries
QCAR_SDK_ROOTに問題があるようなので....。
以下のようにEditします
Variableをクリック。
Variable Selectionで「QCAR_SDK_ROOT」をRemoveして、次にNewをクリック。
New Variable Entryで、
Nameに「QCAR_SDK_ROOT」、
Pathには「C:¥Development¥Android¥vuforia-sdk-android-1-5-9¥build¥java¥QCAR¥QCAR.java」
Edit Variable Entryで、「QCAR_SDK_ROOT」。
これで、見た目のエラーは出なくなる...はず。
でも実機に送ると...
なんでやねん(TT;
TOP