Ogre3Dはリアルタイム3Dレンダリングエンジンです。3DCGゲームを作るのに使ったりできるようです。Wikipediaに詳しい説明があります→OGRE - Wikipedia。
今回はこのOgre3Dを使って、MikuMikuDance用のPMDモデルを表示させてみます。
WindowsにおけるOgre3D環境構築
Ogre3Dはクロスプラットフォームに対応しているのですが、ここではWindows環境について説明します。(次の記事ではWindows環境依存のサンプルコードを使う予定です)
Ogre3D開発環境のセットアップ
開発環境のセットアップは、基本的にSetting Up An ApplicationのVisual Studio項の説明に沿って進めます。
- OGRE 1.7.3 SDK for Visual C++ .Net 2010をダウンロードして解凍
- ユーザ環境変数「OGRE_HOME」を作成して解凍したSDKのフォルダを指定
- directx_Jun2010_redist.exeをインストール
- Visual C++ 2010 Express(以下、VC10と表記)をインストール
これでOgre3Dの開発に必要なものがそろいます。
Ogre3D動作確認
続けて、TutorialFramework(Tutorial用ベースコード)を使って動作確認を行います。
- VC10で空のプロジェクトを作成
- TutorialFramework.zipをダウンロードして解凍
- VC10でプロジェクト名を右クリック→「追加」→「既存の項目」からTutorialFramework.zip内のファイルを選択
- プロジェクトのプロパティ設定(Project Configuration参照)
- F5キーで実行
Setup画面でレンダリングシステム(Direct3DかOpenGL)を選んだあと、以下のような画面が表示されれば成功です。Escキーで終了します。
デフォルトではフルスクリーンで描画されますが、「Ogre SDK解凍フォルダ\bin\debug\ogre.cfg」の「Full Screen=Yes」の部分を「No」に変更すればウィンドウ表示に変更できます。また、表示解像度も同ファイルの「Video Mode=」の部分で変更できます。
Ogre3D Basic Tutorial 1の実行
TutorialFrameworkのコードをBasic Tutorial 1を参考に修正し、まずはSDKに含まれている「ogrehead.mesh」モデルを表示してみましょう。
VC10で「TutorialApplication.cpp」を開き、「void TutorialApplication::createScene(void)」のコードを以下の内容にします。
void TutorialApplication::createScene(void)
{
//Entityを定義
Ogre::Entity* ogreHead = mSceneMgr->createEntity("Head", "ogrehead.mesh");
//RootSceneNodeに子ノードを作成してogreHeadをアタッチ
Ogre::SceneNode* headNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
headNode->attachObject(ogreHead);
Ogre::Entity* ogreHead2 = mSceneMgr->createEntity("Head2", "ogrehead.mesh");
//headNodeに子ノードを作成してogreHead2をアタッチ
Ogre::SceneNode* headNode2 = headNode->createChildSceneNode( "HeadNode2", Ogre::Vector3( 100, 0, 0 ) );
headNode2->attachObject( ogreHead2 );
//headNodeを移動(子ノードのheadNode2も一緒に移動する)
headNode->translate(Ogre::Vector3(10, 0, 0));
// Set ambient light
mSceneMgr->setAmbientLight(Ogre::ColourValue(0.5, 0.5, 0.5));
// Create a light
Ogre::Light* l = mSceneMgr->createLight("MainLight");
l->setPosition(20,80,50);
}
保存後、F5で実行すると以下のように表示されます。
表示ウィンドウでは以下のキー操作が可能です。
w,s,a,d:カメラの前後左右移動
r:メッシュ表示・点表示・テクスチャ表示の切り替え
Esc:終了
Tutorialの詳しい内容については、メモブログさんで公開されている日本語訳などを併せて参照してください。
PMDからOgreMeshへの変換
それでは、本題のPMDモデルの表示に進みましょう。フリーの3DCGソフトであるBlenderと、Blender用のスクリプトを使ってPMDのインポートとOgreMeshのエクスポートを行います。
予め任意のPMDモデルデータをダウンロードしておいてください。記事内では例としてSaYaKa Projectさんで公開されている中野梓モデルを使用します。
なお、MMDのスフィアマップ機能(拡張子.sphのテクスチャ)を使用しているモデルはOgre3Dでは正しく表示できないので注意してください。また、PMDモデルの利用は指定されたライセンスに従ってください。
PMD→Blender(インポート)
Blender用のPMDインポート実装は複数存在しますが、ここではVMDMotionImporterの改造板Blenderを使用します。
- Python 2.6.6をインストールしてPATHを通す
- Blender249VMD.zipをダウンロードして解凍
- Blenderを起動(デフォルトで表示されるCubeは右クリックで選択→Deleteで削除する)
- 「Window Type(メイン領域左下のアイコン)」→「Scripts Window」を選択
- 「Scripts」→「Import」→「PMD file for MMD(.pmd)」を選択
- ダウンロードしたPMDファイルを指定
モデルによってコンソールにボーン周りのエラーが表示されたり、足が曲がった状態で読み込まれる場合があるようですが、とりあえずここではモデルの形状が表示できていればOKとします。
Blender→OgreMesh(エクスポート)
BlenderにOgreMeshエクスポート用のスクリプトを追加して使用します。
- BlenderExport.zipをダウンロードして「Blender解凍先\.blender\scripts」に解凍
- Blenderの「Scripts Window」で「Scripts」→「Update Menus」を実行
- 「Scripts」→「Export」→「Ogre Meshes」を選択
- 「Preferences」→「OgreXmlConverter Location:」→「Manual」を選択し、「Ogre SDK解凍フォルダ\bin\release\OgreXMLConverter.exe」のパスを指定→「OK」
- 「Selected:」で「Mesh」を選択
- 「Path:」にエクスポート先のパスを指定し、「OgreXmlConverter」ボタンをアクティブ化
- 「Export」を選択
エラーなく処理されることを確認してください。
PMDから変換したOgreMeshのOgre3D上への表示
Ogre SDK解凍フォルダ内に「my_media」ディレクトリを作成し、エクスポートされた.mesh、.skeleton、.materialファイルを配置します。標準の「media」フォルダ内の配置を参考にしてください。
bin/debug内のresources_d.cfgに「my_media」のパスを追加すれば、プログラムからモデルが参照可能になります。(この配置方法はあまりスマートな方法ではない気がしますが)
VC10に戻り、「TutorialApplication.cpp」の「void TutorialApplication::createScene(void)」を以下の内容に変更します。
void TutorialApplication::createScene(void)
{
//Entityを定義
Ogre::Entity* ogreMesh = mSceneMgr->createEntity("Mesh", "Mesh.mesh");
//RootSceneNodeに子ノードを作成してogreMeshをアタッチ
Ogre::SceneNode* myNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
myNode->attachObject(ogreMesh);
Ogre::Entity* ogreMesh1 = mSceneMgr->createEntity("Mesh1", "Mesh.001.mesh");
Ogre::SceneNode* myNode1 = myNode->createChildSceneNode( "myNode1", Ogre::Vector3( 0, 0, 0 ) );
myNode1->attachObject( ogreMesh1 );
Ogre::Entity* ogreMesh2 = mSceneMgr->createEntity("Mesh2", "Mesh.002.mesh");
Ogre::SceneNode* myNode2 = myNode->createChildSceneNode( "myNode2", Ogre::Vector3( 0, 0, 0 ) );
myNode2->attachObject( ogreMesh2 );
Ogre::Entity* ogreMesh3 = mSceneMgr->createEntity("Mesh3", "Mesh.003.mesh");
Ogre::SceneNode* myNode3 = myNode->createChildSceneNode( "myNode3", Ogre::Vector3( 0, 0, 0 ) );
myNode3->attachObject( ogreMesh3 );
Ogre::Entity* ogreMesh4 = mSceneMgr->createEntity("Mesh4", "Mesh.004.mesh");
Ogre::SceneNode* myNode4 = myNode->createChildSceneNode( "myNode4", Ogre::Vector3( 0, 0, 0 ) );
myNode4->attachObject( ogreMesh4 );
Ogre::Entity* ogreMesh5 = mSceneMgr->createEntity("Mesh5", "Mesh.005.mesh");
Ogre::SceneNode* myNode5 = myNode->createChildSceneNode( "myNode5", Ogre::Vector3( 0, 0, 0 ) );
myNode5->attachObject( ogreMesh5 );
Ogre::Entity* ogreMesh6 = mSceneMgr->createEntity("Mesh6", "Mesh.006.mesh");
Ogre::SceneNode* myNode6 = myNode->createChildSceneNode( "myNode6", Ogre::Vector3( 0, 0, 0 ) );
myNode6->attachObject( ogreMesh6 );
Ogre::Entity* ogreMesh7 = mSceneMgr->createEntity("Mesh7", "Mesh.007.mesh");
Ogre::SceneNode* myNode7 = myNode->createChildSceneNode( "myNode7", Ogre::Vector3( 0, 0, 0 ) );
myNode7->attachObject( ogreMesh7 );
Ogre::Entity* ogreMesh8 = mSceneMgr->createEntity("Mesh8", "Mesh.008.mesh");
Ogre::SceneNode* myNode8 = myNode->createChildSceneNode( "myNode8", Ogre::Vector3( 0, 0, 0 ) );
myNode8->attachObject( ogreMesh8 );
Ogre::Entity* ogreMesh9 = mSceneMgr->createEntity("Mesh9", "Mesh.009.mesh");
Ogre::SceneNode* myNode9 = myNode->createChildSceneNode( "myNode9", Ogre::Vector3( 0, 0, 0 ) );
myNode9->attachObject( ogreMesh9 );
Ogre::Entity* ogreMesh10 = mSceneMgr->createEntity("Mesh10", "Mesh.010.mesh");
Ogre::SceneNode* myNode10 = myNode->createChildSceneNode( "myNode10", Ogre::Vector3( 0, 0, 0 ) );
myNode10->attachObject( ogreMesh10 );
Ogre::Entity* ogreMesh11 = mSceneMgr->createEntity("Mesh11", "Mesh.011.mesh");
Ogre::SceneNode* myNode11 = myNode->createChildSceneNode( "myNode11", Ogre::Vector3( 0, 0, 0 ) );
myNode11->attachObject( ogreMesh11 );
Ogre::Entity* ogreMesh12 = mSceneMgr->createEntity("Mesh12", "Mesh.012.mesh");
Ogre::SceneNode* myNode12 = myNode->createChildSceneNode( "myNode12", Ogre::Vector3( 0, 0, 0 ) );
myNode12->attachObject( ogreMesh12 );
Ogre::Entity* ogreMesh13 = mSceneMgr->createEntity("Mesh13", "Mesh.013.mesh");
Ogre::SceneNode* myNode13 = myNode->createChildSceneNode( "myNode13", Ogre::Vector3( 0, 0, 0 ) );
myNode13->attachObject( ogreMesh13 );
Ogre::Entity* ogreMesh14 = mSceneMgr->createEntity("Mesh14", "Mesh.014.mesh");
Ogre::SceneNode* myNode14 = myNode->createChildSceneNode( "myNode14", Ogre::Vector3( 0, 0, 0 ) );
myNode14->attachObject( ogreMesh14 );
Ogre::Entity* ogreMesh15 = mSceneMgr->createEntity("Mesh15", "Mesh.015.mesh");
Ogre::SceneNode* myNode15 = myNode->createChildSceneNode( "myNode15", Ogre::Vector3( 0, 0, 0 ) );
myNode15->attachObject( ogreMesh15 );
Ogre::Entity* ogreMesh16 = mSceneMgr->createEntity("Mesh16", "Mesh.016.mesh");
Ogre::SceneNode* myNode16 = myNode->createChildSceneNode( "myNode16", Ogre::Vector3( 0, 0, 0 ) );
myNode16->attachObject( ogreMesh16 );
Ogre::Entity* ogreMesh17 = mSceneMgr->createEntity("Mesh17", "Mesh.017.mesh");
Ogre::SceneNode* myNode17 = myNode->createChildSceneNode( "myNode17", Ogre::Vector3( 0, 0, 0 ) );
myNode17->attachObject( ogreMesh17 );
Ogre::Entity* ogreMesh18 = mSceneMgr->createEntity("Mesh18", "Mesh.018.mesh");
Ogre::SceneNode* myNode18 = myNode->createChildSceneNode( "myNode18", Ogre::Vector3( 0, 0, 0 ) );
myNode18->attachObject( ogreMesh18 );
// Set ambient light
mSceneMgr->setAmbientLight(Ogre::ColourValue(0.5, 0.5, 0.5));
// Create a light
Ogre::Light* l = mSceneMgr->createLight("MainLight");
l->setPosition(20,80,50);
}
実行すると以下のように表示されます。(このモデルは目のテクスチャが正しく表示されなかったので、少々強引ですが.material内の「a_tex_eyes2base.tga」を「a_tex_eyes2.tga」に変更して回避しました。)
以上、ここまでで、Ogre3DでMMD用PMDモデルを表示することができました。次回はARToolkitPlusを使った拡張現実表示をやってみたいと思います。
Comments»
[…] Ogre3Dで遊ぼう! 1/2 「MMD用PMDモデルの表示」編 – ナレッジエース […]