04. Begin Drawing!

Programmable Graphics Rendering Pipeline

1. Input Assembler (IA) Stage

2. Vertex Shader (VS) Stage

3. Hull Shader (HS) Stage

4. Tesselator Shader (TS) Stage

5. Domain Shader (DS) Stage

6. Geometry Shader (GS) Stage

7. Stream Output (SO) Stage

8. Rasterizer (RS) Stage

9. Pixel Shader (PS) Stage

10. Output Merger (OM) Stage

 

 

1 Input Assembler (IA) Stage

IA阶段读取几何数据,定点和索引,在发送数据给IA之前,需要create a buffer and set the Primitive Topology, Input Layout, and active buffers

首先创建两个buffer,Vertex Bufer 和 Index buffer (D3D11_BUFFER_DESC)然后创建 the input-layout object (D3D11_INPUT_ELEMENT_DESC)

 1 //The vertex Structure
 2 struct Vertex
 3 {
 4     D3DXVECTOR3 pos;
 5     D3DXCOLOR   color;
 6 };
 7 
 8 
 9 //The input-layout description
10 D3D11_INPUT_ELEMENT_DESC layout[] =
11 {
12     {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
13     {"COLOR",    0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0}
14 };

本节的定点类型

struct Vertex    //Overloaded Vertex Structure
{
    Vertex(){}
    Vertex(float x, float y, float z)
        : pos(x,y,z){}

    XMFLOAT3 pos;
};

本节的input layout

D3D11_INPUT_ELEMENT_DESC layout[] =
{
    { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },  
};
创建inputlayout

ID3D11Device::CreateInputLayout()
创建buffer放我们的物体的顶点 (D3D11_BUFFER_DESC)

ID3D11Device::CreateBuffer()

然后,绑定layout和vertext 给IA
ID3D11DeviceContext::IASetVertexBuffers()  
ID3D11DeviceContext::IASetInputLayout()

然后set the primitive topology 这样IA就知道怎么使用顶点了
ID3D11DeviceContext::IASetPrimitiveTopology()
渲染管线准备好了之后,就可以调draw 把primitives给IA
ID3D11DeviceContext::Draw()

2 Vertex Shader (VS) Stage

VS  是第一个可编程的shader,需自己编写。 每个绘制的顶点都将通过VS. 使用VS,您可以执行诸如转换,缩放,照明,纹理的位移贴图等等。

即使程序中的顶点不需要修改,顶点着色器也必须始终实现管道工作。 流水线中的着色器使用HLSL语言编写,对于本课,我们的顶点着色器什么也不做,所以我们只是返回每个顶点的位置而不修改它。

float4 VS(float4 inPos : POSITION) : SV_POSITION
{
    return inPos;
}

3 Hull Shader (HS) Stage

HS是添加到direct3d 11图形渲染管道的三个新的可选阶段中的第一个。

Hull Shader Stage,Tessellator Stage和Domain Shader Stage三个新阶段共同实现了所谓的tesselation。

tesselation是把一个原始的对象,如一个三角形或线,把它分成许多较小的部分,以增加模型的细节,并且非常快。

它在GPU上创建所有这些新的pirvitives不会被保存到内存中,因此在CPU和内存上创建它们会节省很多时间。 你可以take a simple low  mode,用tesselation使它变成a very high detailed polly 

回到Hull Shader。 这是另一个可编程的阶段。这个阶段所做的是计算如何以及在哪里向基元添加新的顶点以使其更加详细。 然后它将这些数据发送到Tessellator Stage和Domain Shader Stage

4 Tessellator (TS) Stage

 TS是一个固定功能阶段。 这个阶段所做的是HS的输入,进行实际的分割。 然后它将数据传递给Domain Shader.。

5 Domain Shader (DS) Stage

DS是tessellation process的第三个阶段, 这是一个可编程的功能阶段。 这个阶段所做的就是从HS阶段获取新顶点的位置,

并且转换从TS阶段接收到的顶点以创建更多细节。 然后它将顶点传递给the geometry shader stage。

6 Geometry Shader (GS) Stage

这个着色器阶段是可选的。 这也是另一个可编程功能阶段。 它接受基元作为输入,比如3个三角形顶点,2个线,一个点。
它也可以将来自边缘相邻图元的数据作为输入,例如对于一条线另外2个顶点,或对于三角形另外3个顶点。
GS的一个好处是它可以创建或者销毁primitvies 而VS不能。 这个阶段我们可以把一个点变成一个四边形或三角形。 我们可以将数据从GS传送到光栅器阶段,或者传送到内存中的顶点缓冲器。

7 Stream Output (SO) Stage

SO是用来获取vertex date 从GS或者VS(没有GS)Vertex data 发到内存中,从SO发送到存储器的顶点数据被放入一个或多个顶点缓冲区。 
从SO输出的顶点数据总是以列表的形式发送出去,例如行列表或三角形列表。 不完整的图元从不发送出去,它们会被默默地剔除。
不完整的基元例如只有2个顶点的三角形或只有一个顶点的直线

8 Rasterization Stage (RS) Stage

RS阶段将向量信息(形状和图元)通过差值顶点来访问每个primitive来将它们变成像素并发送到下一阶段PS。 它也处理裁剪,最基本的切割在屏幕视图之外的primitive。

我们使用以下命令在RS中设置视口:


ID3D11DeviceContext::RSSetViewports()

9 Pixel Shader (PS) Stage

此阶段进行计算并修改屏幕上可见的每个像素,例如每个像素点的照明。这是另一个可编程功能,以及一个可选的阶段。 RS为primitive中的每个像素调用一次PS。
我们之前说过的那样,基元中每个顶点的值和属性都是在RS中的整个基元内插入的。类似VS,VS有1:1的映射(它取一个顶点并返回一个顶点),PS也有1:1的映射(它取一个像素并返回一个像素)
PS的工作是计算每个像素片段的最终颜色。 像素片段是即将被绘制到屏幕的每个潜在像素。 例如,一个圆圈后面有一个正方形。
正方形中的像素是像素片段,圆圈中的像素是像素片段。
每一个都有机会被写入屏幕,但是一旦它到达输出合并阶段,就决定了哪一个像素会被被绘制到屏幕上,如果该圆的深度值小于该深度值正方形,所以来自圆圈的像素将都被绘制。 PS输出4D颜色值。
在本课中,我们使用像素着色器通过返回等于蓝色的四维浮点值来使三角形变为蓝色。 没有计算,只是简单地将绿色返回,所以通过着色器运行的每个像素都将是蓝色的。
float4 PS() : SV_TARGET
{
    return float4(0.0f, 0.0f, 1.0f, 1.0f);
}

10 Output Merger (OM) Stage

管道的最后一个阶段是产出合并阶段。 基本上这个阶段需要像素片段和深度/模板缓冲区,并确定哪些像素实际写入渲染目标。 我们在上一课中设置渲染目标,通过调用:

ID3D11DeviceContext::OMSetRenderTargets()

在OM阶段之后,剩下要做的就是把我们的backbuffer放在屏幕上。 我们可以通过调用:


IDXGISwapChain::Present();

  第一个是保存我们的顶点数据的Buffer。接下来的两个是我们的VS和PS。 然后,是我们的VS 和PS buffer,这将保存有关我们的VS和PS信息。 最后一个是我们的input layout。

ID3D11Buffer* triangleVertBuffer;
ID3D11VertexShader* VS;
ID3D11PixelShader* PS;
ID3D10Blob* VS_Buffer;
ID3D10Blob* PS_Buffer;
ID3D11InputLayout* vertLayout;
 

Vertex Structure & Input Layout ( D3D11_INPUT_ELEMENT_DESC )

 我们所生产的所有3D对象将由具有属性的点组成,例如颜色,我们称为顶点。 我们必须建立自己的顶点结构。 这是一个重载的顶点结构(所以我们可以很容易地和动态地创建和编辑一个顶点)

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;

SemanticName -

这只是一个与元素关联的字符串。 该字符串将用于将顶点结构中的元素映射到VS中的元素。

SemanticIndex -

这基本上只是用作索引的语义名称之后的数字。 例如,如果我们在顶点结构中有2个纹理元素,而不是创建2个不同的纹理语义名称,我们可以使用2个不同的索引。 如果顶点着色器代码中的语义名称之后没有索引,默认为索引0.

例如在我们的着色器代码中,我们的语义名称是“POSITION”,其实际上与“POSITION0”相同,

Format -

这只是我们顶点结构中组件的格式。 它需要是DXGI_FORMAT枚举类型的成员。 在本课中,我们有一个描述位置的3d向量,所以我们可以使用DXGI_FORMAT:DXGI_FORMAT_R32G32B32_FLOAT。

InputSlot -

Direct3D允许我们使用16个不同的元素插槽(0-15),您可以放置顶点数据。 如果我们的顶点结构有一个位置和颜色,我们可以把这两个元素放在同一个输入位置,或者我们可以把位置数据放在第一个位置,而把颜色数据放在第二个位置。

 AlignedByteOffset -

这是你所描述的元素的字节偏移量。 在单个输入槽中,如果我们有位置和颜色,位置可以是0,因为它从顶点结构的开始处开始,颜色将需要是我们顶点位置的大小,即12个字节(请记住我们的格式 我们的顶点位置是DXGI_FORMAT_R32G32B32_FLOAT,它是96位,位置上的每个分量都是32位,一个字节有8位,所以96/8 == 12)。

InputSlotClass -

现在我们可以使用D3D10_INPUT_PER_VERTEX_DATA。 其他选项用于实例化

InstanceDataStepRate -

这也只用于实例化,所以我们现在要指定0

 1 struct Vertex    //Overloaded Vertex Structure
 2 {
 3     Vertex(){}
 4     Vertex(float x, float y, float z)
 5         : pos(x,y,z){}
 6 
 7     XMFLOAT3 pos;
 8 };
 9 
10 D3D11_INPUT_ELEMENT_DESC layout[] =
11 {
12     { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },  
13 };
14 UINT numElements = ARRAYSIZE(layout);

Cleaning Up

 1 void CleanUp()
 2 {
 3     //Release the COM Objects we created
 4     SwapChain->Release();
 5     d3d11Device->Release();
 6     d3d11DevCon->Release();
 7     renderTargetView->Release();
 8     triangleVertBuffer->Release();
 9     VS->Release();
10     PS->Release();
11     VS_Buffer->Release();
12     PS_Buffer->Release();
13     vertLayout->Release();
14 }

Initializing the Scene

bool InitScene()
{
    //Compile Shaders from shader file
    hr = D3DX11CompileFromFile(L"Effects.fx", 0, 0, "VS", "vs_5_0", 0, 0, 0, &VS_Buffer, 0, 0);
    hr = D3DX11CompileFromFile(L"Effects.fx", 0, 0, "PS", "ps_5_0", 0, 0, 0, &PS_Buffer, 0, 0);

    //Create the Shader Objects
    hr = d3d11Device->CreateVertexShader(VS_Buffer->GetBufferPointer(), VS_Buffer->GetBufferSize(), NULL, &VS);
    hr = d3d11Device->CreatePixelShader(PS_Buffer->GetBufferPointer(), PS_Buffer->GetBufferSize(), NULL, &PS);

    //Set Vertex and Pixel Shaders
    d3d11DevCon->VSSetShader(VS, 0, 0);
    d3d11DevCon->PSSetShader(PS, 0, 0);

    //Create the vertex buffer
    Vertex v[] =
    {
        Vertex( 0.0f, 0.5f, 0.5f ),
        Vertex( 0.5f, -0.5f, 0.5f ),
        Vertex( -0.5f, -0.5f, 0.5f ),
    };

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

    vertexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
    vertexBufferDesc.ByteWidth = sizeof( Vertex ) * 3;
    vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
    vertexBufferDesc.CPUAccessFlags = 0;
    vertexBufferDesc.MiscFlags = 0;

    D3D11_SUBRESOURCE_DATA vertexBufferData; 

    ZeroMemory( &vertexBufferData, sizeof(vertexBufferData) );
    vertexBufferData.pSysMem = v;
    hr = d3d11Device->CreateBuffer( &vertexBufferDesc, &vertexBufferData, &triangleVertBuffer);

    //Set the vertex buffer
    UINT stride = sizeof( Vertex );
    UINT offset = 0;
    d3d11DevCon->IASetVertexBuffers( 0, 1, &triangleVertBuffer, &stride, &offset );

    //Create the Input Layout
    hr = d3d11Device->CreateInputLayout( layout, numElements, VS_Buffer->GetBufferPointer(), 
        VS_Buffer->GetBufferSize(), &vertLayout );

    //Set the Input Layout
    d3d11DevCon->IASetInputLayout( vertLayout );

    //Set Primitive Topology
    d3d11DevCon->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST );

    //Create the Viewport
    D3D11_VIEWPORT viewport;
    ZeroMemory(&viewport, sizeof(D3D11_VIEWPORT));

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

    //Set the Viewport
    d3d11DevCon->RSSetViewports(1, &viewport);

    return true;
}   

