[译]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 450
#extension GL_ARB_separate_shader_objects : enable

layout(location = 0) in vec2 inPosition;
layout(location = 1) in vec3 inColor;

layout(location = 0) 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 = 0) in dvec3 inPosition;
layout(location = 2) 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 = 0;
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, 2> getAttributeDescriptions() {
    std::array<VkVertexInputAttributeDescription, 2> 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[0].binding = 0;
attributeDescriptions[0].location = 0;
attributeDescriptions[0].format = VK_FORMAT_R32G32_SFLOAT;
attributeDescriptions[0].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[1].binding = 0;
attributeDescriptions[1].location = 1;
attributeDescriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT;
attributeDescriptions[1].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 = 1;
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

原文地址:https://www.cnblogs.com/bitzhuwei/p/Vulkan-Tutorial-21-Vertex-input-description.html

时间: 2024-11-09 00:14:04

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

[译]Vulkan教程(03)开发环境

这是我翻译(https://vulkan-tutorial.com)上的Vulkan教程的第3篇. In this chapter we'll set up your environment for developing Vulkan applications and install some useful libraries. All of the tools we'll use, with the exception of the compiler, are compatible with

[译]Vulkan教程(20)重建交换链

Swap chain recreation 重建交换链 Introduction 入门 The application we have now successfully draws a triangle, but there are some circumstances that it isn't handling properly yet. It is possible for the window surface to change such that the swap chain is n

[译]Vulkan教程(06)验证层

What are validation layers? 什么是验证层? The Vulkan API is designed around the idea of minimal driver overhead and one of the manifestations of that goal is that there is very limited error checking in the API by default. Even mistakes as simple as settin

[译]Vulkan教程(08)逻辑设备和队列

Introduction 入门 After selecting a physical device to use we need to set up a logical device to interface with it. The logical device creation process is similar to the instance creation process and describes the features we want to use. We also need

[译]Vulkan教程(17)帧缓存

Framebuffers 帧缓存 We've talked a lot about framebuffers in the past few chapters and we've set up the render pass to expect a single framebuffer with the same format as the swap chain images, but we haven't actually created any yet. 我们在过去的章节谈论过很多次帧缓存了

CSharpGL(56)[译]Vulkan入门

本文是对(http://ogldev.atspace.co.uk/www/tutorial50/tutorial50.html)的翻译,作为学习Vulkan的一次尝试. 不翻译的话,每次都在看第一句,那就学不完了. Background 背景 You've probably heard by now quite a bit about Vulkan, the new Graphics API from Khronos (the non profit organization responsibl

Vulkan Tutorial 19 Vertex input description

操作系统:Windows8.1 显卡:Nivida GTX965M 开发工具:Visual Studio 2017 Introduction 在接下来几个章节中,我们将会使用内存顶点缓冲区来替换之前硬编码到vertex shader中的顶点数据.我们将从最简单的方法开始创建一个CPU可见的缓冲区,并使用memcpy直接将顶点数据直接复制到缓冲区,之后将会使用分段缓冲区将顶点数据赋值到高性能的内存. Vertex shader 首先要修改的是顶点着色器,不再包含顶点数据.顶点着色器接受顶点缓冲区的

CSharpGL(56)[译]Vulkan入门(转)

阅读目录(Content) Background 背景 System Setup 系统安装 Linux Windows Building and Running 建设和运行 Linux Windows General Comments 基础命令 Code Structure 代码结构 Source walkthru 源代码浏览 CSharpGL(56)[译]Vulkan入门 本文是对(http://ogldev.atspace.co.uk/www/tutorial50/tutorial50.ht

CSharpGL(57)[译]Vulkan清空屏幕

本文是对(http://ogldev.atspace.co.uk/www/tutorial51/tutorial51.html)的翻译,作为学习Vulkan的一次尝试. 不翻译的话,每次都在看第一句,那就学不完了. Background 背景 +BIT祝威+悄悄在此留下版了个权的信息说: Welcome back. I hope that you've been able to complete the previous tutorial successfully and you are now