Direct3Dの解説 4 回転する四角形

3角形のポリゴンを表示するソースを四角形が回転するソースに変更したときの

変更箇所。つまり、この部分が3Dの座表計算をしている部分になる。

大雑把に言うと、座標変換用のマトリックスを作成してそれを描画時にどういう位置に見えるかを計算してポリゴンを描画する。

これはY軸回転用のマトリクスを使っているが、ほかにX軸回転、Z軸回転、移動、ZOOMなどがある。それの使い方は次のページにて。
 

/*----------------------------------------------------------
4角形の回転
--------------------------------------------------------------*/
 
#define STRICT
#include <windows.h>
#include <string.h>
 
#define D3D_OVERLOADS
#include <ddraw.h>
#include <d3d.h>
 
#include "jdmatrix.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;
 
LPDIRECT3D2 pD3D = NULL;
LPDIRECT3DDEVICE2 pD3DDevice = NULL;
LPDIRECT3DVIEWPORT2 pD3DVP = NULL;
 
int view_count = 0;
D3DMATRIX viewMatrix;
D3DMATRIX projMatrix;

 
LRESULT CALLBACK MainWndProc(HWND hWnd,UINT msg,UINT wParam,LONG lParam);
 
 
/*-------------------------------------------
アプリケーション初期化
--------------------------------------------*/
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;
}
 
/*---------------------------------------------------------
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;
}
 

/*--------------------------------------------
準備
------------------------------------------------*/
int InitObject(void)
{
//変換マトリックスの設置
CreateViewMatrix(viewMatrix, D3DVECTOR(1000,0,0), D3DVECTOR(0,0,0));
CreateProjectionMatrix(projMatrix, 700, 1300, (float)(atan(0.30)*2));

 
return TRUE;
}

 
/*-------------------------------------------
終了の処理
--------------------------------------------*/
int EndApp(void)
{
RELEASE(pD3DVP);
RELEASE(pD3DDevice);
RELEASE(pD3D);
pBackBuffer = NULL;
RELEASE(pScreen);
RELEASE(pDDraw);
 
return TRUE;
}
 
/*-------------------------------------------
ウィンドウ処理
--------------------------------------------*/
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;
default:
 break;
}
 break;
case WM_DESTROY:
 PostQuitMessage(0);
 break;
default:
 return DefWindowProc(hWnd,msg,wParam,lParam);
}
return 0L;
}
 
/*--------------------------------------------
アイドル時の処理
--------------------------------------------*/
int AppIdle(void)
{
D3DLVERTEX v[4];
DDBLTFX fx;
 
// 背景を塗りつぶす
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_CULLMODE, D3DCULL_NONE);
pD3DDevice->SetRenderState(D3DRENDERSTATE_SHADEMODE, D3DSHADE_GOURAUD);

 
pD3DDevice->BeginScene();
 
D3DMATRIX world;
CreateRotateYMatrix(world, (M_PI * 2.0f * view_count) / 360.0f); // 回転用マトリックスの作成
view_count += 3;           //自動的に回転する(回転角度を増やす)
if(view_count >= 360) view_count = 0;
pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &world);
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,0,0);
v[0].specular = D3DRGB(0,0,0);
v[0].tu = 0;
v[0].tv = 0;
 
v[1].x = -200;
v[1].y = 200;
v[1].z = 0;
v[1].color = RGB_MAKE(0,255,0);
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(0,0,255);
v[2].specular = D3DRGB(0,0,0);
v[2].tu = 0;
v[2].tv = 0;
 
v[3].x = -200; // 四角にするために頂点を増やす
v[3].y = -200;
v[3].z = 0;
v[3].color = RGB_MAKE(255,0,0);
v[3].specular = D3DRGB(0,0,0);
v[3].tu = 0;
v[3].tv = 0;

 
pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP,D3DVT_LVERTEX,
(LPVOID)v,4,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;
}
 

jdmatrix.cpp 3D計算を行うための行列など。
 