Compiling the Shaders( D3DX11CompileFromFile() )

我们将通过创建着色器来开始初始化场景。 我们将从名为“Effects.fx”的效果文件中编译shader。 我们可以使用函数D3DX11CompileFromFile()来做到这一点:

HRESULT WINAPI D3DX11CompileFromFile(
            LPCSTR pSrcFile,
            CONST D3D10_SHADER_MACRO* pDefines, 
            LPD3D10INCLUDE pInclude,
            LPCSTR pFunctionName, 
            LPCSTR pProfile, 
            UINT Flags1, 
            UINT Flags2, 
            ID3DX11ThreadPump* pPump, 
            ID3D10Blob** ppShader, 
            ID3D10Blob** ppErrorMsgs, 
            HRESULT* pHResult);

pSrcFile -
shader文件名。

pDefines -
指向宏数组的指针。我们可以将其设置为NULL

pInclude -
这是一个指向包含界面的指针。如果我们的着色器在文件中使用#include,我们不能在这里放置NULL,但是我们的着色器没有include,所以我们把它设置为NULL。

pFunctionName -
这是该文件名中着色器函数的名称。

pProfile -
您要使用的着色器的版本。 Direct3D 11支持着色器版本5.0。

标志1 -
编译标志,我们将这个设置为NULL。

