Direct3D 11 Tutorial 2: Rendering a Triangle_Direct3D 11 教程2:渲染一个三角形

概要

在之前的教程中,我们建立了一个最小的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 );

  

原文地址:https://www.cnblogs.com/OctoptusLian/p/9745782.html

时间: 2024-10-11 10:44:57

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

dx11 入门 Tutorial 02: 数据传入GPU的设置 和绘制一个三角形 DirectXSampleBrowser(June 2010)

烦...一年前看过教程,但全忘掉了,这一年我都干什么了... 教程2遇到的两个error: error 1:ID3DBlob调用不成功 ,是重复调用版本冲突的原因?ID3DBlob在D3DCommon.h中, 因为window include里和SDK里各有一份,造成了冲突,修改头文件的调用,先调用SDK内的即可.参考:http://www.cnblogs.com/Wilson-Loo/archive/2013/01/20/2797902.html 那为什么先后顺序就解决问题呢> error 2

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

概述 在上一个教程中,我们设置了一个顶点缓冲区并将一个三角形传递给GPU. 现在,我们将逐步完成图形管道并查看每个阶段的工作原理. 将解释着色器和效果系统的概念. 请注意,本教程与前一个源代码共享相同的源代码,但将强调不同的部分. 资源目录 (SDK root)\Samples\C++\Direct3D11\Tutorials\Tutorial03 Github仓库 图形管道 在上一个教程中,我们设置顶点缓冲区,然后将顶点布局与顶点着色器相关联. 现在,我们将解释着色器是什么以及它是如何工作的.

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

概述 在上一个教程中,我们在应用程序窗口的中心成功渲染了一个三角形. 我们没有太注意我们在顶点缓冲区中拾取的顶点位置. 在本教程中,我们将深入研究3D位置和转换的细节. 本教程的结果将是渲染到屏幕的3D对象. 虽然之前的教程侧重于将2D对象渲染到3D世界,但在这里我们展示了一个3D对象. 资源目录 (SDK root)\Samples\C++\Direct3D11\Tutorials\Tutorial04 Github仓库 3D空间 在上一个教程中,三角形的顶点被有策略地放置,以在屏幕上完美地对

Tutorial - Deferred Rendering Shadow Mapping 转

http://www.codinglabs.net/tutorial_opengl_deferred_rendering_shadow_mapping.aspx Tutorial - Deferred Rendering Shadow Mapping In this tutorial I will present the shadow mapping technique implemented in a deferred renderer. This tutorial will lean on

探索Oracle之数据库升级二 11.2.0.3升级到11.2.0.4完整步骤

探索Oracle之数据库升级二  11.2.0.3升级到11.2.0.4完整步骤 说明:         这篇文章主要是记录下单实例环境下Oracle 11.2.0.1升级到11.2.0.3的过程,当然RAC的升级是会有所不同.但是他们每个版本之间升级步骤都是差不多的,先升级Database Software,再升级Oracle Instance. Oracle 11.2.0.4的Patchset No:19852360下载需要有Oracle Support才可以.  Patchset包含有7个

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

作者:王选易,出处:http://www.cnblogs.com/neverdie/ 欢迎转载,也请保留这段声明.如果你喜欢这篇文章,请点[推荐].谢谢! 什么是C++11 C++11是曾经被叫做C++0x,是对目前C++语言的扩展和修正,C++11不仅包含核心语言的新机能,而且扩展了C++的标准程序库(STL),并入了大部分的C++ Technical Report 1(TR1)程序库(数学的特殊函数除外). C++11包括大量的新特性:包括lambda表达式,类型推导关键字auto.decl

ORACLE 11.2.0.1升级到11.2.0.3

ORACLE 11.2.0.1升级到11.2.0.3 最近听了李光老师的关于oracle的升级公开课,深有感悟,之前一直想自己测试的,没有下定决心,这几天自己在虚拟机上测试了一下,测试的过程如下,当然这个只是一些基本的步骤,实际的生产环境我想比这个复杂的多了,但是不用急,慢慢来,循序渐进吧... 1. 数据库情况 单实例非ASM存储 ORACLE_SID : orcl ORACLE_HOME: /u01/app/oracle/product/11.2.0/dbhome_1 1. 数据库原始状态

Oracle 11.2.0.4打PSU 11.2.0.4.161018

最近生产上要给Oracle数据库打11g最新的补丁,这里先做一个测试记录一下. Oracle数据库所有补丁的MOS文档ID 1922396.1下载地址:https://support.oracle.com/epmos/faces/DocContentDisplay?_afrLoop=242245405602967&id=1577380.1&_afrWindowMode=0&_adf.ctrl-state=zv36z4hoo_53这个下载需要有MOS账号 Oracle数据库的补丁有几

探索Oracle之数据库升级四 11.2.0.4.0 PSU 11.2.0.4.3

探索Oracle之数据库升级四 11.2.0.4.0 PSU 11.2.0.4.3   一.  检查当前数据库PSU号: [[email protected] ~]$ cd/DBSoft/Product/11.2.4/db_1/OPatch/ [[email protected] OPatch]$ ls crs docs emdpatch.pl jlib ocm opatch opatch.bat opatchdiag opatchdiag.bat opatch.ini opatch.pl op