06、複数キャラ対応とオブジェクトパネル






06章では複数キャラクターを読み込み、それぞれにアニメーションを付けられるようにします。
キャラクター同士の連係動作などが作れます。

メインウインドウにはボーンの移動ボタンを付けました。

一番親に自動的に作られる全体移動用の「ModelRootBone」に移動回転を設定することで
キャラクター全体の姿勢を付けることが出来ます。

オブジェクトパネルも追加しました。
オブジェクトごとに表示非表示を設定できます。



ソースは下のページからダウンロードしてください。
OpenRDBダウンロードページ


##### 2012/04/27 追記
Visual C++ 2010 Express Editionでソースをビルドすると
リソースファイルに#include "afxres.h"という記述を書いてビルドした時に下のようなコンパイルエラーが発生します。

fatal error RC1015: cannot open include file 'afxres.h'

これを回避するために
RokDeBone2.rcをメモ帳で開き、
#include "afxres.h"を削除して下の二行を追記してください。

//#include "afxres.h"
#include <windows.h>
#define IDC_STATIC -1

######

06−01、全体移動ボーン

第6章では複数モデルに対応します。
モデルを複数回読み込むと、モデル同士が重なって表示されてしまいます。
つまり複数モデルに対応する前に、モデルを移動回転させるための仕組みが必要です。

OpenRDBでは一番親のボーンとして「ModelRootBone」という名前のボーンを自動的に作成することで
モデル全体を移動回転できるようにします。

今まではCModel::m_topboneにmqoで定義された一番親のボーンの配列を持っていました。
この章ではこれをちょっと変えて、mqoで定義されている一番親のボーンのその親に1個、ModelRootBoneを作ります。

ModelRootBoneの始点は原点にします。そして終点はmqoの一番親のボーンです。

この作業はCModel::MakeBoneTriで行います。
ソースを貼り付けます。

int CModel::MakeBoneTri()
{
if( m_boneobject.begin() == m_boneobject.end() ){
m_topbone = 0;
return 0;//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
}

CMQOFace* toplevelface[ MAXBONENUM ];
int toplevelnum = 0;

map<int, CMQOObject*>::iterator itrobj;
itrobj = m_boneobject.begin();
CMQOObject* curobj = itrobj->second;
if( curobj ){
CallF( curobj->SetMikoBoneIndex3(), return 1 );
CallF( curobj->SetMikoBoneIndex2(), return 1 );
CallF( curobj->CheckSameMikoBone(), return 1 );
CallF( curobj->GetTopLevelMikoBone( toplevelface, &toplevelnum, MAXBONENUM ), return 1 );

CallF( curobj->InitFaceDirtyFlag(), return 1 );
int topno;
for( topno = 0; topno < toplevelnum; topno++ ){
CallF( curobj->SetTreeMikoBone( toplevelface[ topno ] ), return 1 );
}

CallF( curobj->InitFaceDirtyFlag(), return 1 );
int islooped = 0;
int jointnum = 0;
int totaljointnum = 0;
for( topno = 0; topno < toplevelnum; topno++ ){
jointnum = 0;
CallF( curobj->CheckLoopedMikoBoneReq( toplevelface[ topno ], &islooped, &jointnum ), return 1 );
if( islooped ){
::MessageBox( NULL, L"ループ又は重複しているボーン構造が見つかりました。(誤判定かも(汗))読み込めません。", L"エラー", MB_OK );
_ASSERT( 0 );
return 1;
}
totaljointnum += jointnum;
if( totaljointnum >= MAXBONENUM ){
::MessageBox( NULL, L"ボーンの数が多すぎます。43以下にしてください。", L"エラー", MB_OK );
_ASSERT( 0 );
return 1;
}
}

CallF( curobj->SetMikoBoneName( m_ancmaterial ), return 1 );
CallF( curobj->SetMikoFloatBoneName(), return 1 );

CBone::ResetBoneCnt();
m_topbone = new CBone;
if( !m_topbone ){
_ASSERT( 0 );
return 1;
}
m_topbone->m_topboneflag = 1;
CallF( m_topbone->SetBoneTri( 0, curobj->m_pointbuf ), return 1 );
m_bonelist[m_topbone->m_boneno] = m_topbone;
m_bonename[m_topbone->m_bonename] = m_topbone;


int secbonenum = toplevelnum;
int errcnt = 0;
int secno;
for( secno = 0; secno < toplevelnum; secno++ ){
CBone* cursec = new CBone;
if( !cursec ){
_ASSERT( 0 );
return 1;
}
cursec->m_topboneflag = 2;
CMQOFace* topface = toplevelface[ secno ];
CallF( cursec->SetBoneTri( topface, curobj->m_pointbuf ), return 1 );
m_bonelist[cursec->m_boneno] = cursec;

CallF( m_topbone->AddChild( cursec ), return 1 );
m_bonename[ cursec->m_bonename ] = cursec;

MakeBoneReq( cursec, topface, curobj->m_pointbuf, 0, &errcnt );
if( errcnt > 0 ){
_ASSERT( 0 );
return 1;
}
}
}
return 0;
}


今までのボーンの一番親に一個ボーンを追加しただけです。
ModelRootBoneとその子供のボーンは、ボーンの名前が特殊なので
その区別をするためにCBone::m_topboneflagを使います。
ModelRootBoneはm_topboneflagに1をセットし、その子供は2をセットし、その他のボーンには0をセットします。


06−02、複数モデル対応

OpenRDBはまだまだシンプルな状態なので
これを複数モデルに対応させるのは簡単です。

読み込んだモデルを保存するメンバーを定義します。
s_modelindexとします。

="hpb-cnt-tb-cell1" width="306">static vector<MODELELEM> s_modelindex;

s_modelindexはMODELELEMのvectorです。
MODELELEMは次のような定義です。

="hpb-cnt-tb-cell1" width="257">typedef struct tag_modelelem
{
CModel* modelptr;
vector<TLELEM> tlarray;
int motmenuindex;
map<int, int> lineno2boneno;
map<int, int> boneno2lineno;
}MODELELEM;

読み込んだモデル分MODELELEMをs_modelindexに格納しておきます。
そしてモデル切り替え時に
modelptrをs_modelに、tlarrayをs_tlarrayに、motmenuindexをs_curmotmenuindexに
lineno2bonenoをs_lineno2bonenoに、bonenotolinenoをs_boneno2linenoにコピーします。

あとはs_*に対して今まで通り処理をするだけです。



06−03、オブジェクトパネル

この章ではオブジェクトパネルの追加もしました。
メタセコイアで作ったオブジェクトの内、表示用のものだけを
オブジェクトパネルにエントリーします。
そして目のマークのボタンをクリックすることで
オブジェクトの表示と非表示を切り替えられるようにします。

オブジェクトパネルのGUIはナゾビーフさんが作ってくれました。

他の操作ウインドウと同じ形式のUIです。
OrgWindowを作り、それにOWP_LayerTableをアタッチすることで作成します。
宣言は以下の通り。

="hpb-cnt-tb-cell1" width="337">static OrgWindow* s_layerWnd = 0;
static OWP_LayerTable* s_owpLayerTable = 0;

作成はInitApp()内で行っています。
newしたのち、アタッチしてListener関数を定義しています。


オープンソースのトップに戻る

トップページに戻る