标志2 -
效果标志。我们也将这个设置为NULL。

pPump -
这与多线程有关。我们设置NULL,所以函数不会返回,直到它完成。

ppShader -
这是返回的着色器。这不是实际的着色器,而更像是一个包含着色器和着色器信息的缓冲区。然后,我们将使用这个缓冲区来创建实际的着色器。

ppErrorMsgs -
这将返回编译着色器时发生的错误和警告列表。这些错误和警告与您在调试器底部看到的相同。

pHResult -
这是返回的HRESULT。我们做了这样的“hr =”这个函数,但是你也可以把“&hr”这个参数做同样的事情。

hr = D3DX11CompileFromFile(L"Effects.fx", 0, 0, "VS", "vs_5_0", 0, 0, 0, &VS_Buffer, 0, 0);
hr = D3DX11CompileFromFile(L"Effects.fx", 0, 0, "PS", "ps_5_0", 0, 0, 0, &PS_Buffer, 0, 0);

 

Creating the Shaders( ID3D11Device::CreateVertexShader() )

HRESULT CreateVertexShader( 
  [in]        const void *pShaderBytecode,
  [in]        SIZE_T BytecodeLength,
  [in]        ID3D11ClassLinkage *pClassLinkage,
  [in, out]   ID3D11VertexShader **ppVertexShader) = 0;
);

HRESULT CreatePixelShader( 
  [in]        const void *pShaderBytecode,
  [in]        SIZE_T BytecodeLength,
  [in]        ID3D11ClassLinkage *pClassLinkage,
  [in, out]   ID3D11PixelShader **ppPixelShader) = 0;
);

 

pShaderBytecode -
这是一个指向着色器缓冲区开始的指针。

BytecodeLength -
这是缓冲区的大小。

