在屏幕绘制一个三角形(使用顶点缓存)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/DY_1024/article/details/84258909

首先头文件d3dUtility.h里面:

Init3D函数:里面实现了Direct3D初始化的整个过程:包括获取接口Direct3D9的指针,检验设备的顶点运算,填充设备属性结构体的内容,创建IDirect3DDevice9的接口等。

EnterMsgLoop函数:该函数接受了一个显示函数的函数指针,然后将应用程序的消息循环进行封装,穿进去的显示函数就是进行绘制的函数,然后EnterMsgLoop函数需要知道什么时候去调用这个显示函数进行显示。

Release模板和Delete模板:资源销毁的时候调用。

头文件可以在这篇博客中找到,直接复制就能用。

还有就是d3dUtility.cpp文件,里面具体实现了刚才我们在d3dUtility.h文件中声明的两个函数。

同样也可以在这篇博客中找到,直接复制拷贝就可以用。

然后在源文件中我们还需要我们的主文件,也就是绘制Triangle的文件:triangle.cpp。我们在代码中以注释的方式进行讲解,会比较明了一点。

//包含我们刚才创建的d3dUtility.h头文件
#include "d3dUtility.h"

//定义一个用来指向设备的指针
IDirect3DDevice9* Device = 0;

//设置好我们窗口的宽和高
const int Width = 640;
const int Height = 480;

//定义一个用来顶点缓存的指针,用来指向我们的三角形顶点的数据
IDirect3DVertexBuffer9* Triangle = 0; 


//定义一个点的结构,有x,y,z的坐标,构造函数,还有灵活顶点格式
struct Vertex
{
	Vertex() {}

	Vertex(float x, float y, float z)
	{
		_x = x;	 _y = y;  _z = z;
	}

	float _x, _y, _z;

	//灵活顶点结构
	static const DWORD FVF;
};
const DWORD Vertex::FVF = D3DFVF_XYZ;


bool Setup()
{
    //使用接口:CreateVertexBuffer创建顶点缓存
	Device->CreateVertexBuffer(
		3 * sizeof(Vertex), // 因为我们只去画一个三角形,所以只有三个顶点,这里就给他开辟三个顶点的空间
		D3DUSAGE_WRITEONLY, // 这个标记代表现在创建的缓存是:只能写的静态缓存
		Vertex::FVF,        // 灵活顶点格式
		D3DPOOL_MANAGED,    // 内存池的类型
		&Triangle,          // 指向顶点缓存的指针的指针
		0);                 // CreatVertexBuffer的最后一个参数,不使用,设置为0,具体参见链接


    //使用顶点结构体定义的顶点指针
	Vertex* vertices;
    //使用之前将要访问的顶点缓存进行上锁
	Triangle->Lock(0, 0, (void**)&vertices, 0);
    
    //对顶点缓存进行赋值操作
	vertices[0] = Vertex(-1.0f, 0.0f, 2.0f);
	vertices[1] = Vertex(0.0f, 1.0f, 2.0f);
	vertices[2] = Vertex(1.0f, 0.0f, 2.0f);
    
    //对顶点缓存使用完成之后进行解锁
	Triangle->Unlock();

    /*正常来说,点设置好之后,经过的变换是:局部坐标系->世界坐标系->观察坐标系->背面消隐
->光照->裁剪->投影变换->视口变换->光栅化
    但是现在只有一个2D的三角形,窗口中(也可以理解成世界坐标和局部坐标是同一个坐标)只有这么一个图形,所以直接进行投影变换
    */
	D3DXMATRIX proj;
	D3DXMatrixPerspectiveFovLH(
		&proj,                        // 要得到的投影矩阵
		D3DX_PI * 0.5f,               // 视域体中的视角
		(float)Width / (float)Height, // 纵横比,为了减少正方形矩阵映射到矩形屏幕而发生的畸变
		1.0f,                         // 摄影机到近平面的距离
		1000.0f);                     // 摄影机到原平面的距离
    
    //使用刚才我们得到的投影矩阵
	Device->SetTransform(D3DTS_PROJECTION, &proj);

    //设置绘制的状态
	Device->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);

	return true;
}

void Cleanup()
{
    //使用d3d里面的Release模板,进行资源的释放
	d3d::Release<IDirect3DVertexBuffer9*>(Triangle);
}

//显示韩式
bool Display(float timeDelta)
{
    //如果Device存在或者不为空,则进入判断
	if (Device)
	{
        //使用此方法进行清除表面
		Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0);
        //绘制必须是在BeginScene和EndScene之间
		Device->BeginScene();
        
        //将需要绘制的顶点缓存和数据流进行链接
		Device->SetStreamSource(0, Triangle, 0, sizeof(Vertex));
        //设置灵活顶点格式
		Device->SetFVF(Vertex::FVF);

		// 绘制三角形
		Device->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1);

		Device->EndScene();

        //在设备拥有的后台缓存区中的显示下一个缓存的内容
		Device->Present(0, 0, 0, 0);
	}
	return true;
}

/*这是一个回调函数,参数和名字是固定的,代表这个窗口在收到对应的消息的时候,应该做出什么动作
现在这个函数里面只是写了当按下“ESC”的时候窗口结束
*/
LRESULT CALLBACK d3d::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch (msg)
	{
    //收到窗口摧毁的消息的时候退出窗口
	case WM_DESTROY:
		::PostQuitMessage(0);
		break;

    //当按键 = ESC 的时候摧毁窗口,并发送一条WM_DESTROY消息
	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)
{
    //初始化Direct3D
	if (!d3d::InitD3D(hinstance,
		Width, Height, true, D3DDEVTYPE_HAL, &Device))
	{
		::MessageBox(0, "InitD3D() - FAILED", 0, 0);
		return 0;
	}

    //分配资源,现在分配资源过程就是:创建顶点缓存,访问顶点缓存,操作顶点缓存,
	if (!Setup())
	{
		::MessageBox(0, "Setup() - FAILED", 0, 0);
		return 0;
	}

    //循环调用传进去的函数
    //穿进去的函数:Display,就是调用:DrawPrimitive进行绘制的过程
	d3d::EnterMsgLoop(Display);

	Cleanup();

	Device->Release();

	return 0;
}

triangle.cpp里面提到的链接是这两篇博客,里面对函数的使用以及一些相关的概念都有详细的解释:

Director3D中的绘制——顶点缓存和索引缓存

绘制流水线

猜你喜欢

转载自blog.csdn.net/DY_1024/article/details/84258909