DirectX 畫三角形 透視投影





#include <d3d9.h>
#include <d3dx9.h>

#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "d3dx9.lib")

#define WINDOW_WIDTH    640
#define WINDOW_HEIGHT   480


PDIRECT3D9 g_D3D = nullptr; // D3D對象
PDIRECT3DDEVICE9 g_D3DDevice = nullptr; // D3D設備對象
D3DXMATRIX g_projection; // 矩陣變量,用於透視投影變換

bool InitializeD3D(HWND hWnd); // 初始化D3D
void ShutdownD3D(); // 退出窗口之前釋放D3D對象和D3D設備對象
void RenderScene(); // 渲染場景
bool InitializeObjects();// 初始化3D圖形對象


// 頂點數據
struct stD3DVertex
{
    float x, y, z; // 座標值(屏幕座標) (左手座標系) rhw 標誌
    unsigned long color; // 漫射光顏色
};
// 頂點緩存
PDIRECT3DVERTEXBUFFER9 g_VertexBuffer = nullptr;

// 頂點格式
#define D3DFVF_VERTEX (D3DFVF_XYZ | D3DFVF_DIFFUSE)

LRESULT WINAPI MsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); // 窗口消息處理過程
void MyCreateWindow(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nShowCmd); // 創建窗口



/************************************************************************/
/* Windows窗口程序入口函數                                               */
/************************************************************************/
int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nShowCmd)
{

    MyCreateWindow(hInstance, hPrevInstance, lpCmdLine, nShowCmd);

    return 0;
}

/************************************************************************/
/* 創建窗口                                                                 */
/************************************************************************/
void MyCreateWindow(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nShowCmd)
{
    // 聲明一個窗口類 包含創建一個窗口所需要的相關數據信息
    WNDCLASSEX wc = {
        sizeof(WNDCLASSEX), // 窗口類的內存空間大小(字節)
        CS_CLASSDC, // 窗口風格
        MsgProc, // 處理消息的函數指針
        0, // 類額外信息
        0, // 窗口額外信息
        hInstance, // 句柄,可以看作是窗口的身份標識
        nullptr, // 圖標樣式
        nullptr, // 鼠標樣式
        nullptr, // 背景畫刷 也可以設置爲一個顏色值 調用UnregisterClass後由系統刪除
        nullptr, // 菜單
        "AppClass", // 窗口類名 
        nullptr // 窗口小圖標
    };

    // 註冊窗口類
    RegisterClassEx(&wc);

    // 創建窗口
    HWND hWnd = CreateWindow(
        "AppClass", // 窗口類名
        "Window Title", // 窗口標題
        WS_OVERLAPPEDWINDOW, // 窗口風格 (可重疊)
        100, // 窗口左上角在屏幕座標中的X值
        100, // 窗口左上角在屏幕座標中的Y值
        WINDOW_WIDTH, // 窗口寬度
        WINDOW_HEIGHT, // 窗口高度
        GetDesktopWindow(), // 窗口父類
        nullptr, // 菜單
        hInstance, // 句柄
        nullptr
        );

    if (InitializeD3D(hWnd))
    {
        // 設置指定窗口爲顯示狀態
        ShowWindow(hWnd, SW_SHOWDEFAULT);

        // 發送繪製消息給窗口
        UpdateWindow(hWnd);


        MSG msg;

        ZeroMemory(&msg, sizeof(msg));

        while (msg.message != WM_QUIT)
        {
            if (PeekMessage(
                &msg, // 存儲消息的結構體指針
                nullptr, // 窗口消息和線程消息都會被處理 
                0, // 消息過濾最小值; 爲0時返回所有可用信息
                0, // 消息過濾最大值; 爲0時返回所有可用信息
                PM_REMOVE // 指定消息如何處理; 消息在處理完後從隊列中移除
                ))
            {
                TranslateMessage(&msg); // 變換虛擬鍵消息到字符消息,字符消息被髮送到調用線程的消息隊列
                DispatchMessage(&msg); // 派發消息到窗口過程
            }
            else
            {
                // 渲染場景
                RenderScene();
            }
        }
    }

    // 釋放D3D對象和D3D設備對象資源
    ShutdownD3D();

    // 註銷窗口類,釋放窗口所佔用資源
    UnregisterClass("AppClass", wc.hInstance);
}

/************************************************************************/
/* 窗口消息處理過程                                                                     */
/************************************************************************/
LRESULT WINAPI MsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
        break;
    default:
        break;
    }

    // windows消息的默認處理函數
    return DefWindowProc(hWnd, msg, wParam, lParam);
}