pClassLinkage -
指向类联动接口的指针。 我们将这个设置为NULL。

ppVertexShader -
这是我们返回的顶点着色器。

ppPixelShader -
这是我们返回的像素着色器。

hr = d3d11Device->CreateVertexShader(VS_Buffer->GetBufferPointer(), VS_Buffer->GetBufferSize(), NULL, &VS);
hr = d3d11Device->CreatePixelShader(PS_Buffer->GetBufferPointer(), PS_Buffer->GetBufferSize(), NULL, &PS);

 

Setting the Shaders( ID3D11DeviceContext::VSSetShader() )

现在我们编译并创建了着色器,我们需要将它们设置为当前的着色器。如果我们要设置顶点着色器,我们可以通过调用ID3D11DeviceContext :: VSSetShader()来实现,

而如果我们想要设置像素着色器,还可以调用ID3D11DeviceContext :: PSSetShader()(还有其他着色器,我们将稍后学习设置,比如几何着色器)。

大多数情况下,应用程序将为不同的几何图形集使用不同的着色器集合,例如,稍后我们将在绘制天空盒时使用单独的像素着色器。

因此,您将在运行时设置着色器,而不是仅在场景设置功能中。请记住,direct3d是一个“状态机”,它将保持当前的状态和设置,直到它稍后被更改,

所以不要指望在代码中设置它们之后,direct3d将着色器设置回默认值,在渲染你的东西之前,总是需要设置正确的着色器。这也适用于渲染状态和其他东西。我们将在稍后的讨论中讨论渲染状态

void  VSSetShader( 
  [in]   ID3D11VertexShader *pVertexShader,
  [in]   (NumClassInstances)  ID3D11ClassInstance *const *ppClassInstances,
  [in]   UINT NumClassInstances);
);

void PSSetShader( 
  [in]   ID3D11PixelShader *pPixelShader,
  [in]   (NumClassInstances)  ID3D11ClassInstance *const *ppClassInstances,
  [in]   UINT NumClassInstances);
);

 

pVertexShader -
这是我们的顶点着色器。

pPixelShader -
这是我们的Pixe Shader。

ppClassInstances -
这只在我们的着色器使用和接口时才使用。 设置为NULL。

NumClassInstances -
这是来自ppClassInstances的数组中的类实例的数量。 我们设置为0,因为没有一个。

 

d3d11DevCon->VSSetShader(VS, 0, 0);
d3d11DevCon->PSSetShader(PS, 0, 0);

Creating the Vertex Buffer( ID3D11Buffer )

现在我们需要创建我们的顶点缓冲区。 我们首先使用我们的顶点结构创建一个顶点数组。

在我们有了一个顶点数组之后,我们将通过填充一个D3D11_BUFFER_DESC结构来描述我们的顶点缓冲区,并通过调用ZeroMemory()来确保它是空的。 D3D11_BUFFER_DESC看起来像这样:

typedef struct D3D11_BUFFER_DESC
{
   UINT             ByteWidth;
   D3D11_USAGE         Usage;
   UINT             BindFlags;
   UINT             CPUAccessFlags;
   UINT             MiscFlags;
   UINT             StructureByteStride;
}    D3D11_BUFFER_DESC;

ByteWidth -
这是我们缓冲区的大小。

Usage -
一个D3D11_USAGE类型,描述如何读取和写入我们的缓冲区。

BindFlags -
我们指定D3D11_BIND_VERTEX_BUFFER,因为这是一个顶点缓冲区。

CPUAccessFlags -
这说明我们的缓冲区将如何被CPU使用。 我们可以将其设置为NULL

MiscFlags -
额外的标志,我们不会使用,也设置为NULL

StructureByteStride -
这里不使用,将其设置为NULL。

 

现在我们已经描述了缓冲区,我们需要用我们需要的数据填充D3D11_SUBRESOURCE_DATA结构。 结构如下所示:

typedef struct D3D11_SUBRESOURCE_DATA
{
   const    void *pSysMem;
   UINT     SysMemPitch;
   UINT     SysMemSlicePitch;
}     D3D11_SUBRESOURCE_DATA;

pSysMem -
这是我们想要放入缓冲区的数据。

SysMemPitch -
这是纹理中从一行到下一行的字节距离。 它仅用于2D和3D纹理。

SysMemSlicePitch -
3D纹理中从一个深度级别到下一级别的距离(以字节为单位)。 仅用于3D纹理。

现在我们可以使用我们刚创建的缓冲区描述和缓冲区数据来创建缓冲区了。 为了创建缓冲区,我们所要做的就是调用ID3D11Device :: CreateBuffer()。 该函数如下所示:

HRESULT CreateBuffer( 
   [in]    const D3D11_BUFFER_DESC *pDesc,
   [in]    const D3D11_SUBRESOURCE_DATA *pInitialData,
   [in]    ID3D11Buffer **ppBuffer
);

 

pDesc -
指向我们缓冲区描述的指针

pInitialData -
指向包含我们想要放在这里的数据的子资源数据结构的指针。 如果我们想稍后添加数据,我们可以将其设置为NULL。

ppBuffer -
返回的ID3D11Buffer。

Vertex v[] =
{
    Vertex( 0.0f, 0.5f, 0.5f ),
    Vertex( 0.5f, -0.5f, 0.5f ),
    Vertex( -0.5f, -0.5f, 0.5f ),
};

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

vertexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
vertexBufferDesc.ByteWidth = sizeof( Vertex ) * 3;
vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
vertexBufferDesc.CPUAccessFlags = 0;
vertexBufferDesc.MiscFlags = 0;

D3D11_SUBRESOURCE_DATA vertexBufferData; 

ZeroMemory( &vertexBufferData, sizeof(vertexBufferData) );
vertexBufferData.pSysMem = v;
hr = d3d11Device->CreateBuffer( &vertexBufferDesc, &vertexBufferData, &triangleVertBuffer);

 

Setting the Vertex Buffer( ID3D11DeviceContext::IASetVertexBuffers() )

现在我们有一个Vertex buffer 我们需要把绑定到IA,调用ID3D11Devicecontext::IASetVertexBuffers function

void IASetVertexBuffers(
   [in]   UINT StartSlot,
   [in]   UINT NumBuffers,
   [in]   ID3D11Buffer *const *ppVertexBuffers,
   [in]   const UINT *pStrides,
   [in]   const UINT *pOffsets
);

StartSlot -
这是我们可以绑定到的输入插槽。 我们在这里设置0。

NumBuffers -
这是我们绑定的缓冲区的数量。 我们只有1个。

ppVertexBuffers -
这是一个指向我们实际的顶点缓冲区的指针。

pStrides -
这是每个顶点的大小。

pOffsets -
这是从开始的缓冲区开始的字节。

 

UINT stride = sizeof( Vertex );
UINT offset = 0;
d3d11DevCon->IASetVertexBuffers( 0, 1, &triangleVertBuffer, &stride, &offset );

Creating the Input (Vertex) Layout ( ID3D11Device::CreateInputLayout() )

接下来,我们需要创建我们的input layout。 我们可以用函数ID3D11Device :: CreateInputLayout来做到这一点:

HRESULT CreateInputLayout( 
   [in]   const D3D11_INPUT_ELEMENT_DESC *pInputElementDescs,
   [in]   UINT NumElements,
   [in]   const void *pShaderBytecodeWithInputSignature,
   [in]   SIZE_T BytecodeLength,
   [out]  ID3D11InputLayout **ppInputLayout
);

 

pInputElementDescs -
这是包含我们的顶点布局的D3D11_INPUT_ELEMENT_DESC元素的数组。

NumElements -
这是我们的顶点布局中的元素的数量。

pShaderBytecodeWithInputSignature -
这是一个指向我们的顶点着色器指针。

BytecodeLength -
这是我们的顶点着色器的大小。

ppInputLayout -
这是我们输入(顶点)布局的返回指针。

hr = d3d11Device->CreateInputLayout( layout, numElements, VS_Buffer->GetBufferPointer(), 
    VS_Buffer->GetBufferSize(), &vertLayout );

Setting the Input (Vertex) Layout ( ID3D11DeviceContext::IASetInputLayout() )

我们已经创建了顶点布局,接下来要做的就是将其绑定到IA作为可操作的输入(顶点)布局。 我们可以通过调用函数ID3D11DeviceContext :: IASetInputLayout()来做到这一点:

void STDMETHODCALLTYPE IASetInputLayout( 
   [in]   ID3D11InputLayout *pInputLayout
);
d3d11DevCon->IASetInputLayout( vertLayout );

Setting the Primitive Topology ( ID3D11DeviceContext::IASetPrimitiveTopology() )

在这里我们告诉IA我们发给他的primitives是什么类型的。我们可以设置primitive toplogy 通过ID3D11DeviceContext::IASetPrimitiveTopology()

唯一的参数是一个D3D11_PRIMITIVE_TOPOLOGY枚举类型。 以下是常用类型的列表:

Point List -

我们可以使用D3D10_PRIMITIVE_TOPOLOGY_POINTLIST。通过使用这种topology,每个顶点将被绘制为一个单独的点。

Line Strip -

我们可以使用D3D10_PRIMITIVE_TOPOLOGY_LINESTRIP。这基本上就像“连接点”。所有的顶点将成为一条线的一部分

Line List -

我们可以使用D3D10_PRIMITIVE_TOPOLOGY_LINELIST。每两个顶点将创建一条线。这和Line Strip之间的区别在于,在一个Line Strip中,所有的顶点将被连接起来以创建线条,这是一条连续的线条。

Triangle Strip -

我们可以使用D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP。这里我们创建三角形。每个三角形与相邻的三角形共享其顶点。所有三角形将被连接。

Triangle List -

我们可以使用D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST。这就是说,每3个顶点构成一个三角形,所以并不是所有的三角形都必须连接。它比Triangle Strip更慢,因为必须使用更多的顶点,不像Triangle Strip,您可以使用4个顶点创建2个三角形。在Triangle List中,您需要有6个顶点来创建2个三角形。

Primitives with Adjacency -

一个例子是D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ。这些仅用于几何着色器。

 

d3d11DevCon->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST );

 

 

 

 

Creating the Viewport( D3D11_VIEWPORT )

现在剩下要做的就是创建并设置我们的视口。 视口会告诉管道的RS阶段要画什么。 我们可以使用D3D11_VIEWPORT结构创建一个视口。

该视口创建一个以像素为单位的正方形,光栅化器使用该正方形来查找在我们窗口的客户区域上显示几何图形的位置。

当我们引入深度缓冲区时,您也将使用视口。 我们可以设置最小和最大深度值,通常在0和1之间。然后,OM将根据深度值决定显示哪个像素“片段”。

