D3D中的地形绘制基础(5)

D3D中的地形绘制基础(5)

13.6例子程序: Terrain

该例子是用一个包含高度信息的 RAW 文件创建一个地形,纹理和光源。用方向键在地形上行走。

D3D中的地形绘制基础(5)_第1张图片

D3D中的地形绘制基础(5)_第2张图片

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

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);
    }

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;
    }

下载源程序

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

       

);

这个函数将一个源Mesh划分多个小的Mesh,pMeshIn参数是一个指针,指向想划分的MeshpAdjacencyIn指向一个邻接数组,MaxSize参数指定作为结果返回的最大顶点数,为返回的Meshe使用指定的创建标记,pMeshesOut参数返回ppMeshArrayOut数组中的Mesh数量,最后3个参数是可选的(可以指定为null),返回邻接信息的数组。

你可能感兴趣的:(D3D中的地形绘制基础(5))