zoukankan      html  css  js  c++  java
  • Rendering PipelineThe Input Assembler stage

      (最近在看龙书10.0, 这篇文章是是关于Rendering Pipeline的The Input Assembler stage的总结)

        Rendering pipeline(渲染管道)提供了一整套从摄像机视口的3D场景转化为2D图片的步骤。图 1显示了 渲染管道的不同时期。

    Rendering Pipeline

    图 1

        下面的文章以及以后会有几篇逐步介绍Direct 10.0 Rendering Pipeline渲染管道的不同时期。

    The Input Assembler stage

        The Input Assembler stage(输入装配器阶段)读取几何数据(vertex buffer 和 index buffer),然后用它们来装配几何图形(线,三角形).

    1. vertex  的定义

        一个vertex 位置,颜色,纹理坐标等属性。Direct3D 可以使我们灵活地创建vertex的格式或者说Direct3D允许我们定义一个vertex的组成。如我们就可以创建下面的结构体来描述一个点的位置,颜色和纹理坐标。

    1 struct vertex1
    2 {
    3 D3DXVECTOR3 pos;
    4 D3DXCOLOR color;
    5 D3DVECTOR2 texc
    6 }
    7  

    1.1. D3D10_INPUT_ELEMENT_DESC

        建立如上的vertex结构体以后, 我们还需要把这个结构体声明的点全部联系起来,Direct3D 用ID3D10InputLayout接口来实现这样的功能。这个接口被D3D10_INPUT_ELEMENT_DESC 描述。D3D10_INPUT_ELEMENT_DESC 中的每一个元素描述了一个vertex 结构体中的属性。所以如果vertex如果有3个属性的话, 就必须是D3D10_INPUT_ELEMENT_DESC layout[3]。

        我们先看下这个结构体是如何被定义的:

    1 typedef struct D3D10_INPUT_ELEMENT_DESC
    2 {
    3 LPCSTR SemanticName;
    4 UINT SemanticIndex;
    5 DXGI_FORMAT Format;
    6 UINT InputSlot;
    7 UINT AlignedByteOffset;
    8 D3D10_INPUT_CLASSIFICATION InputSlotClass;
    9 UINT InstanceDataStepRate;
    10 } D3D10_INPUT_ELEMENT_DESC;

     然后再解析下D3D10_INPUT_ELEMENT_DESC 结构体每一个参数的含义:

    SemanticName: 一个与元素相关的字符串。标识这个layout的名字。

    SemanticIndex: 一个Vectex的结构体可能可能有多个纹理。我们就可一个用SemanticIndex来标识它, 当其值为0的时候表示没有索引被定义。

    Format:DXGI_FORMAT枚举中的一个,表明了元素的格式, 如DXGI_FORMAT_R32G32B32_UINT。

    InputSlot:指定这些元素是从哪里来的, Direct3D 支持16个input slots(0-15)。例如,如果一个vertex 结构体有位置,颜色等,我们即可以用同一个input slots 来装配这个两个属性,也可以分别为这两个属性设置不同的input slot。然后,Direct3D会利用不同Input slot的元素来装配vectex。

    AlignedByteOffset: 表明一个input slot其位置到vertex结构体的距离。如:

    1 struct Vertex2
    2 {
    3 D3DXVECTOR3 pos; // 0-byte offset
    4   D3DXVECTOR3 normal; // 12-byte offset
    5   D3DXVECTOR2 texC; // 24-byte offset
    6  };

    InputSlotClass: 这里指定D3D10_INPUT_PER_VERTEX_DATA。

    InstanceDataStepRate: 这里指定0。

    如对于 Vertex2, 我们可以这样设置 Input Layout:

    1 D3D10_INPUT_ELEMENT_DESC desc2[] =
    2 {
    3 {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0},
    4 {"NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D10_INPUT_PER_VERTEX_DATA, 0},
    5 {"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D10_INPUT_PER_VERTEX_DATA, 0}
    6 };

    1.2 ID3D10Device::CreateInputLayout

        当input layout 设置完毕之后,我们用ID3D10Device::CreateInputLayout来获得一个指向ID3D10InputLayout接口的指针,这个指针就是用来描述 input layout的。

    1 HRESULT ID3D10Device::CreateInputLayout(
    2 const D3D10_INPUT_ELEMENT_DESC *pInputElementDescs,
    3 UINT NumElements,
    4 const void *pShaderBytecodeWithInputSignature,
    5 SIZE_T BytecodeLength,
    6 ID3D10InputLayout **ppInputLayout);

    pInputElementDescs: 1.1 所述的layout的数组

    NumElements: layout数组的大小(数量)

    pShaderBytecodeWithInputSignature: 一个指向顶点着色器的签名的字节码。

    BytecodeLength:以byte为单位的顶点着色器的签名的数据。

    ppInputLayout: 返回一个指向需要创建的input layout的指针前一个参数。

        第三个参数需要一些定制。一个顶点渲染器会为每一个顶点判断一其格式。Vertex 结构体重的每一个元素(顶点的属性)都必须映射到其相应的输入通道中。当在创建input layout 的时候, 通过传递顶点渲染器的签名,Direct3D能够从vetex 结构体到渲染器输入通道的映射。一个input layout能够被不同的渲染器重复使用,并且提供输入签名在不同的时间。

    下面是一个创建 input layout的实例:

    1 ID3D10Effect* mFX;
    2 ID3D10EffectTechnique* mTech;
    3 ID3D10InputLayout* mVertexLayout;
    4 /* ...create the effect... */
    5 mTech = mFX->GetTechniqueByName("ColorTech");
    6 D3D10_PASS_DESC PassDesc;
    7 mTech->GetPassByIndex(0)->GetDesc(&PassDesc);
    8 HR(md3dDevice->CreateInputLayout(vertexDesc, 3,
    9 PassDesc.pIAInputSignature, PassDesc.IAInputSignatureSize,
    10 &mVertexLayout));

        这里解释下 D3D10_PASS_DESC ,首先提出一个概念就是 effect, effect封装了顶点渲染器签名的传递过程,每一个顶点渲染器与这个过程相关联。所以从effect中, 我们可以通过D3D10_PASS_DESC结构体得到一个顶点渲染器的输入签名。

    1.3 IASetInputLayout

        当一个input layout被创建以后,它还没有绑定到一个device中, 调用IASetInputLayout函数可以把它绑定一个divece中,如:

    1 md3dDevice->IASetInputLayout(mVertexLayout);

    2 Vertex Buffers

        为了使GPU能够得到我们定义的点的数组的入口点, 我们必须定义一个专门的资源结构体(buffer)来描述这些点, D3D中用ID3D10Buffer接口来描述这个buffer。如果这个buffer是用来储存vertex的就叫 vertex buffer。为了创建一个vertex buffer,我们需要做如下步骤:

    (1) 填充D3D10_BUFFER_DESC结构体,这个结构体是用来描述 buffer的

    (2) 填充D3D10_SUBRESOURCE_DATA结构体, 这个结构体指定我们需要初始化的数据。

    (3) 调用ID3D10Device::CreateBuffer来创建 buffer。

    (4)调用ID3D10Device:IASetVertexBuffers把vertex buffer 设入device中。

    3 Primitive Topology

        一个vertex buffer只是在内存中存储了一系列内存点。它没有描述这些点是怎么组合在一起从而形成几何图形的。我们用 Primitive Topology 告诉Direct3D用点形成几何图形的方式。

    1 void ID3D10Device::IASetPrimitiveTopology(
    2 D3D10_PRIMITIVE_TOPOLOGY Topology);
    3 typedef enum D3D10_PRIMITIVE_TOPOLOGY
    4 {
    5 D3D10_PRIMITIVE_TOPOLOGY_UNDEFINED = 0,
    6 D3D10_PRIMITIVE_TOPOLOGY_POINTLIST = 1,
    7 D3D10_PRIMITIVE_TOPOLOGY_LINELIST = 2,
    8 D3D10_PRIMITIVE_TOPOLOGY_LINESTRIP = 3,
    9 D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST = 4,
    10 D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP = 5,
    11 D3D10_PRIMITIVE_TOPOLOGY_LINELIST_ADJ = 10,
    12 D3D10_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ = 11,
    13 D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ = 12,
    14 D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ = 13,
    15 } D3D10_PRIMITIVE_TOPOLOGY;

    3.1 Point List

        Point List 被D3D10_PRIMITIVE_TOPOLOGY_POINTLIST 定义。如果定义了Point List, Vertex buffer中的每一个点作为一个单独的点。如下图 2 a 所示。

    Point_List

     图 2

    3.2 Line Strip

        D3D10_PRIMITIVE_TOPOLOGY_LINESTRIP 定义了 Line Strip.如果定义了Line Strip, vertex buffer中的每一个点都会依次连接。所以如果有n+1个点,就会有n 条线。如图 2, b 所示。

    3.3 Line List

        D3D10_PRIMITIVE_TOPOLOGY_LINELIST 定义了 Line List. 如果定义了 Line List, 如图2 c 所示,每两个点会形成一条线。

    3.4 Triangle strip

        D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP定义了 Triangle Strip. 如果定义了Triangle strip,如图2 d 所示。

    3.5 Triangle List

        D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST定义了 Triangle List。如果定义了Triangle List,每三个点会形成一个三角形。如图 2. a 所示。

    Triangle_List

    图 3

    3.6 Primitives with Adjacency

        上面提到, 一个 triangle List 形成的是一个一个的三角形。如果把这些三角形连成一片的话,就必须包含他们的临近的三角形。我们可以用“adjacent triangles”技术来实现这个功能。 如图 3 . b 所示。为了使几何着色器能知道这些临近的三角形,这些三角形就必须向渲染管道提交 vertex/index buffer .并且D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ必须被定义。

    4 Indices and Index buffer

        三角形式形成几何图形的基础。如果我们要画如 图 4 所示的几何图形, 我们可以用如下代码

    代码
    Vertex quad[6] = {
    v0, v1, v2,
    // Triangle 0
    v0, v2, v3, // Triangle 1
    };
    Vertex octagon[
    24] = {
    v0, v1, v2,
    // Triangle 0
    v0, v2, v3, // Triangle 1
    v0, v3, v4, // Triangle 2
    v0, v4, v5, // Triangle 3
    v0, v5, v6, // Triangle 4
    v0, v6, v7, // Triangle 5
    v0, v7, v8, // Triangle 6
    v0, v8, v1 // Triangle 7
    };

    Index

    图 4

        但是我们代码中,我们发现, 有好多点是重复定义的。这里有两个原因需要去除这些重复定义的点:

              (1). 减少所需内存空间的大小。

              (2). 减少图形硬件对顶点的渲染。

        如果定义Triangle strips , 是可以渲染连续的点从而形成三角形的。但是triangle lists却更合适。所以这就有必要为triangle list 移去完全一样的点。这就需要 index buffer 显身手了。如: 如果我们想渲染如图 4  a 所示的四边形。我们可以先定义一个Vertex buffer:

    1 Vertex v[4] = {v0, v1, v2,v3};

    然后再定义一个 index buffer :

    1 DWORD indexList[6] = {0, 1, 2, // Triangle 0
    2   0, 2, 3}; // Triangle 1

    4.1 Index buffer 的创建

        因为Index buffer要被GPU接受, 所以我们在使用Index buffer的时候就必须如同一般资源一样被创建。EX:

    代码

    4.2 Index buffer 的绑定

        当创建完 index buffer 之后, 我们必须把index buffer 绑定到渲染管道中。我们可用ID3D10Device::IASetIndexBuffer接口来干这件事情。Ex:

    1 md3dDevice->IASetIndexBuffer(mIB, DXGI_FORMAT_R32_UINT, 0);

     4.4 用Index buffer 画几何图形

    最后,当我们使用 index buffer之后, 我们用DrawIndex()方法来渲染几何图形,而不是Draw()方法。Ex:

    1 md3dDevice->DrawIndexed(numSphereIndices, 0, 0);
  • 相关阅读:
    Git安装(操作篇)
    Git安装
    ES6基础练习
    SVN的安装与搭建及使用
    解决SVN文件不显示绿色小钩图标问题
    混入(mixin)
    ref属性与props配置项
    docker-compose部署 Mysql 8.0 主从模式基于GTID
    项目统一处理
    Docker Compose实战
  • 原文地址:https://www.cnblogs.com/sld666666/p/1830273.html
Copyright © 2011-2022 走看看