我们希望视口覆盖整个窗口客户区域,所以我们将框的左上角设置为0,0,将框右下角的宽度,高度 单位像素。

 

D3D11_VIEWPORT viewport;
ZeroMemory(&viewport, sizeof(D3D11_VIEWPORT));

 

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

Setting the Viewport( ID3D11DeviceContext::RSSetViewports() )

在我们创建视口之后,我们需要使用ID3D11DeviceContext :: RSSViewports()函数将其绑定到管道的RS阶段。 第一个参数是要绑定的视口数量,第二个参数是指向视口数组的指针。 这是你可以有多个“窗口”的地方,比如玩家一和玩家二。

d3d11DevCon->RSSetViewports(1, &viewport);

Rendering the Primitive( ID3D11DeviceContext::Draw() )

现在我们回到DrawScene()函数,在这里我们使用包含4个值的浮点数组RBGA将背景颜色改回黑色。 这里的新行是Draw函数。 第一个参数是要绘制的顶点数量,第二个参数是从开始绘制的顶点数组开始的偏移量。

void DrawScene()
{
    float bgColor[4] = {(0.0f, 0.0f, 0.0f, 0.0f)};
    d3d11DevCon->ClearRenderTargetView(renderTargetView, bgColor);

    d3d11DevCon->Draw( 3, 0 );

    SwapChain->Present(0, 0);
}

Effect File (Shaders)( Vertex Shader )

现在我们转到Effectfile。 我们有一个非常非常简单的effectfile,只包含一个VS和PS着色器。 而且这些功能中的每一个功能都是最小的。 在这里,我们将顶点着色器命名为“VS”,并将其参数设置为接受名为“Pos”的4d浮点值。 “位置”是IA将在我们的顶点结构中发送位置元素的位置,因为我们在输入布局中告诉它这样做。 只要你记得在你的顶点布局中改变它,你可以把“POSITION”改成其他任何东西。 我们在这里做的唯一事情是将Pos值返回到管道中的下一个活动阶段。

float4 VS(float4 inPos : POSITION) : SV_POSITION
{
    return inPos;
}

Effect File (Shaders)( Pixel Shader )

我们在本课中做的最后一件事就是创建一个像素着色器功能。 这个函数唯一的作用是从光栅阶段传入的每个像素返回蓝色。 然后,我们将返回来自顶点着色器的纹理坐标,法线和/或颜色值,并将它们作为此像素着色器中的输入。 然后,我们可以使用所有这些值来确定像素的最终颜色。 这也是我们将启用基于像素的照明的地方。

float4 PS() : SV_TARGET
{
    return float4(0.0f, 0.0f, 1.0f, 1.0f);
}

 

full source  main.cpp

  1 //Include and link appropriate libraries and headers//
  2 #include <windows.h>
  3 #include <d3d11.h>
  4 #include <d3dx11.h>
  5 #include <D3DX10.h>
  6 #include <xnamath.h>
  7 
  8 //Global Declarations - Interfaces//
  9 IDXGISwapChain* SwapChain;
 10 ID3D11Device* d3d11Device;
 11 ID3D11DeviceContext* d3d11DevCon;
 12 ID3D11RenderTargetView* renderTargetView;
 13 
 14 ///////////////**************new**************////////////////////
 15 ID3D11Buffer* triangleVertBuffer;
 16 ID3D11VertexShader* VS;
 17 ID3D11PixelShader* PS;
 18 ID3D10Blob* VS_Buffer;
 19 ID3D10Blob* PS_Buffer;
 20 ID3D11InputLayout* vertLayout;
 21 ///////////////**************new**************////////////////////
 22 
 23 //Global Declarations - Others//
 24 LPCTSTR WndClassName = L"firstwindow";
 25 HWND hwnd = NULL;
 26 HRESULT hr;
 27 
 28 const int Width  = 300;
 29 const int Height = 300;
 30 
 31 //Function Prototypes//
 32 bool InitializeDirect3d11App(HINSTANCE hInstance);
 33 void CleanUp();
 34 bool InitScene();
 35 void UpdateScene();
 36 void DrawScene();
 37 
 38 bool InitializeWindow(HINSTANCE hInstance,
 39                       int ShowWnd,
 40                       int width, int height,
 41                       bool windowed);
 42 int messageloop();
 43 
 44 LRESULT CALLBACK WndProc(HWND hWnd,
 45                          UINT msg,
 46                          WPARAM wParam,
 47                          LPARAM lParam);
 48 
 49 ///////////////**************new**************////////////////////
 50 //Vertex Structure and Vertex Layout (Input Layout)//
 51 struct Vertex    //Overloaded Vertex Structure
 52 {
 53     Vertex(){}
 54     Vertex(float x, float y, float z)
 55         : pos(x,y,z){}
 56 
 57     XMFLOAT3 pos;
 58 };
 59 
 60 D3D11_INPUT_ELEMENT_DESC layout[] =
 61 {
 62     { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },  
 63 };
 64 UINT numElements = ARRAYSIZE(layout);
 65 ///////////////**************new**************////////////////////
 66 
 67 int WINAPI WinMain(HINSTANCE hInstance,    //Main windows function
 68                    HINSTANCE hPrevInstance, 
 69                    LPSTR lpCmdLine,
 70                    int nShowCmd)
 71 {
 72 
 73     if(!InitializeWindow(hInstance, nShowCmd, Width, Height, true))
 74     {
 75         MessageBox(0, L"Window Initialization - Failed",
 76             L"Error", MB_OK);
 77         return 0;
 78     }
 79 
 80     if(!InitializeDirect3d11App(hInstance))    //Initialize Direct3D
 81     {
 82         MessageBox(0, L"Direct3D Initialization - Failed",
 83             L"Error", MB_OK);
 84         return 0;
 85     }
 86 
 87     if(!InitScene())    //Initialize our scene
 88     {
 89         MessageBox(0, L"Scene Initialization - Failed",
 90             L"Error", MB_OK);
 91         return 0;
 92     }
 93 
 94     messageloop();
 95 
 96     CleanUp();    
 97 
 98     return 0;
 99 }
