概要

在之前的教程中,我们建立了一个最小的Direct3D 11的应用程序,它用来在窗口上输出一个单一颜色。在本次教程中,我们将扩展这个应用程序,在屏幕上渲染出一个单一颜色的三角形。我们将通过设置数据机构的过程关联到三角形。

这个教程的输出结果是在窗口中央渲染出一个三角形。

资源目录

(SDK root)\Samples\C++\Direct3D11\Tutorials\Tutorial02

Github-LearnDirectX-DX3D11 tutorial02 (源码已上传至Github)

三角形的元素

三角形由其三个点定义,也称为顶点。 具有唯一位置的一组三个顶点定义了唯一的三角形。 为了让GPU渲染三角形,我们必须告诉它三角形的三个顶点的位置。举一个2D的例子,假设我们希望渲染一个三角形,例如图1中的三角形。我们将三个顶点与位置(0,0)(0,1)和(1,0)一起传递给GPU,然后 GPU有足够的信息来渲染我们想要的三角形。

图1.由三个顶点定义的2D三角形

所以现在我们知道我们必须将三个位置传递给GPU才能渲染三角形。 我们如何将这些信息传递给GPU? 在Direct3D 11中,诸如位置的顶点信息存储在缓冲区资源中。 用于存储顶点信息的缓冲区被称为顶点缓冲区,这并不奇怪。 我们必须为三个顶点创建一个足够大的顶点缓冲区,并用顶点位置填充它。 在Direct3D 11中,应用程序必须在创建缓冲区资源时指定缓冲区大小(以字节为单位)。 我们知道缓冲区必须足够大才能容纳三个顶点,但每个顶点需要多少字节? 要回答这个问题,需要了解顶点布局。

输入布局

顶点有一个位置。 通常,它还具有其他属性,例如法线,一种或多种颜色,纹理坐标(用于纹理映射)等。 顶点布局定义了这些属性在内存中的位置:每个属性使用的数据类型,每个属性的大小以及内存中属性的顺序。 因为属性通常具有不同的类型,类似于C结构中的字段,所以顶点通常由结构表示。 顶点的大小可以方便地从结构的大小中获得。

在本教程中,我们只处理顶点的位置。 因此,我们使用XMFLOAT3类型的单个字段定义顶点结构。 此类型是三个浮点组件的向量,通常是用于3D位置的数据类型。

struct SimpleVertex
{
XMFLOAT3 Pos; // Position
};

  

我们现在有一个表示我们的顶点的结构。 它负责在我们的应用程序中将顶点信息存储在系统内存中。 然而,当我们向GPU提供包含顶点的顶点缓冲区时,我们只是给它一块内存。 GPU还必须知道顶点布局,以便从缓冲区中提取正确的属性。 要实现此目的,需要使用输入布局。

在Direct3D 11中,输入布局是Direct3D对象,它以GPU可以理解的方式描述顶点的结构。 可以使用D3D11_INPUT_ELEMENT_DESC结构描述每个顶点属性。 应用程序定义一个或多个D3D11_INPUT_ELEMENT_DESC的数组,然后使用该数组创建输入布局对象,该对象将顶点描述为一个整体。 现在我们将详细介绍D3D11_INPUT_ELEMENT_DESC的字段。

SemanticName

SemanticName是一个字符串,其中包含描述此元素的性质或目的(或语义)的单词。 这个词可以是C标识符可以的任何形式,也可以是我们选择的任何形式。 例如,顶点位置的良好语义名称是POSITION。 语义名称不区分大小写。

SemanticIndex

SemanticIndex补充了语义名称。 顶点可以具有相同性质的多个属性。 例如,它可以具有2组纹理坐标或2组颜色。 不是使用附加了数字的语义名称,例如“COLOR0”和“COLOR1”,这两个元素可以共享单个语义名称“COLOR”,具有不同的语义索引0和1。

Format

格式定义要用于此元素的数据类型。 例如,DXGI_FORMAT_R32G32B32_FLOAT的格式有三个32位浮点数,使元素长12个字节。 DXGI_FORMAT_R16G16B16A16_UINT的格式有四个16位无符号整数,使元素长8个字节。

InputSlot

如前所述,Direct3D 11应用程序通过使用顶点缓冲区将顶点数据传递给GPU。 在Direct3D 11中,可以同时向GPU提供多个顶点缓冲区,准确地说是16。 每个顶点缓冲区都绑定到0到15之间的输入槽号.InputSlot字段告诉GPU它应该为该元素获取哪个顶点缓冲区。

AlignedByteOffset

