d3d 程序简单demo 解析

吐槽下编辑器,刚开始以后一定不能写代码,否则很不好改了~
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nShowCmd)
{
	//开始设计一个完整的窗口类
	WNDCLASSEX wndClass = { 0 };					//用WINDCLASSEX定义了一个窗口类
	wndClass.cbSize = sizeof( WNDCLASSEX ) ;			//设置结构体的字节数大小
	wndClass.style = CS_HREDRAW | CS_VREDRAW;	//设置窗口的样式
	wndClass.lpfnWndProc = WndProc;					
	wndClass.cbClsExtra		= 0;	          //窗口类的附加内存,取0
	wndClass.cbWndExtra		= 0;             //窗口的附加内存,依然取0
	wndClass.hInstance = hInstance;			//指定包含窗口过程的程序的实例句柄。
	wndClass.hIcon=(HICON)::LoadImage(NULL,L"icon.ico",IMAGE_ICON,0,0,LR_DEFAULTSIZE|LR_LOADFROMFILE);  //本地加载自定义ico图标
	wndClass.hCursor = LoadCursor( NULL, IDC_ARROW );    //指定窗口类的光标句柄。
	wndClass.hbrBackground=(HBRUSH)GetStockObject(GRAY_BRUSH);  //为hbrBackground成员指定一个白色画刷句柄	
	wndClass.lpszMenuName = NULL;						//用一个以空终止的字符串,指定菜单资源的名字。
	wndClass.lpszClassName = L"ForTheDreamOfGameDevelop";	//用一个以空终止的字符串,指定窗口类的名字。

	//注册窗口类
	if( !RegisterClassEx( &wndClass ) )			//设计完窗口后,需要对窗口类进行注册,这样才能创建该类型的窗口
		return -1;		

	//正式创建窗口
	HWND hwnd = CreateWindow( L"ForTheDreamOfGameDevelop",WINDOW_TITLE  //创建窗口函数CreateWindow
		WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, WINDOW_WIDTH,
		WINDOW_HEIGHT, NULL, NULL, hInstance, NULL );

	//Direct3D资源的初始化
	if (!(S_OK==Direct3D_Init (hwnd)))
	{
		MessageBox(hwnd, _T("Direct3D初始化失败~!"), _T("消息窗口"), 0); //使用MessageBox函数,创建一个消息窗口 
	}

	//窗口的移动、显示与更新
	MoveWindow(hwnd,250,80,WINDOW_WIDTH,WINDOW_HEIGHT,true);		//调整窗口显示时的位置,使窗口左上角位于(250,80)处
	ShowWindow( hwnd, nShowCmd );    //调用ShowWindow函数来显示窗口
	UpdateWindow(hwnd);						//对窗口进行更新,就像我们买了新房子要装修一样

	//消息循环过程
	MSG msg = { 0 };  //初始化msg
	while( msg.message != WM_QUIT )			//使用while循环
	{
		if( PeekMessage( &msg, 0, 0, 0, PM_REMOVE ) )   //查看应用程序消息队列,有消息时将队列中的消息派发出去。
		{
			TranslateMessage( &msg );		//将虚拟键消息转换为字符消息
			DispatchMessage( &msg );		//该函数分发一个消息给窗口程序。
		}
		else
		{
			Direct3D_Render(hwnd);   //进行渲染
		}
	}
	//【6】窗口类的注销
	UnregisterClass(L"ForTheDreamOfGameDevelop", wndClass.hInstance);  //程序准备结束,注销窗口类
	return 0;  
}
 
设置材质,diffuse 表示物体表面对漫反射光的反射率。Ambient 表示物体表面对环境光的反射率,Specular表示对镜面反射光的反射率,Emissice 表示自发光的颜色值。以上均可以像用D3DCOLOR(ARGB)来表示某种颜色。 

