之後的一段時間准備學習一下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的程序