DirectX 3D_实践之DirectX3D中通过XFile文件来创建网格

                 成熟程序员,什么样的程序员是一个成熟的程序员了,技术高手,不是,我想说成熟的程序员是,可以很快完成需求,但是不炫耀,说话的语速不快不慢,跟平常说话一样。别人再急,我们都不能急,因为我们是程序员,很多东西,都需要考虑清楚,头脑不清晰,是程序员最最忌讳的。心态很平和,不以物喜,不以己悲,不因为别人跳槽而羡慕,不因为有的人被辞退而幸灾乐祸,可以永远以自己的速度去处理所有的事情,工作仅仅是工作,不工作的时候,完全不工作。

 

                 今天,我们看一下,如果使用3D建模工具生成的3D模型。我们知道,如果单单只用顶点,三角形,来完成3D图形,以及游戏的显示是非常困难的。我们必须借助于一些第三方的建模工具,进行专业模型,图像的绘制,再由DIRECTX框架来进行模型的操作。正好,Direct3D提供了这样的功能。我们可以通过3D MAX或者MAYA建好模型,由DirectX来进行显示。

我们先来看DirectX3D.h的代码:

#ifndef __DirectX3DH__
#define __DirectX3DH__

#include <d3dx9.h>
#include <string>

namespace d3d
{
	bool InitD3D(
		HINSTANCE hInstance,       // [in] Application instance.
		int width, int height,     // [in] Backbuffer dimensions.
		bool windowed,             // [in] Windowed (true)or full screen (false).
		D3DDEVTYPE deviceType,     // [in] HAL or REF
		IDirect3DDevice9** device);// [out]The created device.
	
	int EnterMsgLoop( 
		bool (*ptr_display)(float timeDelta));
	
	LRESULT CALLBACK WndProc(
		HWND hwnd,
		UINT msg, 
		WPARAM wParam,
		LPARAM lParam);
	
	template<class T> void Release(T t)
	{
		if( t )
		{
			t->Release();
			t = 0;
		}
	}
	
	template<class T> void Delete(T t)
	{
		if( t )
		{
			delete t;
			t = 0;
		}
	}
	
	const D3DXCOLOR      WHITE( D3DCOLOR_XRGB(255, 255, 255) );
	const D3DXCOLOR      BLACK( D3DCOLOR_XRGB(  0,   0,   0) );
	const D3DXCOLOR        RED( D3DCOLOR_XRGB(255,   0,   0) );
	const D3DXCOLOR      GREEN( D3DCOLOR_XRGB(  0, 255,   0) );
	const D3DXCOLOR       BLUE( D3DCOLOR_XRGB(  0,   0, 255) );
	const D3DXCOLOR     YELLOW( D3DCOLOR_XRGB(255, 255,   0) );
	const D3DXCOLOR       CYAN( D3DCOLOR_XRGB(  0, 255, 255) );
	const D3DXCOLOR    MAGENTA( D3DCOLOR_XRGB(255,   0, 255) );
	
	//
	// Lights
	//
	
	D3DLIGHT9 InitDirectionalLight(D3DXVECTOR3* direction, D3DXCOLOR* color);
	D3DLIGHT9 InitPointLight(D3DXVECTOR3* position, D3DXCOLOR* color);
	D3DLIGHT9 InitSpotLight(D3DXVECTOR3* position, D3DXVECTOR3* direction, D3DXCOLOR* color);
	
	//
	// Materials
	//
	
	D3DMATERIAL9 InitMtrl(D3DXCOLOR a, D3DXCOLOR d, D3DXCOLOR s, D3DXCOLOR e, float p);
	
	const D3DMATERIAL9 WHITE_MTRL  = InitMtrl(WHITE, WHITE, WHITE, BLACK, 2.0f);
	const D3DMATERIAL9 RED_MTRL    = InitMtrl(RED, RED, RED, BLACK, 2.0f);
	const D3DMATERIAL9 GREEN_MTRL  = InitMtrl(GREEN, GREEN, GREEN, BLACK, 2.0f);
	const D3DMATERIAL9 BLUE_MTRL   = InitMtrl(BLUE, BLUE, BLUE, BLACK, 2.0f);
	const D3DMATERIAL9 YELLOW_MTRL = InitMtrl(YELLOW, YELLOW, YELLOW, BLACK, 2.0f);	

}




