immediate:Direct3D 8.0 Immediate Mode 教學 II



Immediate Mode 教學 1 介紹了畫 \"已經Transform成螢幕座標\" 3角形感覺上跟2D功能很像那當 3角形資訊是尚未 Transform要如何投影到螢幕座標系統呢?整個投影原理先不詳細介紹先藉助 Direct3D本身Transform機制提供 Direct3D 世界座標端點資料由 Direct3D 幫我們轉換成螢幕座標並畫出來 這次範例仍然是畫個 3角形但是 3角形座標為世界座標同時要畫世界座標東西了當然就要指定攝影機位置與對哪點拍攝此時2D螢幕呈現其實就是以攝影機角度觀看世界
完整程式列表:
//-----------------------------------------------------------------------------
// File: d3d8im_2.cpp
//
// Desc: This is the second tutorial for using Direct3D 8.0.
//
// http://latte.fanmesh.com
//-----------------------------------------------------------------------------
# <d3d8.h>
# <d3dx8.h>
# <d3dx8math.h>

//-----------------------------------------------------------------------------
// Global variables
//-----------------------------------------------------------------------------
LPDIRECT3D8 pD3D = NULL; // Used to create the D3DDevice
LPDIRECT3DDEVICE8 pDev = NULL; // Our RenderD3Ding device
LPDIRECT3DVERTEXBUFFER8 pVB = NULL;

//-----------------------------------------------------------------------------
// Name: InitD3D
// Desc: Initializes Direct3D
//-----------------------------------------------------------------------------
HRESULT InitD3D( HWND hWnd )
{
// Create the D3D object, which is needed to create the D3DDevice.
( NULL ( pD3D = Direct3DCreate8( D3D_SDK_VERSION ) ) )
E_FAIL;

// Get the current desktop display mode
D3DDISPLAYMODE d3ddm;
( FAILED( pD3D->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &d3ddm ) ) )
E_FAIL;

D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory( &d3dpp, (d3dpp) );

d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = d3ddm.Format;

( FAILED( pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &pDev ) ) )
{
E_FAIL;
}

D3DXMATRIX matWorld;
D3DXMatrixIdentity( &matWorld );
pDev->SetTransform( D3DTS_WORLD, &matWorld );

D3DXMATRIX matView;
D3DXMatrixLookAtLH( &matView, &D3DXVECTOR3( 0.0f, 50.0f,-200.0f ),
&D3DXVECTOR3( 0.0f, 0.0f, 0.0f ),
&D3DXVECTOR3( 0.0f, 1.0f, 0.0f ) );
pDev->SetTransform( D3DTS_VIEW, &matView );

D3DXMATRIX matProj;
D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, 1.0f, 1.0f, 500.0f );
pDev->SetTransform( D3DTS_PROJECTION, &matProj );

pDev->SetRenderState( D3DRS_LIGHTING, FALSE );

// Device state would normally be here
S_OK;
}

//-----------------------------------------------------------------------------
// Name: CloseD3D
// Desc: Releases all previously initialized objects
//-----------------------------------------------------------------------------
void CloseD3D(void)
{
( pVB != NULL)
pVB->Release;

( pDev != NULL)
pDev->Release;

( pD3D != NULL)
pD3D->Release;
}

//-----------------------------------------------------------------------------
// Name: RenderD3D
// Desc: Draws the scene
//-----------------------------------------------------------------------------
struct MYVERTEX
{
FLOAT x,y,z;
DWORD color;
};

# NUM_VERT 3

struct MYVERTEX vert[NUM_VERT]=
{
0, 50, 0, 0x00FF0000,
40, 0, 0, 0x000000FF,
-40, 0, 0, 0x0000FF00
};

BOOL NeedCreateVBFlag=true;
float rad=0.0f;

void RenderD3D(void)
{
( NULL pDev )
;

// Clear the backbuffer to a blue color
pDev->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,255), 1.0f, 0 );

// Begin the scene
pDev->BeginScene;

