操作系统: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. spring cloud 集成 swagger2 构建Restful APIS 说明文档

    在Pom.xml文件中引用依赖 <dependencies> <dependency> <groupId>org.springframework.cloud< ...

  2. js图片轮播

    html部分 <a href="" id="pta"><div id="picture" class="pt&q ...

  3. jquery获取文件名称

    $("#fileupload").on("change",function(){ var filePath=$(this).val(); if(filePath ...

  4. 玩玩kafka1 单机安装

    今天主要来一遍kafka单机版的安装,比较简单易上手,关于kafka的介绍我就不贴了,大家可以自行搜索 1.首先将tgz包传到centos目录下(这里使用xftp工具) ok后查看一下tgz包是否已经 ...

  5. Docker - 生成镜像

    利用docker commit命令生成镜像 Docker镜像是多层存储,每一层是在前一层的基础上进行的修改.而容器是镜像为基础层的多层存储. 如果不使用数据卷,运行一个容器的时候,对任何文件的修改都会 ...

  6. 深入分析 Java I/O 的工作机制

    I/O 问题可以说是当今互联网 Web 应用中所面临的主要问题之一,因为当前在这个海量数据时代,数据在网络中随处流动.这个流动的过程中都涉及到 I/O 问题,可以说大部分 Web 应用系统的瓶颈都是 ...

  7. Spring框架学习1

    AnonymouL 兴之所至,心之所安;尽其在我,顺其自然 新随笔 管理   Spring框架学习(一)   阅读目录 一. spring概述 核心容器: Spring 上下文: Spring AOP ...

  8. 镜像命名的最佳实践 - 每天5分钟玩转 Docker 容器技术(18)

    我们已经学会构建自己的镜像了.接下来的问题是如何在多个 Docker Host 上使用镜像. 这里有几种可用的方法: 用相同的 Dockerfile 在其他 host 构建镜像. 将镜像上传到公共 R ...

  9. Debian系统简要说明

    Debian这个是我最喜欢也是比较熟悉的一个系统了,BD下做个简要说明 一,APT以及dpkg常见用法如下:功能具体语句 软件源设置     /etc/apt/sources.list 更新软件源数据 ...

  10. 开涛spring3(6.9) - AOP 之 6.9 代理机制

    Spring AOP通过代理模式实现,目前支持两种代理:JDK动态代理.CGLIB代理来创建AOP代理,Spring建议优先使用JDK动态代理. JDK动态代理:使用java.lang.reflect ...