Last update: 2014/06/04
ここでは、Visual Studioでのプロジェクト作成から、DirectXでLive2D モデルを描画するまでの手順を説明します。 推奨環境などはSDK付属のReadMeをご覧ください。
- Visual Studio (ここではVisual Studio 2012を使用します)
DirectXのダウンロードを済ませておく。
- Live2D ライブラリ (ダウンロードしたLive2D SDK の「lib」フォルダ。ここでは1.0.02のバージョンを使用します)
本来は、Live2Dのリソースは作成するモデルに応じてそれぞれ用意します。
ここではサンプルプロジェクトの「ハル」のリソースを使って説明をしていきます。
simple/res/haru/
- haru.moc
- haru.1024/texture_00.png
- haru.1024/texture_01.png
- haru.1024/texture_02.png
◆プロジェクトの設定と下準備新規プロジェクトを作成して、必要なファイルをインポートしていきます。
Visual Studioのメニューバーの「ファイル(F)」 > 「新規作成(N)」 > 「プロジェクト(P)...」をクリックします。
テンプレートから「Visual C++」 > 「Win32 プロジェクト」を選択し、名前や保存場所を設定して「OK」をクリックします。
「Win32 アプリケーション ウィザード」が表示されるので、「次へ」をクリックします。
次の画面で「空のプロジェクト(E)」のチェックを入れて「完了」をクリックします。
次に、プロジェクトの設定を行います。
プロジェクトを右クリックして「プロパティ(R)」をクリックします。
「構成プロパティ」 > 「全般」を選択して、「文字セット」の項目を「マルチバイト文字セットを使用する」に設定します。
次に、「構成プロパティ」 > 「C/C++」 > 「全般」を選択し、「追加のインクルードディレクトリ」の項目の、 右端にある下向きの三角をクリック > 「<編集...>」をクリックします。 ダイアログが出てくるので、ダイアログ上部の白い枠内に
"include" 、 "$(DXSDK_DIR)\Include" の2つを入力し、OKをクリックします。
同様に、「構成プロパティ」 > 「C/C++」 > 「プリプロセッサ」を選択し、「プリプロセッサの定義」の項目に
"L2D_TARGET_D3D" を追加してOKをクリックします。
「構成プロパティ」> 「リンカー」 > 「全般」 を選択し、「追加のライブラリディレクトリ」の項目に、
"lib" 、 "$(DXSDK_DIR)\Lib\x86" の二つを追加します。
最後に、「構成プロパティ」> 「リンカー」 > 「入力」を選択し、「追加の依存ファイル」の項目に、
"d3d9.lib" 、 "d3dx9.lib" 、 "live2d_directX_mdd.lib" の3つを追加してOKをクリックします。
これでプロジェクトの設定は終了です。 次はプロジェクトに必要なファイルを追加していきます。
プロジェクトを右クリックして「エクスプローラーでフォルダーを開く(X)」をクリックして、フォルダを開きます。 開いたプロジェクトフォルダの中に、SDKフォルダルートにある「include」と「lib」をドラッグアンドドロップ(またはコピー・ペースト)します。
SDKの \sample\Simple にある「res」フォルダも同様に追加します。 プロジェクトに.cppファイルを追加します。ここでは「main.cpp」とします
以上でプロジェクトへの追加は完了です。 これからモデルの読み込み、表示を行います。
main.cppを開き、以下のように記述してウィンドウの作成を行います。
#include <windows.h> LRESULT WINAPI WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInst, LPSTR lpCmdLine,int nShow) { MSG msg; // ウィンドウ作成 WNDCLASSEX wc = {sizeof(WNDCLASSEX), CS_VREDRAW|CS_HREDRAW|CS_OWNDC, WndProc, 0, 0, hInstance, NULL, NULL, (HBRUSH)(COLOR_WINDOW+1), NULL, "DX9_TUTORIAL1_CLASS", NULL}; RegisterClassEx(&wc); HWND hMainWnd = CreateWindow("DX9_TUTORIAL1_CLASS", "Live2D Sample", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 800, 800, NULL, NULL, hInstance, NULL); // ウィンドウの表示 ShowWindow(hMainWnd, nShow); UpdateWindow(hMainWnd); while(GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return(0); } LRESULT WINAPI WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { case WM_DESTROY: PostQuitMessage(0); return(0); } return(DefWindowProc(hwnd, msg, wParam, lParam)); }
ここまでで実行すると空のウィンドウが表示されます。 次に、DirectXの設定を行います。
以下のようにインクルードとグローバルな関数を追加します。 - #include <d3d9.h>
// globals LPDIRECT3D9 g_pDirect3D = NULL; LPDIRECT3DDEVICE9 g_pDirect3D_Device = NULL; D3DPRESENT_PARAMETERS g_D3DPP;
WinMain() 関数内のCreateWindow()関数の直下で、以下のようにDirectXの初期化を行います。 // DirectXの初期化 g_pDirect3D = Direct3DCreate9(D3D_SDK_VERSION); D3DPRESENT_PARAMETERS PresentParams; memset(&PresentParams, 0, sizeof(D3DPRESENT_PARAMETERS)); PresentParams.Windowed = TRUE; PresentParams.SwapEffect = D3DSWAPEFFECT_DISCARD; g_pDirect3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hMainWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &PresentParams, &g_pDirect3D_Device); // ビューポートの設定 D3DVIEWPORT9 vp; vp.X = 0; vp.Y = 0; vp.Width = 800; vp.Height = 800; vp.MinZ = 0.0f; vp.MaxZ = 1.0f; g_pDirect3D_Device->SetViewport(&vp);
WinMain() 関数の return 直前に、以下のように追加します。
g_pDirect3D_Device->Release(); g_pDirect3D->Release(); return(0); }
WndProc() 関数内のswitch文に、以下を追加します。
case WM_PAINT: g_pDirect3D_Device->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(255, 255, 255), 1.0f, 0); g_pDirect3D_Device->BeginScene(); g_pDirect3D_Device->Present(NULL, NULL, NULL, NULL); ValidateRect(hwnd, NULL); return(0);
それでは、これからLive2Dの初期化、描画まで行います。
live2d::Live2DModelD3D* live2DModel ;
Live2Dモデルの初期化を、WinMain()関数のWindouUpdate()の下に、以下のように設定します。
// Live2Dの初期化 live2d::Live2D::init(); const LPCWSTR TEXTURES[] = { L"res\\haru\\haru.1024\\texture_00.png" , L"res\\haru\\haru.1024\\texture_01.png" , L"res\\haru\\haru.1024\\texture_02.png" , NULL , }; // モデルのロード live2DModel = live2d::Live2DModelD3D::loadModel("res\\haru\\haru.moc"); // テクスチャのロード for( int i = 0 ; i < 1000 ; i++ ){ if( ! TEXTURES[i] ) break; LPDIRECT3DTEXTURE9 tex; // テクスチャ画像をDirextXでの表示用に変換 if( FAILED( D3DXCreateTextureFromFileExW( g_pDirect3D_Device , TEXTURES[i] , 0 //width , 0 //height , 0 // mipmap( 0なら完全なミップマップチェーン) , 0 //Usage , D3DFMT_A8R8G8B8 , D3DPOOL_MANAGED , D3DX_FILTER_LINEAR , D3DX_FILTER_BOX , 0 , NULL , NULL , &tex ) ) ) { live2d::UtDebug::print("Could not create texture"); return FALSE; } else { live2DModel->setTexture( i , tex ); } }
WndProc()関数のcase WM_PAINT: の中で、モデルの行列を設定します。
BrginScene()とPresent()の間に記述してください。
// 行列の設定 D3DXMATRIXA16 matWorld; D3DXMatrixIdentity( &matWorld ); D3DXMATRIX Ortho2D; D3DXMATRIX Identity; D3DXMatrixOrthoLH(&Ortho2D, 3000.0f, 3000.0f, -1.0f, 1.0f); D3DXMatrixIdentity(&Identity); g_pDirect3D_Device->SetTransform(D3DTS_PROJECTION, &Ortho2D); g_pDirect3D_Device->SetTransform(D3DTS_WORLD, &Identity); g_pDirect3D_Device->SetTransform(D3DTS_VIEW , &Identity);
最後に、上のモデルの行列と、Present()の間で、Live2Dの描画を設定して実行すれば完了です! // --- Live2D 用の描画設定 --- g_pDirect3D_Device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); g_pDirect3D_Device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); g_pDirect3D_Device->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); g_pDirect3D_Device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);// アルファ・ブレンディングを行う g_pDirect3D_Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);// 透過処理を行う g_pDirect3D_Device->SetRenderState(D3DRS_SRCBLEND , D3DBLEND_SRCALPHA);// 半透明処理を行う g_pDirect3D_Device->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); g_pDirect3D_Device->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); g_pDirect3D_Device->SetSamplerState( 0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR); // --- 座標変換 // 現在のLive2Dモデルは、画像のように下向きに(0,0,w,h)に配置されるため // センタリングと上下逆転を行う float modelWidth = live2DModel->getModelImpl()->getCanvasWidth(); float modelHeight = live2DModel->getModelImpl()->getCanvasHeight(); D3DXMATRIXA16 world, scale, trans; g_pDirect3D_Device->GetTransform(D3DTS_WORLD, &world); D3DXMatrixScaling(&scale, 1, -1, 1); // 上下逆転 D3DXMatrixTranslation(&trans , -modelWidth/2, -modelHeight/2, 0); world = trans * scale * world; g_pDirect3D_Device->SetTransform(D3DTS_WORLD, &world);
// --- 描画 live2DModel->setDevice(g_pDirect3D_Device); live2DModel->update(); live2DModel->draw(); g_pDirect3D_Device->EndScene();
最終的なコードは以下のようになります。 #include <windows.h> #include <d3d9.h> #include "Live2D.h" #include "Live2DModelD3D.h" // globals LPDIRECT3D9 g_pDirect3D = NULL; LPDIRECT3DDEVICE9 g_pDirect3D_Device = NULL; D3DPRESENT_PARAMETERS g_D3DPP; live2d::Live2DModelD3D* live2DModel ; LRESULT WINAPI WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nShow) { MSG msg; // ウィンドウ作成 WNDCLASSEX wc = {sizeof(WNDCLASSEX), CS_VREDRAW|CS_HREDRAW|CS_OWNDC, WndProc, 0, 0, hInstance, NULL, NULL, (HBRUSH)(COLOR_WINDOW+1), NULL, "DX9_TUTORIAL1_CLASS", NULL}; RegisterClassEx(&wc); HWND hMainWnd = CreateWindow("DX9_TUTORIAL1_CLASS", "Live2D Sample", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 800, 800, NULL, NULL, hInstance, NULL); // DirectXの初期化 g_pDirect3D = Direct3DCreate9(D3D_SDK_VERSION); D3DPRESENT_PARAMETERS PresentParams; memset(&PresentParams, 0, sizeof(D3DPRESENT_PARAMETERS)); PresentParams.Windowed = TRUE; PresentParams.SwapEffect = D3DSWAPEFFECT_DISCARD; g_pDirect3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hMainWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &PresentParams, &g_pDirect3D_Device); // ビューポートの設定 D3DVIEWPORT9 vp; vp.X = 0; vp.Y = 0; vp.Width = 800; vp.Height = 800; vp.MinZ = 0.0f; vp.MaxZ = 1.0f; g_pDirect3D_Device->SetViewport(&vp); // ウィンドウの表示 ShowWindow(hMainWnd, nShow); UpdateWindow(hMainWnd); // Live2Dの初期化 live2d::Live2D::init(); const LPCWSTR TEXTURES[] = { L"res\\haru\\haru.1024\\texture_00.png" , L"res\\haru\\haru.1024\\texture_01.png" , L"res\\haru\\haru.1024\\texture_02.png" , NULL , }; // モデルのロード live2DModel = live2d::Live2DModelD3D::loadModel("res\\haru\\haru.moc"); // テクスチャのロード for( int i = 0 ; i < 1000 ; i++ ){ if( ! TEXTURES[i] ) break; LPDIRECT3DTEXTURE9 tex; // テクスチャ画像をDirextXでの表示用に変換 if( FAILED( D3DXCreateTextureFromFileExW( g_pDirect3D_Device , TEXTURES[i] , 0 //width , 0 //height , 0 // mipmap( 0なら完全なミップマップチェーン) , 0 //Usage , D3DFMT_A8R8G8B8 , D3DPOOL_MANAGED , D3DX_FILTER_LINEAR , D3DX_FILTER_BOX , 0 , NULL , NULL , &tex ) ) ) { live2d::UtDebug::print("Could not create texture"); return FALSE; } else { live2DModel->setTexture( i , tex ); } } while(GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } g_pDirect3D_Device->Release(); g_pDirect3D->Release(); return(0); } LRESULT WINAPI WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { case WM_DESTROY: PostQuitMessage(0); return(0); case WM_PAINT: g_pDirect3D_Device->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(255, 255, 255), 1.0f, 0); g_pDirect3D_Device->BeginScene(); // 行列の設定 D3DXMATRIXA16 matWorld; D3DXMatrixIdentity( &matWorld ); D3DXMATRIX Ortho2D; D3DXMATRIX Identity; D3DXMatrixOrthoLH(&Ortho2D, 3000.0f, 3000.0f, -1.0f, 1.0f); D3DXMatrixIdentity(&Identity); g_pDirect3D_Device->SetTransform(D3DTS_PROJECTION, &Ortho2D); g_pDirect3D_Device->SetTransform(D3DTS_WORLD, &Identity); g_pDirect3D_Device->SetTransform(D3DTS_VIEW , &Identity); // --- Live2D 用の描画設定 --- g_pDirect3D_Device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); g_pDirect3D_Device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); g_pDirect3D_Device->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); g_pDirect3D_Device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);// アルファ・ブレンディングを行う g_pDirect3D_Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);// 透過処理を行う g_pDirect3D_Device->SetRenderState(D3DRS_SRCBLEND , D3DBLEND_SRCALPHA);// 半透明処理を行う g_pDirect3D_Device->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); g_pDirect3D_Device->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); g_pDirect3D_Device->SetSamplerState( 0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR); // --- 座標変換 // 現在のLive2Dモデルは、画像のように下向きに(0,0,w,h)に配置されるため // センタリングと上下逆転を行う float modelWidth = live2DModel->getModelImpl()->getCanvasWidth(); float modelHeight = live2DModel->getModelImpl()->getCanvasHeight(); D3DXMATRIXA16 world, scale, trans; g_pDirect3D_Device->GetTransform(D3DTS_WORLD, &world); D3DXMatrixScaling(&scale, 1, -1, 1); // 上下逆転 D3DXMatrixTranslation(&trans , -modelWidth/2, -modelHeight/2, 0); world = trans * scale * world; g_pDirect3D_Device->SetTransform(D3DTS_WORLD, &world);
// --- 描画 live2DModel->setDevice(g_pDirect3D_Device); live2DModel->update(); live2DModel->draw(); g_pDirect3D_Device->EndScene(); g_pDirect3D_Device->Present(NULL, NULL, NULL, NULL); ValidateRect(hwnd, NULL); return(0); } return(DefWindowProc(hwnd, msg, wParam, lParam)); }
|