[译]Vulkan教程(21)顶点input描述

Vertex input description 顶点input描述

Introduction 入门

In the next few chapters, we're going to replace the hardcoded vertex data in the vertex shader with a vertex buffer in memory. We'll start with the easiest approach of creating a CPU visible buffer and using memcpy to copy the vertex data into it directly, and after that we'll see how to use a staging buffer to copy the vertex data to high performance memory.

接下来的几章,我们将替换顶点shader里硬编码的顶点数据with一个内存中的顶点buffer。我们从最简单的方式开始,创建一个CPU可见的buffer,用memcpy 直接复制顶点数据进顶点buffer,之后,我们将看一下如何用一个阶段buffer to复制顶点数据to高性能内存。

Vertex shader 顶点shader

First change the vertex shader to no longer include the vertex data in the shader code itself. The vertex shader takes input from a vertex buffer using the in keyword.

首先,修改顶点shader,不再包含顶点数据。顶点shader从一个顶点buffer(用in 关键字表示)接收input。

#version
#extension GL_ARB_separate_shader_objects : enable layout(location = ) in vec2 inPosition;
layout(location = ) in vec3 inColor; layout(location = ) out vec3 fragColor; void main() {
gl_Position = vec4(inPosition, 0.0, 1.0);
fragColor = inColor;
}

The inPosition and inColor variables are vertex attributes. They're properties that are specified per-vertex in the vertex buffer, just like we manually specified a position and color per vertex using the two arrays. Make sure to recompile the vertex shader!

inPosition 和inColor 变量是顶点属性。它们是顶点buffer中逐顶点的属性,就像我们手工逐顶点地指定一个位置和颜色-用2个数组。确保重新编译这个顶点shader!

Just like fragColor, the layout(location = x) annotations assign indices to the inputs that we can later use to reference them. It is important to know that some types, like dvec3 64 bit vectors, use multiple slots. That means that the index after it must be at least 2 higher:

就像fragColor一样,layout(location = x) 注解赋予索引to输入that我们之后可以用来引用它们。重要的一点是,有的类型(例如64位向量dvec3 )使用多个slot。这意味着,它之后的索引必须最少增加2:

layout(location = ) in dvec3 inPosition;
layout(location = ) in vec3 inColor;

You can find more info about the layout qualifier in the OpenGL wiki.

你可以在OpenGL wiki找到更多关于布局标识符的信息。

Vertex data 顶点数据

We're moving the vertex data from the shader code to an array in the code of our program. Start by including the GLM library, which provides us with linear algebra related types like vectors and matrices. We're going to use these types to specify the position and color vectors.

我们要把shader代码中的数据移动到我们程序代码的一个数组里。首先,引入GLM库,which提供线性代数相关的类型-例如向量和矩阵。我们要用这些类型to指定位置和颜色向量。

#include <glm/glm.hpp>

Create a new structure called Vertex with the two attributes that we're going to use in the vertex shader inside it:

创建新结构体Vertex ,添加2个属性that我们要在顶点shader中使用:

struct Vertex {
glm::vec2 pos;
glm::vec3 color;
};

GLM conveniently provides us with C++ types that exactly match the vector types used in the shader language.

GLM贴心地提供的C++类型与shader语言的向量类型完全匹配。

const std::vector<Vertex> vertices = {
{{0.0f, -0.5f}, {1.0f, 0.0f, 0.0f}},
{{0.5f, 0.5f}, {0.0f, 1.0f, 0.0f}},
{{-0.5f, 0.5f}, {0.0f, 0.0f, 1.0f}}
};

Now use the Vertex structure to specify an array of vertex data. We're using exactly the same position and color values as before, but now they're combined into one array of vertices. This is known as interleaving vertex attributes.

现在用Vertex 结构体指定顶点数据的数组。我们使用和之前完全一样的位置和颜色值,但现在它们组合进一个顶点数组了。这被称为交错顶点属性。

Binding descriptions 绑定描述

The next step is to tell Vulkan how to pass this data format to the vertex shader once it's been uploaded into GPU memory. There are two types of structures needed to convey this information.

下一步是告诉Vulkan,当它被上传到GPU内存后,如何传入这个数据格式到顶点shader。需要用2种类型的结构体来传达这个信息。