/*----------------------------------------------------
マトリックス生成など
Direct3D IM
 
jdmatrix.cpp
 
1997 DOIchan!
 
doichan@super.win.or.jp
----------------------------------------------------*/
 
#define STRICT
#define D3D_OVERLOADS
#include <windows.h>
 
#include <math.h>
 
#include <ddraw.h>
#include <d3d.h>
 
#include "jdmatrix.h"
 
/*-----------------------------------------------------
視点座標変換マトリックスの作成
------------------------------------------------------*/
void CreateViewMatrix(D3DMATRIX& mat,D3DVECTOR& vf,D3DVECTOR& va, float roll)
{
D3DVECTOR world_up(0,1,0);
 
CreateUnitMatrix(mat);
 
D3DVECTOR up, right, view_dir;
view_dir = Normalize(va - vf);
right = CrossProduct(world_up, view_dir);
up = CrossProduct(view_dir, right);
 
right = Normalize(right);
up = Normalize(up);
 
mat(0, 0) = right.x;
mat(1, 0) = right.y;
mat(2, 0) = right.z;
mat(0, 1) = up.x;
mat(1, 1) = up.y;
mat(2, 1) = up.z;
mat(0, 2) = view_dir.x;
mat(1, 2) = view_dir.y;
mat(2, 2) = view_dir.z;
 
mat(3, 0) = -DotProduct(right, vf);
mat(3, 1) = -DotProduct(up, vf);
mat(3, 2) = -DotProduct(view_dir, vf);
 
if (roll != 0.0f) {
 D3DMATRIX zmat;
 CreateRotateZMatrix(zmat, -roll);
 MulMatrix(zmat, mat, mat);
}
}
 
/*----------------------------------------------------
透視変換マトリックスの作成
-------------------------------------------------------*/
void CreateProjectionMatrix(D3DMATRIX& mat, float near_plane, float far_plane, float fov)
{
float c, s, Q;
c = (float) cos(fov*0.5);
s = (float) sin(fov*0.5);
Q = s/(1.0f - near_plane/far_plane);
 
CreateZeroMatrix(mat);
mat(0, 0) = c;
mat(1, 1) = c;
mat(2, 2) = Q;
mat(3, 2) = -Q*near_plane;
mat(2, 3) = s;
}
 
/*-------------------------------------------------------
単位マトリックス
----------------------------------------------------------*/
void CreateUnitMatrix(D3DMATRIX& mat)
{
 int i,j;
 
  for(i=0;i<4;i++){
   for(j=0;j<4;j++){
    mat(i,j) = 0;
   }
  mat(i,i) = 1;
 }
}
 
/*--------------------------------------------------------
マトリックスクリア
-----------------------------------------------------------*/
void CreateZeroMatrix(D3DMATRIX& mat)
{
 int i,j;
 
 for(i=0;i<4;i++){
  for(j=0;j<4;j++){
   mat(i,j) = 0;
  }
 }
}
 
/*---------------------------------------------------------
平行移動
----------------------------------------------------------*/
void CreateTranslateMatrix(D3DMATRIX& mat,D3DVALUE x,D3DVALUE y,D3DVALUE z)
{
CreateUnitMatrix(mat);
 
mat(3,0) = x;
mat(3,1) = y;
mat(3,2) = z;
}
 
/*---------------------------------------------------------
スケール
-----------------------------------------------------------*/
void CreateScaleMatrix(D3DMATRIX& mat,D3DVALUE x,D3DVALUE y,D3DVALUE z)
{
CreateUnitMatrix(mat);
 
mat(0,0) = x;
mat(1,1) = y;
mat(2,2) = z;
}
 
/*---------------------------------------------------------
X軸周りの回転
----------------------------------------------------------*/
void CreateRotateXMatrix(D3DMATRIX& mat,D3DVALUE deg)
{
D3DVALUE c,s;
 
CreateUnitMatrix(mat);
 
c = D3DVAL(cos(deg));
s = D3DVAL(sin(deg));
 
mat(1,1) = c;
mat(1,2) = s;
mat(2,1) = -s;
mat(2,2) = c;
}
 
