之後的一段時間准備學習一下DirectX和Shader相關的文章.
為了能夠運行Shader,得先寫個小程序.這裡我選擇了DirectX(其實我個人覺得,如果只是想學習Shader 的話,XNA是個不錯的選擇)
看了幾天的文檔,重點看了一下DirectX Sample裡面的Basic HLSL,可能是微軟為了把一些控件集成進 去,方便大家觀察效果的原因吧,微軟使用了DXUT這個框架,對我等c++和windows編程的初學者來說特別的 不爽,所以我決定脫離DXUT框架來寫一下
首先打開Sample裡面的D3DX9 Create Device.我們就往這個程序裡面添加代碼.
1. 我們添加一個LoadMesh函數: 導入.X文件
HRESULT LoadMesh( IDirect3DDevice9* pd3dDevice, WCHAR* strFileName, ID3DXMesh**
ppMesh )
{
ID3DXMesh* pMesh = NULL;
WCHAR str[MAX_PATH];
HRESULT hr;
//調用D3DXLoadMeshFromX從文件中讀取.X文件
D3DXLoadMeshFromX(strFileName, D3DXMESH_MANAGED, pd3dDevice, NULL, NULL, NULL,
NULL, &pMesh);
DWORD *rgdwAdjacency = NULL;
//確定Mesh具有法線向量,如果沒有的話就調用D3DXComputeNormals來進行計算.
if( !(pMesh->GetFVF() & D3DFVF_NORMAL) )
{
ID3DXMesh* pTempMesh;
pMesh->CloneMeshFVF( pMesh->GetOptions(),
pMesh->GetFVF() |
D3DFVF_NORMAL,
pd3dDevice,
&pTempMesh );
D3DXComputeNormals( pTempMesh, NULL);
pMesh = pTempMesh;
}
*ppMesh = pMesh;
return S_OK;
}
2.我們添加OnCreateDevice函數,在顯卡初始化完成後,可以進行一些處理操作:
HRESULT OnCreateDevice()
{
HRESULT hr;
D3DXVECTOR3* pData;
//.fx文件的文件名
WCHAR str[MAX_PATH];
//設置ShaderFlags
DWORD dwShaderFlags = 0;
dwShaderFlags |= D3DXSHADER_NO_PRESHADER;
//讀取.fx文件
D3DXCreateEffectFromFile( g_pd3dDevice, L"BasicHLSL.fx", NULL, NULL,
dwShaderFlags, NULL, &g_pEffect, NULL );
//讀取貼圖文件
D3DXCreateTextureFromFileEx( g_pd3dDevice, L"Tiny_skin.dds", D3DX_DEFAULT,
D3DX_DEFAULT,
D3DX_DEFAULT,
0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED,
D3DX_DEFAULT,
D3DX_DEFAULT, 0,
NULL, NULL,
&g_pMeshTexture );
//設置Shader的參數
D3DXCOLOR colorMtrlDiffuse(1.0f, 1.0f, 1.0f, 1.0f);
D3DXCOLOR colorMtrlAmbient(0.35f, 0.35f, 0.35f, 0);
g_pEffect->SetValue("g_MaterialAmbientColor", &colorMtrlAmbient, sizeof
(D3DXCOLOR));
g_pEffect->SetValue("g_MaterialDiffuseColor", &colorMtrlDiffuse, sizeof
(D3DXCOLOR));
g_pEffect->SetTexture("g_MeshTexture", g_pMeshTexture);
//設置View Matrix
D3DXVECTOR3 vEyePt ( 0.0f, 500.0f, 500.0f);
D3DXVECTOR3 vLookatPt( 0.0f, 0.0f, 0.0f );
D3DXVECTOR3 vUpVec ( 0.0f, 1.0f, 0.0f );
D3DXMatrixLookAtLH( &g_view, &vEyePt, &vLookatPt, &vUpVec );
g_pd3dDevice->SetTransform( D3DTS_VIEW, &g_view );
//設置Projection Matrix
D3DXMatrixPerspectiveFovLH( &g_proj, D3DX_PI/4, 1.0f, 1.0f, 10000.0f );
g_pd3dDevice->SetTransform( D3DTS_PROJECTION, &g_proj );
//設置World Matrix
D3DXMatrixRotationY( &g_world, timeGetTime()/150.0f );
g_pd3dDevice->SetTransform( D3DTS_WORLD, &g_world );
//設置燈光
g_vLightDir[0] = D3DXVECTOR3(1.0f,0.0f,0.0f);
g_vLightDir[1] = D3DXVECTOR3(0.0f,1.0f,0.0f);
g_vLightDir[2] = D3DXVECTOR3(0.0f,0.0f,1.0f);
g_vLightDiffuse[0] = D3DXCOLOR(1,1,1,1);
g_vLightDiffuse[1] = D3DXCOLOR(1,1,1,1);
g_vLightDiffuse[2] = D3DXCOLOR(1,1,1,1);
return S_OK;
}
3.我們開始渲染:
VOID Render()
{
HRESULT hr;
D3DXMATRIXA16 mWorldViewProjection;
UINT iPass, cPasses;
//清除Render Target和Z緩沖
g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DXCOLOR
(0.0f,0.25f,0.25f,0.55f), 1.0f, 0);
//開始渲染場景
if( SUCCEEDED( g_pd3dDevice->BeginScene() ) )
{
//計算WVP矩陣
mWorldViewProjection = g_world * g_view * g_proj;
D3DXCOLOR vWhite = D3DXCOLOR(1,1,1,1);
//設置Shader參數
g_pEffect->SetValue( "g_LightDir", g_vLightDir, sizeof(D3DXVECTOR3)
*MAX_LIGHTS );
g_pEffect->SetValue( "g_LightDiffuse", g_vLightDiffuse, sizeof
(D3DXVECTOR4)*MAX_LIGHTS );
g_pEffect->SetMatrix( "g_mWorldViewProjection",
&mWorldViewProjection);
g_pEffect->SetMatrix( "g_mWorld", &g_world );
g_pEffect->SetValue("g_MaterialDiffuseColor", &vWhite, sizeof
(D3DXCOLOR));
g_pEffect->SetFloat( "g_fTime", 1.0f);
//設置渲染時候的Technique
g_pEffect->SetTechnique("RenderSceneWithTexture3Light");
//開始執行Shader進行渲染
g_pEffect->Begin(&cPasses, 0);
for (iPass = 0; iPass < cPasses; iPass++)
{
g_pEffect->BeginPass(iPass);
//繪制模型
g_pMesh->DrawSubset(0);
g_pEffect->EndPass();
}
g_pEffect->End();
g_pd3dDevice->EndScene();
}
//顯示渲染結果
g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
}
4.完成程序退出後的釋放操作:
VOID Cleanup()
{
if( g_pMesh != NULL )
g_pMesh->Release();
if( g_pd3dDevice != NULL )
g_pd3dDevice->Release();
if( g_pD3D != NULL )
g_pD3D->Release();
}
5.修改wWinMain函數,使得中間一段看起來這樣:
//// Initialize Direct3D if( SUCCEEDED( InitD3D( hWnd ) ) ) { // Create the scene geometry if( SUCCEEDED( LoadMesh(g_pd3dDevice,L"tiny.x",&g_pMesh) ) ) { OnCreateDevice(); // Show the window ShowWindow( hWnd, SW_SHOWDEFAULT ); UpdateWindow( hWnd ); //
6.添加頭文件和全局變量:
#include <Windows.h> #include <mmsystem.h> #include <d3dx9.h> #pragma warning( disable : 4996 ) // disable deprecated warning #include <strsafe.h> #pragma warning( default : 4996 ) //--------------------------------------------------------------------------// Global variables //-------------------------------------------------------------------------- LPDIRECT3D9 g_pD3D = NULL; // 用來建立 D3DDevice LPDIRECT3DDEVICE9 g_pd3dDevice = NULL; // 我們的Device D3DXMATRIXA16 g_world; D3DXMATRIXA16 g_view; D3DXMATRIXA16 g_proj; ID3DXEffect* g_pEffect = NULL; // D3DX特效接口 ID3DXMesh* g_pMesh = NULL; // 模型對象 IDirect3DTexture9* g_pMeshTexture = NULL; // 模型貼圖 #define MAX_LIGHTS 3 float g_fLightScale; int g_nNumActiveLights = 3; int g_nActiveLight; D3DXVECTOR3 g_vLightDir[MAX_LIGHTS]; D3DXCOLOR g_vLightDiffuse[MAX_LIGHTS];
7.將Tiny.X,Tiny_Skin.dds,BasicHLSL.fx放入項目的目錄,並把BasicHLSL.fx添加進項目,就完成了我 們第一個可以運行Shader的程序