HRESULT Objects_Init(HWND hwnd)
{
	if(FAILED(D3DXCreateFont(g_pd3dDevice, 36, 0, 0, 1, false, DEFAULT_CHARSET, 
		OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, 0, _T("微软雅黑"), &g_pFont)))
		return E_FAIL;
	srand(timeGetTime());    

	// 物体的创建
	if(FAILED(D3DXCreateBox(g_pd3dDevice, 2, 2, 2, &g_cube, NULL)))	       n //立方体的创建
		return false;
	if(FAILED(D3DXCreateTeapot(g_pd3dDevice, &g_teapot, NULL)))		  //茶壶的创建
		return false;	
	if(FAILED(D3DXCreateSphere(g_pd3dDevice, 1.5, 25, 25,			//球面体的创建
		&g_sphere, NULL))) return false;
	if(FAILED(D3DXCreateTorus(g_pd3dDevice, 0.5f, 1.2f, 25, 25,		//圆环体的创建
		&g_torus, NULL))) return false;

	// 设置材质, 
	D3DMATERIAL9 mtrl;
	::ZeroMemory(&mtrl, sizeof(mtrl));
	mtrl.Ambient  = D3DXCOLOR(0.5f, 0.5f, 0.7f, 1.0f);
	mtrl.Diffuse  = D3DXCOLOR(0.6f, 0.6f, 0.6f, 1.0f);
	mtrl.Specular = D3DXCOLOR(0.3f, 0.3f, 0.3f, 0.3f);
	mtrl.Emissive = D3DXCOLOR(0.3f, 0.0f, 0.1f, 1.0f);
	g_pd3dDevice->SetMaterial(&mtrl);

	// 设置光照
	Light_Set(g_pd3dDevice, 1);
	g_pd3dDevice->SetRenderState(D3DRS_LIGHTING, true);
	g_pd3dDevice->SetRenderState(D3DRS_NORMALIZENORMALS, true);
	g_pd3dDevice->SetRenderState(D3DRS_SPECULARENABLE, true);


	g_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);   //开启背面消隐

	return S_OK;
}
SetLight (DWORD Index, const D3DLIGHT9 *pLight) index取值于0~7, pLight 取灯光。

VOID Light_Set(LPDIRECT3DDEVICE9 pd3dDevice, UINT nType)
{
	//定义一个光照类型并初始化
	static D3DLIGHT9 light;
	::ZeroMemory(&light, sizeof(light));

	//一个switch,给3种光源选项
	switch (nType)
	{
	case 1:     //点光源
		light.Type          = D3DLIGHT_POINT;
		light.Ambient       = D3DXCOLOR(0.6f, 0.6f, 0.6f, 1.0f); 
		light.Diffuse       = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f);
		light.Specular      = D3DXCOLOR(0.3f, 0.3f, 0.3f, 1.0f);
		light.Position      = D3DXVECTOR3(0.0f, 200.0f, 0.0f);
		light.Attenuation0  = 1.0f;
		light.Attenuation1  = 0.0f;
		light.Attenuation2  = 0.0f;
		light.Range         = 300.0f;
		break;
	case 2:     //平行光
		light.Type          = D3DLIGHT_DIRECTIONAL;
		light.Ambient       = D3DXCOLOR(0.5f, 0.5f, 0.5f, 1.0f);
		light.Diffuse       = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f);
		light.Specular      = D3DXCOLOR(0.3f, 0.3f, 0.3f, 1.0f);
		light.Direction     = D3DXVECTOR3(1.0f, 0.0f, 0.0f);
		break;
	case 3:     //聚光灯
		light.Type          = D3DLIGHT_SPOT;
		light.Position      = D3DXVECTOR3(100.0f, 100.0f, 100.0f);
		light.Direction     = D3DXVECTOR3(-1.0f, -1.0f, -1.0f);
		light.Ambient       = D3DXCOLOR(0.3f, 0.3f, 0.3f, 1.0f);
		light.Diffuse       = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f);
		light.Specular      = D3DXCOLOR(0.3f, 0.3f, 0.3f, 0.3f);
		light.Attenuation0  = 1.0f; 
		light.Attenuation1  = 0.0f; 
		light.Attenuation2  = 0.0f; 
		light.Range         = 300.0f;
		light.Falloff       = 0.1f;
		light.Phi           = D3DX_PI / 3.0f;
		light.Theta         = D3DX_PI / 6.0f;
		break;
	}

	pd3dDevice->SetLight(0, &light); //设置光源
	pd3dDevice->LightEnable(0, true);//启用光照
	pd3dDevice->SetRenderState(D3DRS_AMBIENT, D3DCOLOR_XRGB(36, 36, 36));   //设置一下环境光
}


四大变换:

1.世界变换:包括平移、旋转和缩放变换。 可以通过D3DXMatrixTranslation、D3DXMAtrixRotation* 和D3DXMAtrixSaling;

2.取景变换:对于不同位置虚拟摄像机和观察点,其观察物体模型和视角方向也不同。为了确定一个虚拟摄像机的位置和观察方向,需要制定虚拟摄像机在世界坐标系中的位置、观察点位置以及正方向;

3.投影变换: 讲三维场景显示在二维平面上,需要通过投影变换讲三维物体投影到二维平面。D3DXMatrixPerspectiveFovLH 函数可以用来计算一个视截体,并根据该视截体计算投影矩阵变换,视截体之外的模型会被 clipping;

4.视口变换:用D3DVIEWPORT9可以把投影窗口中的图形转换到显示屏幕程序窗口中。

