打开\Samples\C++\Direct3D\Tutorials\Tut02_Vertices路径下的工程,这就是微软给的官方绘图教程。
INT WINAPI wWinMain( HINSTANCE hInst, HINSTANCE, LPWSTR, INT )
{
UNREFERENCED_PARAMETER( hInst );
//注册一个窗口类
WNDCLASSEX wc =
{
sizeof( WNDCLASSEX ), CS_CLASSDC, MsgProc, 0L, 0L,
GetModuleHandle( NULL ), NULL, NULL, NULL, NULL,
L"D3D Tutorial", NULL
};
RegisterClassEx( &wc );
// 创建一个应用程序窗口
HWND hWnd = CreateWindow( L"D3D Tutorial", L"D3D Tutorial 02: Vertices",
WS_OVERLAPPEDWINDOW, 100, 100, 300, 300,
NULL, NULL, wc.hInstance, NULL );
// 初始化Direct3D
if( SUCCEEDED( InitD3D( hWnd ) ) )
{
// 创建顶点缓冲
if( SUCCEEDED( InitVB() ) )
{
// 显示窗口
ShowWindow( hWnd, SW_SHOWDEFAULT );
UpdateWindow( hWnd );
// 进入Message循环
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();
}
}
}
UnregisterClass( L"D3D Tutorial", wc.hInstance );
return 0;
}
参数多的眼花缭乱,但都不是重要的,跟着注释走知道在干嘛就行了
大概分为五步:
1.窗口创建
2.初始化D3D设备
3.创建顶点缓存
4.显示窗口
5.进入Message循环(在Message循环里面执行渲染)
其中我觉得比较重要需要注意的是
HWND hWnd = CreateWindow( L"D3D Tutorial", L"D3D Tutorial 02: Vertices",WS_OVERLAPPEDWINDOW, 100, 100, 300, 300,NULL, NULL, wc.hInstance, NULL );
这个函数里的100,100,300,300的意思是指从屏幕坐标的100,100开始创建一个300,300大小的窗口
如果改成CreateWindow( L"D3D Tutorial", L"D3D Tutorial 02: Vertices",WS_OVERLAPPEDWINDOW,200, 200, 600, 600,NULL, NULL, wc.hInstance, NULL );
窗口就会这样显示
还有消息循环,windows通过这种循环让窗口能随时被缩放移动等,我们的渲染函数写在这里
HRESULT InitD3D( HWND hWnd )
{
// 创建D3D物体
if( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
return E_FAIL;
// 建立一个结构体用于D3D设备的创建
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory( &d3dpp, sizeof( d3dpp ) );
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
// 创建D3D设备
if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp, &g_pd3dDevice ) ) )
{
return E_FAIL;
}
return S_OK;
}
需要注意的是d3dpp.Windowed属性决定了是否是窗口模式,d3dpp.SwapEffect属性上一章详细介绍过,不说了,具体链接如下:
Direct3D补充篇:表面缓冲区技术实现动画的流畅显示
d3dpp.BackBufferFormat属性是后缓冲区的格式,一般窗口模式可用D3DFMT_UNKNOWN,全屏模式是CheckDeviceType的返回值
创建D3D设备的函数 D3DDEVTYPE_HAL, hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp, &g_pd3dDevice )
其中D3DADAPTER_DEFAULT是指默认的显卡(如果你的是双显卡的电脑,就要看一看这个属性了)
D3DDEVTYPE_HAL和D3DCREATE_SOFTWARE_VERTEXPROCESSING组合可以实现不同的处理方式:
D3DDEVTYPE_HAL和D3DCREATE_HARDWARE_VERTEXPROCESSING组合:完全交由GPU处理
D3DDEVTYPE_HAL和D3DCREATE_MIXED_VERTEXPROCESSING组合:顶点处理可由CPU或者GPU来做,其他是GPU
D3DDEVTYPE_HAL和D3DCREATE_SOFTWARE_VERTEXPROCESSING组合:顶点处理由CPU,其他由GPU来处理
D3DDEVTYPE_REF和D3DCREATE_SOFTWARE_VERTEXPROCESSING组合:完全由CPU来做,这个很慢
// 自定义顶点类型的结构体
struct CUSTOMVERTEX
{
FLOAT x, y, z, rhw; // 顶点的位置
DWORD color; // 顶点的颜色
};
可是D3D不知道这个结构体中的这些数据记录了什么,我们要指定一种格式让D3D能识别这个结构体
// 自定义的FVF
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE)
这是一种灵活顶点格式 ( Flexible Vertex Format )FVF
HRESULT InitVB()//初始化顶点缓存
{
//为了渲染一个三角形,我们需要初始化三个顶点
CUSTOMVERTEX vertices[] =
{
{ 150.0f, 50.0f, 0.5f, 1.0f, 0xffff0000, }, // x,y,z为坐标,rhw为,后面表示颜色
{ 250.0f, 250.0f, 0.5f, 1.0f, 0xff00ff00, },
{ 50.0f, 250.0f, 0.5f, 1.0f, 0xff00ffff, },
};
//创建顶点缓冲,我们从默认缓冲池中分配足够的内存,存储3个顶点,指定了FVF格式,所以顶点缓冲知道包含的数据
if( FAILED( g_pd3dDevice->CreateVertexBuffer( 3 * sizeof( CUSTOMVERTEX ),
0, D3DFVF_CUSTOMVERTEX,
D3DPOOL_DEFAULT, &g_pVB, NULL ) ) )
{
return E_FAIL;
}
// Now we fill the vertex buffer. To do this, we need to Lock() the VB to
// gain access to the vertices. This mechanism is required becuase vertex
// buffers may be in device memory.
//填充缓冲区,先Lock,在填充最后Unlock(这个过程是必需的)
VOID* pVertices;
if( FAILED( g_pVB->Lock( 0, sizeof( vertices ), ( void** )&pVertices, 0 ) ) )
return E_FAIL;
memcpy( pVertices, vertices, sizeof( vertices ) );
g_pVB->Unlock();
return S_OK;
}
D3DFVF_XYZRHW和D3DFVF_XYZ的区别我们要搞懂
VOID Render()
{
//清除背景的缓冲
g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB( 0, 0, 255 ), 1.0f, 0 );
// 开始绘制场景
if( SUCCEEDED( g_pd3dDevice->BeginScene() ) )
{
//用顶点缓冲来绘制三角形。这分为几个步骤。我们需要把顶点数据传给一个流,所以一开始我们需要确定流的来源,就是我们的顶点缓冲。
//然后我们需要让D3D知道顶点的格式
//最后用DrawPrimitive来做绘制
g_pd3dDevice->SetStreamSource( 0, g_pVB, 0, sizeof( CUSTOMVERTEX ) );
g_pd3dDevice->SetFVF( D3DFVF_CUSTOMVERTEX );
g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, 1 );
// 结束绘制场景
g_pd3dDevice->EndScene();
}
// 交换后台缓存和前台缓存,并提交到渲染管道,将后台缓存内容渲染出来
g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
}
在我们刷新背景的时候可以定义背景的颜色D3DCOLOR_XRGB( 0, 0, 255 ),目前是0,0,225为蓝色
DrawPrimitive函数绘制的时候,需要指定图元类型
D3D图元类型是分六种:
点列集合 D3DPT_POINTLIST 一组点的集合
线列集合 D3DPT_LINELIST 一组线段的集合
线带集合 D3DPT_LINESTRIP 首尾相连的线段的集合
三角形列 D3DPT_TRIANGLELIST 一组三角形的集合
三角形带 D3DPT_TRIANGLESTRIP 首尾相连的三角形,有两个顶点重合
三角形扇 D3DPT_TRIANGLEFAN 组成扇形的一组三角形
这里使用了D3DPT_TRIANGLELIST