//-----------------------------------------------------------------------------
// RenderD3Ding of scene objects can happen here
//-----------------------------------------------------------------------------
(NeedCreateVBFlag) {
pDev->CreateVertexBuffer((MYVERTEX)*NUM_VERT,
D3DUSAGE_WRITEONLY,
D3DFVF_XYZ|D3DFVF_DIFFUSE,
D3DPOOL_DEFAULT,
&pVB);
NeedCreateVBFlag=false;
}

MYVERTEX *v;
pVB->Lock(0,0,(BYTE **)&v,0);
memcpy(v,vert,(MYVERTEX)*NUM_VERT);
pVB->Unlock;

D3DXMATRIX matWorld;
rad 0.001f;
D3DXMatrixRotationY(&matWorld, rad);
pDev->SetTransform( D3DTS_WORLD, &matWorld );

pDev->SetVertexShader(D3DFVF_XYZ|D3DFVF_DIFFUSE);
pDev->SetStreamSource(0,pVB,(MYVERTEX));
pDev->DrawPrimitive(D3DPT_TRIANGLELIST,0,NUM_VERT/3);
//-----------------------------------------------------------------------------



// End the scene
pDev->EndScene;

// Present the backbuffer contents to the display
pDev->Present( NULL, NULL, NULL, NULL );
}

//-----------------------------------------------------------------------------
// Name: MsgProc
// Desc: The window\'s message handler
//-----------------------------------------------------------------------------
LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
switch( msg )
{
WM_DESTROY:
PostQuitMessage( 0 );
0;
}

DefWindowProc( hWnd, msg, wParam, lParam );
}

