地形处理技巧

来源:互联网 发布:2016淘宝直通车卡首屏 编辑:程序博客网 时间:2024/06/06 02:16

//表示ZFLog在VS2010 win32模式一直到最后都没做出来,明明包含了所有头文件和cpp文件,然后就是无法解析,郁闷......

 

 

// map.cpp : 定义应用程序的入口点。
//

#include "stdafx.h"
#include "map.h"
#include"ZFLog.h"
#include<d3dx9.h>
#include<d3d9.h>
#include<windows.h>

#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "d3dx9.lib")


#define MAINBODY
#define WINDOW_W 500
#define WINDOW_H 500
#define WINDOW_TITLE "HeightMap-TList"
#define BMP_HEIGHTMAP "map128.bmp"

HWND                        g_hWnd       = NULL ;
LPDIRECT3D9                 g_pD3D       = NULL ;
LPDIRECT3DDEVICE9           g_pd3dDevice = NULL ;
LPDIRECT3DVERTEXBUFFER9     g_pVB        = NULL ;
LPDIRECT3DINDEXBUFFER9      g_pIB        = NULL ;

 

LPDIRECT3DTEXTURE9     g_pTexHeight  = NULL ;
LPDIRECT3DTEXTURE9     g_pTexDiffuse = NULL ;
D3DXMATRIXA16          g_matAni ;
HWND                   g_hwnd   ;

 

DWORD    g_cxHeight = 0 ;
DWORD    g_czHeight = 0 ;

struct CUSTOMVERTEX
{
 D3DXVECTOR3   p ;
 D3DXVECTOR3   n ;
 D3DXVECTOR3   t ;
};

#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ | D3DFVF_NORMAL |D3DFVF_TEX1)

struct MYINDEX
{
 WORD _0 , _1 ,_2;
};

 

HRESULT InitD3D( HWND hWnd )
{
    /// 创建一个用来创建设备的D3D对象
    if( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
        return E_FAIL;

    /// 创建设备的结构体
    /// 绘制复杂对象时需要Z-缓冲.
    D3DPRESENT_PARAMETERS d3dpp;
    ZeroMemory( &d3dpp, sizeof(d3dpp) );
    d3dpp.Windowed = TRUE;
    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
    d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
    d3dpp.EnableAutoDepthStencil = TRUE;
    d3dpp.AutoDepthStencilFormat = D3DFMT_D16;

    /// 创建设备
    if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
                                      D3DCREATE_SOFTWARE_VERTEXPROCESSING,
                                      &d3dpp, &g_pd3dDevice ) ) )
    {
        return E_FAIL;
    }

    /// 基本卷起,CCW
    g_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_CCW );

    /// 起到Z-缓冲功能.
    g_pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE );

    return S_OK;
}

 

HRESULT  InitTexture()
{
 //高度图
 // 调用该函数处理D3DFMT_X8R8G8B8和 D3DPOOL_MANAGED.
 if( FAILED(D3DXCreateTextureFromFileEx(g_pd3dDevice,L"map128.bmp",
   D3DX_DEFAULT, D3DX_DEFAULT,
   D3DX_DEFAULT,0,
   D3DFMT_X8R8G8B8,D3DPOOL_MANAGED,
    D3DX_DEFAULT, D3DX_DEFAULT,0,
    NULL,NULL,&g_pTexHeight)))
 return E_FAIL;


 //颜色图
 if(FAILED(D3DXCreateTextureFromFile(g_pd3dDevice,L"tile2.tga",&g_pTexDiffuse)))
  return E_FAIL;
               

 return S_OK;
}


