D3D中的地形绘制基础(5)
13.6例子程序: Terrain
该例子是用一个包含高度信息的 RAW 文件创建一个地形,纹理和光源。用方向键在地形上行走。fps.h:
/*********************************************************************************
PURPOISE:
Wraps the code to compute and display the frames rendered per second.
*********************************************************************************/
#ifndef FPS_H
#define FPS_H
#include <d3dx9.h>
class cFpsCounter
{
private :
IDirect3DDevice9* m_device;
ID3DXFont* m_font;
DWORD m_frame_count;
float m_time_elapsed;
float m_fps;
char m_fps_string[9];
public :
cFpsCounter(IDirect3DDevice9* device);
~cFpsCounter();
void render(D3DCOLOR color, float time_delta,
int window_width, int window_height);
};
#endif
PURPOISE:
Wraps the code to compute and display the frames rendered per second.
*********************************************************************************/
#ifndef FPS_H
#define FPS_H
#include <d3dx9.h>
class cFpsCounter
{
private :
IDirect3DDevice9* m_device;
ID3DXFont* m_font;
DWORD m_frame_count;
float m_time_elapsed;
float m_fps;
char m_fps_string[9];
public :
cFpsCounter(IDirect3DDevice9* device);
~cFpsCounter();
void render(D3DCOLOR color, float time_delta,
int window_width, int window_height);
};
#endif
fps.cpp:
/*********************************************************************************
PURPOISE:
Wraps the code to compute and display the frames rendered per second.
*********************************************************************************/
#include <cstdio>
#include "d3dUtility.h"
#include "fps.h"
#pragma warning(disable : 4996)
cFpsCounter::cFpsCounter(IDirect3DDevice9* device)
{
m_device = device;
D3DXFONT_DESC font_desc;
ZeroMemory(&font_desc, sizeof (font_desc));
font_desc.Height = 25; // in logical units
font_desc.Width = 12; // in logical units
font_desc.Weight = 500; // boldness, range 0(light) - 1000(bold)
font_desc.Italic = FALSE;
font_desc.CharSet = DEFAULT_CHARSET;
font_desc.OutputPrecision = 0;
font_desc.Quality = 0;
font_desc.PitchAndFamily = 0;
strcpy(font_desc.FaceName, "Times New Roman");
D3DXCreateFontIndirect(device, &font_desc, &m_font);
m_frame_count = 0;
m_time_elapsed = 0.0f;
m_fps = 0.0f;
m_fps_string[0] = '\0';
}
cFpsCounter::~cFpsCounter()
{
safe_release<ID3DXFont*>(m_font);
}
void cFpsCounter::render(D3DCOLOR color, float time_delta,
int window_width, int window_height)
{
if (m_font == NULL)
return ;
m_frame_count++;
m_time_elapsed += time_delta;
if (m_time_elapsed >= 1.0f)
{
m_fps = m_frame_count / m_time_elapsed;
sprintf(m_fps_string, "%f", m_fps);
m_fps_string[8] = '\0'; // mark end of string
m_time_elapsed = 0.0f;
m_frame_count = 0;
}
RECT rect = {0, 0, window_width, window_height};
m_font->DrawText(NULL, m_fps_string, -1, &rect, DT_TOP | DT_LEFT, color);
}
PURPOISE:
Wraps the code to compute and display the frames rendered per second.
*********************************************************************************/
#include <cstdio>
#include "d3dUtility.h"
#include "fps.h"
#pragma warning(disable : 4996)
cFpsCounter::cFpsCounter(IDirect3DDevice9* device)
{
m_device = device;
D3DXFONT_DESC font_desc;
ZeroMemory(&font_desc, sizeof (font_desc));
font_desc.Height = 25; // in logical units
font_desc.Width = 12; // in logical units
font_desc.Weight = 500; // boldness, range 0(light) - 1000(bold)
font_desc.Italic = FALSE;
font_desc.CharSet = DEFAULT_CHARSET;
font_desc.OutputPrecision = 0;
font_desc.Quality = 0;
font_desc.PitchAndFamily = 0;
strcpy(font_desc.FaceName, "Times New Roman");
D3DXCreateFontIndirect(device, &font_desc, &m_font);
m_frame_count = 0;
m_time_elapsed = 0.0f;
m_fps = 0.0f;
m_fps_string[0] = '\0';
}
cFpsCounter::~cFpsCounter()
{
safe_release<ID3DXFont*>(m_font);
}
void cFpsCounter::render(D3DCOLOR color, float time_delta,
int window_width, int window_height)
{
if (m_font == NULL)
return ;
m_frame_count++;
m_time_elapsed += time_delta;
if (m_time_elapsed >= 1.0f)
{
m_fps = m_frame_count / m_time_elapsed;
sprintf(m_fps_string, "%f", m_fps);
m_fps_string[8] = '\0'; // mark end of string
m_time_elapsed = 0.0f;
m_frame_count = 0;
}
RECT rect = {0, 0, window_width, window_height};
m_font->DrawText(NULL, m_fps_string, -1, &rect, DT_TOP | DT_LEFT, color);
}
TerrainApp.cpp:
/**************************************************************************************
Renders a terrain and allows you to walk around it.
**************************************************************************************/
#include "d3dUtility.h"
#include "camera.h"
#include "terrain.h"
#include "fps.h"
#pragma warning(disable : 4100)
const int WIDTH = 640;
const int HEIGHT = 480;
IDirect3DDevice9* g_device;
cTerrain* g_terrain;
cCamera g_camera(LAND_OBJECT);
cFpsCounter* g_fps_counter;
bool g_draw_triangle;
/////////////////////////////////////////////////////////////////////////////////////////////////// /
bool setup()
{
// create the terrain
D3DXVECTOR3 dir_to_light(0.0f, 1.0f, 0.0f);
g_terrain = new cTerrain(g_device, "coastMountain64.raw", 64, 64, 10, 0.5f);
g_terrain->generate_texture(&dir_to_light);
g_fps_counter = new cFpsCounter(g_device);
// 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 the projection matrix
D3DXMATRIX proj;
D3DXMatrixPerspectiveFovLH(&proj, D3DX_PI/2.0f, ( float )WIDTH/HEIGHT, 1.0f, 1000.0f);
g_device->SetTransform(D3DTS_PROJECTION, &proj);
return true ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////// /
void cleanup()
{
delete g_terrain;
delete g_fps_counter;
}
////////////////////////////////////////////////////////////////////////////////////////////////////// /
bool display( float time_delta)
{
// update the camera
if (GetAsyncKeyState(VK_UP) & 0x80000f)
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);
// set camera height
float height = g_terrain->get_height(g_camera.m_pos.x, g_camera.m_pos.z);
g_camera.m_pos.y = height + 5.0f; // add height because we're standing up
// update the view matrix representing the camera's new position/orientation
D3DXMATRIX view_matrix;
g_camera.get_view_matrix(&view_matrix);
g_device->SetTransform(D3DTS_VIEW, &view_matrix);
// render now
g_device->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x00000000, 1.0f, 0);
g_device->BeginScene();
D3DXMATRIX identity_matrix;
D3DXMatrixIdentity(&identity_matrix);
g_terrain->draw(&identity_matrix, g_draw_triangle);
g_fps_counter->render(0xffffffff, time_delta, WIDTH, HEIGHT);
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);
if (word_param == VK_SPACE)
g_draw_triangle = !g_draw_triangle;
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;
}
Renders a terrain and allows you to walk around it.
**************************************************************************************/
#include "d3dUtility.h"
#include "camera.h"
#include "terrain.h"
#include "fps.h"
#pragma warning(disable : 4100)
const int WIDTH = 640;
const int HEIGHT = 480;
IDirect3DDevice9* g_device;
cTerrain* g_terrain;
cCamera g_camera(LAND_OBJECT);
cFpsCounter* g_fps_counter;
bool g_draw_triangle;
/////////////////////////////////////////////////////////////////////////////////////////////////// /
bool setup()
{
// create the terrain
D3DXVECTOR3 dir_to_light(0.0f, 1.0f, 0.0f);
g_terrain = new cTerrain(g_device, "coastMountain64.raw", 64, 64, 10, 0.5f);
g_terrain->generate_texture(&dir_to_light);
g_fps_counter = new cFpsCounter(g_device);
// 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 the projection matrix
D3DXMATRIX proj;
D3DXMatrixPerspectiveFovLH(&proj, D3DX_PI/2.0f, ( float )WIDTH/HEIGHT, 1.0f, 1000.0f);
g_device->SetTransform(D3DTS_PROJECTION, &proj);
return true ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////// /
void cleanup()
{
delete g_terrain;
delete g_fps_counter;
}
////////////////////////////////////////////////////////////////////////////////////////////////////// /
bool display( float time_delta)
{
// update the camera
if (GetAsyncKeyState(VK_UP) & 0x80000f)
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);
// set camera height
float height = g_terrain->get_height(g_camera.m_pos.x, g_camera.m_pos.z);
g_camera.m_pos.y = height + 5.0f; // add height because we're standing up
// update the view matrix representing the camera's new position/orientation
D3DXMATRIX view_matrix;
g_camera.get_view_matrix(&view_matrix);
g_device->SetTransform(D3DTS_VIEW, &view_matrix);
// render now
g_device->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x00000000, 1.0f, 0);
g_device->BeginScene();
D3DXMATRIX identity_matrix;
D3DXMatrixIdentity(&identity_matrix);
g_terrain->draw(&identity_matrix, g_draw_triangle);
g_fps_counter->render(0xffffffff, time_delta, WIDTH, HEIGHT);
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);
if (word_param == VK_SPACE)
g_draw_triangle = !g_draw_triangle;
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;
}
下载源程序
13.7 一些改进
Terrain读取顶点数据到一个很大的缓存,在多重的顶点缓存中划分地形结构,在速度和可测量性方面都十分有利。为我们提出一个问题:顶点缓存最大支持多大?回答是,这依赖于你的硬件。所以你必须先检测。
将地图划分为许多小的顶点缓存是重要的练习,然后将类似矩阵的数据结构编入索引,并且管理数据,这不需要引入新的概念。我们不必详细讨论它。简单的说,你基本上站在地形中一个我们叫做“blocks”的矩阵上,每个block是地形的一个矩形区域。另外,每个block区域(在它自己的顶点索引缓存中)的下方包含地形中的几何信息,为了画它在地形中的位置。
另外,你可以读取地形到一个很大的ID3DXMesh接口。使用D3D函数D3DXSplitMesh划分地形为许多小的Mesh,以下是D3DXSplitMesh函数原型:
void D3DXSplitMesh( const LPD3DXMESH pMeshIn, const DWORD *pAdjacencyIn, const DWORD MaxSize, const DWORD Options, DWORD *pMeshesOut, LPD3DXBUFFER *ppMeshArrayOut, LPD3DXBUFFER *ppAdjacencyArrayOut, LPD3DXBUFFER *ppFaceRemapArrayOut, LPD3DXBUFFER *ppVertRemapArrayOut ); |