jump to navigation

Ogre3Dで遊ぼう! 1/2 「MMD用PMDモデルの表示」編

2011-08-18 00:21 Posted by
nase
in : 未分類
rainbow_curtain.jpg

Ogre3Dリアルタイム3Dレンダリングエンジンです。3DCGゲームを作るのに使ったりできるようです。Wikipediaに詳しい説明があります→OGRE - Wikipedia

今回はこのOgre3Dを使って、MikuMikuDance用のPMDモデルを表示させてみます。

WindowsにおけるOgre3D環境構築

Ogre3Dはクロスプラットフォームに対応しているのですが、ここではWindows環境について説明します。(次の記事ではWindows環境依存のサンプルコードを使う予定です)

Ogre3D開発環境のセットアップ

開発環境のセットアップは、基本的にSetting Up An ApplicationのVisual Studio項の説明に沿って進めます。

これでOgre3Dの開発に必要なものがそろいます。

Ogre3D動作確認

続けて、TutorialFramework(Tutorial用ベースコード)を使って動作確認を行います。

  • VC10で空のプロジェクトを作成
  • TutorialFramework.zipをダウンロードして解凍
  • VC10でプロジェクト名を右クリック→「追加」→「既存の項目」からTutorialFramework.zip内のファイルを選択
  • プロジェクトのプロパティ設定(Project Configuration参照)
  • F5キーで実行

Setup画面でレンダリングシステム(Direct3DかOpenGL)を選んだあと、以下のような画面が表示されれば成功です。Escキーで終了します。

ogre3d_01_01.jpg
TutorialFramework初期画面

デフォルトではフルスクリーンで描画されますが、「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で実行すると以下のように表示されます。

ogre3d_01_02.jpg
ogrehead.mesh 表示例

表示ウィンドウでは以下のキー操作が可能です。

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ファイルを指定

ogre3d_01_03.jpg
Blenderに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」を選択

ogre3d_01_04.jpg
OgreMeshエクスポート画面

エラーなく処理されることを確認してください。

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_01_05.jpg
OgreMeshエクスポート画面

以上、ここまでで、Ogre3DでMMD用PMDモデルを表示することができました。次回はARToolkitPlusを使った拡張現実表示をやってみたいと思います。

Comments»

1. Ogre 3D Tutorial Framework を VS2010 x64 でビルド « 可音月堂 - 2012-3-19

[…] Ogre3Dで遊ぼう! 1/2 「MMD用PMDモデルの表示」編 – ナレッジエース […]


*Comments and trackbacks will appear after it is approved by the administrator.