HRESULT InitVB()
{
 D3DSURFACE_DESC          ddsd   ;
 D3DLOCKED_RECT           d3drc  ;

 g_pTexHeight->GetLevelDesc(0 , &ddsd);
 g_cxHeight  = ddsd.Width  ;     //纹理长度
 g_czHeight  = ddsd.Height ;     //纹理宽度

 
 
 if(FAILED(g_pd3dDevice->CreateVertexBuffer( g_cxHeight*g_czHeight*sizeof(CUSTOMVERTEX),0,
  D3DFVF_CUSTOMVERTEX,D3DPOOL_DEFAULT ,&g_pVB ,NULL)))
     return E_FAIL;
 
 g_pTexHeight->LockRect(0, &d3drc ,NULL ,D3DLOCK_READONLY);//只读
 
 void         *pVertices ;
   
 if(FAILED(g_pVB->Lock( 0 ,g_cxHeight*g_czHeight *sizeof(CUSTOMVERTEX),(void **)&pVertices,0)))
  return E_FAIL;

 CUSTOMVERTEX     v ;
 CUSTOMVERTEX    *pV = (CUSTOMVERTEX *)pVertices;

 for (DWORD z=0;z<g_cxHeight ;z++ )
 {
  for(DWORD x=0 ;x<g_czHeight ;x++)
  {
   v.p.x = (float)x -g_cxHeight/2.0f;
   v.p.z = -((float)z-g_czHeight/2.0f);
   //因为z轴指向显示器的,所以为-
   v.p.y = ((float)(*((LPDWORD)d3drc.pBits+x+z*(d3drc.Pitch/4))&0x000000ff))/10.0f;
/*
   为了让生成的地形是以原点为中心的,,所以x,y分别减去了高度图长度和宽度的一半.

接下来v.p.y = ((float)(*((LPDWORD)d3drc.pBits+x+z*(d3drc.Pitch/4))&0x000000ff))/10.0f; 这句就是设置顶点高度,算是全篇核心.
在这里纹理存储器相当于一个矩阵,矩阵的[0,0]单元存储位置是用d3drc.pBits来指示的,假设它的列数是P,那么[x,z]单元的存储位置就是
d3drc.pBits+x+z*P.而在纹理存储结构中,用d3drc.Pitch来表示列数,并且是按byte数的,也就是说,对于一张128象素宽的图片,它每个象素
有32位,即4bytes,那么在纹理存储结构中,d3drc.Pithc=128*4.这就是为什么代码中要除4了.
找到象素的存储位置后,前面加*号,取其内容,与0x000000ff进行按位与运算,由于灰度图片中r,g,b值都是相同的,所以只需要取最低的8位就
可以表示象素的明暗,,也就可以表示顶点的高低了.

*/
    v.n.x = v.p.x;
             v.n.y = v.p.y;
             v.n.z = v.p.z;
             D3DXVec3Normalize(&v.n,&v.n);
             v.t.x = (float)x / (g_cxHeight-1);
             v.t.y = (float)z / (g_czHeight-1);
             *pV++ = v;


  }
 }
 g_pVB->Unlock();
 g_pTexHeight->UnlockRect(0);
 
}


HRESULT  InitIB()
{
 if(FAILED(g_pd3dDevice->CreateIndexBuffer( (g_cxHeight-1)*(g_czHeight-1)*2*sizeof(MYINDEX),
  0,D3DFMT_INDEX16,D3DPOOL_DEFAULT,&g_pIB,NULL)))
  return E_FAIL;

 MYINDEX   i;
 MYINDEX  *PI1;
 if(FAILED(g_pIB->Lock( 0 , (g_cxHeight-1)*(g_czHeight-1)*2*sizeof(MYINDEX),(void **)&PI1 ,0)))
  return E_FAIL;

 for(DWORD z=0 ; z<g_czHeight -1 ;z++)
  for(DWORD x=0; x<g_cxHeight -1 ;x++)
  {
      i._0 = (z*g_cxHeight+x);
               i._1 = (z*g_cxHeight+x+1);
               i._2 = ((z+1)*g_cxHeight+x);
               *PI1++ = i;
               i._0 = ((z+1)*g_cxHeight+x);
               i._1 = (z*g_cxHeight+x+1);
               i._2 = ((z+1)*g_cxHeight+x+1);
      *PI1++=i;
      /*最后这段填充索引缓冲,索引个数为(g_cxHeight-1)*(g_czHeight-1)*2,
      这是因为x,z方向分别有了g_cxHeight和g_czHeight个顶点,那么一共可以
      生成(g_cxHeight-1)*(g_czHeight-1)个四边形,而每个四边形由左上角和
      右下角两个三角形组成,所以再乘2*/
  }
  g_pIB->Unlock();
  
  return S_OK;
}


/**-----------------------------------------------------------------------------
 * 几何信息初始化
 *------------------------------------------------------------------------------
 */
