Direct3Dの解説 8 Zバッファ


/*----------------------------------------------------------
DirectX 5
Direct3D IM
--------------------------------------------------------------*/
 
#define STRICT
#include <windows.h>
#include <string.h>
 
#define D3D_OVERLOADS
#include <ddraw.h>
#include <d3d.h>
 
#include "jdmatrix.h"
#include "jdtex.h"
 
#define RELEASE(x) if(x){x->Release();x=NULL;}
 
/*-------------------------------------------
外部変数
--------------------------------------------*/
 
HINSTANCE hInstApp;
HWND hwndApp;
 
char szAppName[] = "Direct3D IM test";
char szDevice[128], szDDDeviceName[128] = "default";
 
LPDIRECTDRAW2 pDDraw = NULL;
LPDIRECTDRAWSURFACE3 pScreen = NULL;
LPDIRECTDRAWSURFACE3 pBackBuffer = NULL;
LPDIRECTDRAWSURFACE3 pZBuffer = NULL;
 
LPDIRECT3D2 pD3D = NULL;
LPDIRECT3DDEVICE2 pD3DDevice = NULL;
LPDIRECT3DVIEWPORT2 pD3DVP = NULL;
D3DTexture* pTexture = NULL;
D3DTEXTUREHANDLE hTexture;
 
LPDIRECT3DMATERIAL2 pD3DMat = NULL;
LPDIRECT3DLIGHT pD3DLight = NULL;
D3DMATERIALHANDLE hMaterial;
 
int view_countx = 0;
int view_count = 0;
int view_county = 0;
int view_countz = 0;
 
D3DMATRIX viewMatrix;
D3DMATRIX projMatrix;
 
LRESULT CALLBACK MainWndProc(HWND hWnd,UINT msg,UINT wParam,LONG lParam);
 
 
/*-----------------------------------------
立体データ
---------------------------------------------*/
long cubeVertex[8][3] = {
{100,100,100},
{-100,100,100},
{-100,-100,100},
{100,-100,100},
{100,100,-100},
{100,-100,-100},
{-100,-100,-100},
{-100,100,-100},
};
 
int cubeFace[6][4] = {
{3,2,6,5},
{4,5,6,7},
{0,3,5,4},
{1,0,4,7},
{2,1,7,6},
{0,1,2,3},
};
 
long cubeVNormal[8][3] = {
{1,1,1},
{-1,1,1},
{-1,-1,1},
{1,-1,1},
{1,1,-1},
{1,-1,-1},
{-1,-1,-1},
{-1,1,-1},
};
 
/*-------------------------------------------
アプリケーション初期化
--------------------------------------------*/
int InitApp(HINSTANCE hInst,int nCmdShow)
{
WNDCLASS wndclass;
 
hInstApp=hInst;
 
/*ウィンドウクラスの登録*/
wndclass.hCursor =LoadCursor(NULL,IDC_ARROW);
wndclass.hIcon =NULL;
wndclass.lpszMenuName =NULL;
wndclass.lpszClassName ="Main Window";
wndclass.hbrBackground =(HBRUSH)GetStockObject(BLACK_BRUSH);
wndclass.hInstance =hInst;
wndclass.style =CS_BYTEALIGNCLIENT|CS_VREDRAW|CS_HREDRAW;
wndclass.lpfnWndProc =(WNDPROC)MainWndProc;
wndclass.cbClsExtra =0;
wndclass.cbWndExtra =0;
 
if(!RegisterClass(&wndclass))
 return FALSE;
 
/*メインウィンドウ*/
hwndApp = CreateWindowEx(0,"Main Window",szAppName,
WS_POPUP,
0,0,640,480,
(HWND)NULL,(HMENU)NULL,
hInst,(LPSTR)NULL);
ShowWindow(hwndApp,nCmdShow);
UpdateWindow(hwndApp);
 
return TRUE;
}
/*-------------------------------------------
// DirectDraw デバイスの列挙と選定
--------------------------------------------*/
BOOL CALLBACK DDEnumCallback(GUID FAR* lpGUID, LPSTR lpDriverDesc, LPSTR lpDriverName, LPVOID lpContext)
{
 LPDIRECTDRAW lpDD;
 DDCAPS DriverCaps, HELCaps;
 
 // DirectDraw オブジェクトを試験的に生成する
 if ( DirectDrawCreate(lpGUID, &lpDD, NULL) != DD_OK ) {
  *(LPDIRECTDRAW*)lpContext = NULL;
  return DDENUMRET_OK;
 }
 
// DirectDrawの能力を取得
ZeroMemory(&DriverCaps, sizeof(DDCAPS));
DriverCaps.dwSize = sizeof(DDCAPS);
ZeroMemory(&HELCaps, sizeof(DDCAPS));
HELCaps.dwSize = sizeof(DDCAPS);
 
 if (lpDD->GetCaps(&DriverCaps, &HELCaps) == DD_OK) {
  // ハードウェア3D支援が期待できる場合で.
  // なおかつテクスチャが使用できる場合それを使う
   if ((DriverCaps.dwCaps & DDCAPS_3D) && (DriverCaps.ddsCaps.dwCaps & DDSCAPS_TEXTURE)) {
    *(LPDIRECTDRAW*)lpContext = lpDD;
    lstrcpy(szDDDeviceName, lpDriverDesc);
    return DDENUMRET_CANCEL;
   }
 }
 
// 他のドライバを試す
*(LPDIRECTDRAW*)lpContext = NULL;
RELEASE(lpDD);
 
return DDENUMRET_OK;
}
 
