DirectX学习笔记(七):Direct3D纹理映射技术详解及实现

前言:


在前面的章节中,我们讲了如何绘制一个正方体,那么现在有个问题,如何绘制一个如图的正方体呢?


或许你想的是通过很多点来模拟,但是用很多顶点来模拟的方式效率无疑是底下的。正确的方式:先绘制一个正方体,延后将2D图像“贴”在正方体上。这就是所谓的纹理映射技术的简单理解。或者通俗来讲,纹理映射技术就是将2D的图像映射到3D的物体上的技术。而纹理是一种像素矩阵,它可以被映射到三角形单元中,我们通过将图像数据映射到三角形单元中,以达到绘制上图所示正方体的目的。

(如上图所示,你可以看到纹理映射技术的好处。在场景中利用纹理映射技术可以显著的增加所绘制场景的真实性。)



纹理映射流程:




1.纹理坐标:

Direct3D所使用的纹理坐标由沿水平方向的u轴和沿垂直方向的v轴构成。并且用(u,v)坐标对来标识纹理元素,被称作纹理元。





但是要注意的是,在Direct3D中,为了能够处理不同尺度的纹理,Direct3D将纹理坐标做了规范化处理,使之限定在区间范围[0,1]中。

那么问题来了:

纹理坐标的区间必须规定在0-1范围内,但是有时坐标是超过这个范围的。此时该如何处理呢?

这里不得不提到Direct3D的寻址模式。Direct3D定义了4中用来处理纹理坐标超出[0,1]区间的纹理映射模式。

1.重复模式寻址模式

2.边界颜色寻址模式

3.筘位寻址模式

4.镜像寻址模式


从左到右如图所示:

DirectX学习笔记(七):Direct3D纹理映射技术详解及实现_第1张图片DirectX学习笔记(七):Direct3D纹理映射技术详解及实现_第2张图片DirectX学习笔记(七):Direct3D纹理映射技术详解及实现_第3张图片DirectX学习笔记(七):Direct3D纹理映射技术详解及实现_第4张图片


回到主话题,为了能够实现该映射,我们需要重新修改顶点结构:

//顶点结构
struct Vertex
{
	float _x, _y, _z; // 位置
	float _u, _v;      //纹理坐标
	Vertex(){}

	Vertex(float x, float y, float z, float u, float v)
	:_x(x), _y(y), _z(z), _u(u), _v(v){}

};



2.顶点数据写入:

为了能够正确的达到我们想要的绘制结果,我们必须对此正方体的顶点数据进行写入。要写入数据,那么顶点缓存和索引缓存就必须要做了。

一个多边形中相邻的交汇点称为顶点,描述三角形单元时,我们需要指定该三角形3个顶点的位置。那么如果我们要通过三角形单元来描述一个物体,就需要指定构成该物体的三角形单元。


但是要知道的是,在构成一个3D物体时,三角形单元之间会存在很多的公共顶点。如果模型的复杂度特别高,那么顶点的重复会更多。比如说:一个正方体,如果用简单的三角形构成,需要12个三角形,如果分开来算,需要36个顶点。但是实际上一个正方体只需要8个顶点。那么在Direct3D中使用了顶点缓存和索引缓存来处理这种情况。


例如:对于一个立方体:
我们利用顶点缓存,来存储这8个顶点并对顶点进行编号,然后利用索引缓存来记录每个三角形都使用了哪些顶点:

Vertex vertexList[8] = { 0, 1, 2, 3, 4, 5, 6, 7 };
WORD IndexList[6] = { 0, 1, 2  //三角形0  
0,2,3//三角形1  
}


那么现在我们来写入正方体数据:


