《Shaders for Game Programmers and Artists》是一本介绍shader很好的书籍,书中使用RenderMonkey给出了shader源代码,该系列文章将通过Effect的方式在VS2008环境下实现所有例子源代码,如无特殊声明,开发环境为VS2008+DirectXSDK(March 2009).书中用到的茶壶模型为Microsoft DirectX SDK (March 2009)/Samples/Media/misc目录下的teapot.x
#include <d3dx9.h> //----------------------------------------------------------------------------- // Desc: 全局变量 //----------------------------------------------------------------------------- LPDIRECT3D9 g_pD3D = NULL; //Direct3D对象 LPDIRECT3DDEVICE9 g_pd3dDevice = NULL; //Direct3D设备对象 LPD3DXMESH g_pMeshTeapot = NULL; //网格模型对象 D3DMATERIAL9* g_pMeshTeapotMaterials = NULL; //网格模型材质 LPDIRECT3DTEXTURE9* g_pMeshTeapotTextures = NULL; //网格模型纹理 DWORD g_dwTeapotNumMaterials = 0L; //网格模型材质数量 ID3DXEffect* g_pEffect = NULL; //效果指针 //常量句柄 D3DXHANDLE hWVPMatrixHandle = NULL; //变换矩阵 D3DXHANDLE hTech0 = NULL; //技术句柄 //----------------------------------------------------------------------------- // Desc: 设置世界矩阵 //----------------------------------------------------------------------------- VOID SetWorldMatrix() { //创建并设置世界矩阵 D3DXMATRIXA16 matWorld; D3DXMatrixRotationX( &matWorld, -D3DX_PI / 5.0 ); g_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld ); } //----------------------------------------------------------------------------- // Desc: 设置观察矩阵和投影矩阵 //----------------------------------------------------------------------------- VOID SetViewAndProjMatrix() { //创建并设置观察矩阵 D3DXVECTOR3 vEyePt( 0.0f, 0.0f,-5.0f ); D3DXVECTOR3 vLookatPt( 0.0f, 0.0f, 0.0f ); D3DXVECTOR3 vUpVec( 0.0f, 1.0f, 0.0f ); D3DXMATRIXA16 matView; D3DXMatrixLookAtLH( &matView, &vEyePt, &vLookatPt, &vUpVec ); g_pd3dDevice->SetTransform( D3DTS_VIEW, &matView ); //创建并设置投影矩阵 D3DXMATRIXA16 matProj; D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, 1.0f, 1.0f, 100.0f ); g_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj ); } //----------------------------------------------------------------------------- // Desc: 初始化Direct3D //----------------------------------------------------------------------------- HRESULT InitD3D( HWND hWnd ) { //创建Direct3D对象, 该对象用于创建Direct3D设备对象 if( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) ) return E_FAIL; //设置D3DPRESENT_PARAMETERS结构, 准备创建Direct3D设备对象 D3DPRESENT_PARAMETERS d3dpp; ZeroMemory( &d3dpp, sizeof(d3dpp) ); d3dpp.Windowed = TRUE; d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; d3dpp.BackBufferFormat = D3DFMT_UNKNOWN; d3dpp.EnableAutoDepthStencil = TRUE; d3dpp.AutoDepthStencilFormat = D3DFMT_D16; //创建Direct3D设备对象 if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &g_pd3dDevice ) ) ) { return E_FAIL; } //创建Effect ID3DXBuffer* errBuffer = NULL; if (FAILED(D3DXCreateEffectFromFile(g_pd3dDevice, L"0401.fx", NULL, NULL, D3DXSHADER_DEBUG | D3DXSHADER_SKIPOPTIMIZATION, NULL, &g_pEffect, &errBuffer))) { if (errBuffer) { MessageBox(0, (LPCTSTR)errBuffer->GetBufferPointer(), 0, 0); errBuffer->Release(); } return E_FAIL; } //获取常量句柄 hWVPMatrixHandle = g_pEffect->GetParameterByName(0, "matWVP"); hTech0 = g_pEffect->GetTechniqueByName("Basic01"); //设置环境光 g_pd3dDevice->SetRenderState( D3DRS_AMBIENT, 0xffffffff ); //设置观察矩阵和投影矩阵 SetViewAndProjMatrix(); return S_OK; } //----------------------------------------------------------------------------- // Desc: 从绝对路径中提取纹理文件名 //----------------------------------------------------------------------------- void RemovePathFromFileName(LPSTR fullPath, LPWSTR fileName) { //先将fullPath的类型变换为LPWSTR WCHAR wszBuf[MAX_PATH]; MultiByteToWideChar( CP_ACP, 0, fullPath, -1, wszBuf, MAX_PATH ); wszBuf[MAX_PATH-1] = L'/0'; WCHAR* wszFullPath = wszBuf; //从绝对路径中提取文件名 LPWSTR pch=wcsrchr(wszFullPath,'//'); if (pch) lstrcpy(fileName, ++pch); else lstrcpy(fileName, wszFullPath); } //----------------------------------------------------------------------------- // Desc: 创建场景图形 //----------------------------------------------------------------------------- HRESULT InitGeometry() { LPD3DXBUFFER pD3DXMtrlBuffer; //存储网格模型材质的缓冲区对象 //从磁盘文件加载网格模型 if( FAILED( D3DXLoadMeshFromX( L"teapot.x", D3DXMESH_MANAGED, g_pd3dDevice, NULL, &pD3DXMtrlBuffer, NULL, &g_dwTeapotNumMaterials, &g_pMeshTeapot ) ) ) { MessageBox(NULL, L"Could not find airplane.x", L"Mesh", MB_OK); return E_FAIL; } //从网格模型中提取材质属性和纹理文件名 D3DXMATERIAL* d3dxMaterials = (D3DXMATERIAL*)pD3DXMtrlBuffer->GetBufferPointer(); g_pMeshTeapotMaterials = new D3DMATERIAL9[g_dwTeapotNumMaterials]; if( g_pMeshTeapotMaterials == NULL ) return E_OUTOFMEMORY; g_pMeshTeapotTextures = new LPDIRECT3DTEXTURE9[g_dwTeapotNumMaterials]; if( g_pMeshTeapotTextures == NULL ) return E_OUTOFMEMORY; //逐块提取网格模型材质属性和纹理文件名 for( DWORD i=0; i<g_dwTeapotNumMaterials; i++ ) { //材料属性 g_pMeshTeapotMaterials[i] = d3dxMaterials[i].MatD3D; //设置模型材料的环境光反射系数, 因为模型材料本身没有设置环境光反射系数 g_pMeshTeapotMaterials[i].Ambient = g_pMeshTeapotMaterials[i].Diffuse; g_pMeshTeapotTextures[i] = NULL; if( d3dxMaterials[i].pTextureFilename != NULL && strlen(d3dxMaterials[i].pTextureFilename) > 0 ) { //获取纹理文件名 WCHAR filename[256]; RemovePathFromFileName(d3dxMaterials[i].pTextureFilename, filename); //创建纹理 if( FAILED( D3DXCreateTextureFromFile( g_pd3dDevice, filename, &g_pMeshTeapotTextures[i] ) ) ) { MessageBox(NULL, L"Could not find texture file", L"Mesh", MB_OK); } } } //释放在加载模型文件时创建的保存模型材质和纹理数据的缓冲区对象 pD3DXMtrlBuffer->Release(); return S_OK; } //----------------------------------------------------------------------------- // Desc: 释放创建的对象 //----------------------------------------------------------------------------- VOID Cleanup() { //释放网格模型材质 if( g_pMeshTeapotMaterials != NULL ) delete[] g_pMeshTeapotMaterials; //释放网格模型纹理 if( g_pMeshTeapotTextures ) { for( DWORD i = 0; i < g_dwTeapotNumMaterials; i++ ) { if( g_pMeshTeapotTextures[i] ) g_pMeshTeapotTextures[i]->Release(); } delete[] g_pMeshTeapotTextures; } //释放网格模型对象 if( g_pMeshTeapot != NULL ) g_pMeshTeapot->Release(); if (g_pEffect != NULL) { g_pEffect->Release(); } //释放Direct3D设备对象 if( g_pd3dDevice != NULL ) g_pd3dDevice->Release(); //释放Direct3D对象 if( g_pD3D != NULL ) g_pD3D->Release(); } //----------------------------------------------------------------------------- // Desc: 渲染场景 //----------------------------------------------------------------------------- VOID Render() { // 清除缓冲区 g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,0,0), 1.0f, 0 ); //开始渲染场景 if( SUCCEEDED( g_pd3dDevice->BeginScene() ) ) { SetWorldMatrix(); //设置世界矩阵 D3DXMATRIX matWorld, matView, matProj; g_pd3dDevice->GetTransform(D3DTS_WORLD, &matWorld); g_pd3dDevice->GetTransform(D3DTS_VIEW, &matView); g_pd3dDevice->GetTransform(D3DTS_PROJECTION, &matProj); D3DXMATRIX matWVP = matWorld * matView * matProj; g_pEffect->SetMatrix(hWVPMatrixHandle, &matWVP); // 设置要使用的Technique g_pEffect->SetTechnique(hTech0); //遍历技术中包含的所有过程进行多次渲染 UINT numPasses = 0; g_pEffect->Begin(&numPasses, 0); for (int i = 0; i < numPasses; i++) { g_pEffect->BeginPass(i); //逐块渲染网格模型 for( DWORD i=0; i<g_dwTeapotNumMaterials; i++ ) { //渲染模型 g_pMeshTeapot->DrawSubset( i ); } g_pEffect->EndPass(); } g_pEffect->End(); //场景渲染结束 g_pd3dDevice->EndScene(); } //在屏幕上显示场景 g_pd3dDevice->Present( NULL, NULL, NULL, NULL ); } //----------------------------------------------------------------------------- // Desc: 窗口过程, 处理消息 //----------------------------------------------------------------------------- LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) { switch( msg ) { case WM_DESTROY: Cleanup(); PostQuitMessage( 0 ); return 0; } return DefWindowProc( hWnd, msg, wParam, lParam ); } //----------------------------------------------------------------------------- // Desc: 入口函数 //----------------------------------------------------------------------------- INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR, INT ) { //注册窗口类 WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L, GetModuleHandle(NULL), NULL, NULL, NULL, NULL, L"ClassName", NULL }; RegisterClassEx( &wc ); //创建窗口 HWND hWnd = CreateWindow( L"ClassName", L"Effect 实现", WS_OVERLAPPEDWINDOW, 200, 100, 500, 500, GetDesktopWindow(), NULL, wc.hInstance, NULL ); //初始化Direct3D if( SUCCEEDED( InitD3D( hWnd ) ) ) { //创建场景图形 if( SUCCEEDED( InitGeometry() ) ) { //显示窗口 ShowWindow( hWnd, SW_SHOWDEFAULT ); UpdateWindow( hWnd ); //进入消息循环 MSG msg; ZeroMemory( &msg, sizeof(msg) ); while( msg.message!=WM_QUIT ) { if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) { TranslateMessage( &msg ); DispatchMessage( &msg ); } else { Render(); //渲染场景 } } } } UnregisterClass( L"ClassName", wc.hInstance ); return 0; }
Effect代码如下:
/******************************** * Author: rabbit729 * E-mail: [email protected] * Date: 2011-04-23 ********************************/ //------------------------------ // 顶点着色器 //------------------------------ matrix matWVP; struct VS_OUTPUT { float4 Pos: POSITION; }; VS_OUTPUT vs_main( float4 inPos: POSITION ) { VS_OUTPUT Out; Out.Pos = mul(inPos, matWVP); return Out; } //------------------------------ // 像素着色器 //------------------------------ float4 ps_main() : COLOR0 { // Output a constant color: float4 color; color[0] = color[3] = 1.0; color[1] = color[2] = 0.0; return color; } //------------------------------ // 效果框架 //------------------------------ technique Basic01 { pass P0 { VertexShader = compile vs_3_0 vs_main(); PixelShader = compile ps_3_0 ps_main(); } }