顶点存储在顶点缓冲区中,顶层缓冲区只是一块内存。 AlignedByteOffset字段告诉GPU开始获取此元素数据的内存位置。

InputSlotClass

该字段的值通常为D3D11_INPUT_PER_VERTEX_DATA。 当应用程序使用实例化时,它可以将输入布局的InputSlotClass设置为D3D11_INPUT_PER_INSTANCE_DATA以使用包含实例数据的顶点缓冲区。 Instancing是一个高级的Direct3D主题,这里不再讨论。 对于我们的教程,我们将专门使用D3D11_INPUT_PER_VERTEX_DATA。

InstanceDataStepRate

该字段用于实例化。 由于我们不使用实例化,因此不使用此字段,必须将其设置为0。

现在我们可以定义D3D11_INPUT_ELEMENT_DESC数组并创建输入布局:

// Define the input layout
D3D11_INPUT_ELEMENT_DESC layout[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
UINT numElements = ARRAYSIZE(layout);

  

顶点布局

在下一个教程中,我们将解释技术对象和关联的着色器。 目前,我们将专注于为该技术创建Direct3D 11顶点布局对象。 但是,我们将了解顶点着色器与此顶点布局紧密耦合。 原因是创建顶点布局对象需要顶点着色器的输入签名。 我们使用从D3DX11CompileFromFile返回的ID3DBlob对象来检索表示顶点着色器的输入签名的二进制数据。 获得此数据后,我们可以调用ID3D11Device :: CreateInputLayout()来创建顶点布局对象,并使用ID3D11DeviceContext :: IASetInputLayout()将其设置为活动顶点布局。 完成所有这些操作的代码如下所示:

// Create the input layout
if( FAILED( g_pd3dDevice->CreateInputLayout( layout, numElements, pVSBlob->GetBufferPointer(),
pVSBlob->GetBufferSize(), &g_pVertexLayout ) ) )
return FALSE;
// Set the input layout
g_pImmediateContext->IASetInputLayout( g_pVertexLayout );

  

创建顶点缓冲区

在初始化期间我们还需要做的一件事是创建保存顶点数据的顶点缓冲区。 要在Direct3D 11中创建顶点缓冲区,我们填写两个结构D3D11_BUFFER_DESC和D3D11_SUBRESOURCE_DATA,然后调用ID3D11Device :: CreateBuffer()。

D3D11_BUFFER_DESC描述了要创建的顶点缓冲区对象,D3D11_SUBRESOURCE_DATA描述了在创建过程中将复制到顶点缓冲区的实际数据。 顶点缓冲区的创建和初始化是一次完成的,因此我们以后不需要初始化缓冲区。 将复制到顶点缓冲区的数据是顶点,即三个简单结构的数组。 选择顶点数组中的坐标,以便在使用着色器渲染时在应用程序窗口的中间看到一个三角形。 创建顶点缓冲区后,我们可以调用ID3D11DeviceContext :: IASetVertexBuffers()将其绑定到设备。 完整的代码如下所示:

// Create vertex buffer
SimpleVertex vertices[] =
{
XMFLOAT3( 0.0f, 0.5f, 0.5f ),
XMFLOAT3( 0.5f, -0.5f, 0.5f ),
XMFLOAT3( -0.5f, -0.5f, 0.5f ),
};
D3D11_BUFFER_DESC bd;
ZeroMemory( &bd, sizeof(bd) );
bd.Usage = D3D11_USAGE_DEFAULT;
bd.ByteWidth = sizeof( SimpleVertex ) * 3;
bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bd.CPUAccessFlags = 0;
bd.MiscFlags = 0;
D3D11_SUBRESOURCE_DATA InitData;
ZeroMemory( &InitData, sizeof(InitData) );
InitData.pSysMem = vertices;
if( FAILED( g_pd3dDevice->CreateBuffer( &bd, &InitData, &g_pVertexBuffer ) ) )
return FALSE; // Set vertex buffer
UINT stride = sizeof( SimpleVertex );
UINT offset = 0;
g_pImmediateContext->IASetVertexBuffers( 0, 1, &g_pVertexBuffer, &stride, &offset );

  

原始拓扑

原始拓扑是指GPU如何获得渲染三角形所需的三个顶点。 我们在上面讨论过,为了渲染单个三角形,应用程序需要向GPU发送三个顶点。 因此,顶点缓冲区中有三个顶点。 如果我们想渲染两个三角形怎么办? 一种方法是将6个顶点发送到GPU。 前三个顶点定义第一个三角形,后三个顶点定义第二个三角形。 此拓扑称为三角形列表。 三角形列表具有易于理解的优点,但在某些情况下它们效率非常低。 当连续渲染的三角形共享顶点时会出现这种情况。 例如,图3a左侧显示了由两个三角形组成的正方形:ABC和CB D.(按照惯例,三角形通常通过按顺时针顺序列出它们的顶点来定义。)如果我们使用三角形列表将这两个三角形发送到GPU ,我们的顶点缓冲区会这样:

A B C C B D

请注意,B和C在顶点缓冲区中出现两次,因为它们由两个三角形共享。

图3a包含一个由两个三角形组成的正方形; 图3b包含由三个三角形组成的五边形。

如果我们可以告诉GPU在渲染第二个三角形时,我们可以使顶点缓冲区更小,而不是从顶点缓冲区获取所有三个顶点,使用前一个三角形中的2个顶点,并从顶点缓冲区中仅获取1个顶点。 事实证明,这是由Direct3D支持的,拓扑结构称为三角形条带。 渲染三角形条带时,第一个三角形由顶点缓冲区中的前三个顶点定义。 下一个三角形由前一个三角形的最后两个顶点加上顶点缓冲区中的下一个顶点定义。 以图3a中的方块为例,使用三角形条带,顶点缓冲区看起来像:

A B C D

前三个顶点A B C定义第一个三角形。 第二个三角形由B和C定义,即第一个三角形的最后两个顶点加上D.因此,通过使用三角形条带拓扑,顶点缓冲区大小从6个顶点变为4个顶点。 类似地,对于三个三角形,例如图3b中的三角形,使用三角形列表将需要顶点缓冲区,例如:

A B C C B D C D E

使用三角形条带,顶点缓冲区的大小显着减少:

A B C D E
你可能已经注意到,在三角形条带示例中,第二个三角形定义为B C D.这三个顶点不形成顺时针顺序。 这是使用三角形条带的自然现象。 为了克服这个问题,GPU会自动交换来自前一个三角形的两个顶点的顺序。 它只对第二个三角形,第四个三角形,第六个三角形,第八个三角形等执行此操作。 这确保每个三角形由顶点以正确的缠绕顺序(在这种情况下为顺时针方向)定义。 除了三角形列表和三角形条带外,Direct3D 11还支持许多其他类型的原始拓扑。 我们不会在本教程中讨论它们。

在我们的代码中,我们有一个三角形,所以我们指定的并不重要。 但是,我们必须指定一些内容,因此我们选择了三角形列表。

// Set primitive topology
g_pImmediateContext->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST );

  

