Vulkan Tutorial 27 combined image sampler
操作系统:Windows8.1
显卡:Nivida GTX965M
开发工具:Visual Studio 2017
Introduction
我们在教程的 uniform buffer 章节中首次了解了描述符。在本章节我们会看到一种新的描述符类型:combined image sampler 组合图像取样器。该描述符使着色器通过类似上一章创建的采样器对象那样,来访问图像资源。
我们将首先修改描述符布局,描述符对象池和描述符集合,以包括这样一个组合的图像采样器描述符。完成之后,我们会添加纹理贴图坐标到Vertex数据中,并修改片段着色器从纹理中读取颜色,而不是内插顶点颜色。
Updating the descriptors
浏览到createDesriptorSetLayout函数,并为组合图像采样器描述符添加一个VkDescriptorSetLayoutBinding。我们将简单的在uniform buffer之后进行绑定操作。
VkDescriptorSetLayoutBinding samplerLayoutBinding = {};
samplerLayoutBinding.binding = ;
samplerLayoutBinding.descriptorCount = ;
samplerLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
samplerLayoutBinding.pImmutableSamplers = nullptr;
samplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
std::array<VkDescriptorSetLayoutBinding, > bindings = {uboLayoutBinding, samplerLayoutBinding};
VkDescriptorSetLayoutCreateInfo layoutInfo = {};
layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
layoutInfo.bindingCount = static_cast<uint32_t>(bindings.size());
layoutInfo.pBindings = bindings.data();
确保stageFlags正确设置,指定我们打算在片段着色器中使用组合图像采样器描述符。这就是片段颜色最终被确定的地方。可以在顶点着色器中使用纹理采样,比如,通过高度图 heightmap 动态的变形顶点的网格。
如果你开启validation layers运行程序,你将会看到它引起了描述符对象池不能使用这个布局分配描述符集合,因为它没有任何组合图像采样器描述符。来到createDescriptorPool函数,以包含此描述符的VkDescriptorPoolSize:
std::array<VkDescriptorPoolSize, > poolSizes = {};
poolSizes[].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
poolSizes[].descriptorCount = ;
poolSizes[].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
poolSizes[].descriptorCount = ;
VkDescriptorPoolCreateInfo poolInfo = {};
poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
poolInfo.poolSizeCount = static_cast<uint32_t>(poolSizes.size());
poolInfo.pPoolSizes = poolSizes.data();
poolInfo.maxSets = ;
最后一步是将实际的图像和采样器资源绑定到描述符集合中的具体描述符。来到createDescriptorSet函数。
VkDescriptorImageInfo imageInfo = {};
imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
imageInfo.imageView = textureImageView;
imageInfo.sampler = textureSampler;
组合图像采样器结构体的资源必须在VkDescriptorImageInfo结构进行指定。就像在VkDescriptorBufferInfo结构体中指定一个 uniform buffer descriptor 缓冲区资源一样。这是上一章节中的对象汇集的代码段。
std::array<VkWriteDescriptorSet, > descriptorWrites = {};
descriptorWrites[].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptorWrites[].dstSet = descriptorSet;
descriptorWrites[].dstBinding = ;
descriptorWrites[].dstArrayElement = ;
descriptorWrites[].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
descriptorWrites[].descriptorCount = ;
descriptorWrites[].pBufferInfo = &bufferInfo;
descriptorWrites[].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptorWrites[].dstSet = descriptorSet;
descriptorWrites[].dstBinding = ;
descriptorWrites[].dstArrayElement = ;
descriptorWrites[].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
descriptorWrites[].descriptorCount = ;
descriptorWrites[].pImageInfo = &imageInfo;
vkUpdateDescriptorSets(device, static_cast<uint32_t>(descriptorWrites.size()), descriptorWrites.data(), , nullptr);
描述符必须与此图像信息一起更新,就像缓冲区一样。这次我们使用pImageInfo数组代替pBufferInfo。描述符现在可以被着色器使用!
Texture coordinates
纹理映射的一个重要组成部分仍然缺少,这是每个顶点的实际坐标。坐标决定如何实际的映射到几何图形上。
struct Vertex {
glm::vec2 pos;
glm::vec3 color;
glm::vec2 texCoord;
static VkVertexInputBindingDescription getBindingDescription() {
VkVertexInputBindingDescription bindingDescription = {};
bindingDescription.binding = ;
bindingDescription.stride = sizeof(Vertex);
bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
return bindingDescription;
}
static std::array<VkVertexInputAttributeDescription, > getAttributeDescriptions() {
std::array<VkVertexInputAttributeDescription, > attributeDescriptions = {};
attributeDescriptions[].binding = ;
attributeDescriptions[].location = ;
attributeDescriptions[].format = VK_FORMAT_R32G32_SFLOAT;
attributeDescriptions[].offset = offsetof(Vertex, pos);
attributeDescriptions[].binding = ;
attributeDescriptions[].location = ;
attributeDescriptions[].format = VK_FORMAT_R32G32B32_SFLOAT;
attributeDescriptions[].offset = offsetof(Vertex, color);
attributeDescriptions[].binding = ;
attributeDescriptions[].location = ;
attributeDescriptions[].format = VK_FORMAT_R32G32_SFLOAT;
attributeDescriptions[].offset = offsetof(Vertex, texCoord);
return attributeDescriptions;
}
};
修改Vertex结构体包含vec2结构用于纹理坐标。确保加入VkVertexInputAttributeDescription结构体,如此我们就可以在顶点着色器中访问纹理UV坐标数据。这是必要的,以便能够将它们传递到片段着色器,以便在正方形的表面进行插值处理。
const std::vector<Vertex> vertices = {
{{-0.5f, -0.5f}, {1.0f, 0.0f, 0.0f}, {1.0f, 0.0f}},
{{0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}, {0.0f, 0.0f}},
{{0.5f, 0.5f}, {0.0f, 0.0f, 1.0f}, {0.0f, 1.0f}},
{{-0.5f, 0.5f}, {1.0f, 1.0f, 1.0f}, {1.0f, 1.0f}}
};
在本教程中,使用坐标从左上角 0,0 到右下角的 1,1 来映射纹理,从而简单的填充矩形。在这里可以尝试各种坐标。尝试使用低于 0 或者 1 以上的坐标来查看寻址模式的不同表现。
Shaders
最后一步是修改着色器从纹理中采样颜色。我们首先需要修改顶点着色器,传递纹理坐标到片段着色器。
layout(location = ) in vec2 inPosition;
layout(location = ) in vec3 inColor;
layout(location = ) in vec2 inTexCoord; layout(location = ) out vec3 fragColor;
layout(location = ) out vec2 fragTexCoord; void main() {
gl_Position = ubo.proj * ubo.view * ubo.model * vec4(inPosition, 0.0, 1.0);
fragColor = inColor;
fragTexCoord = inTexCoord;
}
就像每个顶点的颜色,fragTexCoord值通过光栅化平滑的插值到矩形区域内。我们可以通过使片段着色器输出的纹理坐标为颜色来可视化看到这些:
#version
#extension GL_ARB_separate_shader_objects : enable layout(location = ) in vec3 fragColor;
layout(location = ) in vec2 fragTexCoord; layout(location = ) out vec4 outColor; void main() {
outColor = vec4(fragTexCoord, 0.0, 1.0);
}
现在应该可以看到如下图所示的效果。不要忘记重新编译着色器!

