DirectX 渲染的主要步骤

  • 创建窗口
  • DirectX 初始化
  • 创建设备和设备上下文
  • 创建Factroy
  • 填充交换链描述符
  • 创建交换链
  • 创建渲染目标视图,设置视口大小
  • 创建着色器
  • 填充缓冲区并绑定到渲染管线
  • 定义顶点数据结构体
  • 创建顶点缓冲区、填充并绑定
  • 创建索引缓冲区、填充并绑定
  • 创建顶点常量缓冲区、填充并绑定
  • 创建像素常量缓冲区、填充并绑定
  • 设置图元类型
  • 创建并绑定输入布局(也可以在创建完顶点着色器后立马创建)
  • 将着色器和相应阶段的常量缓冲区绑定到渲染管线。
  • 渲染
  • 主函数调用所有流程
  • 着色器代码


  1. 创建窗口。
  2. 创建设备和上下文。
  3. 创建交换链和渲染视图。
  4. 创建顶点着色器。
  5. 创建并绑定输入布局。
  6. 创建片段着色器。
  7. 创建顶点、索引、常量缓冲区,并填充和绑定。
  8. 设置图元拓扑(图元类型)。
  9. 将着色器和常量缓冲区绑定到渲染管线。
  10. 清空渲染视图。
  11. 绘制
  12. 呈现
  13. 转到步骤10.

以下是每个步骤的代码
准备工作
需要包含的头文件

#include <windows.h>
#include <wrl/client.h> // Comptr智能指针
#include <d3d11_1.h>
#include <d3d11_2.h>
#include <string>
#include <DirectXMath.h>
#include <d3dcompiler.h>

// 添加DirectX11所有要引用的库
#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "dxgi.lib")
#pragma comment(lib, "dxguid.lib")
#pragma comment(lib, "D3DCompiler.lib")
#pragma comment(lib, "winmm.lib")

整个流程所需要的变量和结构体

template <class T>
using ComPtr = Microsoft::WRL::ComPtr<T>; // 微软的智能指针

using namespace DirectX;
// 需要的所有变量
int winX = 0;
int winY = 0;
int winWidth = 1920;
int winHeight = 1080;


struct VertexPosColor
{
    DirectX::XMFLOAT3 pos;
    DirectX::XMFLOAT4 color;
    static const D3D11_INPUT_ELEMENT_DESC inputLayout[2];
};

