Lesson 11: 绘制三角形

DirectX11 顶点和顶点布局 顶点和顶点布局 1. 如何描述顶点? 5.5.1节已经讲过,在Direct3D中,顶点由空间位置和各种附加属性组成,Direct3D可以让我们灵活地建立属于我们自己的顶点格式;换句话说,它允许我们定义顶点的分量。要创建一个自定义的顶点格式,我们必须先创建一个包含顶点数据的结构体。例如,下面是两种不同类型的顶点格式;一个由位置和颜色组成,另一个由位置、法线和纹理坐标组成。struct Vertex 阅读详情

原文地址:
http://www.directxtutorial.com/Lesson.aspx?lessonid=11-4-5

一个三角形由三个点组成,也可以叫做顶点。用一个顶点数组来定义一个三角形,为了GPU能够渲染这个三角形,我们必须告诉GPU三角形的三个顶点的坐标。

顶点缓存:
在Direct3D 11中,向顶点信息(如坐标)叫保存在一个缓冲区资源内。如果一个缓冲区用来存放顶点信息,那么它就叫做顶点缓冲区。我们必须创建一个足够大的顶点缓冲区来保存者三个顶点坐标。在Direct3D 11中,创建一个顶点缓冲区必须指定大小(以byte为单位)。我们知道这个缓冲区有足够的空间来存放这个顶点,但是每个顶点有多少byte呢?回答好这个问题之前,我们需要知道顶点格式。

一个顶点有一个坐标信息。但通常不仅仅只有顶点信息,它也可能有其他的属性。比如:向量,多个的颜色,纹理坐标等等。顶点格式将定义这些属性在内存中如何存放:每个数据属性的用法,每个数据属性的大小,还有属性之间的排列。由于属性通常有不同的类型,类似于C中的结构体,一个顶点通常用一个结构体表示。可以方便地根据一个结构体的大小来获取顶点的大小。

struct VERTEX
{
      FLOAT X, Y, Z;      // position
      D3DXCOLOR Color;    // color
};

现在我们有一个结构体来表示我们的顶点。在应用程序中要保存好这些顶点信息。然而,当我们需要GPU渲染包含这些顶点的顶点缓冲区的时候,我们要将它填入一个内存块中。GPU也必须知道顶点格式,以便于从缓冲区中提取顶点信息。完成这个需要了解input layout。

Input Layout:
在Direct3D 11中,Input Layout是Direct3D对象,它能以一种GPU能够理解的方式来描述顶点结构体。每个顶点属性能够用D3D11_INPUT_ELEMENT_DESC结构体来描述。一个应用程序定义一个或多个的D3D11_INPUT_ELEMENT_DESC 结构体数组。使用这些数组来创建Input Layout对象来描述顶点。

D3D11_INPUT_ELEMENT_DESC结构体细节如下:

typedef struct D3D11_INPUT_ELEMENT_DESC    {
    LPCSTR SemanticName;
    UINT SemanticIndex;
    DXGI_FORMAT Format;
    UINT InputSlot;
    UINT AlignedByteOffset;
    D3D11_INPUT_CLASSIFICATION InputSlotClass;
    UINT InstanceDataStepRate;
    }     D3D11_INPUT_ELEMENT_DESC;

Semantic Name是一个用来描述属性的字符串。这个字符串表示一个单词,这个单词可以使用C能够定义的任何格式。比如用于描述顶点坐标可以使用“POSITION”字符串。
Semantic Index,这个用来描述索引,当SemanticName相同的情况下就可以使用索引来描述到底哪个才是当前需要的。因为一个顶点可能包含多个颜色,或纹理坐标等等,例如多个颜色可以使用如COLOR0,COLOR1来描述,也可以都是用COLOR来描述,使用0和1来填充SemanticIndex。
Format描述这个数据的数据类型。目前,DXGI_FORMAT_R32G32B32_FLOAT数据格式有3个32位的浮点数,使这个元素有12字节大小。DXGI_FORMAT_R16G16B16A16_UINT有4个16字节无符号整型数,使这个元素8字节大小。
InputSlot,输入槽,在前面提到过的,每一个顶点信息都通过一个Vertex Buffer输入让GPU识别,在Direct 3D 11中多个顶点信息可以同时的输入,最多可以有16个,这样就需要让GPU知道当前将使用哪个Vertex Buffer信息,也就是这个值将在0到15之间了。
AlignedByteOffset,内存偏移量,告诉GPU当前缓存内存起始偏移量。
InputSlotClass,这个一般使用D3D11_INPUT_PER_VERTEX_DATA来填充,当使用实例数据类型时,将使用D3D11_INPUT_PER_INSTANCE_DATA,这个是比较高级的或许在我们以后的学习当中会遇到,这里我们不大清楚,就先放过。
InstanceDataStepRate, 这个用于Instancing,既然我们没有使用Instancing,InstanceDataStepRate没有被用到,所以必须设置为0。

