《精通DirectX 3D》第二十章 效果 03_BasicHLSL
这个的难度陡然上升了许多,感觉很迷糊,不清晰了。这次读就是囫囵吞枣,大体看看有些啥东西,以后用到了的时候再细看。
BasicHLSL.fx
//
==============================================================
// Desc: 效果文件
// ==============================================================
// --------------------------------------------------------------
// 全局变量
// --------------------------------------------------------------
float4 g_MaterialAmbientColor; // 环境光材质
float4 g_MaterialDiffuseColor; // 漫反射光材质
int g_nNumLights; // 灯光数量
float3 g_LightDir[ 3 ]; // 灯光方向(世界空间)
float4 g_LightDiffuse[ 3 ]; // 灯光漫反射颜色
float4 g_LightAmbient; // 环境光颜色
texture g_MeshTexture; // 纹理
float g_fTime; // 程序运行的时间
float4x4 g_mWorld; // 世界矩阵
float4x4 g_mWorldViewProjection; // 组合变换矩阵
// --------------------------------------------------------------
// 纹理采样器
// --------------------------------------------------------------
sampler MeshTextureSampler =
sampler_state
{
Texture = < g_MeshTexture > ;
MipFilter = LINEAR;
MinFilter = LINEAR;
MagFilter = LINEAR;
};
// --------------------------------------------------------------
// 顶点渲染器输出结构
// --------------------------------------------------------------
struct VS_OUTPUT
{
float4 Position : POSITION; // 顶点位置
float4 Diffuse : COLOR0; // 顶点漫反射颜色(COLOR0取值在[0,1]之间)
float2 TextureUV : TEXCOORD0; // 顶点纹理坐标
};
// --------------------------------------------------------------
// 顶点渲染器
// --------------------------------------------------------------
VS_OUTPUT RenderSceneVS( float4 vPos : POSITION,
float3 vNormal : NORMAL,
float2 vTexCoord0 : TEXCOORD0,
uniform int nNumLights, // 灯光数量
uniform bool bTexture, // 是否使用纹理映射
uniform bool bAnimate ) // 是否产生动画
{
VS_OUTPUT Output;
float3 vNormalWorldSpace;
float4 vAnimatedPos = vPos;
// 根据时间改变顶点位置
if ( bAnimate )
vAnimatedPos += float4(vNormal, 0 ) * (sin(g_fTime + 5.5 ) + 0.5 ) * 5 ;
// 将顶点位置坐标从本地空间变换到其次投影空间
Output.Position = mul(vAnimatedPos, g_mWorldViewProjection);
// 将顶点法向量从本地空间变换到世界空间,并单位化
vNormalWorldSpace = normalize(mul(vNormal, (float3x3)g_mWorld));
// 计算顶点光照颜色
float3 vTotalLightDiffuse = float3( 0 , 0 , 0 );
for ( int i = 0 ; i < nNumLights; i ++ )
vTotalLightDiffuse += g_LightDiffuse[i] * max( 0 ,dot(vNormalWorldSpace, g_LightDir[i]));
Output.Diffuse.rgb = g_MaterialDiffuseColor * vTotalLightDiffuse +
g_MaterialAmbientColor * g_LightAmbient;
Output.Diffuse.a = 1.0f ;
// 原样输出顶点纹理坐标
if ( bTexture )
Output.TextureUV = vTexCoord0;
else
Output.TextureUV = 0 ;
return Output;
}
// --------------------------------------------------------------
// 像素渲染器输出结构
// --------------------------------------------------------------
struct PS_OUTPUT
{
float4 RGBColor : COLOR0; // 像素颜色
};
// --------------------------------------------------------------
// 像素渲染器
// --------------------------------------------------------------
PS_OUTPUT RenderScenePS( VS_OUTPUT In,
uniform bool bTexture )
{
PS_OUTPUT Output;
// 计算每个像素的颜色(纹理颜色*漫反射颜色)
if ( bTexture )
Output.RGBColor = tex2D(MeshTextureSampler, In.TextureUV) * In.Diffuse;
else
Output.RGBColor = In.Diffuse;
return Output;
}
// --------------------------------------------------------------
// 技术
// --------------------------------------------------------------
technique RenderSceneWithTexture1Light
{
pass P0
{
VertexShader = compile vs_2_0 RenderSceneVS( 1 , true , true ); // hew: DX June 2007的话,要改成这个,否则执行程序会出错
PixelShader = compile ps_2_0 RenderScenePS( true ); // trivial pixel shader (could use FF instead if desired)
}
}
technique RenderSceneWithTexture2Light
{
pass P0
{
VertexShader = compile vs_2_0 RenderSceneVS( 2 , true , true );
PixelShader = compile ps_2_0 RenderScenePS( true ); // trivial pixel shader (could use FF instead if desired)
}
}
technique RenderSceneWithTexture3Light
{
pass P0
{
VertexShader = compile vs_2_0 RenderSceneVS( 3 , true , true );
PixelShader = compile ps_2_0 RenderScenePS( true ); // trivial pixel shader (could use FF instead if desired)
}
}
technique RenderSceneNoTexture
{
pass P0
{
VertexShader = compile vs_2_0 RenderSceneVS( 1 , false , false );
PixelShader = compile ps_2_0 RenderScenePS( false ); // trivial pixel shader (could use FF instead if desired)
}
}
// Desc: 效果文件
// ==============================================================
// --------------------------------------------------------------
// 全局变量
// --------------------------------------------------------------
float4 g_MaterialAmbientColor; // 环境光材质
float4 g_MaterialDiffuseColor; // 漫反射光材质
int g_nNumLights; // 灯光数量
float3 g_LightDir[ 3 ]; // 灯光方向(世界空间)
float4 g_LightDiffuse[ 3 ]; // 灯光漫反射颜色
float4 g_LightAmbient; // 环境光颜色
texture g_MeshTexture; // 纹理
float g_fTime; // 程序运行的时间
float4x4 g_mWorld; // 世界矩阵
float4x4 g_mWorldViewProjection; // 组合变换矩阵
// --------------------------------------------------------------
// 纹理采样器
// --------------------------------------------------------------
sampler MeshTextureSampler =
sampler_state
{
Texture = < g_MeshTexture > ;
MipFilter = LINEAR;
MinFilter = LINEAR;
MagFilter = LINEAR;
};
// --------------------------------------------------------------
// 顶点渲染器输出结构
// --------------------------------------------------------------
struct VS_OUTPUT
{
float4 Position : POSITION; // 顶点位置
float4 Diffuse : COLOR0; // 顶点漫反射颜色(COLOR0取值在[0,1]之间)
float2 TextureUV : TEXCOORD0; // 顶点纹理坐标
};
// --------------------------------------------------------------
// 顶点渲染器
// --------------------------------------------------------------
VS_OUTPUT RenderSceneVS( float4 vPos : POSITION,
float3 vNormal : NORMAL,
float2 vTexCoord0 : TEXCOORD0,
uniform int nNumLights, // 灯光数量
uniform bool bTexture, // 是否使用纹理映射
uniform bool bAnimate ) // 是否产生动画
{
VS_OUTPUT Output;
float3 vNormalWorldSpace;
float4 vAnimatedPos = vPos;
// 根据时间改变顶点位置
if ( bAnimate )
vAnimatedPos += float4(vNormal, 0 ) * (sin(g_fTime + 5.5 ) + 0.5 ) * 5 ;
// 将顶点位置坐标从本地空间变换到其次投影空间
Output.Position = mul(vAnimatedPos, g_mWorldViewProjection);
// 将顶点法向量从本地空间变换到世界空间,并单位化
vNormalWorldSpace = normalize(mul(vNormal, (float3x3)g_mWorld));
// 计算顶点光照颜色
float3 vTotalLightDiffuse = float3( 0 , 0 , 0 );
for ( int i = 0 ; i < nNumLights; i ++ )
vTotalLightDiffuse += g_LightDiffuse[i] * max( 0 ,dot(vNormalWorldSpace, g_LightDir[i]));
Output.Diffuse.rgb = g_MaterialDiffuseColor * vTotalLightDiffuse +
g_MaterialAmbientColor * g_LightAmbient;
Output.Diffuse.a = 1.0f ;
// 原样输出顶点纹理坐标
if ( bTexture )
Output.TextureUV = vTexCoord0;
else
Output.TextureUV = 0 ;
return Output;
}
// --------------------------------------------------------------
// 像素渲染器输出结构
// --------------------------------------------------------------
struct PS_OUTPUT
{
float4 RGBColor : COLOR0; // 像素颜色
};
// --------------------------------------------------------------
// 像素渲染器
// --------------------------------------------------------------
PS_OUTPUT RenderScenePS( VS_OUTPUT In,
uniform bool bTexture )
{
PS_OUTPUT Output;
// 计算每个像素的颜色(纹理颜色*漫反射颜色)
if ( bTexture )
Output.RGBColor = tex2D(MeshTextureSampler, In.TextureUV) * In.Diffuse;
else
Output.RGBColor = In.Diffuse;
return Output;
}
// --------------------------------------------------------------
// 技术
// --------------------------------------------------------------
technique RenderSceneWithTexture1Light
{
pass P0
{
VertexShader = compile vs_2_0 RenderSceneVS( 1 , true , true ); // hew: DX June 2007的话,要改成这个,否则执行程序会出错
PixelShader = compile ps_2_0 RenderScenePS( true ); // trivial pixel shader (could use FF instead if desired)
}
}
technique RenderSceneWithTexture2Light
{
pass P0
{
VertexShader = compile vs_2_0 RenderSceneVS( 2 , true , true );
PixelShader = compile ps_2_0 RenderScenePS( true ); // trivial pixel shader (could use FF instead if desired)
}
}
technique RenderSceneWithTexture3Light
{
pass P0
{
VertexShader = compile vs_2_0 RenderSceneVS( 3 , true , true );
PixelShader = compile ps_2_0 RenderScenePS( true ); // trivial pixel shader (could use FF instead if desired)
}
}
technique RenderSceneNoTexture
{
pass P0
{
VertexShader = compile vs_2_0 RenderSceneVS( 1 , false , false );
PixelShader = compile ps_2_0 RenderScenePS( false ); // trivial pixel shader (could use FF instead if desired)
}
}
//
=============================================================================
// Desc: 主程序源文件
// =============================================================================
#include " dxstdafx.h "
#include " resource.h "
// #define DEBUG_VS // Uncomment this line to debug vertex shaders
// #define DEBUG_PS // Uncomment this line to debug pixel shaders
// -----------------------------------------------------------------------------
// 全局变量
// -----------------------------------------------------------------------------
ID3DXFont * g_pFont = NULL; // ID3DXFont字体对象
ID3DXSprite * g_pSprite = NULL; // ID3DXSprite文本精灵对象
bool g_bShowHelp = true ; // 标识是否显示简单说明文本
CDXUTDialogResourceManager g_DialogResourceManager; // 对话框资源管理器
CD3DSettingsDlg g_SettingsDlg; // Direct3D设备设置对话框
CDXUTDialog g_HUD; // 3DUI对话框
CDXUTDialog g_SampleUI; // 其它控件对话框
CModelViewerCamera g_Camera; // 摄影机对象
ID3DXEffect * g_pEffect = NULL; // 效果
ID3DXMesh * g_pMesh = NULL; // 网格模型
IDirect3DTexture9 * g_pMeshTexture = NULL; // 网格模型纹理
bool g_bEnablePreshader; // 标志是否启用预编译渲染器
D3DXMATRIXA16 g_mCenterWorld; // 调整矩阵, 将网格模型调整到窗口中心显示
#define MAX_LIGHTS 3 // 灯光数量
CDXUTDirectionWidget g_LightControl[MAX_LIGHTS];
float g_fLightScale;
int g_nNumActiveLights;
int g_nActiveLight;
// --------------------------------------------------------------------------------------
// 控件ID
// --------------------------------------------------------------------------------------
#define IDC_TOGGLEFULLSCREEN 1
#define IDC_TOGGLEREF 3
#define IDC_CHANGEDEVICE 4
#define IDC_ENABLE_PRESHADER 5
#define IDC_NUM_LIGHTS 6
#define IDC_NUM_LIGHTS_STATIC 7
#define IDC_ACTIVE_LIGHT 8
#define IDC_LIGHT_SCALE 9
#define IDC_LIGHT_SCALE_STATIC 10
// -----------------------------------------------------------------------------
// Desc: 函数声明
// -----------------------------------------------------------------------------
bool CALLBACK IsDeviceAcceptable( D3DCAPS9 * pCaps, D3DFORMAT AdapterFormat, D3DFORMAT BackBufferFormat, bool bWindowed, void * pUserContext );
bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings * pDeviceSettings, const D3DCAPS9 * pCaps, void * pUserContext );
HRESULT CALLBACK OnCreateDevice( IDirect3DDevice9 * pd3dDevice, const D3DSURFACE_DESC * pBackBufferSurfaceDesc, void * pUserContext );
HRESULT CALLBACK OnResetDevice( IDirect3DDevice9 * pd3dDevice, const D3DSURFACE_DESC * pBackBufferSurfaceDesc, void * pUserContext );
void CALLBACK OnFrameMove( IDirect3DDevice9 * pd3dDevice, double fTime, float fElapsedTime, void * pUserContext );
void CALLBACK OnFrameRender( IDirect3DDevice9 * pd3dDevice, double fTime, float fElapsedTime, void * pUserContext );
LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool * pbNoFurtherProcessing, void * pUserContext );
void CALLBACK KeyboardProc( UINT nChar, bool bKeyDown, bool bAltDown, void * pUserContext );
void CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl * pControl, void * pUserContext );
void CALLBACK OnLostDevice( void * pUserContext );
void CALLBACK OnDestroyDevice( void * pUserContext );
void InitApp();
HRESULT LoadMesh( IDirect3DDevice9 * pd3dDevice, WCHAR * strFileName, ID3DXMesh ** ppMesh );
void RenderText( double fTime );
// -----------------------------------------------------------------------------
// Desc: 入口函数
// -----------------------------------------------------------------------------
INT WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, int )
{
// 为Debug配置启用运行时内存检查功能
#if defined(DEBUG) | defined(_DEBUG)
_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
#endif
// 设置回调函数
DXUTSetCallbackDeviceCreated( OnCreateDevice );
DXUTSetCallbackDeviceReset( OnResetDevice );
DXUTSetCallbackDeviceLost( OnLostDevice );
DXUTSetCallbackDeviceDestroyed( OnDestroyDevice );
DXUTSetCallbackMsgProc( MsgProc );
DXUTSetCallbackKeyboard( KeyboardProc );
DXUTSetCallbackFrameRender( OnFrameRender );
DXUTSetCallbackFrameMove( OnFrameMove );
// 切换到全屏幕时显示鼠标
DXUTSetCursorSettings( true , true );
// 应用程序相关的初始化
InitApp();
// 初始化DXUT, 创建窗口, 创建Direct3D设备对象
DXUTInit( true , true , true );
DXUTCreateWindow( L " BasicHLSL " );
DXUTCreateDevice( D3DADAPTER_DEFAULT, true , 640 , 480 ,
IsDeviceAcceptable, ModifyDeviceSettings );
// 进入消息循环和场景渲染
DXUTMainLoop();
// 在此进行应用程序相关的清除工作
return DXUTGetExitCode();
}
// -----------------------------------------------------------------------------
// Desc: 应用程序相关初始化
// -----------------------------------------------------------------------------
void InitApp()
{
// 初始化全局变量
g_bEnablePreshader = true ;
for ( int i = 0 ; i < MAX_LIGHTS; i ++ )
g_LightControl[i].SetLightDirection( D3DXVECTOR3( sinf(D3DX_PI * 2 * i / MAX_LIGHTS - D3DX_PI / 6 ), 0 , - cosf(D3DX_PI * 2 * i / MAX_LIGHTS - D3DX_PI / 6 ) ) );
g_nActiveLight = 0 ;
g_nNumActiveLights = 1 ;
g_fLightScale = 1.0f ;
// 初始化对话框
g_SettingsDlg.Init( & g_DialogResourceManager );
g_HUD.Init( & g_DialogResourceManager );
g_SampleUI.Init( & g_DialogResourceManager );
// 为g_HUD对话框设置消息处理函数,添加控件
g_HUD.SetCallback( OnGUIEvent ); int iY = 10 ;
g_HUD.AddButton( IDC_TOGGLEFULLSCREEN, L " Toggle full screen " , 35 , iY, 125 , 22 );
g_HUD.AddButton( IDC_TOGGLEREF, L " Toggle REF (F3) " , 35 , iY += 24 , 125 , 22 );
g_HUD.AddButton( IDC_CHANGEDEVICE, L " Change device (F2) " , 35 , iY += 24 , 125 , 22 , VK_F2 );
// 为g_SampleUI对话框设置消息处理函数,添加控件
g_SampleUI.SetCallback( OnGUIEvent ); iY = 10 ;
WCHAR sz[ 100 ];
iY += 24 ;
StringCchPrintf( sz, 100 , L " # Lights: %d " , g_nNumActiveLights );
g_SampleUI.AddStatic( IDC_NUM_LIGHTS_STATIC, sz, 35 , iY += 24 , 125 , 22 );
g_SampleUI.AddSlider( IDC_NUM_LIGHTS, 50 , iY += 24 , 100 , 22 , 1 , MAX_LIGHTS, g_nNumActiveLights );
iY += 24 ;
StringCchPrintf( sz, 100 , L " Light scale: %0.2f " , g_fLightScale );
g_SampleUI.AddStatic( IDC_LIGHT_SCALE_STATIC, sz, 35 , iY += 24 , 125 , 22 );
g_SampleUI.AddSlider( IDC_LIGHT_SCALE, 50 , iY += 24 , 100 , 22 , 0 , 20 , ( int ) (g_fLightScale * 10.0f ) );
iY += 24 ;
g_SampleUI.AddButton( IDC_ACTIVE_LIGHT, L " Change active light (K) " , 35 , iY += 24 , 125 , 22 , ' K ' );
g_SampleUI.AddCheckBox( IDC_ENABLE_PRESHADER, L " Enable preshaders " , 35 , iY += 24 , 125 , 22 , g_bEnablePreshader );
}
// -----------------------------------------------------------------------------
// Desc: 设备能力检查
// -----------------------------------------------------------------------------
bool CALLBACK IsDeviceAcceptable( D3DCAPS9 * pCaps, D3DFORMAT AdapterFormat,
D3DFORMAT BackBufferFormat, bool bWindowed, void * pUserContext )
{
// 检查后台缓冲区格式是否支持Alpha混合等操作(post pixel blending operations)
IDirect3D9 * pD3D = DXUTGetD3DObject();
if ( FAILED( pD3D -> CheckDeviceFormat( pCaps -> AdapterOrdinal, pCaps -> DeviceType,
AdapterFormat, D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING,
D3DRTYPE_TEXTURE, BackBufferFormat ) ) )
return false ;
// 检查设备支持的像素渲染器版本
if ( pCaps -> PixelShaderVersion < D3DPS_VERSION( 1 , 1 ) )
return false ;
return true ;
}
// -----------------------------------------------------------------------------
// Desc: 修改Direct3D渲染设备设置
// -----------------------------------------------------------------------------
bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings * pDeviceSettings, const D3DCAPS9 * pCaps, void * pUserContext )
{
// 如果硬件不支持, 则使用软件顶点处理
if ( (pCaps -> DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0 ||
pCaps -> VertexShaderVersion < D3DVS_VERSION( 1 , 1 ) )
{
pDeviceSettings -> BehaviorFlags = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
}
// 调试顶点渲染器需要参考设备或软件顶点处理
#ifdef DEBUG_VS
if ( pDeviceSettings -> DeviceType != D3DDEVTYPE_REF )
{
pDeviceSettings -> BehaviorFlags &= ~ D3DCREATE_HARDWARE_VERTEXPROCESSING;
pDeviceSettings -> BehaviorFlags &= ~ D3DCREATE_PUREDEVICE;
pDeviceSettings -> BehaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
}
#endif
// 调试像素渲染器需要参考设备
#ifdef DEBUG_PS
pDeviceSettings -> DeviceType = D3DDEVTYPE_REF;
#endif
// 如果使用参考设备,则弹出警告对话框
static bool s_bFirstTime = true ;
if ( s_bFirstTime )
{
s_bFirstTime = false ;
if ( pDeviceSettings -> DeviceType == D3DDEVTYPE_REF )
DXUTDisplaySwitchingToREFWarning();
}
return true ;
}
// -----------------------------------------------------------------------------
// Desc: 在此创建管理内存资源对象
// -----------------------------------------------------------------------------
HRESULT CALLBACK OnCreateDevice( IDirect3DDevice9 * pd3dDevice, const D3DSURFACE_DESC * pBackBufferSurfaceDesc, void * pUserContext )
{
HRESULT hr;
V_RETURN( g_DialogResourceManager.OnCreateDevice( pd3dDevice ) );
V_RETURN( g_SettingsDlg.OnCreateDevice( pd3dDevice ) );
// 创建字体
V_RETURN( D3DXCreateFont( pd3dDevice, 15 , 0 , FW_BOLD, 1 , FALSE, DEFAULT_CHARSET,
OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE,
L " Arial " , & g_pFont ) );
// 加载网格
V_RETURN( LoadMesh( pd3dDevice, L " tiny\\tiny.x " , & g_pMesh ) );
// 计算网格模型外包围球半径和中心点坐标
D3DXVECTOR3 * pData;
D3DXVECTOR3 vCenter;
FLOAT fObjectRadius;
V( g_pMesh -> LockVertexBuffer( 0 , (LPVOID * ) & pData ) );
V( D3DXComputeBoundingSphere( pData, g_pMesh -> GetNumVertices(), D3DXGetFVFVertexSize( g_pMesh -> GetFVF() ), & vCenter, & fObjectRadius ) );
V( g_pMesh -> UnlockVertexBuffer() );
// 构造网格模型世界矩阵
D3DXMatrixTranslation( & g_mCenterWorld, - vCenter.x, - vCenter.y, - vCenter.z );
D3DXMATRIXA16 m;
D3DXMatrixRotationY( & m, D3DX_PI );
g_mCenterWorld *= m;
D3DXMatrixRotationX( & m, D3DX_PI / 2.0f );
g_mCenterWorld *= m;
//
V_RETURN( CDXUTDirectionWidget::StaticOnCreateDevice( pd3dDevice ) );
for ( int i = 0 ; i < MAX_LIGHTS; i ++ )
g_LightControl[i].SetRadius( fObjectRadius );
// 设置渲染器创建标志
DWORD dwShaderFlags = D3DXFX_NOT_CLONEABLE;
#ifdef DEBUG_VS
dwShaderFlags |= D3DXSHADER_FORCE_VS_SOFTWARE_NOOPT;
#endif
#ifdef DEBUG_PS
dwShaderFlags |= D3DXSHADER_FORCE_PS_SOFTWARE_NOOPT;
#endif
if ( ! g_bEnablePreshader )
dwShaderFlags |= D3DXSHADER_NO_PRESHADER;
// 查找效果文件
WCHAR str[MAX_PATH];
V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L " BasicHLSL.fx " ) );
// 从文件创建效果
V_RETURN( D3DXCreateEffectFromFile( pd3dDevice, str, NULL, NULL, dwShaderFlags, NULL, & g_pEffect, NULL ) );
// 查找网格模型纹理文件
V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L " tiny\\tiny_skin.dds " ) );
// 创建网格模型纹理
V_RETURN( D3DXCreateTextureFromFileEx( pd3dDevice, str, D3DX_DEFAULT, D3DX_DEFAULT,
D3DX_DEFAULT, 0 , D3DFMT_UNKNOWN, D3DPOOL_MANAGED,
D3DX_DEFAULT, D3DX_DEFAULT, 0 ,
NULL, NULL, & g_pMeshTexture ) );
// 设置效果参数变量
D3DXCOLOR colorMtrlDiffuse( 1.0f , 1.0f , 1.0f , 1.0f );
D3DXCOLOR colorMtrlAmbient( 0.35f , 0.35f , 0.35f , 0 );
V_RETURN( g_pEffect -> SetValue( " g_MaterialAmbientColor " , & colorMtrlAmbient, sizeof (D3DXCOLOR) ) );
V_RETURN( g_pEffect -> SetValue( " g_MaterialDiffuseColor " , & colorMtrlDiffuse, sizeof (D3DXCOLOR) ) );
V_RETURN( g_pEffect -> SetTexture( " g_MeshTexture " , g_pMeshTexture) );
// 设置摄影机观察参数
D3DXVECTOR3 vecEye( 0.0f , 0.0f , - 15.0f );
D3DXVECTOR3 vecAt ( 0.0f , 0.0f , - 0.0f );
g_Camera.SetViewParams( & vecEye, & vecAt );
g_Camera.SetRadius( fObjectRadius * 3.0f , fObjectRadius * 0.5f , fObjectRadius * 10.0f );
return S_OK;
}
// ------------------------------------------------------------------------------
// Desc: 辅助函数, 加载网格模型
// -----------------------------------------------------------------------------
HRESULT LoadMesh( IDirect3DDevice9 * pd3dDevice, WCHAR * strFileName, ID3DXMesh ** ppMesh )
{
ID3DXMesh * pMesh = NULL;
WCHAR str[MAX_PATH];
HRESULT hr;
// 从文件加载网格模型
V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, strFileName ) );
V_RETURN( D3DXLoadMeshFromX(str, D3DXMESH_MANAGED, pd3dDevice, NULL, NULL, NULL, NULL, & pMesh) );
DWORD * rgdwAdjacency = NULL;
// 确保网格模型顶点包含法线信息,以满足光照计算的需要
if ( ! (pMesh -> GetFVF() & D3DFVF_NORMAL) )
{
ID3DXMesh * pTempMesh;
V( pMesh -> CloneMeshFVF( pMesh -> GetOptions(),
pMesh -> GetFVF() | D3DFVF_NORMAL,
pd3dDevice, & pTempMesh ) );
V( D3DXComputeNormals( pTempMesh, NULL ) );
SAFE_RELEASE( pMesh );
pMesh = pTempMesh;
}
// 对网格模型进行优化,以提高程序运行性能
rgdwAdjacency = new DWORD[pMesh -> GetNumFaces() * 3 ];
if ( rgdwAdjacency == NULL )
return E_OUTOFMEMORY;
V( pMesh -> GenerateAdjacency( 1e-6f ,rgdwAdjacency) );
V( pMesh -> OptimizeInplace(D3DXMESHOPT_VERTEXCACHE, rgdwAdjacency, NULL, NULL, NULL) );
delete []rgdwAdjacency;
* ppMesh = pMesh;
return S_OK;
}
// -----------------------------------------------------------------------------
// Desc: 在此创建默认内存类型资源对象
// -----------------------------------------------------------------------------
HRESULT CALLBACK OnResetDevice( IDirect3DDevice9 * pd3dDevice,
const D3DSURFACE_DESC * pBackBufferSurfaceDesc,
void * pUserContext )
{
HRESULT hr;
V_RETURN( g_DialogResourceManager.OnResetDevice() );
V_RETURN( g_SettingsDlg.OnResetDevice() );
// 恢复字体
if ( g_pFont )
V_RETURN( g_pFont -> OnResetDevice() );
// 创建ID3DXSprite接口对象
V_RETURN( D3DXCreateSprite( pd3dDevice, & g_pSprite ) );
// 设置摄影机对象投影参数
float fAspectRatio = pBackBufferSurfaceDesc -> Width / (FLOAT)pBackBufferSurfaceDesc -> Height;
g_Camera.SetProjParams( D3DX_PI / 4 , fAspectRatio, 2.0f , 4000.0f );
g_Camera.SetWindow( pBackBufferSurfaceDesc -> Width, pBackBufferSurfaceDesc -> Height );
g_Camera.SetButtonMasks( MOUSE_LEFT_BUTTON, MOUSE_WHEEL, MOUSE_MIDDLE_BUTTON );
// 设置对话框位置和尺寸
g_HUD.SetLocation( pBackBufferSurfaceDesc -> Width - 170 , 0 );
g_HUD.SetSize( 170 , 170 );
g_SampleUI.SetLocation( pBackBufferSurfaceDesc -> Width - 170 , pBackBufferSurfaceDesc -> Height - 300 );
g_SampleUI.SetSize( 170 , 300 );
for ( int i = 0 ; i < MAX_LIGHTS; i ++ )
g_LightControl[i].OnResetDevice( pBackBufferSurfaceDesc );
// 恢复效果对象
if ( g_pEffect )
V_RETURN( g_pEffect -> OnResetDevice() );
return S_OK;
}
// -----------------------------------------------------------------------------
// Desc: 更新场景
// -----------------------------------------------------------------------------
void CALLBACK OnFrameMove( IDirect3DDevice9 * pd3dDevice, double fTime, float fElapsedTime, void * pUserContext )
{
// 根据用户位置更新摄影机方向
g_Camera.FrameMove( fElapsedTime );
}
// -----------------------------------------------------------------------------
// Desc: 渲染场景
// -----------------------------------------------------------------------------
void CALLBACK OnFrameRender( IDirect3DDevice9 * pd3dDevice, double fTime, float fElapsedTime, void * pUserContext )
{
// 如果正在利用Direct3D设备设置对话框进行设置, 则不渲染场景
if ( g_SettingsDlg.IsActive() )
{
g_SettingsDlg.OnRender( fElapsedTime );
return ;
}
//
HRESULT hr;
D3DXMATRIXA16 mWorldViewProjection;
D3DXVECTOR3 vLightDir[MAX_LIGHTS];
D3DXCOLOR vLightDiffuse[MAX_LIGHTS];
D3DXMATRIXA16 mWorld;
D3DXMATRIXA16 mView;
D3DXMATRIXA16 mProj;
// 清除后台颜色缓冲区和深度缓冲区
V( pd3dDevice -> Clear( 0 , NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DXCOLOR( 0.0f , 0.25f , 0.25f , 0.55f ), 1.0f , 0 ) );
// 渲染场景
if ( SUCCEEDED( pd3dDevice -> BeginScene() ) )
{
// 通过摄影机对象获得观察矩阵和投影矩镇
mWorld = g_mCenterWorld * * g_Camera.GetWorldMatrix();
mProj = * g_Camera.GetProjMatrix();
mView = * g_Camera.GetViewMatrix();
mWorldViewProjection = mWorld * mView * mProj;
// 渲染表示灯光方向的箭头, 并设置灯光方向和漫反射颜色值
for ( int i = 0 ; i < g_nNumActiveLights; i ++ )
{
D3DXCOLOR arrowColor = ( i == g_nActiveLight ) ? D3DXCOLOR( 1 , 1 , 0 , 1 ) : D3DXCOLOR( 1 , 1 , 1 , 1 );
V( g_LightControl[i].OnRender( arrowColor, & mView, & mProj, g_Camera.GetEyePt() ) );
vLightDir[i] = g_LightControl[i].GetLightDirection();
vLightDiffuse[i] = g_fLightScale * D3DXCOLOR( 1 , 1 , 1 , 1 );
}
// 更新效果参数变量
V( g_pEffect -> SetValue( " g_LightDir " , vLightDir, sizeof (D3DXVECTOR3) * MAX_LIGHTS ) );
V( g_pEffect -> SetValue( " g_LightDiffuse " , vLightDiffuse, sizeof (D3DXVECTOR4) * MAX_LIGHTS ) );
V( g_pEffect -> SetMatrix( " g_mWorldViewProjection " , & mWorldViewProjection ) );
V( g_pEffect -> SetMatrix( " g_mWorld " , & mWorld ) );
V( g_pEffect -> SetFloat( " g_fTime " , ( float )fTime ) );
D3DXCOLOR vWhite = D3DXCOLOR( 1 , 1 , 1 , 1 );
V( g_pEffect -> SetValue( " g_MaterialDiffuseColor " , & vWhite, sizeof (D3DXCOLOR) ) );
V( g_pEffect -> SetFloat( " g_fTime " , ( float )fTime ) );
V( g_pEffect -> SetInt( " g_nNumLights " , g_nNumActiveLights ) );
// 根据灯光数量, 激活适当的技术
switch ( g_nNumActiveLights )
{
case 1 : V( g_pEffect -> SetTechnique( " RenderSceneWithTexture1Light " ) ); break ;
case 2 : V( g_pEffect -> SetTechnique( " RenderSceneWithTexture2Light " ) ); break ;
case 3 : V( g_pEffect -> SetTechnique( " RenderSceneWithTexture3Light " ) ); break ;
}
// 使用效果中的技术渲染场景
UINT iPass, cPasses;
V( g_pEffect -> Begin( & cPasses, 0 ) );
for (iPass = 0 ; iPass < cPasses; iPass ++ )
{
V( g_pEffect -> BeginPass(iPass) );
// 使用技术渲染网格模型
V( g_pMesh -> DrawSubset( 0 ) );
V( g_pEffect -> EndPass() );
}
V( g_pEffect -> End() );
// 渲染对话框
g_HUD.OnRender( fElapsedTime );
g_SampleUI.OnRender( fElapsedTime );
// 渲染文本
RenderText( fTime );
V( pd3dDevice -> EndScene() );
}
}
// -----------------------------------------------------------------------------
// Desc: 渲染文本
// -----------------------------------------------------------------------------
void RenderText( double fTime )
{
CDXUTTextHelper txtHelper( g_pFont, g_pSprite, 15 );
// 显示当前Direct3D设备状态和渲染帧速率
txtHelper.Begin();
txtHelper.SetInsertionPos( 2 , 0 );
txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f , 1.0f , 0.0f , 1.0f ) );
txtHelper.DrawTextLine( DXUTGetFrameStats( true ) );
txtHelper.DrawTextLine( DXUTGetDeviceStats() );
// 显示其他简要信息
txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f , 1.0f , 1.0f , 1.0f ) );
txtHelper.DrawFormattedTextLine( L " fTime: %0.1f sin(fTime): %0.4f " , fTime, sin(fTime) );
txtHelper.DrawFormattedTextLine( L " 多技术效果示例程序 " );
// 显示简单帮助文本
if ( g_bShowHelp )
{
const D3DSURFACE_DESC * pd3dsdBackBuffer = DXUTGetBackBufferSurfaceDesc();
txtHelper.SetInsertionPos( 2 , pd3dsdBackBuffer -> Height - 15 * 6 );
txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f , 0.75f , 0.0f , 1.0f ) );
txtHelper.DrawTextLine( L " Controls: " );
txtHelper.SetInsertionPos( 20 , pd3dsdBackBuffer -> Height - 15 * 5 );
txtHelper.DrawTextLine( L " Rotate model: Left mouse button\n "
L " Rotate light: Right mouse button\n "
L " Rotate camera: Middle mouse button\n "
L " Zoom camera: Mouse wheel scroll\n " );
txtHelper.SetInsertionPos( 250 , pd3dsdBackBuffer -> Height - 15 * 5 );
txtHelper.DrawTextLine( L " Hide help: F1\n "
L " Quit: ESC\n " );
}
else
{
txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f , 1.0f , 1.0f , 1.0f ) );
txtHelper.DrawTextLine( L " Press F1 for help " );
}
txtHelper.End();
}
// -----------------------------------------------------------------------------
// Desc: 消息处理
// -----------------------------------------------------------------------------
LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool * pbNoFurtherProcessing, void * pUserContext )
{
* pbNoFurtherProcessing = g_DialogResourceManager.MsgProc( hWnd, uMsg, wParam, lParam );
if ( * pbNoFurtherProcessing )
return 0 ;
if ( g_SettingsDlg.IsActive() )
{
g_SettingsDlg.MsgProc( hWnd, uMsg, wParam, lParam );
return 0 ;
}
* pbNoFurtherProcessing = g_HUD.MsgProc( hWnd, uMsg, wParam, lParam );
if ( * pbNoFurtherProcessing )
return 0 ;
* pbNoFurtherProcessing = g_SampleUI.MsgProc( hWnd, uMsg, wParam, lParam );
if ( * pbNoFurtherProcessing )
return 0 ;
g_LightControl[g_nActiveLight].HandleMessages( hWnd, uMsg, wParam, lParam );
g_Camera.HandleMessages( hWnd, uMsg, wParam, lParam );
return 0 ;
}
// -----------------------------------------------------------------------------
// Desc: 键盘消息处理
// -----------------------------------------------------------------------------
void CALLBACK KeyboardProc( UINT nChar, bool bKeyDown, bool bAltDown, void * pUserContext )
{
if ( bKeyDown )
{
switch ( nChar )
{
case VK_F1: g_bShowHelp = ! g_bShowHelp; break ;
}
}
}
// -----------------------------------------------------------------------------
// Desc: 各种控件消息处理
// -----------------------------------------------------------------------------
void CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl * pControl, void * pUserContext )
{
switch ( nControlID )
{
case IDC_TOGGLEFULLSCREEN: DXUTToggleFullScreen(); break ;
case IDC_TOGGLEREF: DXUTToggleREF(); break ;
case IDC_CHANGEDEVICE: g_SettingsDlg.SetActive( ! g_SettingsDlg.IsActive() ); break ;
case IDC_ENABLE_PRESHADER:
{
g_bEnablePreshader = g_SampleUI.GetCheckBox( IDC_ENABLE_PRESHADER ) -> GetChecked();
if ( DXUTGetD3DDevice() != NULL )
{
OnLostDevice( NULL );
OnDestroyDevice( NULL );
OnCreateDevice( DXUTGetD3DDevice(), DXUTGetBackBufferSurfaceDesc(), NULL );
OnResetDevice( DXUTGetD3DDevice(), DXUTGetBackBufferSurfaceDesc(), NULL );
}
break ;
}
case IDC_ACTIVE_LIGHT:
if ( ! g_LightControl[g_nActiveLight].IsBeingDragged() )
{
g_nActiveLight ++ ;
g_nActiveLight %= g_nNumActiveLights;
}
break ;
case IDC_NUM_LIGHTS:
if ( ! g_LightControl[g_nActiveLight].IsBeingDragged() )
{
WCHAR sz[ 100 ];
StringCchPrintf( sz, 100 , L " # Lights: %d " , g_SampleUI.GetSlider( IDC_NUM_LIGHTS ) -> GetValue() );
g_SampleUI.GetStatic( IDC_NUM_LIGHTS_STATIC ) -> SetText( sz );
g_nNumActiveLights = g_SampleUI.GetSlider( IDC_NUM_LIGHTS ) -> GetValue();
g_nActiveLight %= g_nNumActiveLights;
}
break ;
case IDC_LIGHT_SCALE:
g_fLightScale = ( float ) (g_SampleUI.GetSlider( IDC_LIGHT_SCALE ) -> GetValue() * 0.10f );
WCHAR sz[ 100 ];
StringCchPrintf( sz, 100 , L " Light scale: %0.2f " , g_fLightScale );
g_SampleUI.GetStatic( IDC_LIGHT_SCALE_STATIC ) -> SetText( sz );
break ;
}
}
// -----------------------------------------------------------------------------
// Desc: 释放在OnResetDevice()中创建的资源
// -----------------------------------------------------------------------------
void CALLBACK OnLostDevice( void * pUserContext )
{
g_DialogResourceManager.OnLostDevice();
g_SettingsDlg.OnLostDevice();
CDXUTDirectionWidget::StaticOnLostDevice();
if ( g_pFont )
g_pFont -> OnLostDevice();
if ( g_pEffect )
g_pEffect -> OnLostDevice();
SAFE_RELEASE(g_pSprite);
}
// ------------------------------------------------------------------------------
// Desc: 释放在OnCreateDevice()中创建的资源
// ------------------------------------------------------------------------------
void CALLBACK OnDestroyDevice( void * pUserContext )
{
g_DialogResourceManager.OnDestroyDevice();
g_SettingsDlg.OnDestroyDevice();
CDXUTDirectionWidget::StaticOnDestroyDevice();
SAFE_RELEASE(g_pEffect);
SAFE_RELEASE(g_pFont);
SAFE_RELEASE(g_pMesh);
SAFE_RELEASE(g_pMeshTexture);
}
// Desc: 主程序源文件
// =============================================================================
#include " dxstdafx.h "
#include " resource.h "
// #define DEBUG_VS // Uncomment this line to debug vertex shaders
// #define DEBUG_PS // Uncomment this line to debug pixel shaders
// -----------------------------------------------------------------------------
// 全局变量
// -----------------------------------------------------------------------------
ID3DXFont * g_pFont = NULL; // ID3DXFont字体对象
ID3DXSprite * g_pSprite = NULL; // ID3DXSprite文本精灵对象
bool g_bShowHelp = true ; // 标识是否显示简单说明文本
CDXUTDialogResourceManager g_DialogResourceManager; // 对话框资源管理器
CD3DSettingsDlg g_SettingsDlg; // Direct3D设备设置对话框
CDXUTDialog g_HUD; // 3DUI对话框
CDXUTDialog g_SampleUI; // 其它控件对话框
CModelViewerCamera g_Camera; // 摄影机对象
ID3DXEffect * g_pEffect = NULL; // 效果
ID3DXMesh * g_pMesh = NULL; // 网格模型
IDirect3DTexture9 * g_pMeshTexture = NULL; // 网格模型纹理
bool g_bEnablePreshader; // 标志是否启用预编译渲染器
D3DXMATRIXA16 g_mCenterWorld; // 调整矩阵, 将网格模型调整到窗口中心显示
#define MAX_LIGHTS 3 // 灯光数量
CDXUTDirectionWidget g_LightControl[MAX_LIGHTS];
float g_fLightScale;
int g_nNumActiveLights;
int g_nActiveLight;
// --------------------------------------------------------------------------------------
// 控件ID
// --------------------------------------------------------------------------------------
#define IDC_TOGGLEFULLSCREEN 1
#define IDC_TOGGLEREF 3
#define IDC_CHANGEDEVICE 4
#define IDC_ENABLE_PRESHADER 5
#define IDC_NUM_LIGHTS 6
#define IDC_NUM_LIGHTS_STATIC 7
#define IDC_ACTIVE_LIGHT 8
#define IDC_LIGHT_SCALE 9
#define IDC_LIGHT_SCALE_STATIC 10
// -----------------------------------------------------------------------------
// Desc: 函数声明
// -----------------------------------------------------------------------------
bool CALLBACK IsDeviceAcceptable( D3DCAPS9 * pCaps, D3DFORMAT AdapterFormat, D3DFORMAT BackBufferFormat, bool bWindowed, void * pUserContext );
bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings * pDeviceSettings, const D3DCAPS9 * pCaps, void * pUserContext );
HRESULT CALLBACK OnCreateDevice( IDirect3DDevice9 * pd3dDevice, const D3DSURFACE_DESC * pBackBufferSurfaceDesc, void * pUserContext );
HRESULT CALLBACK OnResetDevice( IDirect3DDevice9 * pd3dDevice, const D3DSURFACE_DESC * pBackBufferSurfaceDesc, void * pUserContext );
void CALLBACK OnFrameMove( IDirect3DDevice9 * pd3dDevice, double fTime, float fElapsedTime, void * pUserContext );
void CALLBACK OnFrameRender( IDirect3DDevice9 * pd3dDevice, double fTime, float fElapsedTime, void * pUserContext );
LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool * pbNoFurtherProcessing, void * pUserContext );
void CALLBACK KeyboardProc( UINT nChar, bool bKeyDown, bool bAltDown, void * pUserContext );
void CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl * pControl, void * pUserContext );
void CALLBACK OnLostDevice( void * pUserContext );
void CALLBACK OnDestroyDevice( void * pUserContext );
void InitApp();
HRESULT LoadMesh( IDirect3DDevice9 * pd3dDevice, WCHAR * strFileName, ID3DXMesh ** ppMesh );
void RenderText( double fTime );
// -----------------------------------------------------------------------------
// Desc: 入口函数
// -----------------------------------------------------------------------------
INT WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, int )
{
// 为Debug配置启用运行时内存检查功能
#if defined(DEBUG) | defined(_DEBUG)
_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
#endif
// 设置回调函数
DXUTSetCallbackDeviceCreated( OnCreateDevice );
DXUTSetCallbackDeviceReset( OnResetDevice );
DXUTSetCallbackDeviceLost( OnLostDevice );
DXUTSetCallbackDeviceDestroyed( OnDestroyDevice );
DXUTSetCallbackMsgProc( MsgProc );
DXUTSetCallbackKeyboard( KeyboardProc );
DXUTSetCallbackFrameRender( OnFrameRender );
DXUTSetCallbackFrameMove( OnFrameMove );
// 切换到全屏幕时显示鼠标
DXUTSetCursorSettings( true , true );
// 应用程序相关的初始化
InitApp();
// 初始化DXUT, 创建窗口, 创建Direct3D设备对象
DXUTInit( true , true , true );
DXUTCreateWindow( L " BasicHLSL " );
DXUTCreateDevice( D3DADAPTER_DEFAULT, true , 640 , 480 ,
IsDeviceAcceptable, ModifyDeviceSettings );
// 进入消息循环和场景渲染
DXUTMainLoop();
// 在此进行应用程序相关的清除工作
return DXUTGetExitCode();
}
// -----------------------------------------------------------------------------
// Desc: 应用程序相关初始化
// -----------------------------------------------------------------------------
void InitApp()
{
// 初始化全局变量
g_bEnablePreshader = true ;
for ( int i = 0 ; i < MAX_LIGHTS; i ++ )
g_LightControl[i].SetLightDirection( D3DXVECTOR3( sinf(D3DX_PI * 2 * i / MAX_LIGHTS - D3DX_PI / 6 ), 0 , - cosf(D3DX_PI * 2 * i / MAX_LIGHTS - D3DX_PI / 6 ) ) );
g_nActiveLight = 0 ;
g_nNumActiveLights = 1 ;
g_fLightScale = 1.0f ;
// 初始化对话框
g_SettingsDlg.Init( & g_DialogResourceManager );
g_HUD.Init( & g_DialogResourceManager );
g_SampleUI.Init( & g_DialogResourceManager );
// 为g_HUD对话框设置消息处理函数,添加控件
g_HUD.SetCallback( OnGUIEvent ); int iY = 10 ;
g_HUD.AddButton( IDC_TOGGLEFULLSCREEN, L " Toggle full screen " , 35 , iY, 125 , 22 );
g_HUD.AddButton( IDC_TOGGLEREF, L " Toggle REF (F3) " , 35 , iY += 24 , 125 , 22 );
g_HUD.AddButton( IDC_CHANGEDEVICE, L " Change device (F2) " , 35 , iY += 24 , 125 , 22 , VK_F2 );
// 为g_SampleUI对话框设置消息处理函数,添加控件
g_SampleUI.SetCallback( OnGUIEvent ); iY = 10 ;
WCHAR sz[ 100 ];
iY += 24 ;
StringCchPrintf( sz, 100 , L " # Lights: %d " , g_nNumActiveLights );
g_SampleUI.AddStatic( IDC_NUM_LIGHTS_STATIC, sz, 35 , iY += 24 , 125 , 22 );
g_SampleUI.AddSlider( IDC_NUM_LIGHTS, 50 , iY += 24 , 100 , 22 , 1 , MAX_LIGHTS, g_nNumActiveLights );
iY += 24 ;
StringCchPrintf( sz, 100 , L " Light scale: %0.2f " , g_fLightScale );
g_SampleUI.AddStatic( IDC_LIGHT_SCALE_STATIC, sz, 35 , iY += 24 , 125 , 22 );
g_SampleUI.AddSlider( IDC_LIGHT_SCALE, 50 , iY += 24 , 100 , 22 , 0 , 20 , ( int ) (g_fLightScale * 10.0f ) );
iY += 24 ;
g_SampleUI.AddButton( IDC_ACTIVE_LIGHT, L " Change active light (K) " , 35 , iY += 24 , 125 , 22 , ' K ' );
g_SampleUI.AddCheckBox( IDC_ENABLE_PRESHADER, L " Enable preshaders " , 35 , iY += 24 , 125 , 22 , g_bEnablePreshader );
}
// -----------------------------------------------------------------------------
// Desc: 设备能力检查
// -----------------------------------------------------------------------------
bool CALLBACK IsDeviceAcceptable( D3DCAPS9 * pCaps, D3DFORMAT AdapterFormat,
D3DFORMAT BackBufferFormat, bool bWindowed, void * pUserContext )
{
// 检查后台缓冲区格式是否支持Alpha混合等操作(post pixel blending operations)
IDirect3D9 * pD3D = DXUTGetD3DObject();
if ( FAILED( pD3D -> CheckDeviceFormat( pCaps -> AdapterOrdinal, pCaps -> DeviceType,
AdapterFormat, D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING,
D3DRTYPE_TEXTURE, BackBufferFormat ) ) )
return false ;
// 检查设备支持的像素渲染器版本
if ( pCaps -> PixelShaderVersion < D3DPS_VERSION( 1 , 1 ) )
return false ;
return true ;
}
// -----------------------------------------------------------------------------
// Desc: 修改Direct3D渲染设备设置
// -----------------------------------------------------------------------------
bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings * pDeviceSettings, const D3DCAPS9 * pCaps, void * pUserContext )
{
// 如果硬件不支持, 则使用软件顶点处理
if ( (pCaps -> DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0 ||
pCaps -> VertexShaderVersion < D3DVS_VERSION( 1 , 1 ) )
{
pDeviceSettings -> BehaviorFlags = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
}
// 调试顶点渲染器需要参考设备或软件顶点处理
#ifdef DEBUG_VS
if ( pDeviceSettings -> DeviceType != D3DDEVTYPE_REF )
{
pDeviceSettings -> BehaviorFlags &= ~ D3DCREATE_HARDWARE_VERTEXPROCESSING;
pDeviceSettings -> BehaviorFlags &= ~ D3DCREATE_PUREDEVICE;
pDeviceSettings -> BehaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
}
#endif
// 调试像素渲染器需要参考设备
#ifdef DEBUG_PS
pDeviceSettings -> DeviceType = D3DDEVTYPE_REF;
#endif
// 如果使用参考设备,则弹出警告对话框
static bool s_bFirstTime = true ;
if ( s_bFirstTime )
{
s_bFirstTime = false ;
if ( pDeviceSettings -> DeviceType == D3DDEVTYPE_REF )
DXUTDisplaySwitchingToREFWarning();
}
return true ;
}
// -----------------------------------------------------------------------------
// Desc: 在此创建管理内存资源对象
// -----------------------------------------------------------------------------
HRESULT CALLBACK OnCreateDevice( IDirect3DDevice9 * pd3dDevice, const D3DSURFACE_DESC * pBackBufferSurfaceDesc, void * pUserContext )
{
HRESULT hr;
V_RETURN( g_DialogResourceManager.OnCreateDevice( pd3dDevice ) );
V_RETURN( g_SettingsDlg.OnCreateDevice( pd3dDevice ) );
// 创建字体
V_RETURN( D3DXCreateFont( pd3dDevice, 15 , 0 , FW_BOLD, 1 , FALSE, DEFAULT_CHARSET,
OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE,
L " Arial " , & g_pFont ) );
// 加载网格
V_RETURN( LoadMesh( pd3dDevice, L " tiny\\tiny.x " , & g_pMesh ) );
// 计算网格模型外包围球半径和中心点坐标
D3DXVECTOR3 * pData;
D3DXVECTOR3 vCenter;
FLOAT fObjectRadius;
V( g_pMesh -> LockVertexBuffer( 0 , (LPVOID * ) & pData ) );
V( D3DXComputeBoundingSphere( pData, g_pMesh -> GetNumVertices(), D3DXGetFVFVertexSize( g_pMesh -> GetFVF() ), & vCenter, & fObjectRadius ) );
V( g_pMesh -> UnlockVertexBuffer() );
// 构造网格模型世界矩阵
D3DXMatrixTranslation( & g_mCenterWorld, - vCenter.x, - vCenter.y, - vCenter.z );
D3DXMATRIXA16 m;
D3DXMatrixRotationY( & m, D3DX_PI );
g_mCenterWorld *= m;
D3DXMatrixRotationX( & m, D3DX_PI / 2.0f );
g_mCenterWorld *= m;
//
V_RETURN( CDXUTDirectionWidget::StaticOnCreateDevice( pd3dDevice ) );
for ( int i = 0 ; i < MAX_LIGHTS; i ++ )
g_LightControl[i].SetRadius( fObjectRadius );
// 设置渲染器创建标志
DWORD dwShaderFlags = D3DXFX_NOT_CLONEABLE;
#ifdef DEBUG_VS
dwShaderFlags |= D3DXSHADER_FORCE_VS_SOFTWARE_NOOPT;
#endif
#ifdef DEBUG_PS
dwShaderFlags |= D3DXSHADER_FORCE_PS_SOFTWARE_NOOPT;
#endif
if ( ! g_bEnablePreshader )
dwShaderFlags |= D3DXSHADER_NO_PRESHADER;
// 查找效果文件
WCHAR str[MAX_PATH];
V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L " BasicHLSL.fx " ) );
// 从文件创建效果
V_RETURN( D3DXCreateEffectFromFile( pd3dDevice, str, NULL, NULL, dwShaderFlags, NULL, & g_pEffect, NULL ) );
// 查找网格模型纹理文件
V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L " tiny\\tiny_skin.dds " ) );
// 创建网格模型纹理
V_RETURN( D3DXCreateTextureFromFileEx( pd3dDevice, str, D3DX_DEFAULT, D3DX_DEFAULT,
D3DX_DEFAULT, 0 , D3DFMT_UNKNOWN, D3DPOOL_MANAGED,
D3DX_DEFAULT, D3DX_DEFAULT, 0 ,
NULL, NULL, & g_pMeshTexture ) );
// 设置效果参数变量
D3DXCOLOR colorMtrlDiffuse( 1.0f , 1.0f , 1.0f , 1.0f );
D3DXCOLOR colorMtrlAmbient( 0.35f , 0.35f , 0.35f , 0 );
V_RETURN( g_pEffect -> SetValue( " g_MaterialAmbientColor " , & colorMtrlAmbient, sizeof (D3DXCOLOR) ) );
V_RETURN( g_pEffect -> SetValue( " g_MaterialDiffuseColor " , & colorMtrlDiffuse, sizeof (D3DXCOLOR) ) );
V_RETURN( g_pEffect -> SetTexture( " g_MeshTexture " , g_pMeshTexture) );
// 设置摄影机观察参数
D3DXVECTOR3 vecEye( 0.0f , 0.0f , - 15.0f );
D3DXVECTOR3 vecAt ( 0.0f , 0.0f , - 0.0f );
g_Camera.SetViewParams( & vecEye, & vecAt );
g_Camera.SetRadius( fObjectRadius * 3.0f , fObjectRadius * 0.5f , fObjectRadius * 10.0f );
return S_OK;
}
// ------------------------------------------------------------------------------
// Desc: 辅助函数, 加载网格模型
// -----------------------------------------------------------------------------
HRESULT LoadMesh( IDirect3DDevice9 * pd3dDevice, WCHAR * strFileName, ID3DXMesh ** ppMesh )
{
ID3DXMesh * pMesh = NULL;
WCHAR str[MAX_PATH];
HRESULT hr;
// 从文件加载网格模型
V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, strFileName ) );
V_RETURN( D3DXLoadMeshFromX(str, D3DXMESH_MANAGED, pd3dDevice, NULL, NULL, NULL, NULL, & pMesh) );
DWORD * rgdwAdjacency = NULL;
// 确保网格模型顶点包含法线信息,以满足光照计算的需要
if ( ! (pMesh -> GetFVF() & D3DFVF_NORMAL) )
{
ID3DXMesh * pTempMesh;
V( pMesh -> CloneMeshFVF( pMesh -> GetOptions(),
pMesh -> GetFVF() | D3DFVF_NORMAL,
pd3dDevice, & pTempMesh ) );
V( D3DXComputeNormals( pTempMesh, NULL ) );
SAFE_RELEASE( pMesh );
pMesh = pTempMesh;
}
// 对网格模型进行优化,以提高程序运行性能
rgdwAdjacency = new DWORD[pMesh -> GetNumFaces() * 3 ];
if ( rgdwAdjacency == NULL )
return E_OUTOFMEMORY;
V( pMesh -> GenerateAdjacency( 1e-6f ,rgdwAdjacency) );
V( pMesh -> OptimizeInplace(D3DXMESHOPT_VERTEXCACHE, rgdwAdjacency, NULL, NULL, NULL) );
delete []rgdwAdjacency;
* ppMesh = pMesh;
return S_OK;
}
// -----------------------------------------------------------------------------
// Desc: 在此创建默认内存类型资源对象
// -----------------------------------------------------------------------------
HRESULT CALLBACK OnResetDevice( IDirect3DDevice9 * pd3dDevice,
const D3DSURFACE_DESC * pBackBufferSurfaceDesc,
void * pUserContext )
{
HRESULT hr;
V_RETURN( g_DialogResourceManager.OnResetDevice() );
V_RETURN( g_SettingsDlg.OnResetDevice() );
// 恢复字体
if ( g_pFont )
V_RETURN( g_pFont -> OnResetDevice() );
// 创建ID3DXSprite接口对象
V_RETURN( D3DXCreateSprite( pd3dDevice, & g_pSprite ) );
// 设置摄影机对象投影参数
float fAspectRatio = pBackBufferSurfaceDesc -> Width / (FLOAT)pBackBufferSurfaceDesc -> Height;
g_Camera.SetProjParams( D3DX_PI / 4 , fAspectRatio, 2.0f , 4000.0f );
g_Camera.SetWindow( pBackBufferSurfaceDesc -> Width, pBackBufferSurfaceDesc -> Height );
g_Camera.SetButtonMasks( MOUSE_LEFT_BUTTON, MOUSE_WHEEL, MOUSE_MIDDLE_BUTTON );
// 设置对话框位置和尺寸
g_HUD.SetLocation( pBackBufferSurfaceDesc -> Width - 170 , 0 );
g_HUD.SetSize( 170 , 170 );
g_SampleUI.SetLocation( pBackBufferSurfaceDesc -> Width - 170 , pBackBufferSurfaceDesc -> Height - 300 );
g_SampleUI.SetSize( 170 , 300 );
for ( int i = 0 ; i < MAX_LIGHTS; i ++ )
g_LightControl[i].OnResetDevice( pBackBufferSurfaceDesc );
// 恢复效果对象
if ( g_pEffect )
V_RETURN( g_pEffect -> OnResetDevice() );
return S_OK;
}
// -----------------------------------------------------------------------------
// Desc: 更新场景
// -----------------------------------------------------------------------------
void CALLBACK OnFrameMove( IDirect3DDevice9 * pd3dDevice, double fTime, float fElapsedTime, void * pUserContext )
{
// 根据用户位置更新摄影机方向
g_Camera.FrameMove( fElapsedTime );
}
// -----------------------------------------------------------------------------
// Desc: 渲染场景
// -----------------------------------------------------------------------------
void CALLBACK OnFrameRender( IDirect3DDevice9 * pd3dDevice, double fTime, float fElapsedTime, void * pUserContext )
{
// 如果正在利用Direct3D设备设置对话框进行设置, 则不渲染场景
if ( g_SettingsDlg.IsActive() )
{
g_SettingsDlg.OnRender( fElapsedTime );
return ;
}
//
HRESULT hr;
D3DXMATRIXA16 mWorldViewProjection;
D3DXVECTOR3 vLightDir[MAX_LIGHTS];
D3DXCOLOR vLightDiffuse[MAX_LIGHTS];
D3DXMATRIXA16 mWorld;
D3DXMATRIXA16 mView;
D3DXMATRIXA16 mProj;
// 清除后台颜色缓冲区和深度缓冲区
V( pd3dDevice -> Clear( 0 , NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DXCOLOR( 0.0f , 0.25f , 0.25f , 0.55f ), 1.0f , 0 ) );
// 渲染场景
if ( SUCCEEDED( pd3dDevice -> BeginScene() ) )
{
// 通过摄影机对象获得观察矩阵和投影矩镇
mWorld = g_mCenterWorld * * g_Camera.GetWorldMatrix();
mProj = * g_Camera.GetProjMatrix();
mView = * g_Camera.GetViewMatrix();
mWorldViewProjection = mWorld * mView * mProj;
// 渲染表示灯光方向的箭头, 并设置灯光方向和漫反射颜色值
for ( int i = 0 ; i < g_nNumActiveLights; i ++ )
{
D3DXCOLOR arrowColor = ( i == g_nActiveLight ) ? D3DXCOLOR( 1 , 1 , 0 , 1 ) : D3DXCOLOR( 1 , 1 , 1 , 1 );
V( g_LightControl[i].OnRender( arrowColor, & mView, & mProj, g_Camera.GetEyePt() ) );
vLightDir[i] = g_LightControl[i].GetLightDirection();
vLightDiffuse[i] = g_fLightScale * D3DXCOLOR( 1 , 1 , 1 , 1 );
}
// 更新效果参数变量
V( g_pEffect -> SetValue( " g_LightDir " , vLightDir, sizeof (D3DXVECTOR3) * MAX_LIGHTS ) );
V( g_pEffect -> SetValue( " g_LightDiffuse " , vLightDiffuse, sizeof (D3DXVECTOR4) * MAX_LIGHTS ) );
V( g_pEffect -> SetMatrix( " g_mWorldViewProjection " , & mWorldViewProjection ) );
V( g_pEffect -> SetMatrix( " g_mWorld " , & mWorld ) );
V( g_pEffect -> SetFloat( " g_fTime " , ( float )fTime ) );
D3DXCOLOR vWhite = D3DXCOLOR( 1 , 1 , 1 , 1 );
V( g_pEffect -> SetValue( " g_MaterialDiffuseColor " , & vWhite, sizeof (D3DXCOLOR) ) );
V( g_pEffect -> SetFloat( " g_fTime " , ( float )fTime ) );
V( g_pEffect -> SetInt( " g_nNumLights " , g_nNumActiveLights ) );
// 根据灯光数量, 激活适当的技术
switch ( g_nNumActiveLights )
{
case 1 : V( g_pEffect -> SetTechnique( " RenderSceneWithTexture1Light " ) ); break ;
case 2 : V( g_pEffect -> SetTechnique( " RenderSceneWithTexture2Light " ) ); break ;
case 3 : V( g_pEffect -> SetTechnique( " RenderSceneWithTexture3Light " ) ); break ;
}
// 使用效果中的技术渲染场景
UINT iPass, cPasses;
V( g_pEffect -> Begin( & cPasses, 0 ) );
for (iPass = 0 ; iPass < cPasses; iPass ++ )
{
V( g_pEffect -> BeginPass(iPass) );
// 使用技术渲染网格模型
V( g_pMesh -> DrawSubset( 0 ) );
V( g_pEffect -> EndPass() );
}
V( g_pEffect -> End() );
// 渲染对话框
g_HUD.OnRender( fElapsedTime );
g_SampleUI.OnRender( fElapsedTime );
// 渲染文本
RenderText( fTime );
V( pd3dDevice -> EndScene() );
}
}
// -----------------------------------------------------------------------------
// Desc: 渲染文本
// -----------------------------------------------------------------------------
void RenderText( double fTime )
{
CDXUTTextHelper txtHelper( g_pFont, g_pSprite, 15 );
// 显示当前Direct3D设备状态和渲染帧速率
txtHelper.Begin();
txtHelper.SetInsertionPos( 2 , 0 );
txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f , 1.0f , 0.0f , 1.0f ) );
txtHelper.DrawTextLine( DXUTGetFrameStats( true ) );
txtHelper.DrawTextLine( DXUTGetDeviceStats() );
// 显示其他简要信息
txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f , 1.0f , 1.0f , 1.0f ) );
txtHelper.DrawFormattedTextLine( L " fTime: %0.1f sin(fTime): %0.4f " , fTime, sin(fTime) );
txtHelper.DrawFormattedTextLine( L " 多技术效果示例程序 " );
// 显示简单帮助文本
if ( g_bShowHelp )
{
const D3DSURFACE_DESC * pd3dsdBackBuffer = DXUTGetBackBufferSurfaceDesc();
txtHelper.SetInsertionPos( 2 , pd3dsdBackBuffer -> Height - 15 * 6 );
txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f , 0.75f , 0.0f , 1.0f ) );
txtHelper.DrawTextLine( L " Controls: " );
txtHelper.SetInsertionPos( 20 , pd3dsdBackBuffer -> Height - 15 * 5 );
txtHelper.DrawTextLine( L " Rotate model: Left mouse button\n "
L " Rotate light: Right mouse button\n "
L " Rotate camera: Middle mouse button\n "
L " Zoom camera: Mouse wheel scroll\n " );
txtHelper.SetInsertionPos( 250 , pd3dsdBackBuffer -> Height - 15 * 5 );
txtHelper.DrawTextLine( L " Hide help: F1\n "
L " Quit: ESC\n " );
}
else
{
txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f , 1.0f , 1.0f , 1.0f ) );
txtHelper.DrawTextLine( L " Press F1 for help " );
}
txtHelper.End();
}
// -----------------------------------------------------------------------------
// Desc: 消息处理
// -----------------------------------------------------------------------------
LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool * pbNoFurtherProcessing, void * pUserContext )
{
* pbNoFurtherProcessing = g_DialogResourceManager.MsgProc( hWnd, uMsg, wParam, lParam );
if ( * pbNoFurtherProcessing )
return 0 ;
if ( g_SettingsDlg.IsActive() )
{
g_SettingsDlg.MsgProc( hWnd, uMsg, wParam, lParam );
return 0 ;
}
* pbNoFurtherProcessing = g_HUD.MsgProc( hWnd, uMsg, wParam, lParam );
if ( * pbNoFurtherProcessing )
return 0 ;
* pbNoFurtherProcessing = g_SampleUI.MsgProc( hWnd, uMsg, wParam, lParam );
if ( * pbNoFurtherProcessing )
return 0 ;
g_LightControl[g_nActiveLight].HandleMessages( hWnd, uMsg, wParam, lParam );
g_Camera.HandleMessages( hWnd, uMsg, wParam, lParam );
return 0 ;
}
// -----------------------------------------------------------------------------
// Desc: 键盘消息处理
// -----------------------------------------------------------------------------
void CALLBACK KeyboardProc( UINT nChar, bool bKeyDown, bool bAltDown, void * pUserContext )
{
if ( bKeyDown )
{
switch ( nChar )
{
case VK_F1: g_bShowHelp = ! g_bShowHelp; break ;
}
}
}
// -----------------------------------------------------------------------------
// Desc: 各种控件消息处理
// -----------------------------------------------------------------------------
void CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl * pControl, void * pUserContext )
{
switch ( nControlID )
{
case IDC_TOGGLEFULLSCREEN: DXUTToggleFullScreen(); break ;
case IDC_TOGGLEREF: DXUTToggleREF(); break ;
case IDC_CHANGEDEVICE: g_SettingsDlg.SetActive( ! g_SettingsDlg.IsActive() ); break ;
case IDC_ENABLE_PRESHADER:
{
g_bEnablePreshader = g_SampleUI.GetCheckBox( IDC_ENABLE_PRESHADER ) -> GetChecked();
if ( DXUTGetD3DDevice() != NULL )
{
OnLostDevice( NULL );
OnDestroyDevice( NULL );
OnCreateDevice( DXUTGetD3DDevice(), DXUTGetBackBufferSurfaceDesc(), NULL );
OnResetDevice( DXUTGetD3DDevice(), DXUTGetBackBufferSurfaceDesc(), NULL );
}
break ;
}
case IDC_ACTIVE_LIGHT:
if ( ! g_LightControl[g_nActiveLight].IsBeingDragged() )
{
g_nActiveLight ++ ;
g_nActiveLight %= g_nNumActiveLights;
}
break ;
case IDC_NUM_LIGHTS:
if ( ! g_LightControl[g_nActiveLight].IsBeingDragged() )
{
WCHAR sz[ 100 ];
StringCchPrintf( sz, 100 , L " # Lights: %d " , g_SampleUI.GetSlider( IDC_NUM_LIGHTS ) -> GetValue() );
g_SampleUI.GetStatic( IDC_NUM_LIGHTS_STATIC ) -> SetText( sz );
g_nNumActiveLights = g_SampleUI.GetSlider( IDC_NUM_LIGHTS ) -> GetValue();
g_nActiveLight %= g_nNumActiveLights;
}
break ;
case IDC_LIGHT_SCALE:
g_fLightScale = ( float ) (g_SampleUI.GetSlider( IDC_LIGHT_SCALE ) -> GetValue() * 0.10f );
WCHAR sz[ 100 ];
StringCchPrintf( sz, 100 , L " Light scale: %0.2f " , g_fLightScale );
g_SampleUI.GetStatic( IDC_LIGHT_SCALE_STATIC ) -> SetText( sz );
break ;
}
}
// -----------------------------------------------------------------------------
// Desc: 释放在OnResetDevice()中创建的资源
// -----------------------------------------------------------------------------
void CALLBACK OnLostDevice( void * pUserContext )
{
g_DialogResourceManager.OnLostDevice();
g_SettingsDlg.OnLostDevice();
CDXUTDirectionWidget::StaticOnLostDevice();
if ( g_pFont )
g_pFont -> OnLostDevice();
if ( g_pEffect )
g_pEffect -> OnLostDevice();
SAFE_RELEASE(g_pSprite);
}
// ------------------------------------------------------------------------------
// Desc: 释放在OnCreateDevice()中创建的资源
// ------------------------------------------------------------------------------
void CALLBACK OnDestroyDevice( void * pUserContext )
{
g_DialogResourceManager.OnDestroyDevice();
g_SettingsDlg.OnDestroyDevice();
CDXUTDirectionWidget::StaticOnDestroyDevice();
SAFE_RELEASE(g_pEffect);
SAFE_RELEASE(g_pFont);
SAFE_RELEASE(g_pMesh);
SAFE_RELEASE(g_pMeshTexture);
}