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
在我们的代码中,我们有一个三角形,所以我们指定的并不重要。 但是,我们必须指定一些内容,因此我们选择了三角形列表。
// 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:渲染一个三角形的更多相关文章
- Direct3D 11 Tutorial 1: Basics_Direct3D 11 教程1:基础
Github-LearnDirectX-DX3D11 tutorial01 概述 在这第一篇教程中,我们将通过介绍创建最小Direct3D应用程序所必需的元素.每一个Direct3D应用程序必需拥有这 ...
- Direct3D 11 Tutorial 4: 3D Spaces_Direct3D 11 教程4:3D空间
概述 在上一个教程中,我们在应用程序窗口的中心成功渲染了一个三角形. 我们没有太注意我们在顶点缓冲区中拾取的顶点位置. 在本教程中,我们将深入研究3D位置和转换的细节. 本教程的结果将是渲染到屏幕的3 ...
- Direct3D 11 Tutorial 3: Shaders and Effect System_Direct3D 11 教程3:着色器和效果系统
概述 在上一个教程中,我们设置了一个顶点缓冲区并将一个三角形传递给GPU. 现在,我们将逐步完成图形管道并查看每个阶段的工作原理. 将解释着色器和效果系统的概念. 请注意,本教程与前一个源代码共享相同 ...
- Java 11 Tutorial
Java 11 Tutorial 参考 https://blog.csdn.net/sihai12345/article/details/82889827 原文 https://winterbe.co ...
- Tutorial - Deferred Rendering Shadow Mapping 转
http://www.codinglabs.net/tutorial_opengl_deferred_rendering_shadow_mapping.aspx Tutorial - Deferred ...
- 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 ...
- 【C++11】30分钟了解C++11新特性
作者:王选易,出处:http://www.cnblogs.com/neverdie/ 欢迎转载,也请保留这段声明.如果你喜欢这篇文章,请点[推荐].谢谢! 什么是C++11 C++11是曾经被叫做C+ ...
- Oracle从11.2.0.2开始,数据库补丁包是一个完整安装包(转)
从11.2.0.2开始,数据库补丁包是一个完整安装包.也就是说:比如要打11.2.0.2的补丁包,直接用11.2.0.2包来安装就可以了,不需要像10G一样先安装数据库软件再来打补丁包. 如果已经安装 ...
- 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 ...
随机推荐
- 潭州课堂25班:Ph201805201 tornado 项目 第二课 项目 基本功能模块和 Git 使用 (课堂笔记)
tornado 相关说明 把图片显示在页面, 创建个 static 文件夹, 在这个文件下存放几张图片 在配置中指定静态文件路径, 在 html 文件中迭代出图片, 创建个包,重构 handlers ...
- npm install出现"Unexpected end of JSON input while parsing near"
打开命令行输入 npm cache clean --force 重新npm i,即可解决报错
- (转自知乎)Unicode编码
很多人都把Unicode编码挂在嘴边,其实咱们现实生活中遇到的编码基本都是Unicode的 因为Unicode兼容了大多数老版本的编码规范例如 ASCII Unicode编码定义了这个世界上几乎所有字 ...
- Android 中的设计模式
1.单例模式 ContentProvider是单例模式,多个ContentResolver操作的都是同一个ContentProvider.
- 编程菜鸟的日记-初学尝试编程-寻找2到n之间的素数并输出
//输入一个整数n,输出2到n之间的具体素数值 #include <iostream> #include <algorithm> #include <cmath> ...
- Flask CBV
from flask import Flask, views import time app = Flask(__name__) def zhuangshiqi(func): def inner(*a ...
- Egret 类的创建和继承--TypeScript
class test extends egret.DisplayObjectContainer { /** * 类的创建 */ //属性 name: string; age: number; ts: ...
- 深入理解JVM(6)——JVM性能调优实战
如何在高性能服务器上进行JVM调优:以便充分利用高性能服务器的硬件资源,有两种JVM调优方案. 一. 采用64位操作系统,并为JVM分配大内存 分析:如果JVM中堆内存太小,那么就会频繁 ...
- 词向量保存为txt
model.wv.save_word2vec_format('w2v_mod.txt',binary=False)
- python之接口与归一化设计
1接口 接口的概念: Java 语言中的接口很好的展现了接口的含义: IAnimal.java /* * Java的Interface很好的体现了我们前面分析的接口的特征: * 1)是一组功能的集合, ...