次に3Dモデルを描画、アニメーションさせる処理を行います。ここで行うeruptionの主な処理は以下のようになります。
それでは、ソースコードを確認してみます(ソース2)。
boolean drawEruption(eruption1* pMe){
uint32 now_time; // 現在の経過時間
hi_exception exception; // 例外処理
// 変換行列の計算用
mceTransform matrix;
mceTransform matrix2;
mceVector3D rotate;
now_time = ISHELL_GetUpTimeMS(pMe->Applet.m_pIShell);
if((now_time - pMe->OldTime) > UPDATE_TIME){
pMe->OldTime = now_time; //時間更新
// 背景クリア
exception = mceGraphics3D_clear(pMe->G3d, MCE_GRAPHICS3D_CLEAR_DEPTH |
MCE_GRAPHICS3D_CLEAR_COLOR, 0x00808080);
if (exception != hi_NoException){
return FALSE;
}
// カメラ設定 透視投影の設定
exception = mceCamera_setPerspectiveFov(pMe->Camera, pMe->AspectRate,
pMe->ViewAngle / ANGLE, pMe->NearClip, pMe->FarClip);
if (exception != hi_NoException){
return FALSE;
}
// デフォルトカメラの設定
exception = mceGraphics3D_setCamera(pMe->G3d, pMe->Camera, NULL);
if (exception != hi_NoException){
return FALSE;
}
// モデル描画 モデル平行移動
mceTransform_setTranslate(&matrix, MCE_F2C (0.0f), MCE_F2C (0.0f), MCE_F2C (-50.0f));
// モデル回転量の更新
pMe->ObjRy += MCE_F2C(0.6f);
pMe->ObjRx += MCE_F2C(0.6f);
// モデルX軸回転
mceVector3D_set(&rotate, MCE_F2C (1.0f), MCE_F2C (0.0f), MCE_F2C (0.0f));
mceTransform_setRotate(&matrix2, &rotate, pMe->ObjRx / ANGLE);
mceTransform_multiply(&matrix, &matrix2);
// モデルY軸回転
mceVector3D_set(&rotate, MCE_F2C (0.0f), MCE_F2C (1.0f), MCE_F2C (0.0f));
mceTransform_setRotate(&matrix2, &rotate, pMe->ObjRy / ANGLE);
mceTransform_multiply(&matrix, &matrix2);
// モデルにのみ変換行列を掛ける
mceNodeDeformerNode_setTransform(pMe->Fig_model, &matrix);
// mceFigureの描画
exception = mceGraphics3D_drawFigure(pMe->G3d, pMe->Figure, NULL, 0);
if (exception != hi_NoException){
return FALSE;
}
// 描画完了処理
exception = mceGraphics3D_flush(pMe->G3d);
if (exception != hi_NoException){
return FALSE;
}
// EGLサーフェースカラーバッファをネイティブウィンドウに転送
mceGraphics3D_swapContext ();
}
// 指定時間後に自身を呼び出す
CALLBACK_Init(&pMe->Callback, (PFNNOTIFY)drawEruption, pMe);
ISHELL_Resume(pMe->a.m_pIShell, &pMe->Callback);
return TRUE;
}
| ソース2 eruptionの主な処理に関するソースコード |
描画更新と回転角度設定用のマクロを定義します。
#define UPDATE_TIME (30) // 描画更新間隔(ms) #define ANGLE (360) // 360度の角度を表す
併せて、関数宣言も行います。
boolean drawEruption(eruption1* pMe);
投影設定は、OpenGL ESとは異なりGLUの「gluPerspective()」と同様の関数が「mceCamera_setPerspectiveFov()」という形で提供されています。この関数により、透視投影の設定が可能になります。OpenGL ESで行った二等辺三角形の底辺を求める必要がなくなりますので、投影設定はずいぶんと楽になることが分かるかと思います。
また「mceGraphics3D_setCamera()」は、mceGraphics3Dに対してカメラを設定する関数です。eruptionには大きく2つのカメラ制御があり、1つが3Dオーサリングツールで設定するカメラに対しての制御と、もう1つがプログラム側で作成するカメラオブジェクトに対する制御です。ここではプログラム側でカメラオブジェクトを生成し、制御していますので、デフォルトカメラをmceGraphics3D_setCamera()で設定しています。
このモデルデータの立方体は原点にありますので、まず「mceTransform_setTranslate()」で平行移動を行い、視錐台の中に移動させます。この関数では、第1引数に設定した行列に対して、第2、3、4引数の座標の移動成分を設定します。
次に、立方体の回転を行います。ここでは「mceVector3D_set()」「mceTransform_setRotate()」「mceTransform_multiply()」の3つの関数を使い、X軸、Y軸の回転処理を行います。まず、mceVector3D_set()で回転のベクトルを設定します。X軸の回転では(1,0,0)、Y軸の回転では(0,1,0)を設定しています。
回転ベクトルを設定したらmceTransform_setRotate()で回転成分を設定します。ここでは、設定した回転ベクトルに対しての角度を設定し、その結果が第1引数に格納されます。そして、mceTransform_multiply()で平行移動した行列と回転した行列の乗算を行います。これにより平行移動した先での回転が行われる行列が出来上がります。
最後に以上で作成した行列を「mceNodeDeformerNode_setTransform()」で、立方体に対して設定します。
それでは、以上で設定した状態を描画処理します。まず、「mceGraphics3D_drawFigure()」で移動、回転の要素を設定した立方体のデータをmceGraphics3Dに設定します。次に描画完了の処理として「mceGraphics3D_flush()」を実行します。これはOpenGL ESのglFlushに相当する処理になります。そして、最終的なネイティブの描画ターゲットであるネイティブウィンドウに対して描画を行う「mceGraphics3D_swapContext()」を実行します。これはOpenGL ESの最終描画処理である「IEGL_eglSwapBuffers」を内部的には実行しています。以上で描画処理は完了です。
生成した各オブジェクトを破棄する関数を作成します(ソース3)。
boolean cleanup(eruption1* pMe){
CALLBACK_Cancel (&pMe->Callback); // コールバック、タイマを停止
// 各種終了処理
if (pMe->pIMC != NULL){
// 各データの破棄
mceObject3D_unref ((mceObject3D *)pMe->Figure); // モデルデータ
mceObject3D_unref ((mceObject3D *)pMe->Fig_model); // ボックスデータ
mceObject3D_unref ((mceObject3D *)pMe->Camera); // カメラオブジェクト
mceObject3D_unref ((mceObject3D *)pMe->G3d ); // レンダリング機能
mceGraphics3D_finalizeContext (); // MceGraphics3Dの破棄
IMC_Release (pMe->pIMC); // eruptionの終了処理
pMe->pIMC = NULL;
}
return TRUE;
}
| ソース3 生成した各オブジェクトを破棄する関数 |
関数宣言を追加します。
boolean cleanup(eruption1* pMe);
さらに前回、ファイル入出力で利用したBREWの入出力関数のヘッダファイルをインクルードします。
#include ≪ AEEFile.h ≫
ここでは、生成した各オブジェクトやリソースの破棄がメインになります。各オブジェクトの破棄は「mceObject3D_unref()」で行い、OpenGL ESのリソースを管理するMceGraphics3Dオブジェクトの破棄は「mceGraphics3D_finalizeContext()」で行います。
最後に、イベント処理の部分に各関数を実装して完了です。
case EVT_APP_START:
// Add your code here...
if(setup(pMe)){
if(!drawEruption(pMe)){
return FALSE;
}
}else{
return FALSE;
}
return(TRUE);
case EVT_APP_STOP:
// Add your code here...
cleanup(pMe);
return(TRUE);
ここまでの解説を見る限り、OpneGL ESに比べて多少便利な部分もあったとは思いますが、さほどミドルウェアを導入する恩恵は感じられなかったのではないでしょうか。しかし、焦りは禁物です。実は、最低限必要な実装を行った後からがミドルウェアの恩恵を大きく感じられるのです。
例えば、OpenGL ESで別形状の3Dオブジェクトを表示したい場合、プログラムのデータ処理部分をかなり変更する必要がありますが、ミドルウェアを利用した場合は、ロードするファイルを変更するだけで描画されるオブジェクトを簡単に変更できます。
それでは、「sample_pot.mcm」をダウンロードして、実際に別のオブジェクトを表示してみましょう。ソース中の以下の部分を変更します。
| ダウンロード: | |
|---|---|
| ⇒ | 「sample_pot.mcm」のダウンロード |
if (!dataLoad(pMe, “data\\sample_pot.mcm”)){
| setup関数 |
以上のように、単純にデータファイルを差し替えるだけで、まったく異なる3Dオブジェクトを表示できますし、形状の複雑さを特に気にする必要もありません。
このようにミドルウェアを利用することにより、応用部分で必要となる機能が提供されますのでプログラムが楽になると同時に、コンテンツのデザインに注力できるようになります。
今回は、eruptionで3D描画を行うところまで見てきましたが、基本的に連載第7回で実装した内容を置き換えただけでした。次回からは、OpneGL ESではなくMascotCapsuleシリーズを使う利点である3Dモデルの「ボーンアニメーション」という部分にフォーカスして解説したいと思います。ボーンアニメーションが可能になると、人や動物などのより複雑な3Dデータのアニメーションを効果的に作成・適用できるようになります。(次回に続く)
Copyright © ITmedia, Inc. All Rights Reserved.
組み込み開発の記事ランキング
コーナーリンク