const D3D11_INPUT_ELEMENT_DESC VertexPosColor::inputLayout[2] = {
    //-|-语义名字-|--|语义索引-|----|---------数据格式-----------|--|-输入槽索引[0-15]-|---|-字节对齐偏移量-|---|----输入槽类(顶点or索引)-----|---|-多实例渲染个数-|- 
    {  "POSITION",       0,           DXGI_FORMAT_R32G32B32_FLOAT,          0,                   0,                D3D11_INPUT_PER_VERTEX_DATA,          0     },
    {  "COLOR",          0,           DXGI_FORMAT_R32G32B32_FLOAT,          0,                   12,               D3D11_INPUT_PER_VERTEX_DAT
    struct VSConstantBuffer  //顶点常量缓冲区
{
    XMMATRIX world;
    XMMATRIX view;
    XMMATRIX proj;
};

struct PSConstantBuffer
{
    XMFLOAT4 color;
    XMMATRIX proj;
};

HWND ghMainWnd = 0;   // 窗口句柄


ComPtr<ID3D11Device> pd3dDevice = nullptr;                    // D3D11设备
ComPtr<ID3D11DeviceContext> pd3dDeviceContext = nullptr;      // D3D11设备上下文

DXGI_SWAP_CHAIN_DESC sd;
ComPtr<IDXGISwapChain> pSwapChain = nullptr;                  // D3D11交换链
ComPtr<IDXGIFactory1> dxgiFactory = nullptr;

//常用资源
ComPtr<ID3D11Texture2D> m_pDepthStencilBuffer = nullptr;        // 深度模板缓冲区
ComPtr<ID3D11RenderTargetView> m_pRenderTargetView = nullptr;   // 渲染目标视图
ComPtr<ID3D11DepthStencilView> m_pDepthStencilView = nullptr;   // 深度模板视图
D3D11_VIEWPORT m_ScreenViewport;                                // 视口

//着色器资源

ComPtr<ID3DBlob> vertexBlob;  // 顶点着色器
ComPtr<ID3DBlob> pixBlob;     //像素着色器


ComPtr<ID3D11InputLayout> pVertexLayout = nullptr;     // 顶点输入布局
ComPtr<ID3D11Buffer> pVertexBuffer = nullptr;          // 顶点缓冲区
ComPtr<ID3D11VertexShader> pVertexShader = nullptr;    // 顶点着色器
ComPtr<ID3D11PixelShader> pPixelShader = nullptr;      // 像素着色器
ComPtr<ID3D11Buffer> pIndexBuffer = nullptr;           // 索引缓冲区

ComPtr<ID3D11Buffer> pVSConstBuffer = nullptr;         // 顶点常量缓冲区
ComPtr<ID3D11Buffer> pPSConstBuffer = nullptr;         // 顶点常量缓冲区
VSConstantBuffer VSCBuffer;                           // 用于修改顶点GPU常量缓冲区的变量
PSConstantBuffer PSCBuffer;                           // 用于修改顶点GPU常量缓冲区的变量

创建窗口

/*************************************************创建窗口*************************************************/
/* 注意
* 1. 必须设置窗口事件处理回调函数 LRESULT  CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
* 2. 窗口的信息可以在 WNDCLASS 中设置,比如窗口的图标,标题等。
* 3. 调用CreateWindow创建窗口。
* 4. 创建完窗口,可以得到一个窗口句柄(HWND ghMainWnd),后面创建交换链会用到这个窗口句柄。
*/
// 窗口事件处理回调函数
LRESULT  CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 

{
    switch (msg)
    {
    case WM_LBUTTONDOWN:
        MessageBox(0, L"Hello,world!", L"Hello", MB_OK);
        return 0;
    case WM_KEYDOWN:
        if (wParam == VK_ESCAPE)
            DestroyWindow(ghMainWnd);
        return 0;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }

    return DefWindowProc(hWnd, msg, wParam, lParam);
}

//创建窗口函数
bool InitWindowsApp(HINSTANCE instanceHandle, int show) 
{
    WNDCLASS wc;
    wc.style = CS_HREDRAW | CS_VREDRAW;  // 水平或者垂直方向发生变化时,重新绘制 redraw
    wc.lpfnWndProc = WndProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = instanceHandle;
    wc.hIcon = LoadIcon(0, IDI_APPLICATION);
    wc.hCursor = LoadCursor(0,IDC_ARROW);
    wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    wc.lpszMenuName = 0;
    wc.lpszClassName = L"BasicWndClass";
   if (!RegisterClass(&wc))
    {
        MessageBox(0, L"RegisterClass FAILED", 0, 0);
        return false;
    }

    ghMainWnd = CreateWindow(
        L"BasicWndClass",
        L"Win32Basic",
        WS_OVERLAPPEDWINDOW,
        winX,
        winY,
        winWidth,
        winHeight,
        0,
        0,
        instanceHandle,
        0
    );
    if (ghMainWnd == 0)
    {
        MessageBox(0, L"CreateWindow FAILED", 0, 0);
        return false;
    }
    ShowWindow(ghMainWnd,show);
    UpdateWindow(ghMainWnd);
    return true;
}

DirectX 初始化

  • 创建设备和设备上下文
  • 创建Factory
  • 填充交换链描述符
  • 创建交换链
  • 创建渲染目标视图(窗口大小发生变化时)
  • 设置视口变换

创建设备和设备上下文

// 创建设备和设备上下文
bool createDirectDevice(){
    UINT createDeviceFlags = 0;
#if defined(DEBUG) || defined(_DEBUG)
    createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif

    // 驱动类型数组
    D3D_DRIVER_TYPE driverTypes[] =
    {
        D3D_DRIVER_TYPE_HARDWARE,   //硬件驱动
        //D3D_DRIVER_TYPE_WARP,       //WARP驱动
        D3D_DRIVER_TYPE_REFERENCE,  //软件驱动
    };
    UINT numDriverTypes = ARRAYSIZE(driverTypes);

      // 特性等级数组
    D3D_FEATURE_LEVEL featureLevels[] =
    {
        D3D_FEATURE_LEVEL_11_1,
        D3D_FEATURE_LEVEL_11_0,
    };
    UINT numFeatureLevels = ARRAYSIZE(featureLevels);

    D3D_FEATURE_LEVEL featureLevel;
    D3D_DRIVER_TYPE d3dDriverType;

    HRESULT hr;
        for (UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; driverTypeIndex++)
    {
        d3dDriverType = driverTypes[driverTypeIndex];
        hr = D3D11CreateDevice(nullptr, d3dDriverType, nullptr, createDeviceFlags, featureLevels, numFeatureLevels,
            D3D11_SDK_VERSION, pd3dDevice.GetAddressOf(), &featureLevel, pd3dDeviceContext.GetAddressOf());

        // 如果你的系统不支持Direct3D 11.1的API,D3D11CreateDevice会立即停止特性数组的轮询并返回E_INVALIDARG
              if (hr == E_INVALIDARG)
        {
            // Direct3D 11.0 的API不承认D3D_FEATURE_LEVEL_11_1,所以我们需要尝试特性等级11.0以及以下的版本
            hr = D3D11CreateDevice(nullptr, d3dDriverType, nullptr, createDeviceFlags, &featureLevels[1], numFeatureLevels - 1,
                D3D11_SDK_VERSION, pd3dDevice.GetAddressOf(), &featureLevel, pd3dDeviceContext.GetAddressOf());
        }

        if (SUCCEEDED(hr))
            break;
       if (FAILED(hr))
    {
        MessageBox(0, L"D3D11CreateDevice Failed.", 0, 0);
        return false;
    }
        // 检测是否支持特性等级11.0或11.1
    if (featureLevel != D3D_FEATURE_LEVEL_11_0 && featureLevel != D3D_FEATURE_LEVEL_11_1)
    {
        MessageBox(0, L"Direct3D Feature Level 11 unsupported.", 0, 0);
        return false;
    }
    return hr == S_OK;

创建Factroy

// 创建Factroy
bool createFactroy()
{
    //
    HRESULT hr;
    ComPtr<IDXGIDevice> dxgiDevice = nullptr;
    ComPtr<IDXGIAdapter> dxgiAdapter = nullptr;
    hr =  pd3dDevice.As(&dxgiDevice);
    dxgiDevice->GetAdapter(dxgiAdapter.GetAddressOf());
    dxgiAdapter->GetParent(__uuidof(IDXGIFactory1),reinterpret_cast<void**>(dxgiFactory.GetAddressOf()));

    return hr == S_OK;
}

填充交换链描述符

// 填充交换链描述符
bool initSwapChainDesc()
{

    HRESULT hr;

    ZeroMemory(&sd, sizeof(sd));
    sd.BufferCount = 1;
    sd.BufferDesc.Width = winWidth;
    sd.BufferDesc.Height = winHeight;
    sd.BufferDesc.RefreshRate.Numerator = 60;
    sd.BufferDesc.RefreshRate.Denominator = 1;
    sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    sd.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
    sd.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
    sd.SampleDe

创建交换链

// 创建交换链
bool createSwapChain()
{
    HRESULT hr;
    hr = dxgiFactory->CreateSwapChain(pd3dDevice.Get(),&sd,pSwapChain.GetAddressOf());
    return hr == S_OK;
}

创建渲染目标视图,设置视口大小

// 创建渲染目标视图,设置视口大小(窗口大小发生变化时重新创建)
void resizeWin()
{
    assert(pd3dDevice);
    assert(pd3dDeviceContext);
    assert(pSwapChain);

    m_pRenderTargetView.Reset();

    HRESULT hr;

    ComPtr<ID3D11Texture2D> backBuffer;
    hr = pSwapChain->ResizeBuffers(1,winWidth,winHeight,DXGI_FORMAT_R8G8B8A8_UNORM,0);
    hr = pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast<void**>(backBuffer.GetAddressOf()));
      hr = pd3dDevice->CreateRenderTargetView(backBuffer.Get(),nullptr,m_pRenderTargetView.GetAddressOf());

    backBuffer.Reset();

    pd3dDeviceContext->OMSetRenderTargets(1,m_pRenderTargetView.GetAddressOf(),nullptr);
    m_ScreenViewport.TopLeftX = 0.0f;
    m_ScreenViewport.TopLeftY = 0.0f;
    m_ScreenViewport.Width = static_cast<float>(winWidth);
    m_ScreenViewport.Height = static_cast<float>(winHeight);
    m_ScreenViewport.MinDepth = 0.0f;
    m_ScreenViewport.MaxDepth = 1.0f;
    pd3dDeviceContext->RSSetViewports(1,&m_ScreenViewport);

创建着色器

  • 编译顶点着色器到Blob,同时写入到cso文件,着色器若未修改,下次直接读取,不用编译。
  • 使用设备创建顶点着色器。
  • 编译像素着色器到Blob,同时写入到cso文件,着色器若未修改,下次直接读取,不用编译。
  • 使用设备创建像素着色器。
/*************************************************创建着色器*************************************************/
bool createShader()
{
    HRESULT hr;
    DWORD dwShaderFlags = D3DCOMPILE_ENABLE_STRICTNESS;
#ifdef _DEBUG
    // 设置 D3DCOMPILE_DEBUG 标志用于获取着色器调试信息。该标志可以提升调试体验,
    // 但仍然允许着色器进行优化操作
    dwShaderFlags |= D3DCOMPILE_DEBUG;

    // 在Debug环境下禁用优化以避免出现一些不合理的情况
    dwShaderFlags |= D3DCOMPILE_SKIP_OPTIMIZATION;
#endif
   //创建顶点着色器
    {
        hr = D3DCompileFromFile(L"C:\\Users\\MultiMediaServer\\Desktop\\learn\\\D3D11Learn\\HLSL\\D3D11Learn_VS.hlsl",
            nullptr, D3D_COMPILE_STANDARD_FILE_INCLUDE, "VS", "vs_5_0",
            dwShaderFlags, 0, vertexBlob.ReleaseAndGetAddressOf(), nullptr);

        // 若指定了输出文件名,则将着色器二进制信息输出
        hr = D3DWriteBlobToFile(vertexBlob.Get(), L"HLSL\\D3D11Learn_VS.cso", FALSE);
 		hr = pd3dDevice->CreateVertexShader(vertexBlob->GetBufferPointer(), vertexBlob->GetBufferSize(), nullptr, pVertexShader.GetAddressOf());
 	}
 	{
        hr = D3DCompileFromFile(L"C:\\Users\\MultiMediaServer\\Desktop\\learn\\\D3D11Learn\\HLSL\\D3D11Learn_PS.hlsl",
            nullptr, D3D_COMPILE_STANDARD_FILE_INCLUDE, "PS", "ps_5_0",
            dwShaderFlags, 0, pixBlob.ReleaseAndGetAddressOf(), nullptr);
                   // 若指定了输出文件名,则将着色器二进制信息输出
        hr = D3DWriteBlobToFile(pixBlob.Get(), L"HLSL\\D3D11Learn_PS.cso", FALSE);
        hr = pd3dDevice->CreatePixelShader(pixBlob->GetBufferPointer(),pixBlob->GetBufferSize(),nullptr,pPixelShader.GetAddressOf());
    }
       return hr == S_OK;
}

填充缓冲区并绑定到渲染管线

定义顶点数据结构体

创建顶点缓冲区、填充并绑定

创建索引缓冲区、填充并绑定

创建顶点常量缓冲区、填充并绑定

创建像素常量缓冲区、填充并绑定

设置图元类型

创建并绑定输入布局(也可以在创建完顶点着色器后立马创建)

将着色器和相应阶段的常量缓冲区绑定到渲染管线。

bool initResource()
{
    HRESULT hr;
    // 设置三角形顶点和颜色
    VertexPosColor vertices[] =
    {
        { XMFLOAT3(0.0f, 0.5f, 0.5f), XMFLOAT4(0.0f, 1.0f, 0.0f, 1.0f) },
        { XMFLOAT3(0.5f, -0.5f, 0.5f), XMFLOAT4(0.0f, 0.0f, 1.0f, 1.0f) },
        { XMFLOAT3(-0.5f, -0.5f, 0.5f), XMFLOAT4(1.0f, 0.0f, 0.0f, 1.0f) }
    };
    
    //设置顶点缓冲区描述
    D3D11_BUFFER_DESC vbd;
    ZeroMemory(&vbd,sizeof(vbd));
    vbd.Usage = D3D11_USAGE_IMMUTABLE;
    vbd.ByteWidth = sizeof(vertices);
    vbd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
    vbd.CPUAccessFlags = 0;
    
    // 创建顶点缓冲区
    D3D11_SUBRESOURCE_DATA initData;
    ZeroMemory(&initData, sizeof(initData));
    initData.pSysMem = vertices;
    hr = pd3dDevice->CreateBuffer(&vbd,&initData, pVertexBuffer.GetAddressOf());
    
    //绑定顶点缓冲区
    UINT stride = sizeof(VertexPosColor);   // 跨越字节数
    UINT offset = 0;                        // 起始偏移量
    pd3dDeviceContext->IASetVertexBuffers(0, 1, pVertexBuffer.GetAddressOf(), &stride, &offset);

   DWORD indices[] = {
        0, 1, 2,0
    };
    //设置索引缓冲区描述
    D3D11_BUFFER_DESC ibd;
    ZeroMemory(&ibd, sizeof(ibd));
    ibd.Usage = D3D11_USAGE_IMMUTABLE;
    ibd.ByteWidth = sizeof(indices);
    ibd.BindFlags = D3D11_BIND_INDEX_BUFFER;
    ibd.CPUAccessFlags = 0;
    initData.pSysMem = indices; // D3D11_SUBRESOURCE_DATA 
    
    // 新建索引缓冲区
    hr = pd3dDevice->CreateBuffer(&ibd, &initData, pIndexBuffer.GetAddressOf());
    pd3dDeviceContext->IASetIndexBuffer(pIndexBuffer.Get(), DXGI_FORMAT_R32_UINT,0);
    
	/****************************常量缓冲区***********************************/
    //设置顶点常量缓冲区描述
    D3D11_BUFFER_DESC cbd;
    ZeroMemory(&cbd, sizeof(cbd));
    cbd.Usage = D3D11_USAGE_DYNAMIC;
    cbd.ByteWidth = sizeof(VSConstantBuffer);
    cbd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
    cbd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
    
    //创建顶点常量缓冲区
    hr = pd3dDevice->CreateBuffer(&cbd,nullptr,pVSConstBuffer.GetAddressOf());
    VSCBuffer.world = XMMatrixTranspose(XMMatrixTranslation(0.4, 0.0, 0.0));
    VSCBuffer.view = XMMatrixIdentity();
    VSCBuffer.proj = XMMatrixIdentity();

    //填充顶点常量缓冲区
  	VSCBuffer.world = XMMatrixTranspose(XMMatrixTranslation(0.4, 0.0, 0.0));
    VSCBuffer.view = XMMatrixIdentity();
    VSCBuffer.proj = XMMatrixIdentity();

    D3D11_MAPPED_SUBRESOURCE mappedData;
    hr = pd3dDeviceContext->Map(pVSConstBuffer.Get(),0, D3D11_MAP_WRITE_DISCARD,0,&mappedData);
    memcpy_s(mappedData.pData, sizeof(VSCBuffer), &VSCBuffer, sizeof(VSCBuffer));
    pd3dDeviceContext->Unmap(pVSConstBuffer.Get(), 0);

     //设置像素常量缓冲区描述
    D3D11_BUFFER_DESC cbd1;
    ZeroMemory(&cbd1, sizeof(cbd1));
    cbd1.Usage = D3D11_USAGE_DYNAMIC;
    cbd1.ByteWidth = sizeof(PSConstantBuffer);
    cbd1.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
    cbd1.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;

    //创建像素常量缓冲区
    hr = pd3dDevice->CreateBuffer(&cbd,nullptr,pPSConstBuffer.GetAddressOf());

    
    //填充像素常量缓冲区
    PSCBuffer.color = XMFLOAT4(1.0, 0.0, 0.0, 1.0);
    PSCBuffer.proj = XMMatrixIdentity();
    D3D11_MAPPED_SUBRESOURCE mappedData1;
    hr = pd3dDeviceContext->Map(pPSConstBuffer.Get(),0, D3D11_MAP_WRITE_DISCARD,0,&mappedData1);
    memcpy_s(mappedData1.pData, sizeof(PSCBuffer), &PSCBuffer, sizeof(PSCBuffer));
    pd3dDeviceContext->Unmap(pPSConstBuffer.Get(), 0);
    
    //创建输入布局并绑定
     pd3dDevice->CreateInputLayout(VertexPosColor::inputLayout, ARRAYSIZE(VertexPosColor::inputLayout),  vertexBlob->GetBufferPointer(), vertexBlob->GetBufferSize(), pVertexLayout.GetAddressOf());
    pd3dDeviceContext->IASetInputLayout(pVertexLayout.Get());
    
    //设置图元类型
    pd3dDeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);

    // 将着色器绑定到渲染管线
    pd3dDeviceContext->VSSetShader(pVertexShader.Get(), nullptr, 0);
    pd3dDeviceContext->VSSetConstantBuffers(0, 1, pVSConstBuffer.GetAddressOf());
    pd3dDeviceContext->PSSetShader(pPixelShader.Get(), nullptr, 0);
    pd3dDeviceContext->PSSetConstantBuffers(1, 1, pPSConstBuffer.GetAddressOf());
    
    return hr == S_OK;
}

渲染

int Run()
{
    MSG msg = { 0 };
    BOOL bRet = 1;
    assert(pd3dDeviceContext);
    assert(pSwapChain);
    while ((bRet = GetMessage(&msg,0,0,0)) != 0)
    {
        static float black[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
        pd3dDeviceContext->ClearRenderTargetView(m_pRenderTargetView.Get(), black);
        pd3dDeviceContext->DrawIndexed(3, 0, 0);
        pSwapChain->Present(1, 0);
    }
	return (int)msg.wParam;
}

主函数调用所有流程

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR pCmdLine, int nCmdShow)
{
    if (!InitWindowsApp(hInstance, nCmdShow))
        return 0;

    bool b = createDirectDevice();
    b = createFactroy();
    b = initSwapChainDesc();
    b = createSwapChain();
    resizeWin();
    b = createShader();
    b = initResource();
    return Run();
}

着色器代码

头文件

cbuffer VSConstantBuffer : register(b0)
{
    matrix g_World;
    matrix g_View;
    matrix g_Proj;
}

cbuffer PSConstantBuffer : register(b1)
{
    float4 g_color;
    matrix temp;
}
struct VertexIn
{
    float3 pos : POSITION;
};
struct VertexOut
{
    float4 pos : SV_POSITION;
};

像素着色器

#include "D3D11Learn.hlsli"


float4 PS() : SV_Target
{
    return g_color;
}

// 顶点着色器

#include "D3D11Learn.hlsli"
VertexOut VS(VertexIn vIn)
{
    VertexOut vOut;
    vOut.pos = mul(float4(vIn.pos, 1.0f), g_World);
    vOut.pos = mul(vOut.pos, g_View);
    vOut.pos = mul(vOut.pos, g_Proj);
    //vOut.pos = float4(vIn.pos, 1.0f);
    return vOut;
}