《Practical Rendering & Computation with Direct3D11》读书总结 Chapter-3-Direct3D 11 The Rendering Pipeline

本文详细解析Direct3D11渲染管线的各个阶段,包括Input Assembler、Vertex Shader、Tessellation、Geometry Shader、Rasterizer、Pixel Shader和Output Merger。内容涵盖每个阶段的功能、输入输出、配置选项及处理流程,为理解3D图形渲染提供了深入见解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本章是这本书最长的一章,也比较枯燥= = 这一章详细介绍了流水线各个阶段的一些细节。对于流水线的每一个环节,需要注意它的输入、配置、处理过程、输出
下面进行逐个的总结:

Input Assembler

Input Assembler(输入装配阶段)是流水线的第一个阶段,在一个流水线中,被处理的对象都是一系列的顶点,因此在这个阶段就进行将顶点的数据以流水线中规定的形式输入到流水线中。
Input Assembler Pipeline Input
装配顶点数据首先需要有顶点的输入,对应的资源为Vertex Buffer,其次还有可能需要顶点索引,对应的资源为Index Buffer,这两个Buffer的创建在前一章已经详细介绍了。下面分别来看这两个Buffer的用法。
Vertex Buffer的装配方法:
对于一个顶点来说,它蕴含的数据有多种,例如位置、法线、纹理坐标等等,但并不总是需要获取它所有的数据,比如说在单纯地以线框模式渲染时可能只需要它的位置就够了,所以对顶点数据的组织方法是有多种的,要看实际的需求。Vertex Buffer是存储顶点数据的Buffer,在前一章介绍了,它的存储方式是以数组的形式,也就是说所有的顶点数据以数组的方式存储,但是要注意,并不是说顶点的数据只能用一个Vertex Buffer来组织,有的时候可以将顶点的位置数据存在一个Buffer中,然后再将发现数据存在一个Buffer中。Input Assembler是有多个INPUT SLOT的,每一个SLOT都可以填充Vertex Buffer Resource,确切的说,一共有16个INPUT SLOT供Vertex Buffer来装配。

pContext->IASetVertexBuffers(StartSlot,NumBuffers, aBuffers, aStrides,aOffsets);

具体的装配由IASetVertexBuffer函数完成,它的参数分别为 起始用的SLOT、BUFFER的数量、指向BUFFER数组的指针、指向Stride数组的指针、指向Offset数组的指针。其中Stride和Offset都是UINT类型,它们分别代表当前Buffer资源中的单个数据元素的大小 和 起始数据距离Buffer资源起始位置的偏移量。
Index Buffer的装配方法:
Index Buffer中的数据就比较简单了,一般都是UINT类型,代表顶点的索引,也只需要一个Buffer就够了,因为它并没有复杂的类型,Index Buffer的装配由IASetIndexBuffer完成:

m_pContext->IASetIndexBuffer( pBuffer, DXGI_FORMAT_R32_UINT, offset );

三个参数分别是IndexBuffer、IndexBuffer的数据格式、首元素的偏移量。数据格式取16bit和32bit都可以。

Input Assembler State Configuration
在做顶点装配的时候,Input Assembler还有两个独特的配置需要注意。一个是Input Layout,另一个是Primitive Topology。
Input Layout
顶点数据被装配以后,它该如何在Shader中被解析被使用?这就需要Input Layout来解决,先来看一段Input Layout创建的实例:

    HRESULT result;
    ID3D11InputLayout *input;
    D3D11_INPUT_ELEMENT_DESC desc[3];
    desc[0].SemanticName = "POSITION";
    desc[0].SemanticIndex = 0;
    desc[0].InputSlot = 0;
    desc[0].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
    desc[0].AlignedByteOffset = 0;
    desc[0].InstanceDataStepRate = 0;
    desc[0].Format = DXGI_FORMAT_R32G32B32_FLOAT;

    desc[1].SemanticName = "TEXCOORD";
    desc[1].SemanticIndex = 0;
    desc[1].InputSlot = 0;
    desc[1].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
    desc[1].AlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT;
    desc[1].InstanceDataStepRate = 0;
    desc[1].Format = DXGI_FORMAT_R32G32_FLOAT;

    desc[2].SemanticName = "NORMAL";
    desc[2].SemanticIndex = 0;
    desc[2].InputSlot = 0;
    desc[2].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
    desc[2].AlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT;
    desc[2].InstanceDataStepRate = 0;
    desc[2].Format = DXGI_FORMAT_R32G32B32_FLOAT;

    result = device->CreateInputLayout(desc, 3, vertexShaderBuffer->GetBufferPointer(), vertexShaderBuffer->GetBufferSize(), &input);
    HR(result);

它所对应的Shader中的顶点数据类型的声明如下:

struct VertexInputType
{
    float4 position : POSITION;
    float2 tex : TEXCOORD0; 
    float3 normal : NORMAL;
};

创建一个InputLayout需要提供多个InputLayoutDesc,装配的顶点结构中有几种数据成员就需要有多少个Desc,对于每个Desc需要填充七个参数,SemanticName对应它在HLSL中声明时的标志,这个标志是有可能重复的,对于重复的需要在后边加一个编号,即SemanticIndex。InputSlot代表着该数据成员对应的Buffer在哪一个SLOT中,Format代表它的格式,AlignedByteOffset代表它的首元素在当前Buffer中的偏移量。需要着重注意的是剩余的两个参数:InputSlotClass、InstanceDataStepRate。这里涉及到一项技术:Instance Rendering,在实时渲染中,很多时候需要将一个物体模型重复在多个位置渲染多次,这个时候顶点的数据都是不变的,只是整体的位置有所变化而已,那么这个时候可以将不同的位置作为Vertex Buffer装配,这里不同的位置信息就是相对于每个Instance实例的数据,而不是每个顶点的数据。Input Slot Class就表示当前的这个数据究竟是相对于每个Instance的数据,还是对于每个顶点的数据,而InstanceDataStepRate则表示Instance的数据的变化频率是多少,即渲染多少个Instance会改变这个数据的值,和顶点数据不同,顶点数据是每变化一次顶点数据就要进行改变的。

Primitive Topology
决定顶点所表示的几何类型,有的时候输入的顶点就是三角网格的数据,而有的时候输入的顶点是一系列线段的数据,区分这些几何类型就需要Primitive Topology,它是一个枚举类型。Primitive Topology的所有取值
它的取值可以看这个链接。

Input Assembler Stage Processing
接下来介绍Input Assembler在配置完一些信息后具体做了些什么事情。
Vertex Streams
Input Assembler将输入的各种Vertex Buffer的数据进行逐顶点的整合,最终生成一个Vertex Stream,这个Stream有两种可能的顺序,一种是顶点原本的顺序,另一种是由Index Buffer决定的顺序,决定要用哪种顺序的是 Draw 函数的调用方式,这个之后详述。
Primitive Streams
Vertex Stream又进一步地被提炼为一个Primitive Stream,供后续的某些环节使用,这个Primitive Stream的构建方式取决于配置的Primitive Topology和 Draw函数的调用方式。
Draw函数的影响

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值