• Direct3D 顶点缓存


    4


    今天我们来学习下Direct3D的顶点和顶点缓存,首先我们需要在场景中绘制一些物体,物体都是由多个三角形组成,每一个三角形由三个顶点组成,我们来看下面一个NPC的模型

    左图:正常的模型                      右图:看的出模型是有多个三角形组成

    imageimage

    现在我们知道了一个模型最小单位是一个顶点. 如果我们需要自己绘制物体,就要学习下Direct3D如何创建顶点. 顶点在Direct3D中叫顶点缓存(VertexBuffer),顶点缓存保存了顶点的一些数据空间,比如位置,颜色,法向量等等.

    定制顶点缓存(FVF)格式:

    刚刚说了顶点有很多信息,有的时候我们只需要一些信息,根据自己需要定制顶点缓存

    //坐标位置和颜色的顶点
    struct CUSTOMVERTEX1
    {
        float x,y,z;        
        DWORD color;
    };
    //等下创建顶点缓存,要传入这个宏,Direct3D才知道我们用的是那种顶点
    #define D3DFVF_CUSTOMVERTEX1 (D3DFVF_XYZRHW | D3DFVF_DIFFUSE);
    
    //坐标位置和法向量的顶点
    struct CUSTOMVERTEX2
    {
        float x,y,z;            
        float nx,ny,nz;        //法向量
        float u,v;            //纹理坐标
    };
    #define D3DFVF_CUSTOMVERTEX2 (D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1);

    FVF常用格式

    D3DFVF_XYZ 未经过坐标变换的顶点坐标值,不可以和D3DFVF_XYZRHW一起使用
    D3DFVF_XYZRHW 经过坐标变换的顶点坐标值,不可以和D3DFVF_XYZ,D3DFVF_NORMAL一起使用
    D3DFVF_XYZB1~5 顶点混合的权重值
    D3DFVF_NORMAL 法线向量的数值
    D3DFVF_DIFFUSE 漫反射的颜色值
    D3DFVF_SPECULAR 镜面反射的数值
    D3DFVF_TEX1~8 1~8纹理坐标的信息(纹理=贴图)

    顶点格式的顺序原则:

    顶点坐标位置->RHW值->顶点混合权重值->顶点法向量->漫反射颜色值->镜面反射颜色值->纹理坐标信息


     

    创建顶点缓存:

    LPDIRECT3DVERTEXBUFFER9 g_pVertexBuffer = NULL;        //顶点缓存对象
    Device->CreateVertexBuffer(4*sizeof(CUSTOMVERTEX1), 0 , D3DFVF_CUSTOMVERTEX1 , D3DPOOL_DEFAULT,&g_pVertexBuffer,NULL);

     

    访问顶点缓存:

    //创建顶点缓存
    if(FAILED(g_pd3dDevice->CreateVertexBuffer(3*sizeof(CUSTOMVERTEX),0,D3DFVF_CUSTOMVERTEX,D3DPOOL_DEFAULT,&g_pVertexBuffer,NULL)))
    {
        return E_FAIL;
    }
    
    //创建顶点数据
    CUSTOMVERTEX vertices [] = 
    {
        { 100.0f, 100.0f, 0.0f, 1.0f,  D3DCOLOR_XRGB(0, 0,0), },
        { 300.0f, 100.0f, 0.0f, 1.0f,  D3DCOLOR_XRGB(255, 255, 255), }, 
        { 300.0f, 300.0f, 0.0f, 1.0f,  D3DCOLOR_XRGB(0,0,0), },
    };
    
    //填充顶点缓冲区
    VOID *pVertices;
    if(FAILED(g_pVertexBuffer->Lock(0,sizeof(vertices),(void**)&pVertices,0)))        //加锁
    {
        return E_FAIL;
    }
    
    memcpy(pVertices,vertices,sizeof(vertices));        //把顶点数据保存到顶点缓存中
    g_pVertexBuffer->Unlock();                            //解锁
    
    
    g_pd3dDevice->SetRenderState(D3DRS_CULLMODE,false);

     

    图形的绘制: 上面我们已经准备好了顶点数据,现在只需要把顶点绘制到屏幕上就可以啦,绘制图形都是的BeginScene() 和 EndScene()函数中间,接下来我们需要依次调用以下函数,、

    1. IDirect3DDevice9::SetStreamSource() 设置顶点源

    2. IDirect3DDevice9::SetFVF() 设置灵活顶点格式

    3. IDirect3DDevice9::DrawPrimitive() 绘制图形

    g_pd3dDevice->SetStreamSource(0,g_pVertexBuffer,0,sizeof(CUSTOMVERTEX));        //设置绘制的顶点数据
    g_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX);                                      //设置灵活顶点格式
    g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST,0,2);                            //绘制两个三角形

    效果图:

    image

    全部代码:

    #include <d3d9.h>
    #include <d3dx9.h>
    #include <tchar.h>
    
    #pragma comment(lib,"winmm.lib")
    #pragma comment(lib,"d3d9.lib")
    #pragma comment(lib,"d3dx9.lib")
    
    #define WINDOW_WIDTH 800
    #define WINDOW_HEIGHT 600
    #define WINDOW_TITLE L"盘子脸的程序"
    #define SAFE_RELEASE(p) { if(p) { (p) -> Release();(p)=NULL;} }
    
    
    struct  CUSTOMVERTEX
    {
        float x,y,z,rhw;
        DWORD color;
    };
    #define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZRHW | D3DFVF_DIFFUSE) 
    
    //声明变量
    LPDIRECT3DDEVICE9 g_pd3dDevice = NULL;
    ID3DXFont* g_pFont = NULL;                    
    float g_FPS = 0.0f;
    wchar_t g_strFPS[50];            //包含帧速率的字符
    LPDIRECT3DVERTEXBUFFER9 g_pVertexBuffer = NULL;            //顶点缓冲区对象
    
    //全局函数声明部分
    LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam);
    HRESULT Direct3DInit(HWND hwnd);
    HRESULT ObjectsInit(HWND hwnd);
    VOID Direct3DRender(HWND hwnd);
    VOID Direct3DCleanUp();
    
    
    
    //主函数
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd)
    {
        //设置一个完整的窗口类,没有设置图标
        WNDCLASSEX wndClass = {0};
        wndClass.cbSize = sizeof(WNDCLASSEX);
        wndClass.style = CS_HREDRAW | CS_VREDRAW;            //设置窗口样式
        wndClass.lpfnWndProc = WndProc;
        wndClass.cbClsExtra = 0;
        wndClass.cbWndExtra = 0;
        wndClass.hInstance = hInstance;
        wndClass.hCursor = LoadCursor(NULL,IDC_ARROW);
        wndClass.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
        wndClass.lpszMenuName = NULL;
        wndClass.lpszClassName = L"GameDevelop";
    
    
        //注册窗口类
        if(!RegisterClassEx(&wndClass))
        {
            return -1;
        }
    
        //正式创建窗口
        HWND hwnd = CreateWindow(L"GameDevelop",WINDOW_TITLE,WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,WINDOW_WIDTH,
            WINDOW_HEIGHT,NULL,NULL,hInstance,NULL);
    
        //初始化Direct3D资源
        if(!(S_OK == Direct3DInit(hwnd)))
        {
            MessageBox(hwnd,_T("初始化Direct3D失败"),_T("盘子脸的消息窗口"),0);
        }
    
    
        MoveWindow(hwnd,250,80,WINDOW_WIDTH,WINDOW_HEIGHT,true);
        ShowWindow(hwnd,nShowCmd);
        UpdateWindow(hwnd);
    
        //消息循环过程
        MSG msg = {0};        
        while(msg.message != WM_QUIT)
        {
            if(PeekMessage(&msg,0,0,0,PM_REMOVE))
            {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }else
            {
                Direct3DRender(hwnd);
            }
        }
    
        //窗口类的注销
        UnregisterClass(L"GameDevelop",wndClass.hInstance);
    
        return 0;
    }
    
    //消息处理函数
    LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
    {
        switch (message)
        {
        case WM_PAINT:
            Direct3DRender(hwnd);
            ValidateRect(hwnd,NULL);
            break;
        case WM_KEYDOWN:
            if(wParam == VK_ESCAPE)
            {
                DestroyWindow(hwnd);
            }
            break;
        case WM_DESTROY:
            Direct3DCleanUp();                //失败Direct3D资源
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hwnd,message,wParam,lParam);
        }
    
        return 0;
    }
    
    HRESULT Direct3DInit(HWND hwnd)
    {
        //创建Direct3D接口对象
        LPDIRECT3D9 pD3D = NULL;
        if(NULL == (pD3D = Direct3DCreate9(D3D_SDK_VERSION)))
        {
            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;
        }
    
    
        //填充Direct3Dpresent参数
        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;
        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);
    
        if(!(S_OK == ObjectsInit(hwnd)))
        {
            return E_FAIL;
        }
    
        return S_OK;
    }
    
    HRESULT ObjectsInit(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;
        }
    
        //创建顶点缓存
        if(FAILED(g_pd3dDevice->CreateVertexBuffer(3*sizeof(CUSTOMVERTEX),0,D3DFVF_CUSTOMVERTEX,D3DPOOL_DEFAULT,&g_pVertexBuffer,NULL)))
        {
            return E_FAIL;
        }
    
        //创建顶点数据
        CUSTOMVERTEX vertices [] = 
        {
            { 100.0f, 100.0f, 0.0f, 1.0f,  D3DCOLOR_XRGB(0, 0,0), },
            { 300.0f, 100.0f, 0.0f, 1.0f,  D3DCOLOR_XRGB(255, 255, 255), }, 
            { 300.0f, 300.0f, 0.0f, 1.0f,  D3DCOLOR_XRGB(0,0,0), },
        };
    
        //填充顶点缓冲区
        VOID *pVertices;
        if(FAILED(g_pVertexBuffer->Lock(0,sizeof(vertices),(void**)&pVertices,0)))        //加锁
        {
            return E_FAIL;
        }
    
        memcpy(pVertices,vertices,sizeof(vertices));        //把顶点数据保存到顶点缓存中
        g_pVertexBuffer->Unlock();                            //解锁
    
    
        g_pd3dDevice->SetRenderState(D3DRS_CULLMODE,false);
        return S_OK;
    
    }
    
    void Direct3DRender(HWND hwnd)
    {
        g_pd3dDevice->Clear(0,NULL,D3DCLEAR_TARGET,D3DCOLOR_XRGB(0,0,0),1.0f,0);
        
        //定义一个矩形
        RECT formatRect;
        GetClientRect(hwnd,&formatRect);
    
        g_pd3dDevice->BeginScene();
        g_pd3dDevice->SetRenderState(D3DRS_SHADEMODE,D3DSHADE_GOURAUD);
    
        //绘制图形
        g_pd3dDevice->SetStreamSource(0,g_pVertexBuffer,0,sizeof(CUSTOMVERTEX));        //设置绘制的顶点数据
        g_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX);                                        //设置灵活顶点格式
        g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST,0,2);                            //绘制两个三角形
    
        //绘制文本信息
        g_pFont->DrawTextW(NULL,L"盘子脸",3,&formatRect,DT_TOP | DT_RIGHT , D3DCOLOR_XRGB(255,39,136));
    
        g_pd3dDevice->EndScene();
        g_pd3dDevice->Present(NULL,NULL,NULL,NULL);
    }
    
    void Direct3DCleanUp()
    {
        SAFE_RELEASE(g_pVertexBuffer);
        SAFE_RELEASE(g_pFont);
        SAFE_RELEASE(g_pd3dDevice);
    }
  • 相关阅读:
    ZZ 一些有意思的算法代码
    ff 怎样让新打开的标签就放在当前页面的右边
    111
    Windows平台下GO语言编译器(GOwindows)
    My Bookmarks
    使用googleperftools的tcmalloc
    memcached安装及测试
    erlang 入门(1)
    MS UI Automation
    twisted: echo server
  • 原文地址:https://www.cnblogs.com/plateFace/p/4967678.html
Copyright © 2020-2023  润新知