//顶点缓存 和索引缓存
bool InitCube()
{
	//创建顶端缓存
	_device->CreateVertexBuffer(
		24 * sizeof(Vertex), 
		D3DUSAGE_WRITEONLY,
		FVF_VERTEX, 
		D3DPOOL_MANAGED,
		&_vb,
		0);

	Vertex* v;
	//数据锁定,写入
	_vb->Lock(0, 0, (void**)&v, 0);

	// 正面数据
	v[0] = Vertex(-1.0f, -1.0f, -1.0f, 0.0f, 0.0f);
	v[1] = Vertex(-1.0f, 1.0f, -1.0f, 0.0f, 1.0f);
	v[2] = Vertex(1.0f, 1.0f, -1.0f, 1.0f, 1.0f);
	v[3] = Vertex(1.0f, -1.0f, -1.0f, 1.0f, 0.0f);

	//背面数据
	v[4] = Vertex(-1.0f, -1.0f, 1.0f, 0.0f, 0.0f);
	v[5] = Vertex(1.0f, -1.0f, 1.0f, 0.0f, 1.0f);
	v[6] = Vertex(1.0f, 1.0f, 1.0f, 1.0f, 1.0f);
	v[7] = Vertex(-1.0f, 1.0f, 1.0f,1.0f, 0.0f);

	// 上面数据
	v[8] = Vertex(-1.0f, 1.0f, -1.0f, 0.0f, 0.0f);
	v[9] = Vertex(-1.0f, 1.0f, 1.0f,0.0f, 1.0f);
	v[10] = Vertex(1.0f, 1.0f, 1.0f, 1.0f, 1.0f);
	v[11] = Vertex(1.0f, 1.0f, -1.0f, 1.0f, 0.0f);

	// 下面数据
	v[12] = Vertex(-1.0f, -1.0f, -1.0f, 0.0f, 0.0f);
	v[13] = Vertex(1.0f, -1.0f, -1.0f,  0.0f, 1.0f);
	v[14] = Vertex(1.0f, -1.0f, 1.0f,  1.0f, 1.0f);
	v[15] = Vertex(-1.0f, -1.0f, 1.0f, 1.0f, 0.0f);

	// 左面数据
	v[16] = Vertex(-1.0f, -1.0f, 1.0f, 0.0f, 0.0f);
	v[17] = Vertex(-1.0f, 1.0f, 1.0f, 0.0f, 1.0f);
	v[18] = Vertex(-1.0f, 1.0f, -1.0f,  1.0f, 1.0f);
	v[19] = Vertex(-1.0f, -1.0f, -1.0f, 1.0f, 0.0f);

	// 右面数据
	v[20] = Vertex(1.0f, -1.0f, -1.0f, 0.0f, 0.0f);
	v[21] = Vertex(1.0f, 1.0f, -1.0f, 0.0f, 1.0f);
	v[22] = Vertex(1.0f, 1.0f, 1.0f, 1.0f, 1.0f);
	v[23] = Vertex(1.0f, -1.0f, 1.0f, 1.0f, 0.0f);

	//解锁
	_vb->Unlock();

	//创建索引缓存
	_device->CreateIndexBuffer(	36 * sizeof(WORD),
		D3DUSAGE_WRITEONLY,
		D3DFMT_INDEX16,
		D3DPOOL_MANAGED,
		&_ib,
		0);

	WORD* i = 0;
	//锁定,数据写入
	_ib->Lock(0, 0, (void**)&i, 0);

	// 正面
	i[0] = 0; i[1] = 1; i[2] = 2;
	i[3] = 0; i[4] = 2; i[5] = 3;

	// 背面
	i[6] = 4; i[7] = 5; i[8] = 6;
	i[9] = 4; i[10] = 6; i[11] = 7;

	//上面
	i[12] = 8; i[13] = 9; i[14] = 10;
	i[15] = 8; i[16] = 10; i[17] = 11;

	// 下面
	i[18] = 12; i[19] = 13; i[20] = 14;
	i[21] = 12; i[22] = 14; i[23] = 15;

	// 左面
	i[24] = 16; i[25] = 17; i[26] = 18;
	i[27] = 16; i[28] = 18; i[29] = 19;

	//右面
	i[30] = 20; i[31] = 21; i[32] = 22;
	i[33] = 20; i[34] = 22; i[35] = 23;

	//解锁
	_ib->Unlock();

	return true;
}




3.创建并启用纹理:

纹理数据一般congratulation磁盘的图像文件读入,然后再添加到IDirect3DTexture9对象中,为了实现这一点,我们用下面这个函数:
D3DXCreateTextureFromFile函数:
HRESULT  D3DXCreateTextureFromFile(
__in   LPDIRECT3DDEVICE9 pDevice,
__in   LPCTSTR pSrcFile,
__out  LPDIRECT3DTEXTURE9 *ppTexture
);