现在我们能够定义我们的D3D11_INPUT_ELEMENT_DESC数组并且创建input layout:

D3D11_INPUT_ELEMENT_DESC ied[] =
{
    {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
    {"COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0},
};

接下来通过ID3D11Device::CreateInputLayout()方法来创建我们的Vertex Layout对象。
函数原型如下:

HRESULT CreateInputLayout(
    D3D11_INPUT_ELEMENT_DESC *pInputElementDescs,
    UINT NumElements,
    void *pShaderBytecodeWithInputSignature,
    SIZE_T BytecodeLength,
    ID3D11InputLayout **pInputLayout);

D3D11_INPUT_ELEMENT_DESC *pInputElementDescs,
输入元素描述数组的指针,例如这里我们是ied数组,传入的是它的地址。

UINT NumElements,
这个数组里元素的数量,这里是2。

void *pShaderBytecodeWithInputSignature,
流水线中第一个着色器的指针,也就是顶点着色器。我们通过调用GetBufferPointer()函数来获得。

SIZE_T BytecodeLength,
着色器文件的字节长度,我们通过调用GetBufferSize()函数来获得。

ID3D11InputLayout **pInputLayout
Input Layout的COM接口指针。

最后,我们完成创建之后,需要调用IASetInputLayout()函数对它进行激活,唯一参数是Input Layout接口。

所以整个初始化流水线函数修改如下:

void InitPipeline()
{
    // load and compile the two shaders
    ID3D10Blob *VS, *PS;
    D3DX11CompileFromFile(L"shaders.shader", 0, 0, "VShader", "vs_4_0", 0, 0, 0, &VS, 0, 0);
    D3DX11CompileFromFile(L"shaders.shader", 0, 0, "PShader", "ps_4_0", 0, 0, 0, &PS, 0, 0);

    // encapsulate both shaders into shader objects
    dev->CreateVertexShader(VS->GetBufferPointer(), VS->GetBufferSize(), NULL, &pVS);
    dev->CreatePixelShader(PS->GetBufferPointer(), PS->GetBufferSize(), NULL, &pPS);

    // set the shader objects
    devcon->VSSetShader(pVS, 0, 0);
    devcon->PSSetShader(pPS, 0, 0);

    // create the input layout object
    D3D11_INPUT_ELEMENT_DESC ied[] =
    {
        {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
        {"COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0},
    };

    dev->CreateInputLayout(ied, 2, VS->GetBufferPointer(), VS->GetBufferSize(), &pLayout);
    devcon->IASetInputLayout(pLayout);
}

创建顶点缓存:
知道了上面的内容我们还需要做一件事,在初始化时我们必须创建一个Vertex Buffer并且承载了这个顶点的数据信息。
为了创建Vertex Buffer,必须填充两个结构D3D11_BUFFER_DESC和D3D11_SUBRESOURCE_DATA,然后使用ID3D11Device::CreateBuffer()方法进行创建。
D3D11_BUFFER_DESC结构对Vertex Buffer要创建的内容对象进行描述,而D3D11_SUBRESOURCE_DATA则是包含了具体的数据信息,这些数据信息在创建时会进行拷贝。创建缓存和初始化是在同一时间完成的,在创建后我们可以使用ID3D11DeviceContext::IASetVertexBuffers()方法将其绑定到设备中,那样我们就可以在屏幕上呈现出来了。

Vertex Buffer in Video Memory When Needed
这里写图片描述

填充D3D11_BUFFER_DESC结构体:

ID3D11Buffer *pVBuffer;    // global

D3D11_BUFFER_DESC bd;
ZeroMemory(&bd, sizeof(bd));

bd.Usage = D3D11_USAGE_DYNAMIC;                // write access access by CPU and GPU
bd.ByteWidth = sizeof(VERTEX) * 3;             // size is the VERTEX struct * 3
bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;       // use as a vertex buffer
bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;    // allow CPU to write in buffer

dev->CreateBuffer(&bd, NULL, &pVBuffer);       // create the buffer

bd.Usage:
为了有效地设置缓存,Direct3D必须知道我们对CPU和GPU的使用权。
可有以下参数选择:
这里写图片描述

bd.ByteWidth:
创建的缓冲区的大小。

bd.BindFlags:
绑定标识,用于告诉Direct3D我们打算使用的缓冲区种类。

bd.CPUAccessFlags:
CPU使用权标识,可选D3D11_CPU_ACCESS_WRITE 和D3D11_CPU_ACCESS_READ。这里我们需要在系统内存中拷贝数据到缓冲区中,所以我们选用前者。

dev->CreateBuffer(&bd, NULL, &pVBuffer);
通过设备调用CreateBuffer()函数完成缓冲区的创建。
第一个参数是描述结构体的地址。
第二个参数用于使用特定格式来初始化内存。
第三个参数是缓冲区对象的地址。

通过映射来填充顶点缓存:
Map是CPU和GPU沟通的桥梁。

D3D11_MAPPED_SUBRESOURCE ms;
devcon->Map(pVBuffer, NULL, D3D11_MAP_WRITE_DISCARD, NULL, &ms);   // map the buffer
memcpy(ms.pData, OurVertices, sizeof(OurVertices));                // copy the data
devcon->Unmap(pVBuffer, NULL);                                     // unmap the buffer

D3D11_MAPPED_SUBRESOURCE ms;
这个结构体用于返回描述填充缓冲区的信息。
这个结构体原型:

typedef struct D3D11_MAPPED_SUBRESOURCE
    {
    void *pData;
    UINT RowPitch;
    UINT DepthPitch;
    }  D3D11_MAPPED_SUBRESOURCE;

devcon->Map()
第一个参数是缓冲区的地址。
第二个参数,UINT Subresource。暂且设为NULL。
第三个参数,当映射时我们允许CPU控制的使用权。可有下列参数选择:
这里写图片描述
第四个参数是一个标识,在NULL或者D3D11_MAP_FLAG_DO_NOT_WAIT中进行选择。它强制程序运行,即使是GPU仍在对缓冲区进行工作中。
第五个参数是D3D11_MAPPED_SUBRESOURCE结构体的地址,它将返回我们所需要的信息。

memcpy()
复制所需要的信息
ms.pData作为目标,OurVertices作为内容,以及sizeof(OurVertices)作为大小

devcon->Unmap()
解映射,使得GPU重新获取对该resouce的读写权。
第一个参数是缓冲区。
第二个参数是UINT Subresource。

设置顶点缓存:
IASetVertexBuffers函数原型如下:

void IASetVertexBuffers(UINT StartSlot,
                        UINT NumBuffers,
                        ID3D11Buffer **ppVertexBuffers,
                        UINT *pStrides,
                        UINT *pOffsets);

第一个参数是要进行绑定的buff 索引, 因为 buffer 会有很多个, 这里需要进行指定。
第二个参数是指上述的 buffer 个数;
第三个参数就是存储这些buffer的地方;
第四个参数是指向步值数组的指针。每个步值就是顶点缓存中被使用的元素的大小(用字节表示)。
第五个参数是指向偏移值数组的指针。每个偏移值就是顶点缓存中第一个元素和第一个被使用的元素之间的字节数。

这个函数就像这样解释:

UINT stride = sizeof(VERTEX);
UINT offset = 0;
devcon->IASetVertexBuffers(0, 1, &pBuffer, &stride, &offset);

IAsetPrimitiveTopology():
这个函数仅仅有一个参数,用于告诉 Direct3D 采用哪种方式渲染几何体。

可用方式有如下:
这里写图片描述

它在设备上下文中进行调用:
devcon->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

接下来,就在后台缓冲区中进行绘制:

//通过设备上下文调用Draw()函数
devcon->Draw(3, 0);    // draw 3 vertices, starting from vertex 0

函数原型如下:

void Draw(UINT VertexCount,             // the number of vertices to be drawn
          UINT StartVertexLocation);    // the first vertex to be drawn

我们知道,整个绘制工作是在渲染框架中完成的,所以这个函数修改如下:

// this is the function used to render a single frame
void RenderFrame(void)
{
    // clear the back buffer to a deep blue
    devcon->ClearRenderTargetView(backbuffer, D3DXCOLOR(0.0f, 0.2f, 0.4f, 1.0f));

        // select which vertex buffer to display
        UINT stride = sizeof(VERTEX);
        UINT offset = 0;
        devcon->IASetVertexBuffers(0, 1, &pVBuffer, &stride, &offset);

        // select which primtive type we are using
        devcon->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

        // draw the vertex buffer to the back buffer
        devcon->Draw(3, 0);

    // switch the back buffer and the front buffer
    swapchain->Present(0, 0);
}

整个流程快速复习:
1.使用着色器:

  1. Loaded and compiled the two shaders
  2. Created objects for each one.
  3. Set the two objects.

2.顶点缓存:

  1. Created three vertices with both position and color.
  2. Created a vertex buffer object.
  3. Copied the vertices into the vertex buffer by mapping it, copying the data, and unmapping it.

3.验证Input Layout:

  1. Created input element descriptions for the position and the color.
  2. Created an input layout object using the shader information.
  3. Set the input layout object.

4.简单绘制:

  1. Set which vertex buffer to use (there was only one to choose from).
  2. Set which primitive type to use.
  3. Draw the triangle.

完整代码:
main.cpp:

// include the basic windows header files and the Direct3D header files
#include <windows.h>
#include <windowsx.h>
#include <d3d11.h>
#include <d3dx11.h>
#include <d3dx10.h>

// include the Direct3D Library file
#pragma comment (lib, "d3d11.lib")
#pragma comment (lib, "d3dx11.lib")
#pragma comment (lib, "d3dx10.lib")

// define the screen resolution
#define SCREEN_WIDTH  800
#define SCREEN_HEIGHT 600

// global declarations
IDXGISwapChain *swapchain;             // the pointer to the swap chain interface
ID3D11Device *dev;                     // the pointer to our Direct3D device interface
ID3D11DeviceContext *devcon;           // the pointer to our Direct3D device context
ID3D11RenderTargetView *backbuffer;    // the pointer to our back buffer
ID3D11InputLayout *pLayout;            // the pointer to the input layout
ID3D11VertexShader *pVS;               // the pointer to the vertex shader
ID3D11PixelShader *pPS;                // the pointer to the pixel shader
ID3D11Buffer *pVBuffer;                // the pointer to the vertex buffer

// a struct to define a single vertex
struct VERTEX{FLOAT X, Y, Z; D3DXCOLOR Color;};

// function prototypes
void InitD3D(HWND hWnd);    // sets up and initializes Direct3D
void RenderFrame(void);     // renders a single frame
void CleanD3D(void);        // closes Direct3D and releases memory
void InitGraphics(void);    // creates the shape to render
void InitPipeline(void);    // loads and prepares the shaders

// the WindowProc function prototype
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);


// the entry point for any Windows program
int WINAPI WinMain(HINSTANCE hInstance,
                   HINSTANCE hPrevInstance,
                   LPSTR lpCmdLine,
                   int nCmdShow)
{
    HWND hWnd;
    WNDCLASSEX wc;

    ZeroMemory(&wc, sizeof(WNDCLASSEX));

    wc.cbSize = sizeof(WNDCLASSEX);
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = WindowProc;
    wc.hInstance = hInstance;
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.lpszClassName = L"WindowClass";

    RegisterClassEx(&wc);

    RECT wr = {0, 0, SCREEN_WIDTH, SCREEN_HEIGHT};
    AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE);

    hWnd = CreateWindowEx(NULL,
                          L"WindowClass",
                          L"Our First Direct3D Program",
                          WS_OVERLAPPEDWINDOW,
                          300,
                          300,
                          wr.right - wr.left,
                          wr.bottom - wr.top,
                          NULL,
                          NULL,
                          hInstance,
                          NULL);

    ShowWindow(hWnd, nCmdShow);

    // set up and initialize Direct3D
    InitD3D(hWnd);

    // enter the main loop:

    MSG msg;

    while(TRUE)
    {
        if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);

            if(msg.message == WM_QUIT)
                break;
        }

        RenderFrame();
    }

    // clean up DirectX and COM
    CleanD3D();

    return msg.wParam;
}


