<@乌龟:>第一个可以运行HLSL的DirectX程序
之后的一段时间准备学习一下DirectX和Shader相关的文章.
为了能够运行Shader,得先写个小程序.这里我选择了DirectX(其实我个人觉得,如果只是想学习Shader的话,XNA是个不错的选择)
看了几天的文档,重点看了一下DirectX Sample里面的Basic HLSL,可能是微软为了把一些控件集成进去,方便大家观察效果的原因吧,微软使用了DXUT这个框架,对我等c++和windows编程的初学者来说特别的不爽,所以我决定脱离DXUT框架来写一下
首先打开Sample里面的D3DX9 Create Device.我们就往这个程序里面添加代码.
1. 我们添加一个LoadMesh函数: 导入.X文件
Code
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;
}
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函数,在显卡初始化完成后,可以进行一些处理操作:
Code
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;
}
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.我们开始渲染:
Code
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 );
}
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.完成程序退出后的释放操作:
Code
VOID Cleanup()
{
if( g_pMesh != NULL )
g_pMesh->Release();
if( g_pd3dDevice != NULL )
g_pd3dDevice->Release();
if( g_pD3D != NULL )
g_pD3D->Release();
}
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函数,使得中间一段看起来这样:
Code
//
// 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 );
//
//
// 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.添加头文件和全局变量:
Code
#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];
#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的程序