山本ワールド
Windowsプログラミング
アルゴリズム Vitual C++ 2008/2013によるWin32/Win64 APIレベルのプログラム 基礎 Vitual C++ 2008/2013によるAPIレベルのプログラム(32/64bit) Wix3でインストーラーを作る Visual C++ 2008 Standard Editonによるフォームアプリケーションのプログラム(32/64bit) Vitual C++ 2008 Standard EditonによるAPIレベルのプログラム(32/64bit) Windows 7対応 Visual C++ 2008 ExpressによるAPIレベルのプログラム Visual C++ 2005 ExpressによるAPIレベルのプログラム Visual C++ Versiosn 5 BORLAND C++ Windowsプログラム全般 Excel VBA その他DrawTextを用いて文字をワールド座標に描画(DirectX9 32/64bit)
概要
Direct X 9を用い、3D空間にX軸として赤線(0,0,0)-(500,0,0)、Y軸として緑線(0,0,0)-(0,500,0)、Z軸として青線(0,0,0)-(0,0,500)を描画します。
文字は、DrawText関数を用いて描画します。DrawText関数は、スクリーン座標で位置を指定するため、ワールド座標をスクリーン座標に変換する必要があります。D3DXVec3Project関数をもちいれば簡単に変換できます。
ソースコードのダウンロード 3d_drawtext.zip
ソースコードの説明
WinMain
最初に実行される関数です。
最初にウィンドウを作成し、Init3DDev関数でDirect Xの初期化を行います。
その後通常のWinMain関数と同じ様にメッセージループを構成しますが、メッセージの取り出しにGetMessage関数ではなく、PeekMessage関数を使用し、メッセージがないときもループが回るようにします。メッセージがないときにDraw関数を呼び出し描画を行います。
プログラム終了前にInit3DDevで作成したデバイスを開放します。
WndProc
ウィンドウプロシージャーです。ウィンドウ関係のメッセージを処理します。通常WM_PAINTメッセージにより再描画を行いますが、スピードが要求される場合は、前期のとおり別の場所で処理しています。
Init3Devices
Direct Xの初期化を行います。
InitFont
D3DXCreateFont関数によりフォントオブジェクトを作成します。
Render
画面のクリア Clear
レンタリング開始 BeginScene
D3DXMatrixLookAtLH
ワールド座標をビュー座標に変換する。ワールド座標のどの方向からどの範囲を見るか(描画するか)を設定する。この関数は、左手座標(Xが右、Yが上、Zが奥行方向で奥 左手で手のひらを上側がにし人差し指をX方向に向けた時における親指のさしている方向がZ値が増える方向である。)においてワールド座標をビュー座標に変換する。SetTransform関数により設定。
D3DXMatrixPerspectiveFovLH
描画する遠近それぞれのZ値、画面の縦横比(アスペクト)、Y方向の視野角を指定する。SetTransform関数により設定。
DrawPrimitiveUP
線分を描画します。
D3DXVec3Project( D3DXVECTOR3 *pOut, CONST D3DXVECTOR3 *pV, CONST D3DVIEWPORT9 *pViewport, CONST D3DXMATRIX *pProjection, CONST D3DXMATRIX *pView, CONST D3DXMATRIX *pWorld );
ワールド座標をスクリーン座標に変換する。
pvに変換したいワールド座標
pViewportにウィンドウサイズを設定
pProjectionにD3DXMatrixPerspectiveFovLHで使用したマトリックスを設定
pViewにD3DXMatrixLookAtLHで使用したマトリックスを設定
pwordにワールド変換行列を設定します。本プログラムの場合、pvにワールド座標を設定しますので、D3DXMatrixIdentityで初期化された行列を設定します。
SetRect
文字の表示位置を設定します。
DrawText
文字を表示します。内部でGDIを使っていますので、遅いです。デバック用といったところでしょうか。
レンタリング終了 EndScene
バッファの内容を表示 Present
コンパイル方法
Visual C++ 2008
Microsoft DirectX SDK June 2010をインストールをあらかじめ行っておく
プロジェクトに下記のパスを追加(64bit Windowsで64bitの実行ファイルを作成する場合)
includeパスにC:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\Include
LibパスにC:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\Lib\x64
を追加
ソースコード
// DrawTextを使ったワールド座標への文字表示 Direct X 9
#define szClassName TEXT("3D_DrawText")
#include <windows.h>
#include <d3dx9.h>
#include <tchar.h>
#pragma once
#pragma comment(lib,"d3d9.lib")
#pragma comment(lib,"d3dx9.lib")
#pragma comment(lib,"winmm.lib")
#define SAFE_RELEASE(p) { if (p) { (p)->Release(); (p)=NULL; } }
typedef struct _D3DVERTEX{
D3DXVECTOR3 position; // 頂点座標
D3DXVECTOR3 normal; // 法線方向
} D3DVERTEX;
#define D3DFVF_VERTEX (D3DFVF_XYZ|D3DFVF_NORMAL)
//頂点フォーマット
#define D3DFVF_VERTEXCOL (D3DFVF_XYZ | D3DFVF_DIFFUSE) //トランスフォームされていない頂点の位置座標+ディフューズ カラー成分
typedef struct _D3DVERTEXCOR_ {
float x,y,z; // トランスフォームされていない頂点の位置座標
DWORD color; // ディフューズ カラー成分
} D3DVERTEXCOR;
D3DVERTEXCOR gauge_x[]={ { 0,0,0,0xffff0000 }
,{400,0,0,0xffff0000 } };
D3DVERTEXCOR gauge_y[]={ { 0,0,0,0xff00ff00 },
{ 0,400,0,0xff00ff00 } };
D3DVERTEXCOR gauge_z[]={ { 0,0,0,0xff0000ff },
{ 0,0,400,0xff0000ff } };
int sx=0; // スクリーン座標
int sy=0;
D3DPRESENT_PARAMETERS D3DPPWin;
LPDIRECT3DDEVICE9 pDEV=0;
LPDIRECT3D9 pD3D=0;
LPD3DXFONT pFont = NULL; //フォント
BOOL InitApp(HINSTANCE, WNDPROC, TCHAR*);
BOOL InitInstance(HINSTANCE, TCHAR*, int);
HWND hWnd;
HRESULT InitDevices(HWND hWnd); // デバイス/モード等の初期化
LRESULT WINAPI WndProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam);
void Render(void);// 描画処理
//フォントの初期化
HRESULT InitFont(HWND hWnd){
//フォントの生成 MSゴシック
//デバイス,文字高さ,文字幅,フォントスタイル,ミップマップのレベル,斜体にするかどうか,文字セット,出力精度,出力品質,フォントピッチとファミリ,フォント名,フォントポインタ
HRESULT hr = D3DXCreateFont( pDEV, 20, 0, FW_HEAVY, 1, false, DEFAULT_CHARSET, OUT_TT_ONLY_PRECIS,
ANTIALIASED_QUALITY, FF_DONTCARE, TEXT("MS 明朝"), &pFont );
if FAILED(hr){return(E_FAIL);}
return S_OK;
}
void Cleanup(void); // オブジェクトの開放
INT WINAPI _tWinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPTSTR lptsCmdLine, INT nCmdShow){
MSG msg;
if (!hPrevInst) {
if (!InitApp(hInst,WndProc, szClassName)) // ウィンドウクラスの登録
return FALSE;
}
if (!InitInstance(hInst, szClassName, nCmdShow)) { // ウィンドウの作成
return FALSE;
}
if (FAILED(InitDevices(hWnd)))
return FALSE;
ShowWindow(hWnd,SW_SHOWDEFAULT);
UpdateWindow(hWnd);
ZeroMemory(&msg,sizeof(msg));
while(msg.message!=WM_QUIT){
if (PeekMessage(&msg,NULL,0U,0U,PM_REMOVE)){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
Render();
}
Cleanup();
return 0;
}
BOOL InitApp(HINSTANCE hInst,WNDPROC WndProc,TCHAR* Name){
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInst;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = (TCHAR*)Name;
return (RegisterClass(&wc));
}
BOOL InitInstance(HINSTANCE hInst, TCHAR* Name, int nCmdShow){
hWnd = CreateWindow(Name,
Name,
WS_OVERLAPPEDWINDOW,
0,
0,
320,
240,
NULL,
NULL,
hInst,
NULL);
if (!hWnd)
return FALSE;
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
// デバイス/モード等の初期化
HRESULT InitDevices(HWND hWnd){
D3DDISPLAYMODE dmode;
HRESULT hr;
// デバイス/モード等の初期化
if (pD3D==NULL)
pD3D = Direct3DCreate9(D3D_SDK_VERSION);
if (pD3D==NULL)
return E_FAIL;
//現在のディスプレイモードを得る
if (FAILED(pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,&dmode)))
return E_FAIL;
// D3DDeviceオブジェクトの作成
ZeroMemory(&D3DPPWin, sizeof(D3DPPWin));
D3DPPWin.BackBufferFormat = dmode.Format;
D3DPPWin.BackBufferCount = 1;
D3DPPWin.SwapEffect = D3DSWAPEFFECT_DISCARD;
D3DPPWin.Windowed = TRUE;
D3DPPWin.EnableAutoDepthStencil = TRUE;
D3DPPWin.AutoDepthStencilFormat = D3DFMT_D16;
D3DPPWin.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
hr = pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
D3DCREATE_HARDWARE_VERTEXPROCESSING, &D3DPPWin, &pDEV);
if (FAILED(hr)){
hr = pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,D3DCREATE_SOFTWARE_VERTEXPROCESSING, &D3DPPWin, &pDEV);
if (FAILED(hr)){
hr = pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &D3DPPWin, &pDEV);
if (FAILED(hr)){
MessageBox(NULL,TEXT("Create Device Error"),TEXT("Surface Error"),MB_OK);
return E_FAIL;
}
}
}
InitFont(hWnd);
return S_OK;
}
LRESULT WINAPI WndProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam){
switch(msg){
case WM_SIZE:
sx = LOWORD(lParam); // クライアント領域の幅
sy = HIWORD(lParam); // クライアント領域の高さ
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd,msg,wParam,lParam);
}
// 描画処理
void Render(void){
D3DXMATRIX matWorld;
D3DXMATRIX matView;
D3DXMATRIX matProj;
pDEV->Clear(0,NULL,D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,D3DCOLOR_XRGB(0,0,0),1.0f,0);
pDEV->BeginScene();
D3DVIEWPORT9 vp;
vp.X = 0;
vp.Y = 0;
vp.Width = D3DPPWin.BackBufferWidth;
vp.Height =D3DPPWin.BackBufferHeight;
vp.MinZ = 0.0f;
vp.MaxZ = 1.0f;
D3DXMatrixIdentity(&matView);
D3DXMatrixIdentity(&matProj);
D3DXMatrixLookAtLH(&matView, &D3DXVECTOR3( 1000, 1000,-1000),
&D3DXVECTOR3(0,0,0), &D3DXVECTOR3( 0.0f, 1.0f, 0.0f));
pDEV->SetTransform(D3DTS_VIEW, &matView);
D3DXMatrixPerspectiveFovLH(&matProj, D3DX_PI/4, float(sx)/float(sy), -1000,0);
pDEV->SetTransform(D3DTS_PROJECTION, &matProj);
pDEV->SetRenderState(D3DRS_CULLMODE,D3DCULL_CCW); //反時計回りの面を消去
pDEV->SetRenderState(D3DRS_LIGHTING,FALSE); //ライティングしない
pDEV->SetRenderState(D3DRS_ZENABLE,D3DZB_FALSE); //Zバッファ使わない
pDEV->SetFVF(D3DFVF_VERTEXCOL);
pDEV->DrawPrimitiveUP(D3DPT_LINELIST,1,gauge_x,sizeof(D3DVERTEXCOR));
pDEV->DrawPrimitiveUP(D3DPT_LINELIST,1,gauge_y,sizeof(D3DVERTEXCOR));
pDEV->DrawPrimitiveUP(D3DPT_LINELIST,1,gauge_z,sizeof(D3DVERTEXCOR));
D3DXVECTOR3 wvec,vec;
D3DXMATRIX matW;
RECT rect;
D3DXMatrixIdentity( &matW);
wvec.x=0;
wvec.y=0;
wvec.z=0;
D3DXVec3Project(&vec, &wvec, &vp, &matProj, &matView, &matW );
SetRect(&rect ,int(vec.x) , int(vec.y) , 100,20);
pFont->DrawText(NULL, TEXT("0,0,0"), -1, &rect, DT_LEFT | DT_NOCLIP, D3DCOLOR_ARGB(255, 255, 255, 255));
wvec.x=gauge_x[1].x;
wvec.y=gauge_x[1].y;
wvec.z=gauge_x[1].z;
D3DXVec3Project(&vec, &wvec, &vp, &matProj, &matView, &matW );
SetRect(&rect ,int(vec.x) , int(vec.y) , 100,20);
pFont->DrawText(NULL, TEXT("500,0,0"), -1, &rect, DT_LEFT | DT_NOCLIP, D3DCOLOR_ARGB(255, 255, 0, 0));
wvec.x=gauge_y[1].x;
wvec.y=gauge_y[1].y;
wvec.z=gauge_y[1].z;
D3DXVec3Project(&vec, &wvec, &vp, &matProj, &matView, &matW );
SetRect(&rect ,int(vec.x) , int(vec.y) , 100,20);
pFont->DrawText(NULL, TEXT("0,500,0"), -1, &rect, DT_LEFT | DT_NOCLIP, D3DCOLOR_ARGB(255, 0, 255, 0));
wvec.x=gauge_z[1].x;
wvec.y=gauge_z[1].y;
wvec.z=gauge_z[1].z;
D3DXVec3Project(&vec, &wvec, &vp, &matProj, &matView, &matW );
SetRect(&rect ,int(vec.x) , int(vec.y) , 100,20);
pFont->DrawText(NULL, TEXT("0,0,500"), -1, &rect, DT_LEFT | DT_NOCLIP, D3DCOLOR_ARGB(255, 0, 0, 255));
pDEV->EndScene();
pDEV->Present(NULL,NULL,NULL,NULL);
}
// オブジェクトの開放
void Cleanup(void){
SAFE_RELEASE(pFont);
SAFE_RELEASE(pDEV);
SAFE_RELEASE(pD3D);
}