// this is the main message handler for the program
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch(message)
    {
        case WM_DESTROY:
            {
                PostQuitMessage(0);
                return 0;
            } break;
    }

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


// this function initializes and prepares Direct3D for use
void InitD3D(HWND hWnd)
{
    // create a struct to hold information about the swap chain
    DXGI_SWAP_CHAIN_DESC scd;

    // clear out the struct for use
    ZeroMemory(&scd, sizeof(DXGI_SWAP_CHAIN_DESC));

    // fill the swap chain description struct
    scd.BufferCount = 1;                                   // one back buffer
    scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;    // use 32-bit color
    scd.BufferDesc.Width = SCREEN_WIDTH;                   // set the back buffer width
    scd.BufferDesc.Height = SCREEN_HEIGHT;                 // set the back buffer height
    scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;     // how swap chain is to be used
    scd.OutputWindow = hWnd;                               // the window to be used
    scd.SampleDesc.Count = 4;                              // how many multisamples
    scd.Windowed = TRUE;                                   // windowed/full-screen mode
    scd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;    // allow full-screen switching

    // create a device, device context and swap chain using the information in the scd struct
    D3D11CreateDeviceAndSwapChain(NULL,
                                  D3D_DRIVER_TYPE_HARDWARE,
                                  NULL,
                                  NULL,
                                  NULL,
                                  NULL,
                                  D3D11_SDK_VERSION,
                                  &scd,
                                  &swapchain,
                                  &dev,
                                  NULL,
                                  &devcon);


    // get the address of the back buffer
    ID3D11Texture2D *pBackBuffer;
    swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);

    // use the back buffer address to create the render target
    dev->CreateRenderTargetView(pBackBuffer, NULL, &backbuffer);
    pBackBuffer->Release();

    // set the render target as the back buffer
    devcon->OMSetRenderTargets(1, &backbuffer, NULL);


    // Set the viewport
    D3D11_VIEWPORT viewport;
    ZeroMemory(&viewport, sizeof(D3D11_VIEWPORT));

    viewport.TopLeftX = 0;
    viewport.TopLeftY = 0;
    viewport.Width = SCREEN_WIDTH;
    viewport.Height = SCREEN_HEIGHT;

    devcon->RSSetViewports(1, &viewport);

    InitPipeline();
    InitGraphics();
}