■ 第一个参数,LPDIRECT3DDEVICE9类型的pDevice,Direct3D设备对象了。
■ 第二个参数,LPCTSTR类型的pSrcFile,指向了用于创建纹理的图标文件名字的字符串,也就是我们要使用的纹理图片的文件地址。支持的图片格式多种多样,有.bmp、.dds、.dib、.png以及.tga等等。
■ 第三个参数,LPDIRECT3DTEXTURE9类型的*ppTexture,指针的指针,也就是指向IDirect3DTexture9接口的地址,显然我们调用D3DXCreateTexture,就是把最终创建的纹理交给这个参数保管了,后面如果要使用我们创建的这个纹理的话,通过这个参数就可以了。


实现方法:

D3DXCreateTextureFromFile(_device, "crate.jpg", &tex);


为启用当前纹理,我们需要使用下面这个函数:
HRESULT SetTexture(
	[in]  DWORD Sampler,
	[in]  IDirect3DBaseTexture9 *pTexture
	);


实现方法:

_device->SetTexture(0, tex);




4.纹理过滤:

纹理被映射到屏幕空间中,由于纹理三角形与屏幕三角形的大小并不是完全一致,可能会有畸变发生。为了克服这种畸变,Direct3D采用了纹理过滤技Direct3D提供了三种纹理过滤器,每种纹理过滤器代表了一种质量水平。质量越高,开销越大,处理速度越慢,当然效果也会更好。所以我们必须处理好质量和处理速度的关系。我们利用IDirect3DDevice9->SetSamplerState来设置。

1.最近点采样:

这是D3D默认的模式,处理速度最快,但是效果最差,设置放大过滤器和缩小过滤器方式:

_device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
_device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);


2.线性纹理过滤:

该类型的过滤方式可以产生相当好的结果。一般多采用这种方式:

_device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
_device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);

3.各向异性纹理过滤:

该类型的过滤方式可以产生最好的结果,但是处理速度也是最慢的。

_device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_ANISOTROPIC);
_device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_ANISOTROPIC);



图片:



(我们需要将此图更名为crate,为jpg格式,放入工程源目录下)人,然后运行代码,可得到效果)




完整代码:

#include 
#include
#include
#define  SCREEN_WIDTH 800  //窗口宽度
#define  SCREEN_HEIGHT 600  //窗口高度
#define FVF_VERTEX (D3DFVF_XYZ  | D3DFVF_TEX1)
#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }  //自定义一个SAFE_RELEASE()宏,便于资源的释放 

IDirect3DDevice9*       _device; //Direct3D设备
IDirect3DVertexBuffer9* _vb;         //顶点缓存
IDirect3DIndexBuffer9*  _ib;           //索引缓存
IDirect3DTexture9* tex = 0;  // 纹理

//函数声明
//初始化Direct3D
//消息过程,处理消息
//初始化材质
//绘制Cube
bool InitD3D(HINSTANCE hInstance, int width, int height, bool windowed, D3DDEVTYPE deviceType, IDirect3DDevice9 ** device);
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
D3DMATERIAL9 InitMtrl(D3DXCOLOR a, D3DXCOLOR d, D3DXCOLOR s, D3DXCOLOR e, float p);
bool Draw(D3DXMATRIX* world, D3DMATERIAL9* mtrl, IDirect3DTexture9* tex);

//初始颜色属性
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));

//材质
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);


//顶点结构
struct Vertex
{
	float _x, _y, _z; // 位置
	float _u, _v;      //纹理坐标
	Vertex(){}

	Vertex(float x, float y, float z, float u, float v)
	:_x(x), _y(y), _z(z), _u(u), _v(v){}

};

//以下为窗口过程
LRESULT CALLBACK 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);
}