/*---------------------------------------------------------
Y軸周りの回転
----------------------------------------------------------*/
void CreateRotateYMatrix(D3DMATRIX& mat,D3DVALUE deg)
{
D3DVALUE c,s;
 
CreateUnitMatrix(mat);
 
c = D3DVAL(cos(deg));
s = D3DVAL(sin(deg));
 
mat(0,0) = c;
mat(0,2) = -s;
mat(2,0) = s;
mat(2,2) = c;
}
 
/*---------------------------------------------------------
Z軸周りの回転
----------------------------------------------------------*/
void CreateRotateZMatrix(D3DMATRIX& mat,D3DVALUE deg)
{
D3DVALUE c,s;
 
CreateUnitMatrix(mat);
 
c = D3DVAL(cos(deg));
s = D3DVAL(sin(deg));
 
mat(0,0) = c;
mat(0,1) = s;
mat(1,0) = -s;
mat(1,1) = c;
}
 
/*----------------------------------------------------------
変換
----------------------------------------------------------*/
void TransformVector(D3DMATRIX& mat,D3DVECTOR& v,D3DVECTOR& vt)
{
D3DVALUE w;
 
vt.x = mat(0,0) * v.x + mat(1,0) * v.y + mat(2,0) * v.z + mat(3,0);
vt.y = mat(0,1) * v.x + mat(1,1) * v.y + mat(2,1) * v.z + mat(3,1);
vt.z = mat(0,2) * v.x + mat(1,2) * v.y + mat(2,2) * v.z + mat(3,2);
w = mat(0,3) * v.x + mat(1,3) * v.y + mat(2,3) * v.z + mat(3,3);
 
vt.x /= w;
vt.y /= w;
vt.z /= w;
}
 
/*-----------------------------------------------------------
マトリックスの乗算
-------------------------------------------------------------*/
void MulMatrix(D3DMATRIX& m1,D3DMATRIX& m2,D3DMATRIX& mt)
{
 int i,j;
 
 for(i=0;i<4;i++){
  for(j=0;j<4;j++){
   mt(i,j) = m1(i,0) * m2(0,j) + m1(i,1) * m2(1,j) + m1(i,2) * m2(2,j) + m1(i,3) * m2(3,j);
  }
 }
}
 
jdmatrix.cpp のヘッダ
 
/*----------------------------------------------------
マトリックス生成など
Direct3D IM
 
jdmatrix.h
 
1997 DOIchan!
 
doichan@super.win.or.jp
----------------------------------------------------*/
 
#ifndef __JD_MATRIX_H_
#define __JD_MATRIX_H_
 
#ifndef M_PI
#define M_PI 3.14159265359f
#endif //M_PI
 
void CreateViewMatrix(D3DMATRIX& mat,D3DVECTOR& vf,D3DVECTOR& va, float roll=0.0f);
void CreateProjectionMatrix(D3DMATRIX& mat, float near_plane, float far_plane, float fov);
void CreateUnitMatrix(D3DMATRIX& mat);
void CreateZeroMatrix(D3DMATRIX& mat);
void CreateTranslateMatrix(D3DMATRIX& mat,D3DVALUE x,D3DVALUE y,D3DVALUE z);
void CreateScaleMatrix(D3DMATRIX& mat,D3DVALUE x,D3DVALUE y,D3DVALUE z);
void CreateRotateXMatrix(D3DMATRIX& mat,D3DVALUE deg);
void CreateRotateYMatrix(D3DMATRIX& mat,D3DVALUE deg);
void CreateRotateZMatrix(D3DMATRIX& mat,D3DVALUE deg);
void TransformVector(D3DMATRIX& mat,D3DVECTOR& v,D3DVECTOR& vt);
void MulMatrix(D3DMATRIX& m1,D3DMATRIX& m2,D3DMATRIX& mt);
 
#endif //__JD_MATRIX_H_