渲染三角形

缺少的最后一项是执行三角形实际渲染的代码。我们创建了两个用于渲染的着色器,顶点着色器和像素着色器。顶点着色器负责将三角形的各个顶点转换为正确的位置。像素着色器负责计算三角形的每个像素的最终输出颜色。这将在下一个教程中详细介绍。要使用这些着色器,我们必须分别调用ID3D11DeviceContext :: VSSetShader()和ID3D11DeviceContext :: PSSetShader()。我们做的最后一件事是调用ID3D11DeviceContext :: Draw(),它命令GPU使用当前顶点缓冲区,顶点布局和原始拓扑进行渲染。 Draw()的第一个参数是要发送到GPU的顶点数,第二个参数是要开始发送的第一个顶点的索引。因为我们渲染一个三角形并且我们从顶点缓冲区的开头渲染,所以我们分别使用3和0作为两个参数。整个三角形渲染代码如下所示:

// Render a triangle
g_pImmediateContext->VSSetShader( g_pVertexShader, NULL, 0 );
g_pImmediateContext->PSSetShader( g_pPixelShader, NULL, 0 );
g_pImmediateContext->Draw( 3, 0 );

  

最终渲染效果:

Direct3D 11 Tutorial 2: Rendering a Triangle_Direct3D 11 教程2:渲染一个三角形的更多相关文章

  1. Direct3D 11 Tutorial 1: Basics_Direct3D 11 教程1:基础

    Github-LearnDirectX-DX3D11 tutorial01 概述 在这第一篇教程中,我们将通过介绍创建最小Direct3D应用程序所必需的元素.每一个Direct3D应用程序必需拥有这 ...

  2. Direct3D 11 Tutorial 4: 3D Spaces_Direct3D 11 教程4:3D空间

    概述 在上一个教程中,我们在应用程序窗口的中心成功渲染了一个三角形. 我们没有太注意我们在顶点缓冲区中拾取的顶点位置. 在本教程中,我们将深入研究3D位置和转换的细节. 本教程的结果将是渲染到屏幕的3 ...

  3. Direct3D 11 Tutorial 3: Shaders and Effect System_Direct3D 11 教程3:着色器和效果系统

    概述 在上一个教程中,我们设置了一个顶点缓冲区并将一个三角形传递给GPU. 现在,我们将逐步完成图形管道并查看每个阶段的工作原理. 将解释着色器和效果系统的概念. 请注意,本教程与前一个源代码共享相同 ...

  4. Java 11 Tutorial

    Java 11 Tutorial 参考 https://blog.csdn.net/sihai12345/article/details/82889827 原文 https://winterbe.co ...

  5. Tutorial - Deferred Rendering Shadow Mapping 转

    http://www.codinglabs.net/tutorial_opengl_deferred_rendering_shadow_mapping.aspx Tutorial - Deferred ...

  6. Oracle_RAC数据库GI的PSU升级(11.2.0.4.0到11.2.0.4.8)

    Oracle_RAC数据库GI的PSU升级(11.2.0.4.0到11.2.0.4.8) 本次演示为升级oracle rac数据库,用GI的psu升级,从11.2.0.4.0升级到11.2.0.4.8 ...

  7. 【C++11】30分钟了解C++11新特性

    作者:王选易,出处:http://www.cnblogs.com/neverdie/ 欢迎转载,也请保留这段声明.如果你喜欢这篇文章,请点[推荐].谢谢! 什么是C++11 C++11是曾经被叫做C+ ...

  8. Oracle从11.2.0.2开始,数据库补丁包是一个完整安装包(转)

    从11.2.0.2开始,数据库补丁包是一个完整安装包.也就是说:比如要打11.2.0.2的补丁包,直接用11.2.0.2包来安装就可以了,不需要像10G一样先安装数据库软件再来打补丁包. 如果已经安装 ...

  9. PSU 离11.2.0.3.0 -> 11.2.0.3.11 如果解决冲突的整个

    Oracle rdbms 扑灭psu离11.2.0.3.0升级到11.2.0.3.11 参考patch :18522512 停止应用,停止听音乐并DB,将db的oracle_home在下面OPatch ...