//初始化D3D
bool InitD3D(HINSTANCE hInstance, int width, int height, bool windowed, D3DDEVTYPE deviceType, IDirect3DDevice9 ** device)
{

	//定义一个完整的窗口类
	WNDCLASS wc;
	wc.style = CS_VREDRAW | CS_HREDRAW;
	wc.lpfnWndProc = 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.lpszClassName = "LSZDX";
	wc.lpszMenuName = 0;


	//注册窗口类
	if (!(RegisterClass(&wc)))
	{
		MessageBox(0, "RegisterClass is FAILED", 0, 0);
		return false;
	}

	//创建窗口
	HWND hwnd = 0;
	hwnd = CreateWindow("LSZDX", "LSZDXDEMO", WS_OVERLAPPEDWINDOW, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT,0,0, hInstance, 0);
	if (hwnd == 0)
	{
		MessageBox(0, "CreateWIndow is FAILED", 0, 0);
		return false;
	}

	//绘制和更新窗口
	ShowWindow(hwnd, SW_SHOW);
	UpdateWindow(hwnd);


	//以下为初始化D3D
	//*---------------
	//获取IDirect3D9的指针  
	IDirect3D9 *d3d9 = 0;
	d3d9 = Direct3DCreate9((D3D_SDK_VERSION));
	if (!d3d9)
	{
		MessageBox(0, "Direct3D9Create9 is FAILED", 0, 0);
		return false;
	}

	//检验硬件顶点运算  
	D3DCAPS9 caps;
	d3d9->GetDeviceCaps(
		D3DADAPTER_DEFAULT, 
		deviceType, 
		&caps);
	int vp = 0;
	if (caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
		vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;
	else
		vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;


	//填充D3DPRESENT_PARAMETERS
	D3DPRESENT_PARAMETERS d3dpp;
	d3dpp.BackBufferWidth = width;
	d3dpp.BackBufferHeight = height;
	d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8;
	d3dpp.BackBufferCount = 1;
	d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
	d3dpp.MultiSampleQuality = 0;
	d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
	d3dpp.hDeviceWindow = hwnd;
	d3dpp.Windowed = windowed;
	d3dpp.EnableAutoDepthStencil = true;
	d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
	d3dpp.Flags = 0;
	d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
	d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;

	//创建IDirect3DDevice9接口
	if (FAILED(d3d9->CreateDevice(
		D3DADAPTER_DEFAULT, 
		deviceType,
		hwnd, 
		vp,
		&d3dpp,
		device)))
	{
		MessageBox(0, "CreateDevice is FAILED", 0, 0);
		return false;
	}
	d3d9->Release();
	return true;
}

//初始化材质
D3DMATERIAL9 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;
}