// this is the function used to render a single frame
void RenderFrame(void)
{
    // clear the back buffer to a deep blue
    devcon->ClearRenderTargetView(backbuffer, D3DXCOLOR(0.0f, 0.2f, 0.4f, 1.0f));

        // select which vertex buffer to display
        UINT stride = sizeof(VERTEX);
        UINT offset = 0;
        devcon->IASetVertexBuffers(0, 1, &pVBuffer, &stride, &offset);

        // select which primtive type we are using
        devcon->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

        // draw the vertex buffer to the back buffer
        devcon->Draw(3, 0);

    // switch the back buffer and the front buffer
    swapchain->Present(0, 0);
}


// this is the function that cleans up Direct3D and COM
void CleanD3D(void)
{
    swapchain->SetFullscreenState(FALSE, NULL);    // switch to windowed mode

    // close and release all existing COM objects
    pLayout->Release();
    pVS->Release();
    pPS->Release();
    pVBuffer->Release();
    swapchain->Release();
    backbuffer->Release();
    dev->Release();
    devcon->Release();
}


// this is the function that creates the shape to render
void InitGraphics()
{
    // create a triangle using the VERTEX struct
    VERTEX OurVertices[] =
    {
        {0.0f, 0.5f, 0.0f, D3DXCOLOR(1.0f, 0.0f, 0.0f, 1.0f)},
        {0.45f, -0.5, 0.0f, D3DXCOLOR(0.0f, 1.0f, 0.0f, 1.0f)},
        {-0.45f, -0.5f, 0.0f, D3DXCOLOR(0.0f, 0.0f, 1.0f, 1.0f)}
    };


    // create the vertex buffer
    D3D11_BUFFER_DESC bd;
    ZeroMemory(&bd, sizeof(bd));

    bd.Usage = D3D11_USAGE_DYNAMIC;                // write access access by CPU and GPU
    bd.ByteWidth = sizeof(VERTEX) * 3;             // size is the VERTEX struct * 3
    bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;       // use as a vertex buffer
    bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;    // allow CPU to write in buffer

    dev->CreateBuffer(&bd, NULL, &pVBuffer);       // create the buffer


    // copy the vertices into the buffer
    D3D11_MAPPED_SUBRESOURCE ms;
    devcon->Map(pVBuffer, NULL, D3D11_MAP_WRITE_DISCARD, NULL, &ms);    // map the buffer
    memcpy(ms.pData, OurVertices, sizeof(OurVertices));                 // copy the data
    devcon->Unmap(pVBuffer, NULL);                                      // unmap the buffer
}