随机推荐

  1. MySQL连接缓慢,打开缓慢原因

    问题状况:最近由于服务器变换了网段,导致IP地址变换,变化后使用MySQL客户端连接MySQL服务器和在客户端中打开表的速度非常慢(无论表的大小),甚至连接超时,但是直接登录到服务器在本地连接MySQ ...

  2. mongodb更新数组元素中的字段,数组$占位符

    pppCodes为数组,PPPCode,expiredOn为数组元素中的字段 db.getCollection('users').findOneAndUpdate({ _id: userId, 'pp ...

  3. vue给methods中的方法传入当前点击行的值

    <template> <!-- 在template中,只能存在一个根组件 --> <div class="event"> <ul> ...

  4. leetCode中老出现的针对一个int中每个数字的处理

    一个int比如322,我想找happy number就得3平方加2平方再加2平方,怎样找到一个一个的数字,就是322%10,得到2,然后/10,然后再%,就可以依次求得每位上的数字 happy num ...

  5. C#静态代码检查工具StyleCode

    C#静态代码检查工具StyleCode -- 初探 最近我们Advent Data Service (ADS) 在项目上需要按照代码规范进行代码的编写工作,以方便将来代码的阅读与维护. 但是人工检查起 ...

  6. springboot上传文件并检查图片大小与格式

    @PostMapping(value = "/uploadDriverImage") public JsonResVo uploadDriverImage(@RequestPara ...

  7. RestTemplate之GET和POST调用和异步回调

    get方式 String url = "http://hostname:port/v1.0/data/data"; HttpHeaders headers = new HttpHe ...

  8. SpringBoot无废话入门02:SpringBoot启动分析

    1.核心注解 在上文中,我们讲到了@SpringBootApplication是SpringBoot的核心注解. 可以很方便的在idea中下载源码来查看该注解的源码,如下: 可以看到,该注解本身又被其 ...

  9. 诡异的druid链接池链接断开故障经验总结

    背景 症状 排查 修复 背景 最近在陆续做机房升级相关工作,配合DBA对产线数据库链接方式做个调整,将原来直接链接读库的地址切换到统一的读负载均衡的代理 haproxy 上,方便机柜和服务器的搬迁. ...

  10. FtpCopy数据定时自动备份软件(FTP定时备份)

    1. 软件说明 FtpCopy是一款免费的FTP数据自动备份软件,如果FtpCopy对您有较大的帮助,欢迎捐赠我们,我们对您表示衷心的感谢! 如果有需求的话会一直更新下去,将软件做到极致! 有问题可直 ...