//顶点缓存 和索引缓存
bool InitCube()
{
	//创建顶端缓存
	_device->CreateVertexBuffer(
		24 * sizeof(Vertex), 
		D3DUSAGE_WRITEONLY,
		FVF_VERTEX, 
		D3DPOOL_MANAGED,
		&_vb,
		0);

	Vertex* v;
	//数据锁定,写入
	_vb->Lock(0, 0, (void**)&v, 0);

	// 正面数据
	v[0] = Vertex(-1.0f, -1.0f, -1.0f, 0.0f, 0.0f);
	v[1] = Vertex(-1.0f, 1.0f, -1.0f, 0.0f, 1.0f);
	v[2] = Vertex(1.0f, 1.0f, -1.0f, 1.0f, 1.0f);
	v[3] = Vertex(1.0f, -1.0f, -1.0f, 1.0f, 0.0f);

	//背面数据
	v[4] = Vertex(-1.0f, -1.0f, 1.0f, 0.0f, 0.0f);
	v[5] = Vertex(1.0f, -1.0f, 1.0f, 0.0f, 1.0f);
	v[6] = Vertex(1.0f, 1.0f, 1.0f, 1.0f, 1.0f);
	v[7] = Vertex(-1.0f, 1.0f, 1.0f,1.0f, 0.0f);

	// 上面数据
	v[8] = Vertex(-1.0f, 1.0f, -1.0f, 0.0f, 0.0f);
	v[9] = Vertex(-1.0f, 1.0f, 1.0f,0.0f, 1.0f);
	v[10] = Vertex(1.0f, 1.0f, 1.0f, 1.0f, 1.0f);
	v[11] = Vertex(1.0f, 1.0f, -1.0f, 1.0f, 0.0f);

	// 下面数据
	v[12] = Vertex(-1.0f, -1.0f, -1.0f, 0.0f, 0.0f);
	v[13] = Vertex(1.0f, -1.0f, -1.0f,  0.0f, 1.0f);
	v[14] = Vertex(1.0f, -1.0f, 1.0f,  1.0f, 1.0f);
	v[15] = Vertex(-1.0f, -1.0f, 1.0f, 1.0f, 0.0f);

	// 左面数据
	v[16] = Vertex(-1.0f, -1.0f, 1.0f, 0.0f, 0.0f);
	v[17] = Vertex(-1.0f, 1.0f, 1.0f, 0.0f, 1.0f);
	v[18] = Vertex(-1.0f, 1.0f, -1.0f,  1.0f, 1.0f);
	v[19] = Vertex(-1.0f, -1.0f, -1.0f, 1.0f, 0.0f);

	// 右面数据
	v[20] = Vertex(1.0f, -1.0f, -1.0f, 0.0f, 0.0f);
	v[21] = Vertex(1.0f, 1.0f, -1.0f, 0.0f, 1.0f);
	v[22] = Vertex(1.0f, 1.0f, 1.0f, 1.0f, 1.0f);
	v[23] = Vertex(1.0f, -1.0f, 1.0f, 1.0f, 0.0f);

	//解锁
	_vb->Unlock();

	//创建索引缓存
	_device->CreateIndexBuffer(	36 * sizeof(WORD),
		D3DUSAGE_WRITEONLY,
		D3DFMT_INDEX16,
		D3DPOOL_MANAGED,
		&_ib,
		0);

	WORD* i = 0;
	//锁定,数据写入
	_ib->Lock(0, 0, (void**)&i, 0);

	// 正面
	i[0] = 0; i[1] = 1; i[2] = 2;
	i[3] = 0; i[4] = 2; i[5] = 3;

	// 背面
	i[6] = 4; i[7] = 5; i[8] = 6;
	i[9] = 4; i[10] = 6; i[11] = 7;

	//上面
	i[12] = 8; i[13] = 9; i[14] = 10;
	i[15] = 8; i[16] = 10; i[17] = 11;

	// 下面
	i[18] = 12; i[19] = 13; i[20] = 14;
	i[21] = 12; i[22] = 14; i[23] = 15;

	// 左面
	i[24] = 16; i[25] = 17; i[26] = 18;
	i[27] = 16; i[28] = 18; i[29] = 19;

	//右面
	i[30] = 20; i[31] = 21; i[32] = 22;
	i[33] = 20; i[34] = 22; i[35] = 23;

	//解锁
	_ib->Unlock();

	return true;
}

//Cube的绘制
bool Draw(D3DXMATRIX* world, D3DMATERIAL9* mtrl, IDirect3DTexture9* tex)
{
	//
	if (world)
		_device->SetTransform(D3DTS_WORLD, world);
	if (mtrl)
		_device->SetMaterial(mtrl);
	if (tex)
		_device->SetTexture(0, tex);

	//设置数据来源
	_device->SetStreamSource(0, _vb, 0, sizeof(Vertex));

	_device->SetIndices(_ib);
	//设置灵活顶点格式
	_device->SetFVF(FVF_VERTEX);
	//绘制 
	_device->DrawIndexedPrimitive(
		D3DPT_TRIANGLELIST,
		0,
		0,
		24,
		0,
		12);

	return true;
}

//初始化工作
bool Setup()
{
	InitCube();


	//创建一个直射光照
	D3DLIGHT9 light;
	::ZeroMemory(&light, sizeof(light));
	light.Type = D3DLIGHT_DIRECTIONAL;
	light.Ambient = D3DXCOLOR(0.8f, 0.8f, 0.8f, 1.0f);
	light.Diffuse = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f);
	light.Specular = D3DXCOLOR(0.2f, 0.2f, 0.2f, 1.0f);
	light.Direction = D3DXVECTOR3(1.0f, -1.0f, 0.0f);
	_device->SetLight(0, &light);
	_device->LightEnable(0, true);


	_device->SetRenderState(D3DRS_NORMALIZENORMALS, true);
	_device->SetRenderState(D3DRS_SPECULARENABLE, true);

	//
	D3DXCreateTextureFromFile(_device, "crate.jpg", &tex);

	//纹理过滤
	//线性纹理过滤
	_device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
	_device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
	_device->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);


	//投影变换
	D3DXMATRIX proj;
	D3DXMatrixPerspectiveFovLH(
		&proj,
		D3DX_PI * 0.5f, 
		(float)SCREEN_WIDTH / (float)SCREEN_HEIGHT,
		1.0f,
		1000.0f);

	_device->SetTransform(D3DTS_PROJECTION, &proj);

	return true;
}