The first structure is VkVertexInputBindingDescription and we'll add a member function to the Vertex struct to populate it with the right data.

第一个结构体是VkVertexInputBindingDescription ,我们将添加一个成员函数到结构体Vertex  to填入正确的数据给它。

struct Vertex {
glm::vec2 pos;
glm::vec3 color; static VkVertexInputBindingDescription getBindingDescription() {
VkVertexInputBindingDescription bindingDescription = {}; return bindingDescription;
}
};

A vertex binding describes at which rate to load data from memory throughout the vertices. It specifies the number of bytes between data entries and whether to move to the next data entry after each vertex or after each instance.

一个顶点binding描述了,以何等频率从内存中加载顶点数组中的数据。它指定了数据实体直接的字节数,是移动到下一个数据实体还是下一个instance。

VkVertexInputBindingDescription bindingDescription = {};
bindingDescription.binding = ;
bindingDescription.stride = sizeof(Vertex);
bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;

All of our per-vertex data is packed together in one array, so we're only going to have one binding. The binding parameter specifies the index of the binding in the array of bindings. The stride parameter specifies the number of bytes from one entry to the next, and the inputRate parameter can have one of the following values:

  • VK_VERTEX_INPUT_RATE_VERTEX: Move to the next data entry after each vertex
  • VK_VERTEX_INPUT_RATE_INSTANCE: Move to the next data entry after each instance

所有的逐顶点数据都被打包进了一个数组,所以我们只需有一个binding。binding参数指定了binding数组的某个元素的索引。stride 参数指定了相邻实体间隔的字节数,inputRate 参数值为下述2个之一:

  • VK_VERTEX_INPUT_RATE_VERTEX:每个顶点之后,移动到下一个数据实体。
  • VK_VERTEX_INPUT_RATE_INSTANCE:每个实例之后,移动到下一个数据实体。

We're not going to use instanced rendering, so we'll stick to per-vertex data.

我们不会使用instanced渲染,所以我们只用逐顶点的数据。

Attribute descriptions 属性描述

The second structure that describes how to handle vertex input is VkVertexInputAttributeDescription. We're going to add another helper function to Vertex to fill in these structs.

第二个结构体that描述如何处理顶点 是VkVertexInputAttributeDescription。我们要添加另一个辅助函数到Vertex  to填入这些结构体。

#include <array>

...

static std::array<VkVertexInputAttributeDescription, > getAttributeDescriptions() {
std::array<VkVertexInputAttributeDescription, > attributeDescriptions = {}; return attributeDescriptions;
}

As the function prototype indicates, there are going to be two of these structures. An attribute description struct describes how to extract a vertex attribute from a chunk of vertex data originating from a binding description. We have two attributes, position and color, so we need two attribute description structs.

如函数原型所示,会有2个这种结构体。一个属性描述结构体,描述如何根据binding描述从顶点数据块里提取顶点数据。我们有2个属性,位置和颜色,所以我们需要2个属性描述结构体。

attributeDescriptions[].binding = ;
attributeDescriptions[].location = ;
attributeDescriptions[].format = VK_FORMAT_R32G32_SFLOAT;
attributeDescriptions[].offset = offsetof(Vertex, pos);

The binding parameter tells Vulkan from which binding the per-vertex data comes. The location parameter references the location directive of the input in the vertex shader. The input in the vertex shader with location 0 is the position, which has two 32-bit float components.

binding 参数告诉Vulkan,逐顶点数据从哪个binding开始。location 参数指向顶点shader中的location 指令。顶点shader中的位置为0的input是position,它有2个32位浮点数。

The format parameter describes the type of data for the attribute. A bit confusingly, the formats are specified using the same enumeration as color formats. The following shader types and formats are commonly used together:

format 参数描述了属性数据的类型。有点困惑的是,这个格式是用与颜色格式相同的枚举类型指定的。下述shader类型和格式通常是一起用的。

  • floatVK_FORMAT_R32_SFLOAT
  • vec2VK_FORMAT_R32G32_SFLOAT
  • vec3VK_FORMAT_R32G32B32_SFLOAT
  • vec4VK_FORMAT_R32G32B32A32_SFLOAT

