操作系统:Windows8.1

显卡:Nivida GTX965M

开发工具:Visual Studio 2017


Introduction

在接下来几个章节中,我们将会使用内存顶点缓冲区来替换之前硬编码到vertex shader中的顶点数据。我们将从最简单的方法开始创建一个CPU可见的缓冲区,并使用memcpy直接将顶点数据直接复制到缓冲区,之后将会使用暂存缓冲区将顶点数据赋值到高性能的内存。

Vertex shader


首先要修改的是顶点着色器,不再包含顶点数据。顶点着色器接受顶点缓冲区的输入使用in关键字。

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

inPositioninColor变量是顶点属性。它们被顶点缓冲区中的每一个顶点指定,就像我们使用两个数组手动指定每个顶点的position和color一样。现在确保着色器被正确编译!

Vertex data


我们将顶点数组从着色器代码移到我们程序自定义的数组中。首先我们需要引入GLM库,它提供了像向量和矩阵之类的线性代数数据结构。我们使用这些类型指定position和颜色。

#include <glm/glm.hpp>

建立新的数据结构Vertex并定义两个属性,我们将会在顶点着色器内部使用:

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

GLM很方便的提供了与C++类型匹配的可以在着色器中使用的矢量类型。

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}}
};

现在使用Vertex结构体作为顶点数组的元素类型。我们使用与之前完全相同的position和color值,但是现在它们被组合成一个顶点数组。这被称为 interleaving 顶点属性。

Binding descriptions


一旦数据被提交到GPU的显存中,就需要告诉Vulkan传递到顶点着色器中数据的格式。有两个结构体用于描述这部分信息。

第一个结构体VkVertexInputBingdingDescriptionVertex结构体中新增一个成员函数,并使用正确的数值填充它。

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

顶点绑定描述了在整个顶点数据从内存加载的速率。换句话说,它指定数据条目之间的间隔字节数以及是否每个顶点之后或者每个instance之后移动到下一个条目。

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

我们所有的顶点数据都被打包在一个数组中,所以我们需要一个绑定。binding的参数指定了数组中对应的绑定索引。stride参数指定一个条目到下一个条目的字节数,inputRate参数可以具备一下值之一:

  • VK_VERTEX_INPUT_RATE_VERTEX: 移动到每个顶点后的下一个数据条目
  • VK_VERTEX_INPUT_RATE_INSTANCE: 在每个instance之后移动到下一个数据条目

我们不会使用instancing渲染,所以坚持使用per-vertex data方式。

Attribute descriptions


第二个结构体描VkVertexInputAttributeDescription述如何处理顶点的输入。我们需要在Vertex中增加一个新的辅助函数。

#include <array>

...

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

如函数圆形所示,该结构体为两个。一个属性描述结构体最终描述了顶点属性如何从对应的绑定描述过的顶点数据来解析数据。我们有两个属性,position和color,所以我们需要两个属性描述结构体。

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

binding参数告诉了Vulkan每个顶点数据的来源。location参数引用了vertex shader作为输入的location指令。顶点着色器中,location0代表position,它是32bit单精度数据。

format参数描述了属性的类型。该格式使用与颜色格式一样的枚举,看起来有点乱。下列的着色器类型和格式是比较常用的搭配。

  • float: VK_FORMAT_R32_SFLOAT
  • vec2: VK_FORMAT_R32G32_SFLOAT
  • vec3: VK_FORMAT_R32G32B32_SFLOAT
  • vec4: V_FORMAT_R32G32B32A32_SFLOAT

如你所见,你应该使用颜色数量与着色器数据类型中的分量个数匹配的格式。允许使用比着色器中的分量个数更大的范围,但是它将会被默认丢弃。如果低于着色器分量的数量,则BGA组件将使用默认值(0, 0, 1)。颜色类型(SFLOAT, UINT, SINT) 和位宽度应该与着色器输入的类型对应匹配。如下示例:

  • ivec2: VK_FORMAT_R32G32_SINT,由两个32位有符号整数分量组成的向量
  • uvec4: VK_FORMAT_R32G32B32A32_UINT, 由四个32位无符号正式分量组成的向量
  • double: VK_FORMAT_R64_SFLOAT, 双精度浮点数(64-bit)

format参数在属性数据中被隐式的定义为字节单位大小,并且offset参数指定了每个顶点数据读取的字节宽度偏移量。绑定一次加载一个Vertex,position属性(pos)的偏移量在字节数据中为0字节。这是使用offsetof macro宏自动计算的。

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

color颜色属性与position位置属性的描述基本一致。

Pipeline vertex input


我们现在需要在createGraphicsPipeline函数中,配置图形管线可以接受重新定义的顶点数据的格式。找到vertexInputInfo结构体,修改引用之前定义的两个有关输入顶点的description结构体:

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();

图形管线现在准备接受vertices容器封装后的顶点数据,并将该格式的顶点数据传递到vertex shader。如果开启了validation layers运行程序,我们将会看到无顶点缓冲区绑定的提示。所以下一章节我们将会创建顶点缓冲区vertex buffer并把顶点数据存储在里面,最终GPU通过顶点缓冲区读取到顶点数据。

项目代码 GitHub 地址。

