[译]Vulkan教程(21)顶点input描述
[译]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 vertexVK_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类型和格式通常是一起用的。
float:VK_FORMAT_R32_SFLOATvec2:VK_FORMAT_R32G32_SFLOATvec3:VK_FORMAT_R32G32B32_SFLOATvec4:VK_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 (SFLOAT, UINT, SINT) and bit width should also match the type of the shader input. See the following examples:
如你所见,你应当用格式where颜色通道的数量与shader中数据类型的元素数量匹配。你可以用比shader中元素数量更多的通道,但是它们会被默默地忽略。如果通道数量低于元素数量,那么BGA元素会用默认值(0, 0, 1)。颜色类型(SFLOAT, UINT, SINT)和位宽度也应当与shader的输入数据类型匹配。看下面的例子:
ivec2:VK_FORMAT_R32G32_SINT, a 2-component vector of 32-bit signed integers 32位整型有符号2元素向量uvec4:VK_FORMAT_R32G32B32A32_UINT, a 4-component vector of 32-bit unsigned integers 32位整型无符号4元素向量double:VK_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描述的更多相关文章
- [译]Vulkan教程(26)描述符池和set
[译]Vulkan教程(26)描述符池和set Descriptor pool and sets 描述符池和set Introduction 入门 The descriptor layout from ...
- [译]Vulkan教程(25)描述符布局和buffer
[译]Vulkan教程(25)描述符布局和buffer Descriptor layout and buffer 描述符布局和buffer Introduction 入门 We're now able ...
- [译]Vulkan教程(22)创建顶点buffer
[译]Vulkan教程(22)创建顶点buffer Vertex buffer creation 创建顶点buffer Introduction 入门 Buffers in Vulkan are re ...
- [译]Vulkan教程(29)组合的Image采样器
[译]Vulkan教程(29)组合的Image采样器 Combined image sampler 组合的image采样器 Introduction 入门 We looked at descripto ...
- [译]Vulkan教程(27)Image
[译]Vulkan教程(27)Image Images Introduction 入门 The geometry has been colored using per-vertex colors so ...
- [译]Vulkan教程(14)图形管道基础之固定功能
[译]Vulkan教程(14)图形管道基础之固定功能 Fixed functions 固定功能 The older graphics APIs provided default state for m ...
- [译]Vulkan教程(13)图形管道基础之Shader模块
[译]Vulkan教程(13)图形管道基础之Shader模块 Shader modules Unlike earlier APIs, shader code in Vulkan has to be s ...
- [译]Vulkan教程(30)深度缓存
[译]Vulkan教程(30)深度缓存 Depth buffering 深度缓存 Introduction 入门 The geometry we've worked with so far is pr ...
- [译]Vulkan教程(16)图形管道基础之总结
[译]Vulkan教程(16)图形管道基础之总结 Conclusion 总结 We can now combine all of the structures and objects from the ...
随机推荐
- Spring-security-oAuth2分享
Spring-security-oAuth2分享 oAuth2简介 OAuth 2.0是用于授权的行业标准协议.OAuth 2.0致力于简化客户端开发人员的工作,同时为Web应用程序,桌面应用程序,移 ...
- irules
BIG-IP系统iRules基本概念_v11.6.1 2017年10月10日 00:35:16 ifelif 阅读数:1097 1 iRules介绍 什么是iRule iRule是BIG-IP本地 ...
- webpack学习_管理输出(管理资源插件)
管理输出步骤 Step1:在src新建文件print.js添加逻辑 Step2:在src/index.js import 引用新添加的逻辑 Step3:更新dist/index.html文件,修改引入 ...
- 2.java三大特性
1. 封装 方法:将属性值修饰为私有,提供get和set方法.造成所有对对象的访问都是通过方法的调用来完成(配合this的使用) 结果:用户不能直接随意改变一个对象内的属性,必须通过调用方法(验证)来 ...
- 《Java基础知识》Java类的定义及其实例化
类必须先定义才能使用.类是创建对象的模板,创建对象也叫类的实例化. 下面通过一个简单的例子来理解Java中类的定义: public class Dog { String name; int age; ...
- css重点知识和bug解决方法
1.图片向下撑大3像素问题 在一个盒子里面放一张图片,默认情况下,图片会向下撑大3像素,有以下几种解决方法: 1.1 给图片添加display:block: 1.2 给图片添加 float:left: ...
- 【活动】美团技术沙龙第49期:AI在外卖场景中的最佳实践
美团技术沙龙第49期开始啦! 本次沙龙,美团外卖技术部专家会深入介绍AI在对话系统.图像处理.个性化推荐.智能营销等方向在外卖业务中的实践,希望与业界技术同学一起交流学习. 无论你从事智能搜索,或是算 ...
- CTF KFIOFan: 2 Vulnhub Walkthorugh
主机扫描: ╰─ nmap -p- -A 10.10.202.152 Starting Nmap 7.70 ( https://nmap.org ) at 2019-08-29 16:55 CSTNm ...
- View 的绘制过程
配合Activity 从启动到布局绘制的简单分析 阅读 基本概念介绍 Activity:一个 Activity 是一个应用程序组件,提供一个屏幕,用户可以用来交互. View:所有视图控件的基类 Vi ...
- Linux之shell详解
Shell是什么 Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁.Shell 既是一种命令语言,又是一种程序设计语言.Shell 是指一种应用程序,这个应用程序提供了一个界 ...