// this function loads and prepares the shaders
void InitPipeline()
{
    // load and compile the two shaders
    ID3D10Blob *VS, *PS;
    D3DX11CompileFromFile(L"shaders.shader", 0, 0, "VShader", "vs_4_0", 0, 0, 0, &VS, 0, 0);
    D3DX11CompileFromFile(L"shaders.shader", 0, 0, "PShader", "ps_4_0", 0, 0, 0, &PS, 0, 0);

    // encapsulate both shaders into shader objects
    dev->CreateVertexShader(VS->GetBufferPointer(), VS->GetBufferSize(), NULL, &pVS);
    dev->CreatePixelShader(PS->GetBufferPointer(), PS->GetBufferSize(), NULL, &pPS);

    // set the shader objects
    devcon->VSSetShader(pVS, 0, 0);
    devcon->PSSetShader(pPS, 0, 0);

    // create the input layout object
    D3D11_INPUT_ELEMENT_DESC ied[] =
    {
        {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
        {"COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0},
    };

    dev->CreateInputLayout(ied, 2, VS->GetBufferPointer(), VS->GetBufferSize(), &pLayout);
    devcon->IASetInputLayout(pLayout);
}

着色器shaders.shader:

struct VOut
{
    float4 position : SV_POSITION;
    float4 color : COLOR;
};

VOut VShader(float4 position : POSITION, float4 color : COLOR)
{
    VOut output;

    output.position = position;
    output.color = color;

    return output;
}


float4 PShader(float4 position : SV_POSITION, float4 color : COLOR) : SV_TARGET
{
    return color;
}

整个工程应该是这样的:
这里写图片描述

DirectX11 纹理坐标 纹理坐标1. 纹理坐标是什么?Direct3D的纹理坐标系由表示图像水平方向的u轴和表示图像垂直方向的v轴组成。坐标(u,v)指定了纹理上的一个元素,我们将该元素称为纹理元素(texel,译者注:texel是texture element的缩写),其中0≤u,v≤1。注意,v轴的正方向是“垂直向下”的(参见图8.2)。另外,将规范化坐标区间设为[0,1],是因为这样可以使 Direct3D拥有一个独 阅读详情

相关推荐

Lesson 14: SDK文档:Tutorial02 Rendering a Triangle分析

结构体声明:// Structures struct SimpleVertex { D3DXVECTOR3 Pos; };全局变量声明:// Global Variables HINSTANCE g_hInst = NULL; //实例句柄 HWND g_hWnd = NULL; //窗口句柄 D3D10_DRIVER_TY

Nim的辙迹 587

DX11(十五):输入布局一致性

输入布局中的注意点,如何保持一致性,和区分相同的语义名

weixin_44200074的博客 749

Windows下VSCode配置C/C++开发环境:MinGW-w64与GDB调试全攻略

在Windows平台上搭建C/C++开发环境,是许多初学者迈入编程世界的第一步。常见的方案包括使用Visual Studio、CLion或Visual Studio Code,其中VSCode凭借轻量、免费、插件生态丰富等优势,成为算法竞赛、考研复试和课程设计的热门选择。然而,VSCode本身并不包含编译器,需要配合MinGW-w64提供的GCC/G++工具链,以及GDB调试器,才能真正实现从源码编写、编译到断点调试的完整流程。环境变量配置、tasks.json和launch.json的编写,以及常见报错如

weixin_34130389的博客 383

D3d10和D3d11中Map()函数用法一点心得总结

Directx10和Directx11很多resource类都有个Map()函数,个人感觉它是一个蛮重要的CPU和GPU沟通桥梁。下面以ID3D11DeviceContext::Map()为例讲下。   ID3D11DeviceContext::Map官方解释是:ID3D11D

算法,时空数据挖掘 5679

特斯拉AI工程实践:从物理世界建模到量产级MLOps

人工智能在真实工业场景中的落地,本质是将算法能力与物理规律、硬件约束和业务流程深度耦合的过程。其核心原理在于用可解释的混合架构替代黑箱模型,以仿真为数据生成器、以专用芯片保障确定性延迟、以任务间物理关系指导多任务学习。这种工程范式显著提升系统鲁棒性、降低误报率并加速迭代周期,广泛适用于自动驾驶、工业质检、电力巡检等对安全性、实时性和可维护性要求严苛的领域。本文深入拆解特斯拉AI团队如何把‘AI量产’从口号转化为可测量、可复制、可优化的产线级实践,涵盖HydraNets特征拓扑设计、Dojo芯片存算一体架构、

weixin_34109408的博客 410

D3D11 Cube Mapping示例程序

d3d11中通过cube mapping实现天空盒效果。包含全部源代码及可执行程序。 操作方法:通过鼠标左键旋转镜头。

DirectX学习 Tutorial 2

这个例子是展示如何渲染个三角形。 首先提到了一个概念顶点缓冲区,顾名思义专门用来存储顶点的缓冲区,要表示一个三角形则需要存储三个顶点。 顶点有很多属性,如法线,颜色等等。顶点的布局取决于它的属性如何放在内存里,顶点通常由一个struct表示。 struct SimpleVertex { XMFLOAT3 Pos; // Position }; 现在我们可以用这个结构来表示顶点。...

victorika的博客 365

国产安全芯片在密码算法国密体系下的性能适配策略

国密体系即国家商用密码体系,是保障信息安全的核心技术体系。自20世纪90年代末起步,国密体系经历了从无到有、从弱到强的发展历程。1999年,国家密码管理局成立,标志着国密体系的正式建立。2000年,国密SM1算法首次发布,开启了国密算法的标准化进程。此后,SM2、SM3、SM4等算法陆续推出,形成了完整的对称与非对称密码算法体系。:2010年,国密标准正式纳入国家标准体系,国密算法在金融、政务、通信等关键领域的应用得到明确规范。

qq_40552871的博客 1356

【DirecX 教程】Lesson 10:绘制一个三角形

Lesson 10:绘制一个三角形 课程一览

Purplenigma的专栏 1192

[Linux项目实践] LCD Panel的硬件分析及调试

LCD硬件分析 项目使用3.5” TFT-LCD并且支持触摸控制。LCD的硬件可从几个方面学习:1)查看LCD的硬件连线。2)查看数据手册了解寄存器的控制。3)查看LCD DATASHEET了解硬件操作 1)LCD硬件连线 在图中有33个引脚,22根数据引脚和9根控制引脚。 LCD的工作原理:像素点是从左至右,从上至下逐个显示,LCD控制寄存器会从从内存中的framebuffer通

