DirectXの学習をしています。ほぼ初っ端で躓いてしまった感じなので、DirectXは初心者です。
まずはいくらかフレームレートを制御したテンプレートもどきを作成しようと思ったのですが、どうも上手くいきませんでした。
ごく単純な三角形の描画ですらCPU使用率が10%前後出てしまうのです。(PeekMessageは使わなくともです)
しかし、dxlibでは、キャラクターモデルの描画を3DでやってみてもCPU使用率はほぼ0%。
またOpenGLでは、以下のコード(どことなく作法が悪いような気がします)と同じようなやり方をしてもCPU使用率はほぼ0%です。
設定が間違っているのか?あるいは書き方がどこかおかしいのか?
何かがおかしいわけですが、その原因がわかりません。
ひょっとすると馬鹿馬鹿しい思い違いでもしているのかもしれません。
とにかく、どこが間違っているか教えていただきたく思い、書き込みました。
どうぞよろしくお願いします。
// 環境
Win7 64bit
CPU CORE2DUO 3.16GHz
Memory 4G
VisualC++ 2010 SP1
三角形が回転するだけのプログラムです。
#include <Windows.h>
#include <d3dx9.h>
#include <d3d9.h>
//#include <DxErr.h>
//#include <strsafe.h>
#pragma comment( lib , "d3d9.lib")
#pragma comment( lib , "d3dx9.lib")
//#pragma comment( lib , "dxerr.lib")
//#pragma comment( lib , "dxguid.lib")
// このあたり適当です。
#define APP_NAME L"アプリ名だ。"
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ | D3DFVF_DIFFUSE)
struct CUSTOMVERTEX{
FLOAT x,y,z;
DWORD color;
};
// GLOBAL
int testCount=0;// WM_TIMERが動いていないことを証してくれる。
unsigned int count=0;// これを引数にして回転の角度が決まる。
HWND hWnd;
LPDIRECT3D9 g_pD3D=NULL;
LPDIRECT3DDEVICE9 g_pd3dDevice = NULL;
LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL;
D3DPRESENT_PARAMETERS d3dpp;
VOID* pVertices;
// Functions
HRESULT InitD3D(HWND hWnd);// DirectX の初期化
HRESULT InitGeometry();// テスト用三角形のバッファをつくる。ウィンドウ作成前に一度だけ呼ばれる。
VOID Cleanup();// 終了用に色々解放する。
VOID SetupMatrices(int count);// 行列を設定。レンダーの度に呼ばれる。
VOID Render(int county);// 描画。
LRESULT CALLBACK WindowProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam);// コールバック。
// directXの初期化
HRESULT InitD3D(HWND hWnd){
if(NULL==(g_pD3D = Direct3DCreate9(D3D_SDK_VERSION))) return E_FAIL;
ZeroMemory(&d3dpp , sizeof(d3dpp));
d3dpp.Windowed = TRUE ;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
if (FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT , D3DDEVTYPE_HAL , hWnd ,
D3DCREATE_SOFTWARE_VERTEXPROCESSING ,
&d3dpp , &g_pd3dDevice)))
{
return E_FAIL;
}
D3DVIEWPORT9 vp;
vp.X=0;
vp.Y=0;
vp.Width=d3dpp.BackBufferWidth;
vp.Height=d3dpp.BackBufferHeight;
vp.MinZ=0.0f;
vp.MaxZ=1.0f;
HRESULT hr = (g_pd3dDevice->SetViewport(&vp));
if (FAILED(hr)) return E_FAIL;
g_pd3dDevice->SetRenderState(D3DRS_CULLMODE , D3DCULL_NONE);
g_pd3dDevice->SetRenderState(D3DRS_LIGHTING , FALSE);
return S_OK;
}
HRESULT InitGeometry(){
CUSTOMVERTEX g_Vertices[] =
{
{-1.0f , -1.0f , 0.0f , 0xffff8888, },
{ 1.0f , -1.0f , 0.0f , 0xff77aaff, },
{ 0.0f , 1.0f , 0.0f , 0xffddffee, },
};
if (FAILED(g_pd3dDevice->CreateVertexBuffer(3 * sizeof(CUSTOMVERTEX) ,
0 , D3DFVF_CUSTOMVERTEX,
D3DPOOL_DEFAULT , &g_pVB , NULL)))
{
return E_FAIL;
}
if (FAILED(
g_pVB->Lock(0 , sizeof(g_Vertices) , (void**)&pVertices , 0)
)
)
{
return E_FAIL;
}
memcpy(pVertices , g_Vertices , sizeof(g_Vertices));
g_pVB->Unlock();
return S_OK;
}
VOID Cleanup()
{
if( g_pVB != NULL )
g_pVB->Release();
if( g_pd3dDevice != NULL )
g_pd3dDevice->Release();
if( g_pD3D != NULL )
g_pD3D->Release();
}
VOID SetupMatrices(int count)
{
D3DXMATRIXA16 matWorld;
FLOAT fAngle = count * ( 2.0f * D3DX_PI ) / 180.0f;
D3DXMatrixRotationY( &matWorld, fAngle );
g_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );
D3DXVECTOR3 vEyePt( 0.0f, 3.0f,-5.0f );
D3DXVECTOR3 vLookatPt( 0.0f, 0.0f, 0.0f );
D3DXVECTOR3 vUpVec( 0.0f, 1.0f, 0.0f );
D3DXMATRIXA16 matView;
D3DXMatrixLookAtLH( &matView, &vEyePt, &vLookatPt, &vUpVec );
g_pd3dDevice->SetTransform( D3DTS_VIEW, &matView );
D3DXMATRIXA16 matProj;
D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI / 4, 1.0f, 1.0f, 100.0f );
g_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );
}
VOID Render(int count)
{
g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB( 0, 0, 0 ), 1.0f, 0 );
if( SUCCEEDED( g_pd3dDevice->BeginScene() ) )
{
SetupMatrices(count);// これをコメントアウトしてもCPU使用率は高いまま。
g_pd3dDevice->SetStreamSource( 0, g_pVB, 0, sizeof( CUSTOMVERTEX ) );
// ↑if(count <30)のようにしてもCPU使用率は高い。
g_pd3dDevice->SetFVF( D3DFVF_CUSTOMVERTEX );// ブロックの外でこれを描いても変わらず。
g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 1 );// こいつが犯人だと睨んでいる
g_pd3dDevice->EndScene();
}
else {count = 0;}
g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
}
LRESULT CALLBACK WindowProc(
HWND hWnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
switch(uMsg){
case WM_CREATE:
SetTimer(hWnd , 1 , 1 , NULL);// しかし意図したようには動かなかった。
return 0;
case WM_DESTROY:
Cleanup();
PostQuitMessage(0);
return 0;
/////////////////////////////////////////////
/////////////////////////////////////////////
/////////////////////////////////////////////
case WM_TIMER:
// WM_PAINTがコメントアウトされていれば、動くような感じ。
testCount++;// 実行されていない
if (testCount==10){MessageBox(NULL , L"OpenGL" , NULL , MB_OK);}// 実行されていない
count++;// 多分実行されていない
SendMessage(hWnd , WM_PAINT , 0 , 0);// 多分実行されていない
return 0;
case WM_PAINT:
count++;
Render(count);
return 0;
// 1.このWM_PAINTをコメントアウトしてしまえばCPU使用率は0%になります。
// 2.WM_PAINTをコメントアウトして、ShowWindow(hWnd , SW_SHOW)の直後に一度だけRender()を呼ぶとCPU使用率は0%に。
// 3.Render()内の、SetupMatrices()をコメントアウトしても(つまり静止した三角形のみ表示)CPU使用率は10%ほど。などなど。
// DEBUG , RELEASEどちらも同じような謎負荷で動く。
/////////////////////////////////////////////
/////////////////////////////////////////////
/////////////////////////////////////////////
}
return DefWindowProc(hWnd , uMsg , wParam , lParam);
}
int WINAPI WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
PSTR lpCmdLine,
int nCmdShow)
{
WNDCLASS wc;
MSG msg;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WindowProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL , IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL , IDC_ARROW);
wc.hbrBackground= (HBRUSH)COLOR_BACKGROUND + 1;
wc.lpszMenuName = NULL;
wc.lpszClassName= APP_NAME;
if (!RegisterClass(&wc)){
MessageBox(NULL , TEXT("ウィンドウクラスの作成に失敗しました。") , NULL , MB_OK);
return 0;
}
hWnd = CreateWindow(
APP_NAME ,
APP_NAME ,
WS_OVERLAPPEDWINDOW ,
100 ,
100 ,
640 ,
480 ,
NULL,
NULL,
hInstance,
NULL);
HRESULT hr=InitD3D(hWnd);
if (SUCCEEDED(hr)) hr=InitGeometry();
if (FAILED(hr)){
UnregisterClass(APP_NAME , wc.hInstance);
return 0;
}
ShowWindow(hWnd , SW_SHOW);
if (hWnd==NULL){
MessageBox(NULL , TEXT("ウィンドウの生成に失敗しました。") , NULL , MB_OK);
return 0;
}
while (GetMessage(&msg , NULL , 0 , 0) > 0){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
↓ちなみにOpenGLのコードはコレを改変しました。
http://msdn.microsoft.com/en-us/library/windows/desktop/dd369065(v=vs.85).aspx
・WM_CREATEにSetTimer(hWnd , 1 , 1 , NULL)を追加
・WM_PAINTをコメントアウト。(作法としてはよろしくないかも?)
・WM_TIMERでdrawScene();break;
・PeekMessageを含むwhile(1)を、
while(GetMessage(&msg , NULL , 0,0) >0){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
に変更。