#endif 


再来看DirectX3D.cpp的代码:

#include "DirectX3D.h"






bool d3d::InitD3D(
	HINSTANCE hInstance,
	int width, int height,
	bool windowed,
	D3DDEVTYPE deviceType,
	IDirect3DDevice9** device)
{
	//
	// Create the main application window.
	//

	WNDCLASS wc;

	wc.style         = CS_HREDRAW | CS_VREDRAW;
	wc.lpfnWndProc   = (WNDPROC)d3d::WndProc; 
	wc.cbClsExtra    = 0;
	wc.cbWndExtra    = 0;
	wc.hInstance     = hInstance;
	wc.hIcon         = LoadIcon(0, IDI_APPLICATION);
	wc.hCursor       = LoadCursor(0, IDC_ARROW);
	wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wc.lpszMenuName  = 0;
	wc.lpszClassName = "Direct3D9App";

	if( !RegisterClass(&wc) ) 
	{
		::MessageBox(0, "RegisterClass() - FAILED", 0, 0);
		return false;
	}
		
	HWND hwnd = 0;
	hwnd = ::CreateWindow("Direct3D9App", "Direct3D9App", 
		WS_EX_TOPMOST,
		0, 0, width, height,
		0 /*parent hwnd*/, 0 /* menu */, hInstance, 0 /*extra*/); 

	if( !hwnd )
	{
		::MessageBox(0, "CreateWindow() - FAILED", 0, 0);
		return false;
	}

	::ShowWindow(hwnd, SW_SHOW);
	::UpdateWindow(hwnd);

	//
	// Init D3D: 
	//

    //第一步
    //要初始化IDirect3D 首先必须获取IDirect3D9的指针,使用一个专门的Direct3D函数就可以很容易做到
     IDirect3D9 * _d3d9;
  
  //这个对象的主要有两个用途:设备枚举以及创建IDirect3DDevice9类型的对象。设备枚举是指获取系统中可用的的每块图形卡的
  //性能,显示模型,格式以及其他信息。这个函数调用失败会返回一个NULL指针。
  if(NULL == (_d3d9 = Direct3DCreate9(D3D_SDK_VERSION))){


    return FALSE;

  }

  //第二步
  //创建一个代表主显卡的IDirect3DDevice9类型对象时,必须指定使用该对象进行顶点运算的类型。如果可以,我们希望使用硬件顶点运算
  //但是由于并非所有的显卡都支持硬件顶点运算,我们必须首先检查图形卡是否支持该类型的运算。

  //要进行检查,必须先根据主显卡的性能参数初始化一个IDirect3DDevice9类型的对象。我们使用如下方法来完成初始化:
     /*
  HRESULT IDirect3D9:GetDeviceCaps(
      UINT Adapter,
      D3DDEVTYPE DeviceType,
      D3DCAPS9 * pCaps;
   
  )

        Adapter : 指定物理显卡的序号。
  DeviceType:指定设备类(例如硬件设备(D3DDEVTYPE_HAL)或软件设备(D3DDEVTYPE_REF));
  pCaps 返回已初始化的设备性能结构实例。
        */
         D3DCAPS9 caps; 
         int vp = 0; //代表顶点如何操作

        _d3d9->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps);

          if(caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT){

                        vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;
           }
          else
          {
                        vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
          }

          //第三步是填充D3DPRESENT_PARAMETER结构
          //该结构用于指定所要创建的IDirect3DDevice9类型对象的一些特性,该结构定义如下:
          /*
          typedef struct _D3DPRESENT_PARAMETERS_{
                        UINT BackBufferWidth;
                        UINT BackBufferHeight;
                        UINT BackBufferFormat;
                        UINT BackBufferCount;
                        D3DMULTISAMPLE_TYPE MultiSampleType;
                        DWORD MultiSampleQuality;
                        D3DSWAPEFFECT SwapEffect;
                        HWND  hDeviceWindow;
                        BOOL  Windowed;
                        BOOL  EnableAutoDepthStencil;
                        D3DFORMAT AutoDepthStencilFormat;
                        DWORD  Flags;
                        UINT   FullScreen_RefreshRateInHz;
                        UINT   PresentationInterval;
          }; 
         */
        
        /* 
         BackBufferWidth: 后台缓存中表面的宽度,单位为像素。
        BackBufferHeight:后台缓存中表面的高度,单位为像素。
        BackBufferFormat:后台缓存的像素格式(如32位像素格式:D3DFMT_A8R8G8B8);
        BackBufferCount: 所需使用的后台缓存的个数,通常指定为1,表明我们仅需要一个后台缓存。
        MultiSampleType: 后台缓存所使用的多重采样类型。
        MultiSampleQuality:多重采样的质量水平。
        SwapEffect:D3DSWAPEFFECT 枚举类型的一个成员。该枚举类型指定了交换链中的缓存的页面置换方式。指定D3DSWAPEFFECT_DISCARD时效率最高。
        hDeviceWindow:与设备相关的窗口句柄。指定了所要进行绘制的应用程序窗口。
        Windowed:为true时表示窗口模式,false时为全屏模式
        EnableAutoDepthStencil:设为true,则Direct3D自动创建并维护深度缓存或模板缓存。
        AutoDepthStencilFormat:深度缓存或模板缓存的像素格式(例如,用24位表示深度并将8位保留供模板缓存使用,D3DFMT_D24S8).
        Flags:一些附加的特性。可以指定为0,表示无标记,或D3DPRESENTFLAG集合中的一个成员,其中两个成员较常用。
                 D3DPRESENTFLAG_LOCKABLE_DEPTHBUFFER 指定为可锁定的后台缓存。注意,使用一个可锁定的后台缓存会降低性能。
                 D3DPRESENTFLAG_DISCARD_DEPTHBUFFER 指定当下一个后台缓存提交时,哪个深度或模块缓存将被丢弃。丢弃的意思是深度或模板缓存存储区
                                                    中的内容别丢弃或无效。这样可以提升性能。
        FullScreen_RefreshRateInHz: 刷新频率,如果想使用默认的刷新频率,则可将该参数指定为D3DPRESENT_RATE_DEFAULT;
        PresentationInterval:D3DPRESENT集合的一个成员,其中有两个比较常用。
                      D3DPRESENT_INTERVAL_IMMEDIATE 立即提交。
                      D3DPRESENT_INTERVAL_DEFAULT 由Direct3D来选择提交频率,通常该值等于刷新频率。
       */ 

                  D3DPRESENT_PARAMETERS d3dpp;  
                  ZeroMemory(&d3dpp, sizeof(d3dpp));  
                 d3dpp.BackBufferWidth            = 800;  
                 d3dpp.BackBufferHeight           = 600;  
                 d3dpp.BackBufferFormat           = D3DFMT_A8R8G8B8;  
                 d3dpp.BackBufferCount            = 1;  
                 d3dpp.MultiSampleType            = D3DMULTISAMPLE_NONE;  
                 d3dpp.MultiSampleQuality         = 0;  
                 d3dpp.SwapEffect                 = D3DSWAPEFFECT_DISCARD;   
                 d3dpp.hDeviceWindow              = hwnd;  
                 d3dpp.Windowed                   = true;  
                 d3dpp.EnableAutoDepthStencil     = true;   
                 d3dpp.AutoDepthStencilFormat     = D3DFMT_D24S8;  
                 d3dpp.Flags                      = 0;  
                 d3dpp.FullScreen_RefreshRateInHz = 0;  
                 d3dpp.PresentationInterval       = D3DPRESENT_INTERVAL_IMMEDIATE; 

              //第四步 创建IDirectDevice9类型的对象
               /*  
                       HRESULT IDirect3D9::CreateDevice(
                               UINT Adapter,
                               D3DDEVTYPE DeviceType,
                               HWND hFocusWindow,
                               DWORD BehaviorFlags,
                               D3DPRESENT_PARAMETERS *pPresentationParameters,
                               IDirect3DDevice9 ** ppReturnedDeviceInterface
   
   
                       );

       Adapter:指定我们希望用已创建的IDirect3DDevice9对象代表哪块物理显卡。
       DeviceType:指定需要使用的设备类型()如,硬件设备用D3DDEVTYPE_HAL,或D3DDEVTYPE_REF代表软件设备。
       hFocusWindow:与设备相关的窗口句柄。通常情况下是指设备所要进行绘制的目标窗口。
       为了达到预期的目的,该句柄与D3DPRESENT_PARAMETER结构的数据成员hDeviceWindow应为同一个句柄。
       BehaviorFlags:该参数可为D3DCREATE_HARDWARE_VERTEXPROCESSING或D3DCREATE_SOFTWARE_VERTEXPROCESSING.
       pPresentationParameters:一个已经完成初始化的D3DPRESENT_PARAMETERS类型的实例,该实例定义了设备的一些特性。
       ppReturnedDeviceInterface:返回所创建的设备。
*/
  if(FAILED(_d3d9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,   
   hwnd, vp, &d3dpp, device)))  
           return FALSE;  

      _d3d9->Release();

      return TRUE;


}