Terry_Yuan的技术专栏 3024

AXI_IIC读写操作

其实在之前调试过一次AXI_IIC,没调试通,碍于赶进度,就直接使用了zynq-PS侧的IIC,就一直搁置着了,这次抽空将这部分内容继续调试下去,这一次没花多少时间就调通了,现在将我的调试过程,经历,以及参考文档如下: 参考文档:pg090-axi-iic.pdf 参考链接:https://forums.xilinx.com/t5/Design-and-Debug-Techniques-Blog/IIC-Protocol-and-Programming-Sequence/ba-p/1072248 上面的这个

qq_32134427的博客 1万+

C语言刷题——lesson8

1. BC72-平均身高 题目描述 从键盘输入5个人的身高(米),求他们的平均身高(米)。 输入描述: 一行,连续输入5个身高(范围0.00~2.00),用空格分隔。 输出描述: 一行,输出平均身高,保留两位小数。 示例1 输入 1.68 1.75 1.82 1.60 1.92 输出 1.75 参考代码: #include <stdio.h> int main() { int i = 0; double score = 0.0; double sum = 0.0;

fh_1998的博客 503

论文阅读笔记---Deep HDR Video from Sequences with Alternating Exposures

Kalantari N K, Ramamoorthi R. Deep HDR Video from Sequences with Alternating Exposures[C]//Computer Graphics Forum. 2019, 38(2): 193-205. 摘要: 在本文中,提出了一种基于学习的方法来,我们使用两个顺序卷积神经网络(CNN)对整个HDR视频重建过程进...