Vulkan Tutorial 19 Vertex input description的更多相关文章

  1. Vulkan Tutorial 20 Vertex buffer creation

    操作系统:Windows8.1 显卡:Nivida GTX965M 开发工具:Visual Studio 2017 Introduction 在Vulkan中,缓冲区是内存的一块区域,该区域用于向显卡 ...

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

    [译]Vulkan教程(21)顶点input描述 Vertex input description 顶点input描述 Introduction 入门 In the next few chapters ...

  3. [译]Vulkan教程(19)渲染和呈现

    [译]Vulkan教程(19)渲染和呈现 Rendering and presentation 渲染和呈现 Setup 设置 This is the chapter where everything ...

  4. Vulkan Tutorial 12 Fixed functions

    操作系统:Windows8.1 显卡:Nivida GTX965M 开发工具:Visual Studio 2017 早起的图形API在图形渲染管线的许多阶段提供了默认的状态.在Vulkan中,从vie ...

  5. Vulkan Tutorial 10 图形管线

    操作系统:Windows8.1 显卡:Nivida GTX965M 开发工具:Visual Studio 2017 Introduction 通过接下来的章节,我们将会开启有关图形管线的话题,通过对图 ...

  6. Vulkan Tutorial 11 Shader modules

    操作系统:Windows8.1 显卡:Nivida GTX965M 开发工具:Visual Studio 2017 与之前的图像API不同,Vulkan中的着色器代码必须以二进制字节码的格式使用,而不 ...

  7. Vulkan Tutorial 13 Render passes

    操作系统:Windows8.1 显卡:Nivida GTX965M 开发工具:Visual Studio 2017 Setup 在我们完成管线的创建工作,我们接下来需要告诉Vulkan渲染时候使用的f ...

  8. Vulkan Tutorial 18 重构交换链

    操作系统:Windows8.1 显卡:Nivida GTX965M 开发工具:Visual Studio 2017 Introduction 现在我们已经成功的在屏幕上绘制出三角形,但是在某些情况下, ...

  9. Vulkan Tutorial 22 Index buffer

    操作系统:Windows8.1 显卡:Nivida GTX965M 开发工具:Visual Studio 2017 Introduction 在实际产品的运行环境中3D模型的数据往往共享多个三角形之间 ...

随机推荐

  1. ms_celeb_1m数据提取(MsCelebV1-Faces-Aligned.tsv)python脚本

    本文主要介绍了如何对MsCelebV1-Faces-Aligned.tsv文件进行提取 原创by南山南北秋悲 欢迎引用!请注明原地址 http://www.cnblogs.com/hwd9654/p/ ...

  2. 关于WebService、WebApi的跨域问题

    随着移动互联网的发展, 传统营销模式往网站以及移动客户端转移已经成为一种趋势.接触过互联网开发的开发者肯定会很熟悉两种网络服务WebApi.WebService.在使用JavaScript进行数据交互 ...

  3. javascript 函数和作用域(闭包、作用域)(七)

    一.闭包 JavaScript中允许嵌套函数,允许函数用作数据(可以把函数赋值给变量,存储在对象属性中,存储在数组元素中),并且使用词法作用域,这些因素相互交互,创造了惊人的,强大的闭包效果.[upd ...

  4. 【Netty】第一个Netty应用

    一.前言 前面已经学习完了Java NIO的内容,接着来学习Netty,本篇将通过一个简单的应用来了解Netty的使用. 二.Netty应用 2.1 服务端客户端框架图 下图展示了Netty中服务端与 ...

  5. mysql 中文出现?,设置utf8

    windows系统下的mysql: 1.找到mysql的配置文件:文件名可能不是my.ini(如my-default.ini),修改成my.ini. 打开配置文件,并编辑如下:(若是没有[client ...

  6. c#无限循环线程如何正确退出

    c#无限循环线程如何正确退出 在主程序将要结束时,迅速正确退出无限循环执行的子线程.一般子线程循环执行会有一个指定的周期, 在子线程等待(或者睡眠)时,无法唤醒退出,尤其在执行周期较长时,子线程无法即 ...

  7. RabbitMQ集群和失败处理

    RabbitMQ内建集群的设计用于完成两个目标:允许消费者和生产者在RabbitMQ节点在奔溃的情况下继续运行,以及通过添加更多的节点来线性扩展消息通信的吞吐量.当失去一个RabbitMQ节点时客户端 ...

  8. Python装饰器实现几类验证功能做法

    最近新需求来了,要给系统增加几个资源权限.尽量减少代码的改动和程序的复杂程度.所以还是使用装饰器比较科学 之前用了一些登录验证的现成装饰器模块.然后仿写一些用户管理部分的权限装饰器.比如下面这种 de ...

  9. 新鲜小玩意儿- deviceOrientation移动设备旋转事件

    <javascript高级程序设计>第三版 其中事件的章节 提到一个有意思的事件 deviceOrientation 也就是 设备(device) - orientation(方向) 贴代 ...

  10. 求一个二维整数数组最大子数组之和,时间复杂度为N^2

    本随笔只由于时间原因,我就只写写思想了 二维数组最大子数组之和,可以  引用  一维最大子数组之和 的思想一维最大子数组之和 的思想,在本博客上有,这里就不做多的介绍了 我们有一个最初的二维数组a[n ...