int d3d::EnterMsgLoop( bool (*ptr_display)(float timeDelta) )
{
	MSG msg;
	::ZeroMemory(&msg, sizeof(MSG));

	static float lastTime = (float)timeGetTime(); 

	while(msg.message != WM_QUIT)
	{
		if(::PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
		{
			::TranslateMessage(&msg);
			::DispatchMessage(&msg);
		}
		else
        {	
			float currTime  = (float)timeGetTime();
			float timeDelta = (currTime - lastTime)*0.001f;

			ptr_display(timeDelta);

			lastTime = currTime;
        }
    }
    return msg.wParam;
}


D3DLIGHT9 d3d::InitDirectionalLight(D3DXVECTOR3* direction, D3DXCOLOR* color)
{
	D3DLIGHT9 light;
	::ZeroMemory(&light, sizeof(light));
	
	light.Type      = D3DLIGHT_DIRECTIONAL;
	light.Ambient   = *color * 0.4f;
	light.Diffuse   = *color;
	light.Specular  = *color * 0.6f;
	light.Direction = *direction;
	
	return light;
}

D3DLIGHT9 d3d::InitPointLight(D3DXVECTOR3* position, D3DXCOLOR* color)
{
	D3DLIGHT9 light;
	::ZeroMemory(&light, sizeof(light));
	
	light.Type      = D3DLIGHT_POINT;
	light.Ambient   = *color * 0.4f;
	light.Diffuse   = *color;
	light.Specular  = *color * 0.6f;
	light.Position  = *position;
	light.Range        = 1000.0f;
	light.Falloff      = 1.0f;
	light.Attenuation0 = 1.0f;
	light.Attenuation1 = 0.0f;
	light.Attenuation2 = 0.0f;
	
	return light;
}

D3DLIGHT9 d3d::InitSpotLight(D3DXVECTOR3* position, D3DXVECTOR3* direction, D3DXCOLOR* color)
{
	D3DLIGHT9 light;
	::ZeroMemory(&light, sizeof(light));
	
	light.Type      = D3DLIGHT_SPOT;
	light.Ambient   = *color * 0.4f;
	light.Diffuse   = *color;
	light.Specular  = *color * 0.6f;
	light.Position  = *position;
	light.Direction = *direction;
	light.Range        = 1000.0f;
	light.Falloff      = 1.0f;
	light.Attenuation0 = 1.0f;
	light.Attenuation1 = 0.0f;
	light.Attenuation2 = 0.0f;
	light.Theta        = 0.5f;
	light.Phi          = 0.7f;
	
	return light;
}

D3DMATERIAL9 d3d::InitMtrl(D3DXCOLOR a, D3DXCOLOR d, D3DXCOLOR s, D3DXCOLOR e, float p)
{
	D3DMATERIAL9 mtrl;
	mtrl.Ambient  = a;
	mtrl.Diffuse  = d;
	mtrl.Specular = s;
	mtrl.Emissive = e;
	mtrl.Power    = p;
	return mtrl;
}





最后来看一下wmain.cpp的代码:

#include "DirectX3D.h"
#include <fstream>
#include <vector>
//
// Globals
//

IDirect3DDevice9* Device = 0; 

const int Width  = 640;
const int Height = 480;

ID3DXMesh *Mesh = 0;

std::vector<D3DMATERIAL9> Mtrls(0);// 创建一个容器对象,里面的元素是材质
std::vector<IDirect3DTexture9*> Textures(0);//创建一个容器对象,里面的元素是纹理。
//
// Classes and Structures
//
struct Vertex
{
	Vertex(){}
	Vertex(float x, float y, float z, 
		float nx, float ny, float nz, float u, float v)
	{
		_x = x;   _y = y;   _z = z;
		_nx = nx; _ny = ny; _nz = nz;
		_u = u;   _v = v;
	}
	
	float _x, _y, _z, _nx, _ny, _nz, _u, _v;
	
	static const DWORD FVF;
};
const DWORD Vertex::FVF = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1;

//
// Framework Functions
//

bool Setup()
{
	//我们用一个ID3DMesh对象存储XFile文件中的加载的网格数据。
	/*
	现在的建模工具,比如3DS Max和Maya,都可以将网格数据(几何信息,材质,动画以及其他可能的有用数据)导出到文件中。
	我们可以编写一个文件读取程序来提取网格数据,并在我们的3D应用程序中使用。另外还有一种更简单的方法,有一种
	特殊的网格文件格式称为XFile格式(扩展名为.x),许多3D建模工具都可以将模型数据导成这个格式,而且也有许多转换程序可以将
	其他较流行的网格文件格式转换为.x格式,XFile之所以使用方便,主要的原因是他是DirectX定义的格式,提供相应的函数对其直接操作
	*/
    //另外我们用两个向量分别存储该网格的材质和纹理数据。
	HRESULT hr = 0;

    ID3DXBuffer * adjBuffer = 0;
	ID3DXBuffer * mtrlBuffer = 0;
	DWORD numMtrls = 0;


	/*
	  看一下这个函数的参数说明:

	  HRESULT  D3DXLoadMeshFromX(
	  __in   LPCTSTR pFilename,
	  __in   DWORD Options,
	  __in   LPDIRECT3DDEVICE9 pD3DDevice,
	  __out  LPD3DXBUFFER *ppAdjacency,
	  __out  LPD3DXBUFFER *ppMaterials,
	  __out  LPD3DXBUFFER *ppEffectInstances,
	  __out  DWORD *pNumMaterials,
	  __out  LPD3DXMESH *ppMesh
	  );

	  pFilename: 所要加载的XFile文件名。
	  Options:创建网格时所使用的创建标记。标记选项的完整列表可参阅SDK文档中与枚举累型D3DXMESH相关的部分。常用标记如下。
	          D3DXMESH_32BIT 网格将使用32位索引。
			  D3DXMESH_MANAGED 网格数据将被存储于托管内存池中。
			  D3DXMESH_WRITEONLY 指定网格数据为只读。
			  D3DXMESH_DYNAMIC 网格缓存将使用动态内存。
	  pD3DDevice:与该网格对象相关的设备指针。
	  ppAdjacency:返回一个ID3DXBuffer对象,该对象包含了一个描述了该网格对象的邻接信息的DWORD类型的数组。
	  ppMaterials:返回一个ID3DXBuffer对象,该对象包含了一个描述了该网格对象的材质数据D3DXMATERIAL类型的结构数组
	  ppEffectInstances:返回一个ID3DXBuffer对象,该对象包含了一个D3DXEFFECTINSTANCE结构。我们可以通过将该参数设置0将器忽略。
	  pNumMaterials:返回网格中的材质数目。
	  ppMesh:返回所创建的并一填充了XFile几何数据的ID3DXMesh对象。

      XFile材质:
	  D3DXLoadMeshFromX函数中的第7个参数返回了该网格对象所含的材质数目,第5个参数返回了一个存储了材质数据的D3DXMATRIAL类型的结构数组。
	  D3DXMATERIAL结构的定义如下:
	  typedef struct D3DXMATERIAL{
		
				D3DMATERIAL9 MatD3D;
				LPSTR pTextureFilename;
		}D3DXMATERIAL;
		该结构较为简单,包含了一个D3DMATERIAL9结构和一个指向以NULL结尾的字符串指针,该字符串指定了与网格相关的纹理文件名。
		XFile中并为存储纹理数据,是包含了纹理图像文件名,该文件名是对包含了实际纹理数据的纹理对象的引用。这样,当用
		D3DXLoadMeshFromX函数加载一个XFile文件后,必须根据指定的纹理文件名加载纹理数据。

	*/

    
	hr = D3DXLoadMeshFromX(  
		"bigship1.x",
		D3DXMESH_MANAGED,
		Device,
		&adjBuffer,
		&mtrlBuffer,
		0,
		&numMtrls,
		&Mesh);
	
	if(FAILED(hr))
	{
		::MessageBox(0, "D3DXLoadMeshFromX() - FAILED", 0, 0);
		return false;
	}

    //得到材质和纹理。

    if( mtrlBuffer != 0 && numMtrls != 0 ) //如果第5个参数,材质空间不为NUL,而且材质的数目不为0
	{
		D3DXMATERIAL* mtrls = (D3DXMATERIAL*)mtrlBuffer->GetBufferPointer(); //得到材质指针。
		
		for(int i = 0; i < numMtrls; i++)
		{
			// 将环境光和镜面光设置为一样
			mtrls[i].MatD3D.Ambient = mtrls[i].MatD3D.Diffuse;
			
			// 保存材质数据到容器中
			Mtrls.push_back( mtrls[i].MatD3D );
			
			// 检查相应的纹理文件名
			if( mtrls[i].pTextureFilename != 0 )
			{
				// 如果文件名不为NULL,用这个文件名,创建相应的纹理。
				IDirect3DTexture9* tex = 0;
				D3DXCreateTextureFromFile(
					Device,
					mtrls[i].pTextureFilename,
					&tex);
				
				// 保存纹理数据都容器中
				Textures.push_back( tex );
			}
			else
			{
				// 如果纹理文件名为NULL,不保存
				Textures.push_back( 0 );
			}
		}
	}
    //释放材质的指针
	d3d::Release<ID3DXBuffer*>(mtrlBuffer); 


	 //对网格进行优化,这里我们使用到了网格的邻接信息
     hr = Mesh->OptimizeInplace(		
		D3DXMESHOPT_ATTRSORT |
		D3DXMESHOPT_COMPACT  |
		D3DXMESHOPT_VERTEXCACHE,
		(DWORD*)adjBuffer->GetBufferPointer(),
		0, 0, 0);
    
	d3d::Release<ID3DXBuffer*>(adjBuffer); // 释放邻接信息的指针

	
	if(FAILED(hr))
	{
		::MessageBox(0, "OptimizeInplace() - FAILED", 0, 0);
		return false;
	}


    //设置纹理过滤方式,和多级渐进纹理的处理方式。
	
	Device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
	Device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
	Device->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_POINT);

	//设置光照
    
	D3DXVECTOR3 dir(1.0f, -1.0f, 1.0f);
	D3DXCOLOR col(1.0f, 1.0f, 1.0f, 1.0f);
	D3DLIGHT9 light = d3d::InitDirectionalLight(&dir, &col);
	
	Device->SetLight(0, &light);
	Device->LightEnable(0, true);

	Device->SetRenderState(D3DRS_NORMALIZENORMALS, true);
	Device->SetRenderState(D3DRS_SPECULARENABLE, true);
    
	//移动摄像机的位置,进行取景变换。
    
	D3DXVECTOR3 pos(4.0f, 4.f, -13.0f);
	D3DXVECTOR3 target(0.0f, 0.0f, 0.0f);
	D3DXVECTOR3 up(0.0f, 1.0f, 0.0f);
	
	D3DXMATRIX V;
	D3DXMatrixLookAtLH(
		&V,
		&pos,
		&target,
		&up);
	
	Device->SetTransform(D3DTS_VIEW, &V);

	//进行投影变化:
	D3DXMATRIX proj;
	D3DXMatrixPerspectiveFovLH(
		&proj,
		D3DX_PI * 0.5f, // 90 - degree
		(float)Width / (float)Height,
		1.0f,
		1000.0f);

	Device->SetTransform(D3DTS_PROJECTION, &proj);

	return true;
}
//将之前分配的内存进行清理,也就是顶点缓存和索引缓存
void Cleanup()
{

	d3d::Release<ID3DXMesh*>(Mesh);

	for(int i = 0; i < Textures.size(); i++)
		d3d::Release<IDirect3DTexture9*>( Textures[i] );
}


