天行健 君子当自强而不息

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

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),返回邻接信息的数组。

posted on 2008-04-02 21:42 lovedday 阅读(3290) 评论(9)  编辑 收藏 引用

评论

# re: D3D中的地形绘制基础(5) 2008-04-12 18:48 学生

VS2005编译能通过但是运行就会崩溃 哪里出问题了?向楼主请教  回复  更多评论   

# re: D3D中的地形绘制基础(5) 2008-04-12 19:13 lovedday

提示什么?自己在debug模式调试下。
我测试的时候没发现问题。  回复  更多评论   

# re: D3D中的地形绘制基础(5) 2008-04-12 20:00 学生

@lovedday
信息如下

fail: d:\program files\microsoft visual studio 8\vc\include\vector
line :756
Expression: vector subscript out of range
for information on how your program can cause an assertion failure,
see the visual c++ documentation on asserts.
我是新人 麻烦楼主多多指教  回复  更多评论   

# re: D3D中的地形绘制基础(5) 2008-04-12 21:02 lovedday

你把float cTerrain::get_height(float x, float z)中这几行替换成下面试试看,小bug:

if(row < 0)
row = 0;

if(row > m_num_cells_per_col - 1)
row = m_num_cells_per_col - 1;

if(col < 0)
col = 0;

if(col > m_num_cells_per_row - 1)
col = m_num_cells_per_row - 1;  回复  更多评论   

# re: D3D中的地形绘制基础(5) 2008-04-12 23:12 学生

把>=改成=就可以了吗 改完之后还是过不去 原因同上
  回复  更多评论   

# re: D3D中的地形绘制基础(5) 2008-04-13 08:48 lovedday

你必须查看调用栈的上一层来找到出bug的代码行。

这些是STL里的代码:

fail: d:\program files\microsoft visual studio 8\vc\include\vector
line :756   回复  更多评论   

# re: D3D中的地形绘制基础(5) 2008-05-16 15:18 vw

博主你好.我想请教一下.
假设,这只是一个假设.我的显卡只支持 10240 个顶点.30720 个索引顶点.那么.我能不能.使用 D3DXCreateMeshFVF 函数创建一个空的模型.在顶点数和面数的参数的设置上远远超出显卡所支持的数量.比如我在创建时使用了.
1024000000个顶点.然后在用 D3DXSplitMesh 把这个新建的 Mesh 给分解了,这样做可以吗?
如果可以.那么我就可以把他Mesh转换成.ID3DXPMesh 接口.来取带LOD.
那么,距离眼睛越近.顶点和3角型就越多.如果我再加上几个人物模型就超出了显卡所支持顶点时.我该怎么办呢? 因为我无法想到在我的视图中除了地图还会有多少个模型.(玩家有时多.有时少的情况).

再比如一个画面中出现成千上万的玩家的时候. 您看.地图.建筑.NPC.玩家.天空盒.这些是一个也不能少.那么各模型顶点减到最低成度时.顶点还是超过了.我应该怎么办呢?  回复  更多评论   

# re: D3D中的地形绘制基础(5) 2008-05-16 17:35 lovedday

@vw
你的显卡只支持 10240 个顶点.30720 个索引顶点,你在创建时使用了.
1024000000个顶点,应该是不能创建成功的。  回复  更多评论   

# 这里有解决方法 2009-03-06 21:54 ykxggg

http://bbs.gameres.com/showthread.asp?threadid=124286  回复  更多评论   


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


公告

导航

统计

常用链接

随笔分类(178)

3D游戏编程相关链接

搜索

最新评论