这一个例子关于基本的HLSL。首先沿着程序来将关键点梳理一下。
1首先注册了一堆需要用到的回调函数,不懂,不管= =
2然后执行的事InitApp(),在这个函数中主要完成的任务是添加HUD元素和UI元素,就是按钮啊,说明文字啊~
3接下来就是下面的代码。
DXUTInit( true, true ); // Parse the command line and show msgboxes
DXUTSetHotkeyHandling( true, true, true );
DXUTCreateWindow( L"BasicHLSL" );
DXUTCreateDevice( true, 640, 480 );
第一行没什么好说的,第二行设置的是3个常用热键,如ESC。第三行第四行就是创建窗口和设备了。
4接下来进入主循环DXUTMainLoop(),然后这个函数是DXUT框架自定义的,也没什么好说,接下来退出程序。
等等,那这程序干了什么= =嗯,其实很多工作都在回调函数里做的,所以仅仅看主函数是不行的。下面列出真正所做的工作。
1.
//--------------------------------------------------------------------------------------
// This callback function is called immediately before a device is created to allow the
// application to modify the device settings. The supplied pDeviceSettings parameter
// contains the settings that the framework has selected for the new device, and the
// application can make any desired changes directly to this structure. Note however that
// DXUT will not correct invalid device settings so care must be taken
// to return valid device settings, otherwise IDirect3D9::CreateDevice() will fail.
//--------------------------------------------------------------------------------------
bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, void* pUserContext )
正如注释中所说的,这个函数在设备创建完毕前就调用,程序员应该把跟DXUT设备创建默认值不同的属性的修改代码放在这里,而不是直接修改DXUT的代码。
2.
//--------------------------------------------------------------------------------------
// This callback function will be called immediately after the Direct3D device has been
// created, which will happen during application initialization and windowed/full screen
// toggles. This is the best location to create D3DPOOL_MANAGED resources since these
// resources need to be reloaded whenever the device is destroyed. Resources created
// here should be released in the OnDestroyDevice callback.
//--------------------------------------------------------------------------------------
HRESULT CALLBACK OnCreateDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc,
void* pUserContext )
这个函数就是在创建设备后调用的,类型为D3DPOOL_MANAGED的资源载入应该在这个函数中进行。呃,这一种资源是先放在内存中,然后在需要绘制的时候再拷贝到显存中,更新(读写)速度快,但是影响绘制速度,当设备丢失的时候不需要重新载入,除非设备被销毁而且重新创建。
这个函数做了不少事情,让我们来看看。
V_RETURN( g_DialogResourceManager.OnD3D9CreateDevice( pd3dDevice ) );
V_RETURN( g_SettingsDlg.OnD3D9CreateDevice( pd3dDevice ) );
V_RETURN是一个宏,确保参数返回值是正确的,否则出错。第一句设定一个对话框资源管理器,第二句设定了一个设置对话框。
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::StaticOnD3D9CreateDevice( pd3dDevice ) );
for( int i = 0; i < MAX_LIGHTS; i++ )
g_LightControl[i].SetRadius( fObjectRadius );
设置方向小工具,并且设定灯光控制器的半径。
// Read the D3DX effect file
WCHAR str[MAX_PATH];
V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L"BasicHLSL.fx" ) );
// If this fails, there should be debug output as to
// why the .fx file failed to compile
V_RETURN( D3DXCreateEffectFromFile( pd3dDevice, str, NULL, NULL, dwShaderFlags, NULL, &g_pEffect, NULL ) );
创建效果文件。
// Create the mesh texture from a file
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 ) );
创建网格的纹理文件。
// Set effect variables as needed
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 ) );
设定效果文件中的变量。呃,估计是全局静态变量。
// Setup the camera's view parameters
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 );
设定镜头。
3
//--------------------------------------------------------------------------------------
// This function loads the mesh and ensures the mesh has normals; it also optimizes the
// mesh for the graphics card's vertex cache, which improves performance by organizing
// the internal triangle list for less cache misses.
//--------------------------------------------------------------------------------------
HRESULT LoadMesh( IDirect3DDevice9* pd3dDevice, WCHAR* strFileName, ID3DXMesh** ppMesh )
这个是上面调用的载入网格函数,所完成的工作有载入网格,计算法线向量(如果没有)和优化网格。
4
//--------------------------------------------------------------------------------------
// This callback function will be called immediately after the Direct3D device has been
// reset, which will happen after a lost device scenario. This is the best location to
// create D3DPOOL_DEFAULT resources since these resources need to be reloaded whenever
// the device is lost. Resources created here should be released in the OnLostDevice
// callback.
//--------------------------------------------------------------------------------------
HRESULT CALLBACK OnResetDevice( IDirect3DDevice9* pd3dDevice,
const D3DSURFACE_DESC* pBackBufferSurfaceDesc, void* pUserContext )
这个函数会在设备重置是调用,在这个教程中主要需要设定镜头和对话框资源管理器等。
5
//--------------------------------------------------------------------------------------
// This callback function will be called at the end of every frame to perform all the
// rendering calls for the scene, and it will also be called if the window needs to be
// repainted. After this function has returned, DXUT will call
// IDirect3DDevice9::Present to display the contents of the next buffer in the swap chain
//--------------------------------------------------------------------------------------
void CALLBACK OnFrameRender( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext )
这个是重头戏,绘制函数。
// Render the scene
if( SUCCEEDED( pd3dDevice->BeginScene() ) )
{
// Get the projection & view matrix from the camera class
mWorld = g_mCenterWorld * *g_Camera.GetWorldMatrix();
mProj = *g_Camera.GetProjMatrix();
mView = *g_Camera.GetViewMatrix();
mWorldViewProjection = mWorld * mView * mProj;
变换矩阵。
// Render the light arrow so the user can visually see the light dir
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].OnRender9( 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 ) );
渲染光照箭头。
// Update the effect's variables. Instead of using strings, it would
// be more efficient to cache a handle to the parameter by calling
// ID3DXEffect::GetParameterByName
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 ) );
又是设定效果文件变量。
// Render the scene with this technique
// as defined in the .fx file
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;
}
根据灯光数量设定Technique。
V( g_pEffect->Begin( &cPasses, 0 ) );
for( iPass = 0; iPass < cPasses; iPass++ )
{
V( g_pEffect->BeginPass( iPass ) );
// The effect interface queues up the changes and performs them
// with the CommitChanges call. You do not need to call CommitChanges if
// you are not setting any parameters between the BeginPass and EndPass.
// V( g_pEffect->CommitChanges() );
// Render the mesh with the applied technique
V( g_pMesh->DrawSubset( 0 ) );
V( g_pEffect->EndPass() );
}
V( g_pEffect->End() );
绘制~~~
其他函数就不说了。下次转到HLSL文件中。