//-----------------------------------------------------------------------------
// Name: WinMain
// Desc: The application\'s entry po
//-----------------------------------------------------------------------------
INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR, INT )
{
MSG msg;

// Register the window
WNDCLASSEX wc = { (WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L, GetModuleHandle(NULL), NULL, NULL, NULL, NULL, \"D3D Tutorial\", NULL };
RegisterClassEx( &wc );

// Create the application\'s window
HWND hWnd = CreateWindow( \"D3D Tutorial\", \"D3D8 Tutorial 02\", WS_OVERLAPPEDWINDOW, 100, 100, 300, 300, GetDesktopWindow, NULL, wc.hInstance, NULL );

// Initialize Direct3D
( SUCCEEDED( InitD3D( hWnd ) ) )
{
// Show the window
ShowWindow( hWnd, SW_SHOWDEFAULT );
UpdateWindow( hWnd );

while(1)
{
(PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ))
{
( GetMessage( &msg, NULL, 0, 0 ) )
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}

{
// This msg is WM_QUIT.
;
}
}

{
RenderD3D;
}
}
}

// Clean up everything and exit the app
CloseD3D;
UnregisterClass( \"D3D Tutorial\", wc.hInstance );
0;
}

1.# 除了 d3d8.h 還要多個 d3dx8.h 與 d3dx8math.h D3DX 提供了許多以 Direct3D 為基礎有用functions到了世界座標幾乎是非用不可了
//-----------------------------------------------------------------------------
// File: d3d8im_2.cpp
//
// Desc: This is the second tutorial for using Direct3D 8.0.
//
// http://latte.fanmesh.com
//-----------------------------------------------------------------------------
# <d3d8.h>
# <d3dx8.h>
# <d3dx8math.h>

2.此範例只需要3個全域變數 pD3D、pDev、pVB其中 pD3D 就是最新 Direct3D/DirectDraw 綜合體或者該稱為 Direct Graphics 得先產生就對了 pDev是用來通知3D 硬體畫 3角形pVB 是 Vertex Buffer現在通知 pDev畫 3角形 3角形資訊定要放在 Vertex Buffer 了這次 Vertex Buffer 就是世界座標 3角形

//-----------------------------------------------------------------------------
// Global variables
//-----------------------------------------------------------------------------
LPDIRECT3D8 pD3D = NULL; // Used to create the D3DDevice
LPDIRECT3DDEVICE8 pDev = NULL; // Our RenderD3Ding device
LPDIRECT3DVERTEXBUFFER8 pVB = NULL;

3.WinMain與 Message Procedure 與上個範例不再介紹了

4.架構與上個範例分為 InitD3D, RenderD3D, CloseD3D 3大塊先看看 InitD3D 與 CloseD3D

  1. InitD3D 前半段沒變到 CreateDevice的前都
  2. pDev(LPDIRECT3DDEVICE8) 化好了後有 3個跟投影有關矩陣要通知它分別是 World, View, Projection任何個世界座標物件定是依序乘上 world, view, projection 這 3個矩陣
  3. 如果要畫物件還需要位移或旋轉那就放進World Matrix如果都不要動了那就要利用D3DXMatrixIdentity將 matWorld 設定成個 4x4 單位矩陣世界座標乘單位矩陣不會有任何變化
  4. View 矩陣則代表攝影機角度利用 D3DX 提供D3DXMatrixLookAtLH 產生較方便 - 第 2與第 3個參數分別為 LookFrom 與 LookAt在此範例為 (0, 50,-200) 與 ( 0,0,0 ), 表示這台攝影機放在 (0, 50, -200) 這個座標鏡頭看著 (0,0,0) 第 4個參數為 Up Vector - (0,1,0) 表示這個世界中\"上\"抽象概念為 (0,1,0)如果你不填 (0,1,0)整個世界就改觀了
  5. Projection 矩陣則控制投影利用 D3DX 提供D3DXMatrixPerspectiveFovLH產生較方便 - 第 2個參數為 FOV (Field of View) 單位為徑度在此範例為D3DX_PI/4也就是 45 度視角第 3個參數為長寬比例調整沒什麼意外填 1.0f 表示長寬比例不變第 4個與第 5個參數為 Z 區間不在這個區間不畫出來
  6. 本範例還不預備用到光端點資料裡面色彩是手動給所以不需要 Normal 值從 DirectX 7.0 開始不帶有Normal 值端點因為無法算\"光\"導致色彩都變成黑色所以要用 pDev->SetRenderState( D3DRS_LIGHTING, FALSE ); 將計算光源部分關掉通知D3D直接使用端點資料裡面彩色值




至於 CloseD3D就是單純地釋放 pD3D, pDev, pVB 那 3個全域變數

//-----------------------------------------------------------------------------// Name: InitD3D// Desc: Initializes Direct3D//-----------------------------------------------------------------------------HRESULT InitD3D( HWND hWnd ){ // Create the D3D object, which is needed to create the D3DDevice. ( NULL ( pD3D = Direct3DCreate8( D3D_SDK_VERSION ) ) ) E_FAIL; // Get the current desktop display mode D3DDISPLAYMODE d3ddm; ( FAILED( pD3D->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &d3ddm ) ) ) E_FAIL; D3DPRESENT_PARAMETERS d3dpp; ZeroMemory( &d3dpp, (d3dpp) ); d3dpp.Windowed = TRUE; d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; d3dpp.BackBufferFormat = d3ddm.Format; ( FAILED( pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING,&d3dpp, &pDev ) ) ) { E_FAIL; } D3DXMATRIX matWorld; D3DXMatrixIdentity( &matWorld ); pDev->SetTransform( D3DTS_WORLD, &matWorld ); D3DXMATRIX matView; D3DXMatrixLookAtLH( &matView, &D3DXVECTOR3( 0.0f, 50.0f,-200.0f ), &D3DXVECTOR3( 0.0f, 0.0f, 0.0f ), &D3DXVECTOR3( 0.0f, 1.0f, 0.0f ) ); pDev->SetTransform( D3DTS_VIEW, &matView ); D3DXMATRIX matProj; D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, 1.0f, 1.0f, 500.0f ); pDev->SetTransform( D3DTS_PROJECTION, &matProj ); pDev->SetRenderState( D3DRS_LIGHTING, FALSE ); // Device state would normally be here S_OK;}//-----------------------------------------------------------------------------// Name: CloseD3D// Desc: Releases all previously initialized objects//-----------------------------------------------------------------------------void CloseD3D(void){ ( pVB != NULL) pVB->Release; ( pDev != NULL) pDev->Release; ( pD3D != NULL) pD3D->Release;}5.RenderD3D 就是畫 3角形部分:

  • 這次自行設計Vertex 格式為 (x,y,z) 與 端點顏色其中 x,y,z 預備放是世界座標在此範例中 3個點分別為 (0, 50, 0), (40, 0, 0), (-40, 0, 0)各位可以開始想像台放在(0, 50, -200)攝影機看到這片 3角形會長什麼樣了
  • 既然是3D了當然要做點跟 2D不在此範例提供個隨時間改變旋轉矩陣放進 World Matrix 對 Y 軸旋轉所有端點Transform的前定會乘上這個 World Matrix如此表現出來就是片不斷旋轉 3角形讀者可以將這片 3角形擴充為個立方體會更清楚


//-----------------------------------------------------------------------------// Name: RenderD3D// Desc: Draws the scene//-----------------------------------------------------------------------------struct MYVERTEX{ FLOAT x,y,z; DWORD color;};# NUM_VERT 3struct MYVERTEX vert[NUM_VERT]={ 0, 50, 0, 0x00FF0000, 40, 0, 0, 0x000000FF, -40, 0, 0, 0x0000FF00};BOOL NeedCreateVBFlag=true;float rad=0.0f;void RenderD3D(void){ ( NULL pDev ) ; // Clear the backbuffer to a blue color pDev->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,255), 1.0f, 0 ); // Begin the scene pDev->BeginScene;//-----------------------------------------------------------------------------// RenderD3Ding of scene objects can happen here//----------------------------------------------------------------------------- (NeedCreateVBFlag) { pDev->CreateVertexBuffer((MYVERTEX)*NUM_VERT, D3DUSAGE_WRITEONLY, D3DFVF_XYZ|D3DFVF_DIFFUSE, D3DPOOL_DEFAULT, &pVB); NeedCreateVBFlag=false; } MYVERTEX *v; pVB->Lock(0,0,(BYTE **)&v,0); memcpy(v,vert,(MYVERTEX)*NUM_VERT); pVB->Unlock; D3DXMATRIX matWorld; rad 0.001f; D3DXMatrixRotationY(&matWorld, rad); pDev->SetTransform( D3DTS_WORLD, &matWorld ); pDev->SetVertexShader(D3DFVF_XYZ|D3DFVF_DIFFUSE); pDev->SetStreamSource(0,pVB,(MYVERTEX)); pDev->DrawPrimitive(D3DPT_TRIANGLELIST,0,NUM_VERT/3);//----------------------------------------------------------------------------- // End the scene pDev->EndScene; // Present the backbuffer contents to the display pDev->Present( NULL, NULL, NULL, NULL );}

結論:

這片 3角形不斷地對 Y軸旋轉各位應該會發現時間會不見這是因為 SetRenderState 當中 D3DRS_CULLMODE 預設值是 D3DCULL_CCW也就是說 3角形 3個點必須順時鐘才畫如果 3個點變成逆時鐘就會被過濾(CULL)掉這片 3角形對著 Y軸轉了 180度後 3個點排列就變成逆時鐘了也因此被過濾掉了如果讀者想要全部時間都出現可下道 SetRenderState(D3DRS_CULLMODE,D3DCULL_NONE); 就會不管順時鐘、逆時鐘都畫



不過排列為逆時鐘就過濾(CULL_CCW)個簡單又實用加速窍门技巧比如說個3D人物是由 1000片 3角形所組成因此大約正面500片 3角形背面500片 3角形當那個人物面向攝影機時背面500片 3角形其實畫了也沒用 會被正面 3角形蓋掉不畫反而能增加速度 因此CULL_CCW盡量是不要關掉

如何編譯:

1.Visual C Tools -> Options -> Directories 當中 files 與 library files分別要將 c:\\mssdk\\ 與 c:\\mssdk\\library 優先順序放到最前面



2.在 Visual C 當中 個 Win32 Application專案(切記不是 Win32 Console Application)將 d3d8im_2.cpp 加入此專案 source 區

3.Visual C Projects -> Projects Setting -> Link -> Object/library modules 最後面加上 d3d8.lib d3dx8.lib 兩個程式庫

4.按下 F7 即可編譯完成



Tags:  theimmediate immediatemusic executeimmediate immediate

延伸阅读

最新评论

发表评论