As you can see, you should use the format where the amount of color channels matches the number of components in the shader data type. It is allowed to use more channels than the number of components in the shader, but they will be silently discarded. If the number of channels is lower than the number of components, then the BGA components will use default values of (0, 0, 1). The color type (SFLOATUINTSINT) and bit width should also match the type of the shader input. See the following examples:

如你所见,你应当用格式where颜色通道的数量与shader中数据类型的元素数量匹配。你可以用比shader中元素数量更多的通道,但是它们会被默默地忽略。如果通道数量低于元素数量,那么BGA元素会用默认值(0, 0, 1)。颜色类型(SFLOATUINTSINT)和位宽度也应当与shader的输入数据类型匹配。看下面的例子:

  • ivec2VK_FORMAT_R32G32_SINT, a 2-component vector of 32-bit signed integers 32位整型有符号2元素向量
  • uvec4VK_FORMAT_R32G32B32A32_UINT, a 4-component vector of 32-bit unsigned integers 32位整型无符号4元素向量
  • doubleVK_FORMAT_R64_SFLOAT, a double-precision (64-bit) float 双精度(64位)浮点数

The format parameter implicitly defines the byte size of attribute data and the offset parameter specifies the number of bytes since the start of the per-vertex data to read from. The binding is loading one Vertex at a time and the position attribute (pos) is at an offset of 0 bytes from the beginning of this struct. This is automatically calculated using the offsetof macro.

format 参数隐式地定义了属性数据的字节数,offset 参数指定了从第几个字节开始读逐顶点的数据。Binding每个Vertex 加载一次,位置属性(pos)位于这个结构体的第0个偏移量。这可以通过宏offsetof 自动计算。

attributeDescriptions[].binding = ;
attributeDescriptions[].location = ;
attributeDescriptions[].format = VK_FORMAT_R32G32B32_SFLOAT;
attributeDescriptions[].offset = offsetof(Vertex, color);

The color attribute is described in much the same way.

颜色属性也用相同的方式描述。

Pipeline vertex input 管道顶点input

We now need to set up the graphics pipeline to accept vertex data in this format by referencing the structures in createGraphicsPipeline. Find the vertexInputInfo struct and modify it to reference the two descriptions:

我们现在需要设置图形管道to接收这种格式的顶点数据by引用createGraphicsPipeline中的结构体。找到vertexInputInfo 结构体,修改它to引用这2个描述:

auto bindingDescription = Vertex::getBindingDescription();
auto attributeDescriptions = Vertex::getAttributeDescriptions(); vertexInputInfo.vertexBindingDescriptionCount = ;
vertexInputInfo.vertexAttributeDescriptionCount = static_cast<uint32_t>(attributeDescriptions.size());
vertexInputInfo.pVertexBindingDescriptions = &bindingDescription;
vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions.data();

The pipeline is now ready to accept vertex data in the format of the vertices container and pass it on to our vertex shader. If you run the program now with validation layers enabled, you'll see that it complains that there is no vertex buffer bound to the binding. The next step is to create a vertex buffer and move the vertex data to it so the GPU is able to access it.

管道现在准备好接收vertices 容器格式的顶点数据并将其传入顶点shader了。如果你现在运行程序with验证层启用,你会看到它说没有顶点buffer绑定到binding。下一个是创建顶点buffer,将顶点数据放入其中,这样GPU就可以读取它了。

C++ code / Vertex shader / Fragment shader