/************************************************************************/
/* 初始化D3D對象和D3D設備對象*/
/************************************************************************/
bool InitializeD3D(HWND hWnd)
{
    // 顯示模式 (以像素爲單位的屏幕寬高,刷新頻率,surface formt)
    D3DDISPLAYMODE displayMode;

    // 創建D3D對象 獲取主顯卡硬件信息  最先被創建,最後被釋放
    g_D3D = Direct3DCreate9(D3D_SDK_VERSION);
    if (g_D3D == nullptr)
    {
        return false;
    }

    // 獲取顯示模式
    if (FAILED(g_D3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT/*查詢主顯卡*/, &displayMode)))
    {
        return false;
    }

    // D3D 顯示參數
    D3DPRESENT_PARAMETERS d3dpp;
    ZeroMemory(&d3dpp, sizeof(d3dpp));

    d3dpp.Windowed = true; // 是否窗口化
    d3dpp.BackBufferFormat = displayMode.Format;  // D3DFMT_X8R8G8B8  表示爲32位RGB像素格式 每種顏色用一個字節表示
    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; // 幀緩衝區交換方式; 可能是COPY可能是FLIP,由設備來確定適合當前情況的方式

    // 創建D3D設備對象 ---- 代表顯卡
    if (FAILED(g_D3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &g_D3DDevice)))
    {
        return false;
    }

    // 初始化圖形對象需要的頂點數據
    if (!InitializeObjects())
    {
        return false;
    }
    return true;
}

/************************************************************************/
/* 釋放D3D對象及設備對象資源*/
/************************************************************************/
void ShutdownD3D()
{
    if (g_D3DDevice != nullptr)
    {
        g_D3DDevice->Release(); // 釋放設備對象
        g_D3DDevice = nullptr;
    }
    if (g_VertexBuffer != nullptr)
    {
        g_VertexBuffer->Release(); // 釋放頂點緩存
        g_VertexBuffer = nullptr;
    }
    if (g_D3D != nullptr)
    {
        g_D3D->Release(); // 最行創建, 最後釋放
        g_D3D = nullptr;
    }

}

/************************************************************************/
/* 渲染場景                                                             */
/************************************************************************/
void RenderScene()
{

    g_D3DDevice->Clear(0, nullptr, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
    g_D3DDevice->BeginScene();

    // 通知D3D設備對象數據源
    g_D3DDevice->SetStreamSource(
        0,
        g_VertexBuffer, // 數據源地址
        0, // 頂點緩存起始偏移
        sizeof(stD3DVertex) // 每個頂點數據的大小
        );
    g_D3DDevice->SetFVF(D3DFVF_VERTEX);
    // 繪製圖元
    g_D3DDevice->DrawPrimitive(
        D3DPT_TRIANGLELIST,  // 圖元類型; 三角形
        0, // 要加載的第一個頂點的索引
        1 // 圖元數量, 由圖元類型決定(一個三角形)
        );

    g_D3DDevice->EndScene();

    // 顯示backbuffer內容到屏幕
    g_D3DDevice->Present(nullptr, nullptr, nullptr, nullptr);
}

/************************************************************************/
/* 初始化頂點數據                                                        */
/************************************************************************/
bool InitializeObjects()
{

    // 基於攝像機視野創建左手座標系透視投影矩陣
    D3DXMatrixPerspectiveFovLH(
        &g_projection,
        45.f, // 剖面的角度範圍
        WINDOW_WIDTH / WINDOW_HEIGHT, // Aspect 寬度比
        0.1f, // 近裁剪面
        1000.f // 遠裁剪面
        );

    

    // 設置投影變換
    g_D3DDevice->SetTransform(
        D3DTS_PROJECTION, // 標識爲投影變換
        &g_projection // 變幻矩陣
        );
    
    // 設置光照
    g_D3DDevice->SetRenderState(
        D3DRS_LIGHTING, // 渲染狀態類型; 光照
        FALSE // 不使用光照
        );

    // 裁剪 (背面剔除)
    g_D3DDevice->SetRenderState(
        D3DRS_CULLMODE,
        D3DCULL_NONE // 不進行背面剔除
        );

    // 三角形頂點數據
    stD3DVertex objData[] = 
    {
        {-0.3f, -0.3f, 5.f, D3DCOLOR_XRGB(255, 255, 0)}, // 本地座標系,也稱模型座標
        {0.3f, -0.3f, 5.f, D3DCOLOR_XRGB(255, 0, 0)},
        {0.f, 0.3f, 5.f, D3DCOLOR_XRGB(0, 0, 255)}
    };

    // 創建頂點緩存
    ;
    if (FAILED(
        g_D3DDevice->CreateVertexBuffer(
            sizeof(objData), // 頂點緩衝區的大小
            0, // 頂點緩存的處理取決於D3D設備和頂點緩衝區是如何創建的(硬處理 or 軟處理) 創建的設備對象爲 D3DCREATE_HARDWARE_VERTEXPROCESSING 則此值必須爲0
            D3DFVF_VERTEX, // 頂點格式
            D3DPOOL_DEFAULT, // 默認使用顯卡顯存
            &g_VertexBuffer, // 頂點緩存指針
            nullptr // 保留值, 適用於Vista以上系統中資源分享
            )))
    {
        return false;
    }

    void* ptr = nullptr; // 頂點緩存地址
    // 在顯存中獲取一塊顯存空間用於存儲頂點數據
    if (FAILED(g_VertexBuffer->Lock(
        0, // 全部緩存
        sizeof(objData), // 頂點數據大小
        (void**)&ptr, // 將頂點數據首地址返回給ptr指針
        0 // 鎖定標記
        )))
    {
        return false;
    }

    // 將頂數數據複製到頂點緩存裏(顯存)
    memcpy(ptr, objData, sizeof(objData));

    g_VertexBuffer->Unlock(); // 解鎖頂點緩存

    return true;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章