qq_25283239的博客 1447

Lesson 10: 着色器

原文地址: http://blog.youkuaiyun.com/sinat_24229853/article/details/46941927 Direct3D要求使用着色器来渲染几何图形,为了解着色器的由来,我们首先要了解下图形流水线的历史。 图形流水线是什么? 图形流水线是GPU(图形处理器,显卡的心脏)工作的通用模型。它以某种形式表示的三维场景或物体为输入,输出二维的光栅化图像到显示器。 光

Nim的辙迹 730

f2fs学习笔记 - 3. F2FS文件系统布局

目录1.前言2.F2FS布局说明2.1. super block(block 0x0 ~ block 0x1ff)2.2 CP(block 0x200 ~ block 0x5ff)cp page1nat journalsit journaldata summarycurrent hot node summarycurrent warm node summarycurrent cold node summarycp page22nd checkpoint2.3 SIT(block 0x600 ~ block

HZero 4645

VSCode CMake 安装与配置详解

概述 在windows上使用cmake编译C/C++程序时,首先需要CMake,安装gcc/g++编译环境,然后使用VSCode 以及配置下CMakelist.txt。 所需工具: VSCode (需要安装以下插件) C/C++ C++ Intellisense CMake CMake tools CMake Tools Helper CMake MinGW 安装CMake 下载链接:...

Markus 8万+

Lesson 6: 理解计算机图形学

原文地址: http://www.directxtutorial.com/Lesson.aspx?lessonid=11-4-1The CPU Directs the GPU 大意为:CPU驱动GPU绘制图形显示在监视器上。The CPU and GPU Have Separate Memory DirectX图形基础设施(DXGI)示意图: 简单说下,Win32应用程序可以使用Di

Nim的辙迹 580

使用C++实现DNS欺骗攻击

其中,domain_name表示需要欺骗的域名,dns_server_ip表示实际DNS服务器的IP地址,fake_ip表示需要重定向到的IP地址。在DNS查询过程中,当客户端向DNS服务器请求解析某个域名时,DNS服务器会返回该域名对应的IP地址。DNS劫持是一种常见的网络攻击方式,通过篡改DNS响应数据,使得用户访问的网站被重定向到攻击者指定的恶意站点。我们使用C++编写一个简单的DNS欺骗程序,使得当客户端请求解析特定的域名时,我们可以将其重定向到指定的IP地址。使用C++实现DNS欺骗攻击。

TechGlide的博客 411

NeHe OpenGL Lesson11 – Flag Effect (Waving Texture)

This demo shows us how to wave texture though vertex position changing at the running time instead of moving texture coordinated. You could get such cool effect with the method used here. But ob...

abc2912333的博客 177

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

COMP 9417 T2_2021 Lesson5

Pg: 45-End 由于下面要学KNN,素以教授先介绍了各种距离的测算方法并且之间的比较。 k最近邻(KNN)算法是有监督的机器学习算法,可用于解决***分类和回归***问题。算法的具体方式后面会讲(按照老师PPT顺序来)。 课中说了下面的距离公式不用会推导,但是要理解: Minkowski distance,曼哈顿距离,欧氏距离 Minkowski distance其实不是描述两个点之间的距离,而是表示Distance metric。 两个n维变量a(x11,x12,…,x1n)与b(x21,

None_Pan的博客 500

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

妙味课堂HTML课后练习 03 lesson 虾米

效果图 清除默认样式 body, h1, h2, h3, h4, h5, h6, hr, p, blockquote, /* structural elements 结构元素 */ dl, dt, dd, ul, ol, li, /* list elements 列表元素 */ pre, /* text formatting elements 文本格式元素 */ form, fields...

qq_21443353的博客 301

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

Ubuntu学习日记--Lesson10:gcc、make、makefile、cmake、cmakelists区别

1.gcc是GNU Compiler Collection(就是GNU编译器套件),也可以简单认为是编译器,它可以编译很多种编程语言(括C、C++、Objective-C、Fortran、Java等等)。 2.当你的程序只有一个源文件时,直接就可以用gcc命令编译它。 3.但是当你的程序包含很多个源文件时,用gcc命令逐个去编译时,你就很容易混乱而且工作量大 4.所以出现了make工具

鲁点点的博客 340

NeHe OpenGL系列教程(中英文版附带VC++源码)中英文系列

NeHeOpenGL教程(中英文版附带VC++源码)中英文系列 Lesson 01-lesson 02 创建一个OpenGL窗口: 如何创建三角形和四边形http://ieee.org.cn/dispbbs.asp?boardID=61&ID=53679 Lesson 03-lesson 04 添加颜色 旋转http://ieee.org.cn/dispbbs.asp?boar...

wang13342322203的博客 1330

Python入门第一课:环境配置、VSCode与turtle绘图完整指南

编程学习的第一步往往不是语法,而是搭建可运行的开发环境。理解解释器与环境变量的关系,是解决Python安装报错的关键。本文将带你从零开始完成Python环境配置,掌握VSCode编辑器的核心操作,并通过turtle标准库实现可视化绘图。无论是计算机基础薄弱的学生、转行数据处理的职场人,还是少儿编程老师,都能从中找到一条清晰可行的学习路径。通过实践项目快速验证代码效果,先跑通最小闭环,再逐步深入数据采集、自动化办公等进阶方向,是高效入门编程的通用方法论。

weixin_34006965的博客 412

微积分导读:从圆周率到导数与积分

……

u013669912的博客 1400
上一篇: Lesson 10: 着色器
下一篇: Lesson 12: 索引缓存
Nim的辙迹
博客等级 码龄10年 17粉丝 40原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值