//显示操作
bool DisPlay()
{
	MSG msg;
	::ZeroMemory(&msg, sizeof(MSG));//用0来填充消息可类比为:memset()函数    

	while (msg.message != WM_QUIT)
	{
		//PeekMessage函数是以查看的方式从系统中获取消息    
		//并将该消息(如果存在)放于指定的结构    
		if (::PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
		{
			//PM_REMOVE:PeekMessage处理后,消息从队列里除掉。  

			//TranslateMessage函数将虚拟键消息转换为字符消息。  
			//字符消息被寄送到调用线程的消息队列里,    
			//当下一次线程调用函数GetMessage或PeekMessage时被读出。    
			//TranslateMessage只能用于转换调用GetMessage或PeekMessage接收的消息。 
			::TranslateMessage(&msg);

			//DispatchMessage函数  
			//该函数分发一个消息给窗口程序。    
			//通常消息从GetMessage函数获得。    
			//消息被分发到回调函数(过程函数),作用是消息传递给操作系统,    
			//然后操作系统去调用我们的回调函数,也就是说我们在窗体的过程函数中处理消息
			::DispatchMessage(&msg);
		}
		else
		{
			if (_device)
			{
				// 获取键盘消息并做出相应回应
				static float angle = (3.0f * D3DX_PI) / 2.0f;
				static float height = 2.0f;

				if (::GetAsyncKeyState(VK_LEFT) & 0x8000f)
					angle -= 0.5f * 0.01f;

				if (::GetAsyncKeyState(VK_RIGHT) & 0x8000f)
					angle += 0.5f * 0.01f;

				if (::GetAsyncKeyState(VK_UP) & 0x8000f)
					height += 5.0f * 0.01f;

				if (::GetAsyncKeyState(VK_DOWN) & 0x8000f)
					height -= 5.0f * 0.01f;

				//取景变换
				D3DXVECTOR3 position(cosf(angle) * 3.0f, height, sinf(angle) * 3.0f);
				D3DXVECTOR3 target(0.0f, 0.0f, 0.0f);
				D3DXVECTOR3 up(0.0f, 1.0f, 0.0f);
				D3DXMATRIX V;
				D3DXMatrixLookAtLH(&V, &position, &target, &up);
				_device->SetTransform(D3DTS_VIEW, &V);


				//自动旋转
				D3DXMATRIX Rx, Ry;
				D3DXMatrixRotationX(&Rx, 3.14f / 4.0f);
				static float y = 0.0f;
				D3DXMatrixRotationY(&Ry, y);
				y += 0.0001f;
				if (y >= 6.28f)
					y = 0.0f;
				D3DXMATRIX p = Rx * Ry;
				_device->SetTransform(D3DTS_WORLD, &p);


				//
				// 绘制场景
				//

				_device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x00000000, 1.0f, 0);
				_device->BeginScene();

				_device->SetMaterial(&WHITE_MTRL);
				_device->SetTexture(0, tex);

				Draw(0, 0, 0);
				_device->EndScene();
				_device->Present(0, 0, 0, 0);
			}
		}
	}
	return true;
}


//
int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nShowCmd)
{
	if (!InitD3D(hInstance, SCREEN_WIDTH, SCREEN_HEIGHT, true, D3DDEVTYPE_HAL, &_device))
	{
		MessageBox(0, "InitD3D is FAILED", 0, 0);
		return 0;
	}

	if (!Setup())
	{
		MessageBox(0, "Setup() - FAILED", 0, 0);
		return 0;
	}
	DisPlay();
	_device->Release();
	return 0;

}

运行效果(可旋转,可以通过上下左右键控制)


DirectX学习笔记(七):Direct3D纹理映射技术详解及实现_第5张图片



(本文中,有很多函数没有给出函数参数解释,希望大家自行查看API,养成好习惯。一起加油,一起进步)~~!!!

你可能感兴趣的:(DirectX9游戏编程,DX9游戏编程)