/*-------------------------------------------
DirectDraw 初期化
--------------------------------------------*/
int InitDDraw(void)
{
HRESULT ret;
 
LPDIRECTDRAW pOldDDraw = NULL;
// DirectDrawドライバを列挙する
ret = DirectDrawEnumerate(DDEnumCallback, &pOldDDraw);
 
// 列挙によってDirectDrawドライバが決定
// しなかった場合,現在アクティブなドライバを使う
if (!pOldDDraw) {
 lstrcpy(szDDDeviceName, "Active Driver");
 ret = DirectDrawCreate(NULL,&pOldDDraw,NULL);
}
 
if(ret != DD_OK)
 return FALSE;
 
//ここでウィンドウモードを設定する
ret = pOldDDraw->SetCooperativeLevel(hwndApp,DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
 
// 新しいDirectDraw2オブジェクトを取得する
// 古いDirectDrawオブジェクトは破棄する
ret = pOldDDraw->QueryInterface(IID_IDirectDraw2, (LPVOID *)&pDDraw);
RELEASE(pOldDDraw);
if(ret != DD_OK)
 return FALSE;
 
//フル画面のとき画面サイズを設定する
// (640*480-HiColorデフォルトのリフレッシュ・レート)
ret = pDDraw->SetDisplayMode(640,480,16,0,0);
if(ret != DD_OK){
 RELEASE(pDDraw);
 return FALSE;
}
 
//サーフェースを作成する
DDSURFACEDESC ddsd;
 
ZeroMemory(&ddsd,sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX | DDSCAPS_3DDEVICE;
ddsd.dwBackBufferCount = 1;
 
//プライマリサーフェース
LPDIRECTDRAWSURFACE pOldScreen;
ret = pDDraw->CreateSurface(&ddsd,&pOldScreen,NULL);
if(ret != DD_OK){
 RELEASE(pDDraw);
 return FALSE;
}
// 新しいDirectDrawSurface3を生成し古いオブジェクトは開放する
ret = pOldScreen->QueryInterface(IID_IDirectDrawSurface3, (LPVOID *)&pScreen);
RELEASE(pOldScreen);
if(ret != DD_OK) {
 RELEASE(pDDraw);
 return FALSE;
}
 
// バック・バッファを取得する
DDSCAPS ddscaps;
ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
ret = pScreen->GetAttachedSurface(&ddscaps, &pBackBuffer);
if(ret != DD_OK){
 RELEASE(pScreen);
 RELEASE(pDDraw);
 return FALSE;
}
 
return TRUE;
}
 
 
/*-------------------------------------------
Direct3D 初期化
--------------------------------------------*/
int InitD3D(void)
{
HRESULT ret;
 
//Direct3D IMオブジェクトの作成
ret = pDDraw->QueryInterface(IID_IDirect3D2,(void**)&pD3D);
if(ret != DD_OK){
 return FALSE;
}
 
 
// Z Bufferを作る
LPDIRECTDRAWSURFACE pOldScreen;
DDSURFACEDESC ddsd;
D3DFINDDEVICESEARCH findSearch;
D3DFINDDEVICERESULT findResult;
 
// 3Dハードウェア機能の有無を調べる
ZeroMemory(&findSearch,sizeof(findSearch));
findSearch.dwSize = sizeof(findSearch);
findSearch.dwFlags = D3DFDS_HARDWARE;
findSearch.bHardware = TRUE;
ZeroMemory(&findResult,sizeof(findResult));
findResult.dwSize = sizeof(findResult);
ret = pD3D->FindDevice(&findSearch,&findResult);
 
// バック・バッファがビデオ・メモリ上にあるかどうかを調べる
DDSCAPS caps;
pBackBuffer->GetCaps(&caps);
BOOL zsys = caps.dwCaps & DDSCAPS_VIDEOMEMORY;
 
ZeroMemory(&ddsd,sizeof(DDSURFACEDESC));
ddsd.dwSize = sizeof(DDSURFACEDESC);
ddsd.dwFlags = DDSD_CAPS | DDSD_ZBUFFERBITDEPTH | DDSD_HEIGHT | DDSD_WIDTH;
if(ret == DD_OK && zsys)
 ddsd.ddsCaps.dwCaps = DDSCAPS_VIDEOMEMORY | DDSCAPS_ZBUFFER;
else
 ddsd.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY | DDSCAPS_ZBUFFER;
ddsd.dwWidth = 640;
ddsd.dwHeight = 480;
ddsd.dwZBufferBitDepth = 16;
 
ret = pDDraw->CreateSurface(&ddsd,&pOldScreen,NULL);
if(ret==DD_OK)
 ret = pOldScreen->QueryInterface(IID_IDirectDrawSurface3, (LPVOID*)&pZBuffer);
 RELEASE(pOldScreen);
if(ret==DD_OK)
 pBackBuffer->AddAttachedSurface(pZBuffer);
else {
 
 RELEASE(pD3D);
 RELEASE(pScreen);
 RELEASE(pDDraw);
 return FALSE;
}
/*---------------------------------------------------------
D3Dデバイスの取得
HAL , MMX , RGB の優先順位(速い順)で取得テスト
----------------------------------------------------------*/
//HAL
ret = pD3D->CreateDevice(IID_IDirect3DHALDevice,(LPDIRECTDRAWSURFACE)
pBackBuffer,&pD3DDevice);
strcpy(szDevice,"D3D HAL");
if(ret != DD_OK){
//MMX
ret = pD3D->CreateDevice(IID_IDirect3DMMXDevice,(LPDIRECTDRAWSURFACE)
pBackBuffer,&pD3DDevice);
strcpy(szDevice,"D3D MMX Emulation");
}
if(ret != DD_OK){
 //RGB
 ret = pD3D->CreateDevice(IID_IDirect3DRGBDevice,(LPDIRECTDRAWSURFACE)
pBackBuffer,&pD3DDevice);
 strcpy(szDevice,"D3D RGB Emulation");
}
 
if(ret != DD_OK)
 return FALSE; //失敗
 
//ビューポートの作成,設定
D3DVIEWPORT2 vp;
ZeroMemory(&vp,sizeof(vp));
vp.dwSize = sizeof(vp);
vp.dwX = 0;
vp.dwY = 0;
vp.dwWidth = 640;
vp.dwHeight = 480;
vp.dvClipX = -1.0f;
vp.dvClipWidth = 2.0f;
vp.dvClipY = (float)480/(float)640;
vp.dvClipHeight = vp.dvClipY * 2.0f;
vp.dvMinZ = 0.0f;
vp.dvMaxZ = 1.0f;
 
pD3D->CreateViewport(&pD3DVP,NULL);
pD3DDevice->AddViewport(pD3DVP);
pD3DDevice->SetCurrentViewport(pD3DVP);
pD3DVP->SetViewport2(&vp);
 
return TRUE;
}
 
float ly=100;
/*--------------------------------------------
準備
------------------------------------------------*/
int InitObject(void)
{
//テクスチャ作成
pTexture = new D3DTexture;
pTexture->Load(pDDraw, pD3DDevice, "d3dtest.bmp");
hTexture = pTexture->GetHandle();
 
//変換マトリックスの設置
CreateViewMatrix(viewMatrix, D3DVECTOR(0,0,-1000), D3DVECTOR(0,0,0));
CreateProjectionMatrix(projMatrix, 700, 1300, (float)(atan(0.30)*2));
 
//マテリアル作成
D3DMATERIAL mat;
pD3D->CreateMaterial(&pD3DMat,NULL);
ZeroMemory(&mat,sizeof(mat));
mat.dwSize = sizeof(mat);
mat.diffuse.r = 1.0;
mat.diffuse.g = 1.0;
mat.diffuse.b = 1.0;
mat.ambient.r = 0.50;
mat.ambient.g = 0.50;
mat.ambient.b = 0.50;
mat.specular.r = 0;
mat.specular.g = 0;
mat.specular.b = 0;
mat.emissive.r = 0.0;
mat.emissive.g = 0.0;
mat.emissive.b = 0.0;
mat.power = 0.0;
mat.dwRampSize = 1;
//mat.hTexture = hTexture;
pD3DMat->SetMaterial(&mat);
pD3DMat->GetHandle(pD3DDevice,&hMaterial);
 
//ライト生成
D3DLIGHT2 lt;
pD3D->CreateLight(&pD3DLight,NULL);
ZeroMemory(&lt,sizeof(lt));
lt.dwSize = sizeof(lt);
lt.dltType = D3DLIGHT_DIRECTIONAL;
lt.dvPosition.x = -100.0f;
lt.dvPosition.y = ly;//100.0f;
lt.dvPosition.z = 100.0f;
lt.dvDirection.x = 100.0;
lt.dvDirection.y = 100.0;
lt.dvDirection.z = 100.0;
lt.dcvColor.r = D3DVAL(1.0);
lt.dcvColor.g = D3DVAL(1.0);
lt.dcvColor.b = D3DVAL(1.0);
lt.dwFlags = D3DLIGHT_ACTIVE;
 
pD3DLight->SetLight((D3DLIGHT*)&lt);
pD3DVP->AddLight(pD3DLight);
 
return TRUE;
}
 
/*-------------------------------------------
終了の処理
--------------------------------------------*/
int EndApp(void)
{
RELEASE(pD3DMat);
if(pD3DLight != NULL)
pD3DVP->DeleteLight(pD3DLight);
RELEASE(pD3DLight);
 
delete pTexture;
pTexture = NULL;
RELEASE(pD3DVP);
RELEASE(pD3DDevice);
RELEASE(pD3D);
pBackBuffer = NULL;
RELEASE(pScreen);
RELEASE(pDDraw);
 
return TRUE;
}
 
D3DVALUE ax=5,ay=5,az=5;
float sx=0.8,sy=0.8,sz=0.8;
float vec = 1000;
float rol = 0;
float pp=0;
 
/*-------------------------------------------
ウィンドウ処理
--------------------------------------------*/
LRESULT CALLBACK MainWndProc(HWND hWnd,UINT msg,UINT wParam,LONG lParam)
{
 
switch(msg){
case WM_KEYDOWN:
switch(wParam){
case VK_ESCAPE:
case VK_F12:
 DestroyWindow(hWnd);
 break;
 
case VK_NUMPAD1:
 view_county += 3;
 if(view_county >= 360) view_county = 0;
 
 break;
case VK_NUMPAD2:
 view_county -= 3;
 if(view_county < 0) view_county = 360;
 break;
 
// x 方向の移動
case VK_NUMPAD4:
 ax -= 3;
 break;
case VK_NUMPAD7:
 ax += 3;
 break;
 
// y 方向の移動
case VK_NUMPAD5:
 ay -= 3;
 break;
case VK_NUMPAD8:
 ay += 3;
 break;
 
case VK_UP:
 
 view_countz += 3;
 if(view_countz >= 360) view_countz = 0;
 break;
case VK_DOWN:
 view_countz -= 3;
 if(view_countz < 0) view_countz = 360;
 break;
 
case VK_LEFT:
 view_countx += 3;
 if(view_countx >= 360) view_countx = 0;
 break;
case VK_RIGHT:
 view_countx -= 3;
 if(view_countx < 0) view_countx = 360;
 break;
 
 
default:
 break;
}
 break;
case WM_DESTROY:
PostQuitMessage(0);
 break;
 default:
 return DefWindowProc(hWnd,msg,wParam,lParam);
}
 return 0L;
}
 
/*--------------------------------------------
アイドル時の処理
--------------------------------------------*/
int AppIdle(void)
{
 
// D3DLVERTEX v[6];
DDBLTFX fx;
 br /> // 背景を塗りつぶす
ZeroMemory(&fx,sizeof(fx));
fx.dwSize = sizeof(fx);
pBackBuffer->Blt(NULL,NULL,NULL,DDBLT_WAIT | DDBLT_COLORFILL,&fx);
 
// ドライバ名などの文字を書き込む
HDC hdc;
char Data[256];
wsprintf(Data, "%s, [%s]", szDevice, szDDDeviceName);
if(pBackBuffer->GetDC(&hdc) == DD_OK){
 TextOut(hdc,0,0,Data,strlen(Data));
 pBackBuffer->ReleaseDC(hdc);
}
 
// DrawPrimitiveを使ってポリゴンを描画する
 
pD3DDevice->SetRenderState(D3DRENDERSTATE_ZENABLE, TRUE);
 
D3DRECT rect;
rect.x1 = 0; //ここにはクリアする領域を指定します.
rect.y1 = 0;
rect.x2 = 640;
rect.y2 = 480;
pD3DVP->Clear(1,&rect,D3DCLEAR_ZBUFFER);
 
pD3DDevice->SetRenderState(D3DRENDERSTATE_CULLMODE, D3DCULL_NONE);
pD3DDevice->SetRenderState(D3DRENDERSTATE_SHADEMODE, D3DSHADE_GOURAUD);
 
pD3DDevice->BeginScene();
 
pD3DDevice->SetLightState(D3DLIGHTSTATE_MATERIAL,hMaterial);
pD3DDevice->SetLightState(D3DLIGHTSTATE_AMBIENT,RGB_MAKE(128,128,128));
 
pD3DDevice->SetRenderState(D3DRENDERSTATE_TEXTUREHANDLE,hTexture);
 
// Y軸回転
D3DMATRIX worldy;
CreateRotateYMatrix(worldy, (M_PI * 2.0f * view_county) / 360.0f);
 
// Z軸回転
D3DMATRIX worldz;
CreateRotateZMatrix(worldz, (M_PI * 2.0f * view_countz) / 360.0f);
 
D3DMATRIX wo;
D3DMATRIX wo1;
 
MulMatrix(worldz, worldy, wo); // Z軸回転とY軸回転をかける
 
// X軸回転
D3DMATRIX worldx;
CreateRotateXMatrix(worldx, (M_PI * 2.0f * view_countx) / 360.0f);
 
MulMatrix(wo, worldx, wo1); // X軸回転をかける
 
// 平行移動
D3DMATRIX world;
CreateTranslateMatrix(world, ax,ay,az);
 
MulMatrix(wo1, world, wo); // X軸回転をかける
 
 
// スケーリング変換 等倍は1.0
D3DMATRIX worlds;
CreateScaleMatrix(worlds, sx,sy,sz);
 
MulMatrix(wo, worlds, wo1); // X軸回転をかける
 
pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &wo1);
 
// 視点変換
 
CreateZeroMatrix(viewMatrix);
CreateViewMatrix(viewMatrix, D3DVECTOR(1000,0,0), D3DVECTOR(0,0,0), rol);
vec --;
pp -= 1;
if(rol>360) rol=0;
 
pD3DDevice->SetTransform(D3DTRANSFORMSTATE_VIEW, &viewMatrix );
// 透視変換
pD3DDevice->SetTransform(D3DTRANSFORMSTATE_PROJECTION, &projMatrix);
 
pD3DDevice->SetTransform(D3DTRANSFORMSTATE_VIEW, &viewMatrix);
pD3DDevice->SetTransform(D3DTRANSFORMSTATE_PROJECTION, &projMatrix);
 
/*
v[0].x = 200;
v[0].y = 200;
v[0].z = 0;
v[0].color = RGB_MAKE(255,255,255);
v[0].specular = D3DRGB(0,0,0);
v[0].tu = 1;
v[0].tv = 0;
 
v[1].x = -200;
v[1].y = 200;
v[1].z = 0;
v[1].color = RGB_MAKE(255,255,255);
v[1].specular = D3DRGB(0,0,0);
v[1].tu = 0;
v[1].tv = 0;
 
v[2].x = 200;
v[2].y = -200;
v[2].z = 0;
v[2].color = RGB_MAKE(255,255,255);
v[2].specular = D3DRGB(0,0,0);
v[2].tu = 1;
v[2].tv = 1;
 
v[3] = v[2];
v[4] = v[1];
v[5].x = -200;
v[5].y = -200;
v[5].z = 0;
v[5].color = RGB_MAKE(255,255,255);
v[5].specular = D3DRGB(0,0,0);
v[5].tu = 0;
v[5].tv = 1;
 
*/
 
D3DVERTEX v[6];
for(int i=0;i<6;i++){
for(int j=0;j<4;j++){
v[j].x = D3DVAL(cubeVertex[cubeFace[i][j]][0]);
v[j].y = D3DVAL(cubeVertex[cubeFace[i][j]][1]);
v[j].z = D3DVAL(cubeVertex[cubeFace[i][j]][2]);
v[j].nx = D3DVAL(cubeVNormal[cubeFace[i][j]][0]);
v[j].ny = D3DVAL(cubeVNormal[cubeFace[i][j]][1]);
v[j].nz = D3DVAL(cubeVNormal[cubeFace[i][j]][2]);
}
v[0].tu = 0; //テクスチャーの貼り付け位置
v[0].tv = 0;
v[1].tu = 1;
v[1].tv = 0;
v[2].tu = 1;
v[2].tv = 1;
v[3].tu = 0;
v[3].tv = 1;
 
v[5] = v[3];
v[3] = v[0];
v[4] = v[2];
 

// 四角の場合
// pD3DDevice->DrawPrimitive(D3DPT_TRIANGLELIST,D3DVT_
LVERTEX,(LPVOID)v,6,D3DDP_WAIT);
 
pD3DDevice->DrawPrimitive(D3DPT_TRIANGLELIST,D3DVT_
VERTEX,(LPVOID)v,6,D3DDP_WAIT);
}
 
pD3DDevice->EndScene();
 
pScreen->Flip(NULL,DDFLIP_WAIT);
 
return TRUE;
}
 
/*--------------------------------------------
メイン
---------------------------------------------*/
int WINAPI WinMain(HINSTANCE hInst,HINSTANCE hPrevInst,LPSTR lpCmdLine,int nCmdShow)
{
MSG msg;
 
if(!InitApp(hInst,nCmdShow))
 return FALSE;
 
if(!InitDDraw())
 return FALSE;
 
if(!InitD3D())
 return FALSE;
 
if(!InitObject()){
 EndApp();
 return FALSE;
}
 
while(TRUE){
 if(PeekMessage(&msg,0,0,0,PM_REMOVE)){
  if(msg.message == WM_QUIT)
   break;
 
  TranslateMessage(&msg);
  DispatchMessage(&msg);
 }
 else{
  AppIdle();
 }
}
 
EndApp();
 
return msg.wParam;
}