HRESULT InitGeometry()
{
 if( FAILED( InitTexture() ) ) return E_FAIL;
 if( FAILED( InitVB() ) ) return E_FAIL;
 if( FAILED( InitIB() ) ) return E_FAIL;

 return S_OK;
}


/**-----------------------------------------------------------------------------
 * 创建摄像机矩阵
 *------------------------------------------------------------------------------
 */
void SetupCamera()
{
 /// 创建世界矩阵
    D3DXMATRIXA16 matWorld;
 D3DXMatrixIdentity( &matWorld );
    g_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );

    /// 创建视图矩阵
    D3DXVECTOR3 vEyePt( 0.0f, 100.0f, -(float)g_czHeight );
    D3DXVECTOR3 vLookatPt( 0.0f, 0.0f, 0.0f );
    D3DXVECTOR3 vUpVec( 0.0f, 1.0f, 0.0f );
    D3DXMATRIXA16 matView;
    D3DXMatrixLookAtLH( &matView, &vEyePt, &vLookatPt, &vUpVec );
    g_pd3dDevice->SetTransform( D3DTS_VIEW, &matView );

    /// 创建投影矩阵
    D3DXMATRIXA16 matProj;
    D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, 1.0f, 1.0f, 1000.0f );
    g_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );
}

 


void SetupLighter()
{

 //创建设备的材质
 D3DMATERIAL9      matrl;
 ZeroMemory( &matrl, sizeof(D3DMATERIAL9) );
 matrl.Diffuse.r = matrl.Ambient.r = 100.0f;
 matrl.Diffuse.g = matrl.Ambient.g = 100.0f;
 matrl.Diffuse.b = matrl.Ambient.b = 100.0f;
 matrl.Diffuse.a = matrl.Ambient.a = 100.0f;
 g_pd3dDevice->SetMaterial(&matrl);
 

 D3DXVECTOR3   vecDir ;
 D3DLIGHT9     light  ;
 ZeroMemory(&light ,sizeof(D3DLIGHT9));

 light.Type      =  D3DLIGHT_DIRECTIONAL;
 light.Diffuse.r =  1.0f;
 light.Diffuse.g =  1.0f;
 light.Diffuse.b =  0.0f;

 vecDir = D3DXVECTOR3(1 , 1 , 1);
 vecDir = D3DXVECTOR3(cosf(GetTickCount()/350.0f),1.0f,sinf(GetTickCount()/350.0f));    //光源旋转
   
 D3DXVec3Normalize((D3DXVECTOR3 *)&light.Direction, &vecDir);

 light.Range = 1000.0f ;   //光源能照射的距离
 //在设备中设置0号光源
 g_pd3dDevice->SetLight(0 ,&light);
 //打开0号光源
 g_pd3dDevice->SetRenderState(D3DRS_LIGHTING ,TRUE);

 //打开光源设置
 g_pd3dDevice->SetRenderState(D3DRS_AMBIENT , 0x00909090);    //没它就会变黑
 //设定环境光源,例如太阳,线光源
}

 

void LogFPS(void )
{
 static  DWORD  nTick = 0 ;
 static  DWORD  nFPS  = 0 ;
 

 if(GetTickCount()-nTick>1000)
 {
  nTick = GetTickCount();

  nFPS  = 0 ;
  return ;
 }
 nFPS ++;
}

 

/**-----------------------------------------------------------------------------
 * 创建动画
 *------------------------------------------------------------------------------
 */
VOID Animate()
{
 static DWORD t = 0;
 static bool flag = false;
 /// 使用Fixed Point 技巧,改变0~2PI(0~360度)的值
 DWORD d = GetTickCount() % ( (int)((D3DX_PI*2) * 1000) );
 /// Y轴旋转矩阵
 D3DXMatrixRotationY( &g_matAni, d / 1000.0f );
// D3DXMatrixIdentity( &g_matAni );

 /// 创建摄像机矩阵
 SetupCamera();
 SetupLighter();

 if( d < t )
  flag = !flag;
 g_pd3dDevice->SetRenderState( D3DRS_FILLMODE, flag ? D3DFILL_WIREFRAME : D3DFILL_SOLID );
 t = d;

 LogFPS();
}

 


/**-----------------------------------------------------------------------------
 * 删除初始化对象
 *------------------------------------------------------------------------------
 */