bool Display(float timeDelta)
{
	if( Device )
	{
		//
		// 进行旋转,不断进行世界变换
		//
	
		
		static float y = 0.0f;
		D3DXMATRIX yRot;
		D3DXMatrixRotationY(&yRot, y);
		y += timeDelta;
		
		if( y >= 6.28f )
			y = 0.0f;
		
		D3DXMATRIX World = yRot;
		
		Device->SetTransform(D3DTS_WORLD, &World);
		
		//
		// 清屏
		//
		
		Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x0000ffff, 1.0f, 0);

		Device->BeginScene();
		
		for(int i = 0; i < Mtrls.size(); i++)//从容器中得到保存的材质的数目
		{       //纹理设置,并进行子集的绘制。
				Device->SetMaterial( &Mtrls[i] );
				Device->SetTexture(0, Textures[i]);
			    Mesh->DrawSubset(i);
		/*
		值得一提的是,D3DXLoadMeshFromX函数载入XFile数据后,返回的D3DXMATERIAL结构数组中的第i项就与第i个子集相对应。所以我们将
		各子集按照0,1,2...n-1的顺序进行标记,其中n是子集和材质的总数。这样就可用一个简单的循环对全部子集进行遍历和绘制,从而完成
		整个网格的绘制。*/
		}
		
		Device->EndScene();
		Device->Present(0, 0, 0, 0);
	}
	return true;
}	

