我的Direct3D之路2:学习第一个三角形绘制程序以及一些注意点

来源:互联网 发布:mac上类似美图秀秀 编辑:程序博客网 时间:2024/04/30 02:03

打开\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通过这种循环让窗口能随时被缩放移动等,我们的渲染函数写在这里

二、D3D的初始化

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设备的函数
HRESULT  CreateDevice( 
UINT     Adapter,             //显卡序列号
D3DDEVTYPE       DeviceType,           //D3D设备类型
HWND     hFocusWindow,                 //所属窗口句柄
DWORD BehaviorFlags, //设备进行3D运算方式
D3DPRESENT_PARAMETERS        *pPresentationParameters,  //用于存储D3D设备相关信息的指针
 IDirect3DDevice9 **        ppReturnedDeviceInterface  //返回D3D设备接口指针的地址
);
而我们创建CreateDevice( D3DADAPTER_DEFAULT, 

                                               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
FVF的格式可以是以下类型的组合
D3DFVF_XYZ包含未经转换的顶点坐标
D3DFVF_XYZRHW包含经过转换的顶点坐标
D3DFVF_XYZW包含经过转换和裁剪的顶点坐标
D3DFVF_XYZB1………D3DFVF_XYZB5包含用于骨骼动画的顶点和顶点对骨骼的权重信息
D3DFVF_NORMAL包含法线信息
D3DFVF_PSIZE顶点信息指明绘制点的大小
D3DFVF_DIFFUSE包含漫反射的信息
D3DFVF_SPECULAR包含镜面反射的信息
D3DFVF_TEX0………D3DFVF_TEX8包含0-8个纹理坐标信息

所以现在我们指定位置1为D3DFVF_XYZRHW包含经过转换的顶点坐标,位置2为D3DFVF_DIFFUSE包含漫反射的信息(这个在这里就是颜色)
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的区别我们要搞懂
在顶点结构体中没有RHW时,Direct3D将执行视、投影、世界等变换以及进行光线计算,之后你才能在窗口中得到你所绘制的物体。当顶点结构体中有RHW时,告知Direct3D使用的顶点已经在屏幕坐标系中了,不再执行视图、投影、世界等变换和光线计算,因为D3DFVF_XYZRHW标志告诉它顶点已经经过了这些处理,并直接将顶点进行光栅操作,任何用SetTransform进行的转换都对其无效。不过这时的原点就在客户区的左上角了,其中x向右为正,y向下为正,而z的意义已经变为z-buffer的象素深度。
为D3DFVF_XYZ时,没有经过变换,原点在窗口中心,为D3DFVF_XYZRHW时,经过了变换,左上角的屏幕坐标为原点
然后我们再用这个结构体创建三个顶点。

四、渲染函数

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 );}
分为三步:
1.刷新背景缓存
2.开始绘制
3.交换后台缓存和前台缓存

在我们刷新背景的时候可以定义背景的颜色D3DCOLOR_XRGB( 0, 0, 255 ),目前是0,0,225为蓝色


DrawPrimitive函数绘制的时候,需要指定图元类型
D3D图元类型是分六种:
点列集合    D3DPT_POINTLIST   一组点的集合
线列集合    D3DPT_LINELIST      一组线段的集合
线带集合    D3DPT_LINESTRIP    首尾相连的线段的集合
三角形列    D3DPT_TRIANGLELIST      一组三角形的集合
三角形带    D3DPT_TRIANGLESTRIP  首尾相连的三角形,有两个顶点重合
三角形扇    D3DPT_TRIANGLEFAN      组成扇形的一组三角形

这里使用了D3DPT_TRIANGLELIST


五、参考文献:

1.关于图元和FVF顶点格式
2.D3D中D3DFVF_XYZ和D3DFVF_XYZRHW的区别
3.D3DPRESENT_PARAMETERS详解
4.IDirect3DDevice9::Present函数
0 0
原创粉丝点击