VOID Cleanup()
{
    if( g_pTexHeight != NULL )       
        g_pTexHeight->Release();

    if( g_pTexDiffuse!= NULL )       
        g_pTexDiffuse->Release();

    if( g_pIB != NULL )       
        g_pIB->Release();

    if( g_pVB != NULL )       
        g_pVB->Release();

    if( g_pd3dDevice != NULL )
        g_pd3dDevice->Release();

    if( g_pD3D != NULL )      
        g_pD3D->Release();
}


/**-----------------------------------------------------------------------------
 * 绘制网格
 *------------------------------------------------------------------------------
 */
void DrawMesh( D3DXMATRIXA16* pMat )
{
    g_pd3dDevice->SetTransform( D3DTS_WORLD, pMat );
    g_pd3dDevice->SetStreamSource( 0, g_pVB, 0, sizeof(CUSTOMVERTEX) );
    g_pd3dDevice->SetFVF( D3DFVF_CUSTOMVERTEX );
    g_pd3dDevice->SetIndices( g_pIB );
 g_pd3dDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, 0, 0, g_cxHeight*g_czHeight, 0, (g_cxHeight-1)*(g_czHeight-1)*2 );
}

 


/**-----------------------------------------------------------------------------
 * 绘图
 *------------------------------------------------------------------------------
 */
VOID Render()
{
    /// 后置缓冲和Z-缓冲初始化
    g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(255,255,255), 1.0f, 0 );

 /// 创建动画矩阵
 Animate();
    /// 开始渲染
    if( SUCCEEDED( g_pd3dDevice->BeginScene() ) )
    {
  g_pd3dDevice->SetTexture( 0, g_pTexDiffuse );       /// 在0号纹理层固定纹理(颜色图)
  g_pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR ); /// 0号纹理层的放大滤镜
  g_pd3dDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, 0 );  /// 0号纹理:使用0号纹理索引

  g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP,   D3DTOP_MODULATE);
  g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
  g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );

  DrawMesh( &g_matAni );
  /// 结束渲染
  g_pd3dDevice->EndScene();
    }

    /// 显示后置缓冲的画面!
    g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
}

 


/**-----------------------------------------------------------------------------
 * 窗口过程
 *------------------------------------------------------------------------------
 */
LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
    switch( msg )
    {
        case WM_DESTROY:
            Cleanup();
            PostQuitMessage( 0 );
            return 0;
  case WM_KEYDOWN :
   switch( wParam )
   {
    case VK_ESCAPE :
     PostMessage( hWnd, WM_DESTROY, 0, 0L );
     break;
   }
   break;
    }

    return DefWindowProc( hWnd, msg, wParam, lParam );
}

 


/**-----------------------------------------------------------------------------
 * 程序的起始地址
 *------------------------------------------------------------------------------
 */
INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR, INT )
{
    /// 注册窗口类
    WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L,
                      GetModuleHandle(NULL), NULL, NULL, NULL, NULL,
                      L"BasicFrame", NULL };
    RegisterClassEx( &wc );

    /// 创建窗口
    HWND hWnd = CreateWindow( L"BasicFrame", L"BasicFrame",
                              WS_OVERLAPPEDWINDOW, 100, 100, WINDOW_W, WINDOW_H,
                              GetDesktopWindow(), NULL, wc.hInstance, NULL );

 g_hwnd = hWnd;
// g_pLog = new ZFLog( ZF_LOG_TARGET_WINDOW );
    /// Direct3D初始化
    if( SUCCEEDED( InitD3D( hWnd ) ) )
    {
        if( SUCCEEDED( InitGeometry() ) )
        {

         /// 显示窗口
   ShowWindow( hWnd, SW_SHOWDEFAULT );
   UpdateWindow( hWnd );

         /// 消息循环
   MSG msg;
   ZeroMemory( &msg, sizeof(msg) );
   while( msg.message!=WM_QUIT )
   {
             /// 消息队列中有消息时,调用相应的处理过程
    if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) )
    {
     TranslateMessage( &msg );
     DispatchMessage( &msg );
    }
    else
    /// 如果没有需要处理的消息,调用Render()函数
     Render();
   }
  }
    }

 /// 删除注册的类
    UnregisterClass( L"D3D Tutorial", wc.hInstance );
    return 0;
}

 

 

 

原创粉丝点击