雾化效果(以下简称雾)提高了场景的真实性,可以用它来模拟逼真的天气状况。另外,雾可以大大减少远剪裁面
(far-clip)在视觉上带给观者的不自然的感觉。Direct3D雾化是固定功能管线的一部份,受渲染状态限制。
下面的效果文件设置顶点雾,以达到必要的雾化状态。注意:Direct3D也支持像素雾(也叫表格雾table
fog),比顶点雾要更精确。
/**********************************************************************************
Effect file that handles device states for linear vertex fog.
**********************************************************************************/
technique FogTech
{
pass pass0
{
// set misc render states
pixelshader = null;
vertexshader = null;
fvf = XYZ | Normal;
Lighting = true;
NormalizeNormals = true;
SpecularEnable = false;
// fog states
FogVertexMode = LINEAR; // linear fog function
FogStart = 50.0f; // fog starts 50 units away from viewpoint
FogEnd = 300.0f; // fog ends 300 units away from viewpoint
FogColor = 0x00CCCCCC; // gray
FogEnable = true; // enable
}
}
就象你看到的,线性顶点雾能够通过五个简单的渲染状态控制:
FogVertexMode—使用指定的雾函数用于顶点雾。雾函数指定雾如何根据距离增长,自然界的雾在近视口的地方比较薄并且根据距离增长变得厚起来了。有效的任务类型为LINEAR、EXP、EXP2。这些函数被定义为:
注意:如果你用EXP或EXP2雾化函数,你不用设置FogStart
和
FogEnd,因为它们在这些雾函数类型中没被用到。代替的你必须设置雾密度(fog
density)渲染状态(如,FogDensity
= someFloatType)
FogStart—标记了物体将开始雾化的起始深度。
FogEnd—标记了物体将结束雾化的结束深度。
注意:FogStart
与
FogEnd本质上定义了物体被雾化的深度间隔(从视口)。
FogColor—一个DWORD
或
D3DCOLOR值,以描述雾的颜色
FogEnable—指定true以开启顶点雾或false以关闭顶点雾
任何我们用FogShader.cxx效果渲染的几何体将被雾化。通过这种方式,我们可以控制哪一物体得到雾化,而哪些不用雾化。这对只雾化特定区域是很有用的。例如,通常屋外是有雾的,屋里不被雾化。同样的,一定地理部分可能有雾,而另外部分可能没有。下图展示了例程的屏幕截图。
执行程序:
/**************************************************************************************************
Demonstrates using an effect file. Use the arrwo keys, and M, N, W, S, keys to move.
**************************************************************************************************/
#include "d3dUtility.h"
#include "terrain.h"
#include "camera.h"
#pragma warning(disable : 4100)
using namespace std;
const int WIDTH = 640;
const int HEIGHT = 480;
IDirect3DDevice9* g_device;
cTerrain* g_terrain;
cCamera g_camera(AIR_CRAFT);
ID3DXEffect* g_fog_effect;
D3DXHANDLE g_fog_tech_handle;
////////////////////////////////////////////////////////////////////////////////////////////////////
bool setup()
{
// init scene
D3DXVECTOR3 dir_to_light(0.0f, 1.0f, 0.0f);
g_terrain = new cTerrain(g_device, "coastMountain64.raw", 64, 64, 6, 0.5f);
g_terrain->generate_texture(&dir_to_light);
// set texture filters
g_device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
g_device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
g_device->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);
// set camera position
g_camera.m_pos = D3DXVECTOR3(100.0f, 100.0f, -250.0f);
// create effect
ID3DXBuffer* error_buffer;
HRESULT hr = D3DXCreateEffectFromFile(g_device, "FogShader.cxx", NULL, NULL, D3DXSHADER_DEBUG, NULL,
&g_fog_effect, &error_buffer);
// output any error messages
if(error_buffer)
{
MessageBox(NULL, (char*) error_buffer->GetBufferPointer(), "ERROR", MB_OK);
safe_release<ID3DXBuffer*>(error_buffer);
}
if(FAILED(hr))
{
MessageBox(NULL, "D3DXCreateEffectFromFile() - FAILED", "ERROR", MB_OK);
return false;
}
// save frequently accessed parameter handles
g_fog_tech_handle = g_fog_effect->GetTechniqueByName("FogTech");
// set projection
D3DXMATRIX proj_matrix;
D3DXMatrixPerspectiveFovLH(&proj_matrix, D3DX_PI * 0.25f, (float)WIDTH/HEIGHT, 1.0f, 1000.0f);
g_device->SetTransform(D3DTS_PROJECTION, &proj_matrix);
//g_device->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
void cleanup()
{
safe_delete<cTerrain*>(g_terrain);
safe_release<ID3DXEffect*>(g_fog_effect);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
bool display(float time_delta)
{
// update the scene: allow user to rotate around scene.
if(GetAsyncKeyState(VK_UP) & 0x8000f)
g_camera.walk(100.0f * time_delta);
if(GetAsyncKeyState(VK_DOWN) & 0x8000f)
g_camera.walk(-100.0f * time_delta);
if(GetAsyncKeyState(VK_LEFT) & 0x8000f)
g_camera.yaw(-1.0f * time_delta);
if(GetAsyncKeyState(VK_RIGHT) & 0x8000f)
g_camera.yaw(1.0f * time_delta);
if(GetAsyncKeyState('N') & 0x8000f)
g_camera.strafe(-100.0f * time_delta);
if(GetAsyncKeyState('M') & 0x8000f)
g_camera.strafe(100.0f * time_delta);
if(GetAsyncKeyState('W') & 0x8000f)
g_camera.pitch(1.0f * time_delta);
if(GetAsyncKeyState('S') & 0x8000f)
g_camera.pitch(-1.0f * time_delta);
D3DXMATRIX view_matrix;
g_camera.get_view_matrix(&view_matrix);
g_device->SetTransform(D3DTS_VIEW, &view_matrix);
// activate the technique and render
g_device->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x00CCCCCC, 1.0f, 0);
g_device->BeginScene();
// set the technique to use
g_fog_effect->SetTechnique(g_fog_tech_handle);
UINT num_passes;
g_fog_effect->Begin(&num_passes, 0);
D3DXMATRIX world_matrix;
D3DXMatrixIdentity(&world_matrix);
for(UINT i = 0; i < num_passes; i++)
{
g_fog_effect->BeginPass(i);
g_terrain->draw(&world_matrix, false);
g_fog_effect->EndPass();
}
g_fog_effect->End();
g_device->EndScene();
g_device->Present(NULL, NULL, NULL, NULL);
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
LRESULT CALLBACK wnd_proc(HWND hwnd, UINT msg, WPARAM word_param, LPARAM long_param)
{
switch(msg)
{
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_KEYDOWN:
if(word_param == VK_ESCAPE)
DestroyWindow(hwnd);
break;
}
return DefWindowProc(hwnd, msg, word_param, long_param);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
int WINAPI WinMain(HINSTANCE inst, HINSTANCE, PSTR cmd_line, int cmd_show)
{
if(! init_d3d(inst, WIDTH, HEIGHT, true, D3DDEVTYPE_HAL, &g_device))
{
MessageBox(NULL, "init_d3d() - failed.", 0, MB_OK);
return 0;
}
if(! setup())
{
MessageBox(NULL, "Steup() - failed.", 0, MB_OK);
return 0;
}
enter_msg_loop(display);
cleanup();
g_device->Release();
return 0;
}
下载源程序