100 
101 bool InitializeWindow(HINSTANCE hInstance,
102                       int ShowWnd,
103                       int width, int height,
104                       bool windowed)
105 {
106     typedef struct _WNDCLASS {
107         UINT cbSize;
108         UINT style;
109         WNDPROC lpfnWndProc;
110         int cbClsExtra;
111         int cbWndExtra;
112         HANDLE hInstance;
113         HICON hIcon;
114         HCURSOR hCursor;
115         HBRUSH hbrBackground;
116         LPCTSTR lpszMenuName;
117         LPCTSTR lpszClassName;
118     } WNDCLASS;
119 
120     WNDCLASSEX wc;
121 
122     wc.cbSize = sizeof(WNDCLASSEX);
123     wc.style = CS_HREDRAW | CS_VREDRAW;
124     wc.lpfnWndProc = WndProc;
125     wc.cbClsExtra = NULL;
126     wc.cbWndExtra = NULL;
127     wc.hInstance = hInstance;
128     wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
129     wc.hCursor = LoadCursor(NULL, IDC_ARROW);
130     wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 2);
131     wc.lpszMenuName = NULL;
132     wc.lpszClassName = WndClassName;
133     wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
134 
135     if (!RegisterClassEx(&wc))
136     {
137         MessageBox(NULL, L"Error registering class",    
138             L"Error", MB_OK | MB_ICONERROR);
139         return 1;
140     }
141 
142     hwnd = CreateWindowEx(
143         NULL,
144         WndClassName,
145         L"Lesson 4 - Begin Drawing",
146         WS_OVERLAPPEDWINDOW,
147         CW_USEDEFAULT, CW_USEDEFAULT,
148         width, height,
149         NULL,
150         NULL,
151         hInstance,
152         NULL
153         );
154 
155     if (!hwnd)
156     {
157         MessageBox(NULL, L"Error creating window",
158             L"Error", MB_OK | MB_ICONERROR);
159         return 1;
160     }
161 
162     ShowWindow(hwnd, ShowWnd);
163     UpdateWindow(hwnd);
164 
165     return true;
166 }
167 
168 bool InitializeDirect3d11App(HINSTANCE hInstance)
169 {
170     //Describe our Buffer
171     DXGI_MODE_DESC bufferDesc;
172 
173     ZeroMemory(&bufferDesc, sizeof(DXGI_MODE_DESC));
174 
175     bufferDesc.Width = Width;
176     bufferDesc.Height = Height;
177     bufferDesc.RefreshRate.Numerator = 60;
178     bufferDesc.RefreshRate.Denominator = 1;
179     bufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
180     bufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
181     bufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
182 
183     //Describe our SwapChain
184     DXGI_SWAP_CHAIN_DESC swapChainDesc; 
185 
186     ZeroMemory(&swapChainDesc, sizeof(DXGI_SWAP_CHAIN_DESC));
187 
188     swapChainDesc.BufferDesc = bufferDesc;
189     swapChainDesc.SampleDesc.Count = 1;
190     swapChainDesc.SampleDesc.Quality = 0;
191     swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
192     swapChainDesc.BufferCount = 1;
193     swapChainDesc.OutputWindow = hwnd; 
194     swapChainDesc.Windowed = TRUE; 
195     swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
196 
197 
198     //Create our SwapChain
199     hr = D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, NULL, NULL, NULL,
200         D3D11_SDK_VERSION, &swapChainDesc, &SwapChain, &d3d11Device, NULL, &d3d11DevCon);
201 
202     //Create our BackBuffer
203     ID3D11Texture2D* BackBuffer;
204     hr = SwapChain->GetBuffer( 0, __uuidof( ID3D11Texture2D ), (void**)&BackBuffer );
205 
206     //Create our Render Target
207     hr = d3d11Device->CreateRenderTargetView( BackBuffer, NULL, &renderTargetView );
208     BackBuffer->Release();
209 
210     //Set our Render Target
211     d3d11DevCon->OMSetRenderTargets( 1, &renderTargetView, NULL );
212 
213     return true;
214 }
215 
216 void CleanUp()
217 {
218     //Release the COM Objects we created
219     SwapChain->Release();
220     d3d11Device->Release();
221     d3d11DevCon->Release();
222     renderTargetView->Release();
223     ///////////////**************new**************////////////////////
224     triangleVertBuffer->Release();
225     VS->Release();
226     PS->Release();
227     VS_Buffer->Release();
228     PS_Buffer->Release();
229     vertLayout->Release();
230     ///////////////**************new**************////////////////////
231 }
232 
233 ///////////////**************new**************////////////////////
234 bool InitScene()
235 {
236     //Compile Shaders from shader file
237     hr = D3DX11CompileFromFile(L"Effects.fx", 0, 0, "VS", "vs_5_0", 0, 0, 0, &VS_Buffer, 0, 0);
238     hr = D3DX11CompileFromFile(L"Effects.fx", 0, 0, "PS", "ps_5_0", 0, 0, 0, &PS_Buffer, 0, 0);
239 
240     //Create the Shader Objects
241     hr = d3d11Device->CreateVertexShader(VS_Buffer->GetBufferPointer(), VS_Buffer->GetBufferSize(), NULL, &VS);
242     hr = d3d11Device->CreatePixelShader(PS_Buffer->GetBufferPointer(), PS_Buffer->GetBufferSize(), NULL, &PS);
243 
244     //Set Vertex and Pixel Shaders
245     d3d11DevCon->VSSetShader(VS, 0, 0);
246     d3d11DevCon->PSSetShader(PS, 0, 0);
247 
248     //Create the vertex buffer
249     Vertex v[] =
250     {
251         Vertex( 0.0f, 0.5f, 0.5f ),
252         Vertex( 0.5f, -0.5f, 0.5f ),
253         Vertex( -0.5f, -0.5f, 0.5f ),
254     };
255 
256     D3D11_BUFFER_DESC vertexBufferDesc;
257     ZeroMemory( &vertexBufferDesc, sizeof(vertexBufferDesc) );
258 
259     vertexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
260     vertexBufferDesc.ByteWidth = sizeof( Vertex ) * 3;
261     vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
262     vertexBufferDesc.CPUAccessFlags = 0;
263     vertexBufferDesc.MiscFlags = 0;
264 
265     D3D11_SUBRESOURCE_DATA vertexBufferData; 
266 
267     ZeroMemory( &vertexBufferData, sizeof(vertexBufferData) );
268     vertexBufferData.pSysMem = v;
269     hr = d3d11Device->CreateBuffer( &vertexBufferDesc, &vertexBufferData, &triangleVertBuffer);
270 
271     //Set the vertex buffer
272     UINT stride = sizeof( Vertex );
273     UINT offset = 0;
274     d3d11DevCon->IASetVertexBuffers( 0, 1, &triangleVertBuffer, &stride, &offset );
275 
276     //Create the Input Layout
277     d3d11Device->CreateInputLayout( layout, numElements, VS_Buffer->GetBufferPointer(), 
278         VS_Buffer->GetBufferSize(), &vertLayout );
279 
280     //Set the Input Layout
281     d3d11DevCon->IASetInputLayout( vertLayout );
282 
283     //Set Primitive Topology
284     d3d11DevCon->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST );
285 
286     //Create the Viewport
287     D3D11_VIEWPORT viewport;
288     ZeroMemory(&viewport, sizeof(D3D11_VIEWPORT));
289 
290     viewport.TopLeftX = 0;
291     viewport.TopLeftY = 0;
292     viewport.Width = Width;
293     viewport.Height = Height;
294 
295     //Set the Viewport
296     d3d11DevCon->RSSetViewports(1, &viewport);
297 
298     return true;
299 }
300 ///////////////**************new**************////////////////////
301 
302 void UpdateScene()
303 {
304 
305 }
306 
307 ///////////////**************new**************////////////////////
308 void DrawScene()
309 {
310     //Clear our backbuffer
311     float bgColor[4] = {(0.0f, 0.0f, 0.0f, 0.0f)};
312     d3d11DevCon->ClearRenderTargetView(renderTargetView, bgColor);
313 
314     //Draw the triangle
315     d3d11DevCon->Draw( 3, 0 );
316 
317     //Present the backbuffer to the screen
318     SwapChain->Present(0, 0);
319 }
320 ///////////////**************new**************////////////////////
321 
322 int messageloop(){
323     MSG msg;
324     ZeroMemory(&msg, sizeof(MSG));
325     while(true)
326     {
327         BOOL PeekMessageL( 
328             LPMSG lpMsg,
329             HWND hWnd,
330             UINT wMsgFilterMin,
331             UINT wMsgFilterMax,
332             UINT wRemoveMsg
333             );
334 
335         if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
336         {
337             if (msg.message == WM_QUIT)
338                 break;
339             TranslateMessage(&msg);    
340             DispatchMessage(&msg);
341         }
342         else{
343             // run game code            
344             UpdateScene();
345             DrawScene();
346         }
347     }
348     return msg.wParam;
349 }
350 
351 LRESULT CALLBACK WndProc(HWND hwnd,
352                          UINT msg,
353                          WPARAM wParam,
354                          LPARAM lParam)
355 {
356     switch( msg )
357     {
358     case WM_KEYDOWN:
359         if( wParam == VK_ESCAPE ){
360             DestroyWindow(hwnd);
361         }
362         return 0;
363 
364     case WM_DESTROY:
365         PostQuitMessage(0);
366         return 0;
367     }
368     return DefWindowProc(hwnd,
369         msg,
370         wParam,
371         lParam);
372 }

Effect .fx

float4 VS(float4 inPos : POSITION) : SV_POSITION
{
    return inPos;
}

float4 PS() : SV_TARGET
{
    return float4(0.0f, 0.0f, 1.0f, 1.0f);
}

 

 

 

 

 

 

学习资料

https://www.braynzarsoft.net/viewtutorial/q16390-4-begin-drawing

posted @ 2017-12-22 20:32  YinaPan  阅读(374)  评论(0编辑  收藏  举报