绿色通道代表水平坐标,红色通道代表垂直坐标。黑色和黄色角确认了纹理坐标正确的从 0,0 到 1,1 进行插值填充到方形中。使用颜色可视化在着色器中编程等价于 printf 调试,除此之外没有更好的方法!
组合图像采样器描述符在GLSL中通过采样器 uniform代替。在片段着色器中引用它:
layout(binding = ) uniform sampler2D texSampler;
对于其他图像有等价的 sampler1D 和 sampler3D 类型。确保正确的绑定操作。
void main() {
outColor = texture(texSampler, fragTexCoord);
}
纹理采用内置的 texture 函数进行采样。它需要使用 sampler 和 坐标作为参数。采样器在后台自动处理过滤和变化功能。你应该可以看到纹理贴图在方形上:

尝试修改寻址模式放大大于 1 来观测效果。比如,下面的片段着色器输出的结果使用VK_SAMPLER_ADDRESS_MODE_REPEAT:
void main() {
outColor = texture(texSampler, fragTexCoord * 2.0);
}

还可以使用顶点颜色来处理纹理颜色:
void main() {
outColor = vec4(fragColor * texture(texSampler, fragTexCoord).rgb, 1.0);
}
将RGB和alha通道分离开,以便不缩放alpha通道。

现在已经知道如何在着色器中访问图像!当与帧缓冲区中的图像进行结合时,这是一个非常有效的技术。你可以看到这些图像作为输入实现很酷的效果,比如 post-processing和3D世界摄像机显示。
项目代码 GitHub地址。
Vulkan Tutorial 27 combined image sampler的更多相关文章
- Vulkan Tutorial 26 view and sampler
操作系统:Windows8.1 显卡:Nivida GTX965M 开发工具:Visual Studio 2017 在本章节我们将为图形管线创建另外两个资源来对图像进行采样.第一个资源我们之前已经接触 ...
- [译]Vulkan教程(27)Image
[译]Vulkan教程(27)Image Images Introduction 入门 The geometry has been colored using per-vertex colors so ...
- Vulkan Tutorial 26 Image view and sampler
操作系统:Windows8.1 显卡:Nivida GTX965M 开发工具:Visual Studio 2017 在本章节我们将为图形管线创建另外两个资源来对图像进行采样.第一个资源我们之前已经接触 ...
- Vulkan Tutorial 29 Loading models
操作系统:Windows8.1 显卡:Nivida GTX965M 开发工具:Visual Studio 2017 Introduction 应用程序现在已经可以渲染纹理3D模型,但是 vertice ...
- Vulkan Tutorial 开发环境搭建之Windows
操作系统:Windows8.1 显卡:Nivida GTX965M 开发工具:Visual Studio 2017 相信很多人在开始学习Vulkan开发的起始阶段都会在开发环境的配置上下一些功夫,那么 ...
- Vulkan Tutorial 02 编写Vulkan应用程序框架原型
操作系统:Windows8.1 显卡:Nivida GTX965M 开发工具:Visual Studio 2017 General structure 在上一节中,我们创建了一个正确配置.可运行的的V ...
- Vulkan Tutorial 05 物理设备与队列簇
操作系统:Windows8.1 显卡:Nivida GTX965M 开发工具:Visual Studio 2017 Selecting a physical device 通过VkInstance初始 ...
- Vulkan Tutorial 05 逻辑设备与队列
操作系统:Windows8.1 显卡:Nivida GTX965M 开发工具:Visual Studio 2017 Introduction 在选择要使用的物理设备之后,我们需要设置一个逻辑设备用于交 ...
- Vulkan Tutorial 07 Window surface
操作系统:Windows8.1 显卡:Nivida GTX965M 开发工具:Visual Studio 2017 到目前为止,我们了解到Vulkan是一个与平台特性无关联的API集合.它不能直接与窗 ...
随机推荐
- Debian系统简要说明
Debian这个是我最喜欢也是比较熟悉的一个系统了,BD下做个简要说明 一,APT以及dpkg常见用法如下:功能具体语句 软件源设置 /etc/apt/sources.list 更新软件源数据 ...
- java中String是对象还是类?详解java中的String
有很多人搞不懂对象和类的定义.比如说java中String到底是对象还是类呢? 有人说String 既可以说是类,也可以说是对象. 其实他这么说也没问题, 类和对象其实都是一个抽象的概念. 我们可以把 ...
- 12款Linux系统恢复工具
电脑死机,硬盘崩溃,花巨大的money搞个急救保护器……这都是计算机的阴暗面.时间一直这样走着,走着,不定哪天背点儿.对于电脑损坏造成的损失,着急抓狂毫无意义.相反,使用恰当的工具反而会最小化损失.你 ...
- haproxy内存管理-free_list原理
haproxy的内存管理中,通过pool_head->free_list,存储空闲内存块,free_list是个二级指针,却把空闲内存块都串了起来,没有用next,pre之类的指针.怎么实现的? ...
- Spring框架之IOC(控制反转)
[TOC] 第一章Spring框架简介 IOC(控制反转)和AOP(面向方面编程)作为Spring框架的两个核心,很好地实现了解耦合.所以,简单来说,Spring是一个轻量级的控制反转(IoC)和面向 ...
- CPU-Z五大主要功能及使用方法初步了解
CPU-Z这款软件除了具有查看CPU温度这个功能之外,还有很多其他的功能.今天就和小编一起去看看CPU-Z的5大功能以及他们的使用方法吧! CPU信息标签页 CPU-Z介绍: CPU-Z是一款著名的免 ...
- PHP 防恶意刷新实现代码
本质还是采用session方式进行时间比较,在单位时间内允许访问或者访问次数,如果有使用反向代理的话,也可以采用nginx配置 <?phpsession_start(); $k=$_GET[' ...
- 卷积神经网络的变种: PCANet
前言:昨天和大家聊了聊卷积神经网络,今天给大家带来一篇论文:pca+cnn=pcanet.现在就让我带领大家来了解这篇文章吧. 论文:PCANet:A Simple Deep Learning Bas ...
- HttpWebRequest操作已超时
最近我们使用.NET3.5HttpWebRequest会报操作已超时但使用.NET4.0版本及以上却可以正常访问. 一段简单的代码如下: string returnData = "" ...
- NN-Neural Network
开始学习神经网络(Neural Network) 已有线性与逻辑回归,为什么需要用到NN 实际的应用中,需要根据很多特征进行训练分类器,当今有两个特征下,可以通过下图表述: 然而还有太多的特征需要考虑 ...