//
// WndProc
//
LRESULT CALLBACK d3d::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch( msg )
	{
	case WM_DESTROY:
		::PostQuitMessage(0);
		break;
		
	case WM_KEYDOWN:
		if( wParam == VK_ESCAPE )
			::DestroyWindow(hwnd);
		break;
	}
	return ::DefWindowProc(hwnd, msg, wParam, lParam);
}

//
// WinMain
//
int WINAPI WinMain(HINSTANCE hinstance,
				   HINSTANCE prevInstance, 
				   PSTR cmdLine,
				   int showCmd)
{
	if(!d3d::InitD3D(hinstance,
		640, 480, true, D3DDEVTYPE_HAL, &Device))
	{
		::MessageBox(0, "InitD3D() - FAILED", 0, 0);
		return 0;
	}
	
	if(!Setup())
	{
		::MessageBox(0, "Setup() - FAILED", 0, 0);
		return 0;
	}
	
	d3d::EnterMsgLoop( Display );
	
	Cleanup();
	
	Device->Release();
	
	return 0;
}


再来看一下程序的截图:

每日总结:

我们可用3D建模工具构建复杂的三角形网络,并将其导出或转化为XFile文件,然后,借助函数D3DXCreateMeshFromX,我们可将XFile文件中的网格数据加载到一个ID3DXMesh对象中加以使用。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值