VOID Matrix_Set()
{
	//世界变换矩阵的设置


	//取景变换矩阵的设置
	D3DXMATRIX matView;                 //定义一个矩阵
	D3DXVECTOR3 vEye(0.0f, 0.0f, -15.0f);  //摄像机的位置
	D3DXVECTOR3 vAt(0.0f, 0.0f, 0.0f);   //观察点的位置
	D3DXVECTOR3 vUp(0.0f, 1.0f, 0.0f);  //向上的向量
	D3DXMatrixLookAtLH(&matView, &vEye, &vAt, &vUp); //计算出取景变换矩阵
	g_pd3dDevice->SetTransform(D3DTS_VIEW, &matView); //应用取景变换矩阵

	//投影变换矩阵的设置
	D3DXMATRIX matProj; //定义一个矩阵
	D3DXMatrixPerspectiveFovLH(&matProj, D3DX_PI / 4.0f, 1.0f, 1.0f, 1000.0f); //计算投影变换矩阵
	g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &matProj);  //设置投影变换矩阵

	//视口变换的设置
	D3DVIEWPORT9 vp; //实例化一个D3DVIEWPORT9结构体,然后做填空题给各个参数赋值就可以了
	vp.X      = 0;		//表示视口相对于窗口的X坐标
	vp.Y      = 0;		//视口相对对窗口的Y坐标
	vp.Width  = WINDOW_WIDTH;	//视口的宽度
	vp.Height = WINDOW_HEIGHT; //视口的高度
	vp.MinZ   = 0.0f; //视口在深度缓存中的最小深度值
	vp.MaxZ   = 1.0f;	//视口在深度缓存中的最大深度值
	g_pd3dDevice->SetViewport(&vp); //视口的设置

}


D3D 渲染,首先需要clear,进行清屏操作,然后在 BeginScene() 和 EndScene()之间进行绘制。最后调用 Present();

在此之前,需要 init3D,这些才是比较关键的。即创建Direct3D接口对象,获取设备硬件信息 GetDeviceCaps

HRESULT Direct3D_Init(HWND hwnd)
{
	// 创建Direct3D接口对象, 以便用该Direct3D对象创建Direct3D设备对象
	LPDIRECT3D9  pD3D = NULL; //Direct3D接口对象的创建
	if( NULL == ( pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) ) //初始化Direct3D接口对象,并进行DirectX版本协商
		return E_FAIL;

	//获取硬件设备信息
	D3DCAPS9 caps; int vp = 0;
	if( FAILED( pD3D->GetDeviceCaps( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps ) ) )
	{
		return E_FAIL;
	}
	if( caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT )
		vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;   //支持硬件顶点运算,我们就采用硬件顶点运算,妥妥的
	else
		vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING; //不支持硬件顶点运算,无奈只好采用软件顶点运算

	//填充D3DPRESENT_PARAMETERS结构体
	D3DPRESENT_PARAMETERS d3dpp; 
	ZeroMemory(&d3dpp, sizeof(d3dpp));
	d3dpp.BackBufferWidth            = WINDOW_WIDTH;
	d3dpp.BackBufferHeight           = WINDOW_HEIGHT;
	d3dpp.BackBufferFormat           = D3DFMT_A8R8G8B8;// 指定后台缓冲区的保存像素格式
	d3dpp.BackBufferCount            = 1;
	d3dpp.MultiSampleType            = D3DMULTISAMPLE_NONE;  
	d3dpp.MultiSampleQuality         = 0;
	d3dpp.SwapEffect                 = D3DSWAPEFFECT_DISCARD; 
	d3dpp.hDeviceWindow              = hwnd;
	d3dpp.Windowed                   = true;   //ture 表示窗口模式, false 表示 全屏模式
	d3dpp.EnableAutoDepthStencil     = true; 
	d3dpp.AutoDepthStencilFormat     = D3DFMT_D24S8;
	d3dpp.Flags                      = 0;
	d3dpp.FullScreen_RefreshRateInHz = 0;
	d3dpp.PresentationInterval       = D3DPRESENT_INTERVAL_IMMEDIATE;

	//创建Direct3D设备接口
	if(FAILED(pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, 
		hwnd, vp, &d3dpp, &g_pd3dDevice)))
		return E_FAIL;

	SAFE_RELEASE(pD3D) //LPDIRECT3D9接口对象的使命完成,将其释放掉

		if(!(S_OK==Objects_Init(hwnd))) return E_FAIL;     //调用一次Objects_Init,进行渲染资源的初始化

	return S_OK;
}



Reference:

《windows 游戏编程从零开始》第14章

相关代码可以在网盘 pan.baidu.com/share/link?shareid=3237814961&uk=3056331768 下载

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不负初心

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值