[译]Vulkan教程(21)顶点input描述的更多相关文章

  1. [译]Vulkan教程(26)描述符池和set

    [译]Vulkan教程(26)描述符池和set Descriptor pool and sets 描述符池和set Introduction 入门 The descriptor layout from ...

  2. [译]Vulkan教程(25)描述符布局和buffer

    [译]Vulkan教程(25)描述符布局和buffer Descriptor layout and buffer 描述符布局和buffer Introduction 入门 We're now able ...

  3. [译]Vulkan教程(22)创建顶点buffer

    [译]Vulkan教程(22)创建顶点buffer Vertex buffer creation 创建顶点buffer Introduction 入门 Buffers in Vulkan are re ...

  4. [译]Vulkan教程(29)组合的Image采样器

    [译]Vulkan教程(29)组合的Image采样器 Combined image sampler 组合的image采样器 Introduction 入门 We looked at descripto ...

  5. [译]Vulkan教程(27)Image

    [译]Vulkan教程(27)Image Images Introduction 入门 The geometry has been colored using per-vertex colors so ...

  6. [译]Vulkan教程(14)图形管道基础之固定功能

    [译]Vulkan教程(14)图形管道基础之固定功能 Fixed functions 固定功能 The older graphics APIs provided default state for m ...

  7. [译]Vulkan教程(13)图形管道基础之Shader模块

    [译]Vulkan教程(13)图形管道基础之Shader模块 Shader modules Unlike earlier APIs, shader code in Vulkan has to be s ...

  8. [译]Vulkan教程(30)深度缓存

    [译]Vulkan教程(30)深度缓存 Depth buffering 深度缓存 Introduction 入门 The geometry we've worked with so far is pr ...

  9. [译]Vulkan教程(16)图形管道基础之总结

    [译]Vulkan教程(16)图形管道基础之总结 Conclusion 总结 We can now combine all of the structures and objects from the ...

随机推荐

  1. RT-Thread的位图调度算法分析(最新版)

    RT-Thread的内核调度算法 rt-thread的调度算法为基于优先级调度和基于时间片轮转调度共存的策略.rt-thread内核中存在多个线程优先级,并且支持多个线程具有同样的线程优先级.线程级别 ...

  2. 【树莓派】制作启动SD卡

    版权声明:本文为博主原创文章,转载请注明出处. https://www.cnblogs.com/YaoYing/ 下载烧写软件 烧写软件 将下载的压缩文件解压缩并安装到电脑上 下载树莓派镜像 树莓派系 ...

  3. 《Dotnet9》系列-开源C# Winform控件库强力推荐

    时间如流水,只能流去不流回! 点赞再看,养成习惯,这是您给我创作的动力! 本文 Dotnet9 https://dotnet9.com 已收录,站长乐于分享dotnet相关技术,比如Winform.W ...

  4. Golang中类面向对象特性

    一.类型方法的实例成员复制与类型方法的实例成员引用   在Go中可以类似Java等面向对象语言一定为某个对象定义方法,但是Go中并没有类的存在,可以不严格的将Go中的struct类型理解为面向对象中的 ...

  5. spring源码学习(四)-spring生命周期用到的后置处理器

    生命周期的九大后置处理器 第一次调用后置处理器org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory# ...

  6. 迈布-----UE4AI自动巡逻与攻击

    这个行为树给我恶心的都想吐,我用的是4.24,跟着官网做达不到那个效果,跟着视频做也达不到那个效果,跟我弄的非常不耐烦,最后终于在今天整出来了.有的地方用了一下我自己的逻辑.//诸位依靠教程的,一定得 ...

  7. 多线程之美2一ThreadLocal源代码分析

    目录结构 1.应用场景及作用 2.结构关系 2.1.三者关系类图 2.2.ThreadLocalMap结构图 2.3. 内存引用关系 2.4.存在内存泄漏原因 3.源码分析 3.1.重要代码片段 3. ...

  8. Winform中实现向窗体中拖放照片并显示以及拖放文件夹显示树形结构(附代码下载)

    场景 向窗体中拖拽照片并显示效果 向窗体中拖拽文件夹并显示树形结构效果 注: 博客主页: https://blog.csdn.net/badao_liumang_qizhi 关注公众号 霸道的程序猿 ...

  9. 使用 SQL 服务器时,"评估期已过期"错误消息

    当打开sql server2008企业管理器的时候,出现报错“评估期已过.有关如何升级的测试版软件的信息.....” 修改注册表:HKEY_LOCAL_MACHINE/SOFTWARE/Microso ...

  10. ORACLE数据库中执行计划出现INTERNAL_FUNCTION一定是隐式转换吗?

    ORACLE数据库中,我们会使用一些SQL语句找出存在隐式转换的问题SQL,其中网上流传的一个SQL语句如下,查询V$SQL_PLAN的字段FILTER_PREDICATES中是否存在INTERNAL ...