[译]Vulkan教程(29)组合的Image采样器

Combined image sampler 组合的image采样器

Introduction 入门

We looked at descriptors for the first time in the uniform buffers part of the tutorial. In this chapter we will look at a new type of descriptor: combined image sampler. This descriptor makes it possible for shaders to access an image resource through a sampler object like the one we created in the previous chapter.

在本教程的uniform buffer部分,我们首次认识了描述符。本章,我们将认识一个新类型的描述符:组合的image采样器(译者注:后文简称CIS)。这个描述符让shader通过采样器对象(例如我们在上一章创建的那个)存取image资源成为可能。

We'll start by modifying the descriptor layout, descriptor pool and descriptor set to include such a combined image sampler descriptor. After that, we're going to add texture coordinates to Vertex and modify the fragment shader to read colors from the texture instead of just interpolating the vertex colors.

开始,我们修改描述符布局,描述符池和描述符set,以包含这样一个CIS描述符。之后,我们要添加纹理坐标到Vertex ,修改Fragment shader来从纹理读取颜色,而不是从顶点颜色插值。

Updating the descriptors 更新描述符

Browse to the createDescriptorSetLayout function and add a VkDescriptorSetLayoutBinding for a combined image sampler descriptor. We'll simply put it in the binding after the uniform buffer:

找到createDescriptorSetLayout 函数,为CIS描述符添加一个VkDescriptorSetLayoutBinding 。我们简单地将其放到uniform buffer后面的binding:

VkDescriptorSetLayoutBinding samplerLayoutBinding = {};
samplerLayoutBinding.binding = 1;
samplerLayoutBinding.descriptorCount = 1;
samplerLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
samplerLayoutBinding.pImmutableSamplers = nullptr;
samplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; std::array<VkDescriptorSetLayoutBinding, 2> 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();

Make sure to set the stageFlags to indicate that we intend to use the combined image sampler descriptor in the fragment shader. That's where the color of the fragment is going to be determined. It is possible to use texture sampling in the vertex shader, for example to dynamically deform a grid of vertices by a heightmap.

确保设置stageFlags  to表示我们想在Fragment shader中用CIS描述符。那是决定Fragment颜色的地方。可以在顶点shader中用纹理采样,例如用于使顶点网格动态变形by heightmap

If you would run the application with validation layers now, then you'll see that it complains that the descriptor pool cannot allocate descriptor sets with this layout, because it doesn't have any combined image sampler descriptors. Go to the createDescriptorPool function and modify it to include a VkDescriptorPoolSize for this descriptor:

如果你现在启用验证层运行程序,那么你会看到它抱怨说描述符池不能分配这个布局下的描述符set,因为它没有任何CIS描述符。找到createDescriptorPool 函数,修改它to包含VkDescriptorPoolSize for这个描述符:

std::array<VkDescriptorPoolSize, 2> poolSizes = {};
poolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
poolSizes[0].descriptorCount = static_cast<uint32_t>(swapChainImages.size());
poolSizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
poolSizes[1].descriptorCount = static_cast<uint32_t>(swapChainImages.size()); 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 = static_cast<uint32_t>(swapChainImages.size());

The final step is to bind the actual image and sampler resources to the descriptors in the descriptor set. Go to the createDescriptorSets function.

最后一步是,绑定image和采样器资源到描述符set中的描述符。找到createDescriptorSets 函数。

for (size_t i = 0; i < swapChainImages.size(); i++) {
VkDescriptorBufferInfo bufferInfo = {};
bufferInfo.buffer = uniformBuffers[i];
bufferInfo.offset = 0;
bufferInfo.range = sizeof(UniformBufferObject); VkDescriptorImageInfo imageInfo = {};
imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
imageInfo.imageView = textureImageView;
imageInfo.sampler = textureSampler; ...
}

The resources for a combined image sampler structure must be specified in a VkDescriptorImageInfo struct, just like the buffer resource for a uniform buffer descriptor is specified in a VkDescriptorBufferInfo struct. This is where the objects from the previous chapter come together.

CIS结构体的资源必须在VkDescriptorImageInfo 结构体中指定,就像buffer资源for uniform buffer描述符在VkDescriptorBufferInfo 结构体中指定一样。这就与上一章的对象联系起来了。

std::array<VkWriteDescriptorSet, 2> descriptorWrites = {};

descriptorWrites[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptorWrites[0].dstSet = descriptorSets[i];
descriptorWrites[0].dstBinding = 0;
descriptorWrites[0].dstArrayElement = 0;
descriptorWrites[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
descriptorWrites[0].descriptorCount = 1;
descriptorWrites[0].pBufferInfo = &bufferInfo; descriptorWrites[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptorWrites[1].dstSet = descriptorSets[i];
descriptorWrites[1].dstBinding = 1;
descriptorWrites[1].dstArrayElement = 0;
descriptorWrites[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
descriptorWrites[1].descriptorCount = 1;
descriptorWrites[1].pImageInfo = &imageInfo; vkUpdateDescriptorSets(device, static_cast<uint32_t>(descriptorWrites.size()), descriptorWrites.data(), 0, nullptr);

The descriptors must be updated with this image info, just like the buffer. This time we're using the pImageInfo array instead of pBufferInfo. The descriptors are now ready to be used by the shaders!

描述符必须用这个image信息更新,就像buffer那样。这次我们要用pImageInfo数组,而不是pBufferInfo。描述符现在准备好被shader使用了!

Texture coordinates 纹理坐标

There is one important ingredient for texture mapping that is still missing, and that's the actual coordinates for each vertex. The coordinates determine how the image is actually mapped to the geometry.

还有一个元素for纹理映射that没有提到,那就是每个顶点的纹理坐标。这个坐标决定了image如何映射到几何体上。

struct Vertex {
glm::vec2 pos;
glm::vec3 color;
glm::vec2 texCoord; static VkVertexInputBindingDescription getBindingDescription() {
VkVertexInputBindingDescription bindingDescription = {};
bindingDescription.binding = 0;
bindingDescription.stride = sizeof(Vertex);
bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; return bindingDescription;
} static std::array<VkVertexInputAttributeDescription, 3> getAttributeDescriptions() {
std::array<VkVertexInputAttributeDescription, 3> attributeDescriptions = {}; attributeDescriptions[0].binding = 0;
attributeDescriptions[0].location = 0;
attributeDescriptions[0].format = VK_FORMAT_R32G32_SFLOAT;
attributeDescriptions[0].offset = offsetof(Vertex, pos); attributeDescriptions[1].binding = 0;
attributeDescriptions[1].location = 1;
attributeDescriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT;
attributeDescriptions[1].offset = offsetof(Vertex, color); attributeDescriptions[2].binding = 0;
attributeDescriptions[2].location = 2;
attributeDescriptions[2].format = VK_FORMAT_R32G32_SFLOAT;
attributeDescriptions[2].offset = offsetof(Vertex, texCoord); return attributeDescriptions;
}
};

  

Modify the Vertex struct to include a vec2 for texture coordinates. Make sure to also add a VkVertexInputAttributeDescription so that we can use access texture coordinates as input in the vertex shader. That is necessary to be able to pass them to the fragment shader for interpolation across the surface of the square.

修改Vertex 结构体to包含一个vec2  for纹理坐标。确保也添加一个VkVertexInputAttributeDescription ,这样我们可以用纹理坐标作为顶点shader的输入。这对于传递它们到Fragment shader后在四边形上插值是必要的。

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

  

In this tutorial, I will simply fill the square with the texture by using coordinates from 0, 0 in the top-left corner to 1, 1 in the bottom-right corner. Feel free to experiment with different coordinates. Try using coordinates below 0 or above 1 to see the addressing modes in action!

本教程中,我们将简单地填入四边形with这个纹理by使用坐标-从左上角的0, 0到右下角的1, 1。你可以随意体验不同的坐标。尝试使用低于0或高于1的坐标to实际看看取址模式!

Shaders

The final step is modifying the shaders to sample colors from the texture. We first need to modify the vertex shader to pass through the texture coordinates to the fragment shader:

最后一步是修改shader来从纹理中采样颜色。我们首先需要修改顶点shader来传入纹理坐标到Fragment shader:

layout(location = 0) in vec2 inPosition;
layout(location = 1) in vec3 inColor;
layout(location = 2) in vec2 inTexCoord; layout(location = 0) out vec3 fragColor;
layout(location = 1) out vec2 fragTexCoord; void main() {
gl_Position = ubo.proj * ubo.view * ubo.model * vec4(inPosition, 0.0, 1.0);
fragColor = inColor;
fragTexCoord = inTexCoord;
}

  

Just like the per vertex colors, the fragTexCoord values will be smoothly interpolated across the area of the square by the rasterizer. We can visualize this by having the fragment shader output the texture coordinates as colors:

就像逐顶点的颜色一样,fragTexCoord 值会在四边形上被光栅器平滑地插值。我们可以看到这个by让Fragment shader输出纹理坐标为颜色:

#version 450
#extension GL_ARB_separate_shader_objects : enable layout(location = 0) in vec3 fragColor;
layout(location = 1) in vec2 fragTexCoord; layout(location = 0) out vec4 outColor; void main() {
outColor = vec4(fragTexCoord, 0.0, 1.0);
}

  

You should see something like the image below. Don't forget to recompile the shaders!

你会看到下图所示的内容。别忘记重编译shader!

The green channel represents the horizontal coordinates and the red channel the vertical coordinates. The black and yellow corners confirm that the texture coordinates are correctly interpolated from 0, 0 to 1, 1 across the square. Visualizing data using colors is the shader programming equivalent of printf debugging, for lack of a better option!

绿色通道代表水平坐标,红色通道代表竖直坐标。黑色和黄色的角落确认了that纹理坐标被正确得在四边形上从0, 01, 1插值了。彩色可视化数据是shader编程中等价于printf 的调试方式,如果没有更好的选择!

A combined image sampler descriptor is represented in GLSL by a sampler uniform. Add a reference to it in the fragment shader:

一个CIS描述符在GLSL中用一个采样器uniform变量代表。在Fragment shader中添加对它的引用:

layout(binding = 1) uniform sampler2D texSampler;

  

There are equivalent sampler1D and sampler3D types for other types of images. Make sure to use the correct binding here.

对其他类型的image,有等价的sampler1D 和sampler3D 。确保这里使用正确的绑定。

void main() {
outColor = texture(texSampler, fragTexCoord);
}

  

Textures are sampled using the built-in texture function. It takes a sampler and coordinate as arguments. The sampler automatically takes care of the filtering and transformations in the background. You should now see the texture on the square when you run the application:

纹理通过内置的texture 函数进行采样。它接收一个sampler 和坐标作为参数。采样器自动在后台处理过滤和变换问题。你现在可以看到纹理在四边形上when你运行程序:

Try experimenting with the addressing modes by scaling the texture coordinates to values higher than 1. For example, the following fragment shader produces the result in the image below when using VK_SAMPLER_ADDRESS_MODE_REPEAT:

尝试试验取址模式by缩放纹理坐标到大于1的值。例如,下述Fragment shader会产生下述image-when使用VK_SAMPLER_ADDRESS_MODE_REPEAT模式:

void main() {
outColor = texture(texSampler, fragTexCoord * 2.0);
}

You can also manipulate the texture colors using the vertex colors:

你也可以修改纹理颜色-使用顶点颜色:

void main() {
outColor = vec4(fragColor * texture(texSampler, fragTexCoord).rgb, 1.0);
}

I've separated the RGB and alpha channels here to not scale the alpha channel.

我将RGB和alhpa通道分开了to不缩放alpha通道。

You now know how to access images in shaders! This is a very powerful technique when combined with images that are also written to in framebuffers. You can use these images as inputs to implement cool effects like post-processing and camera displays within the 3D world.

现在你指定如何在shader中读取image了!这是个非常强大的技术whne结合写入帧缓存的image。你可以用这些image作为输入来实现很酷的效果-例如后处理和3D世界的摄像机显示。

C++ code / Vertex shader / Fragment shader

[译]Vulkan教程(29)组合的Image采样器的更多相关文章

  1. [译]Vulkan教程(28)Image视图和采样器

    [译]Vulkan教程(28)Image视图和采样器 Image view and sampler - Image视图和采样器 In this chapter we're going to creat ...

  2. [译]Vulkan教程(27)Image

    [译]Vulkan教程(27)Image Images Introduction 入门 The geometry has been colored using per-vertex colors so ...

  3. [译]Vulkan教程(14)图形管道基础之固定功能

    [译]Vulkan教程(14)图形管道基础之固定功能 Fixed functions 固定功能 The older graphics APIs provided default state for m ...

  4. [译]Vulkan教程(32)生成mipmap

    [译]Vulkan教程(32)生成mipmap Generating Mipmaps 生成mipmap Introduction 入门 Our program can now load and ren ...

  5. [译]Vulkan教程(31)加载模型

    [译]Vulkan教程(31)加载模型 Loading models 加载模型 Introduction 入门 Your program is now ready to render textured ...

  6. [译]Vulkan教程(30)深度缓存

    [译]Vulkan教程(30)深度缓存 Depth buffering 深度缓存 Introduction 入门 The geometry we've worked with so far is pr ...

  7. [译]Vulkan教程(25)描述符布局和buffer

    [译]Vulkan教程(25)描述符布局和buffer Descriptor layout and buffer 描述符布局和buffer Introduction 入门 We're now able ...

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

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

  9. [译]Vulkan教程(16)图形管道基础之总结

    [译]Vulkan教程(16)图形管道基础之总结 Conclusion 总结 We can now combine all of the structures and objects from the ...

随机推荐

  1. Python3 面向对象小练习

    定义MySQL类 对象有id.host.port三个属性 定义工具create_id,在实例化时为每个对象随机生成id,保证id唯一 提供两种实例化方式,方式一:用户传入host和port 方式二:从 ...

  2. jvm调优、常用工具

    ps -ef | grep java查出进程id jmap -heap ID 查出jvm配置信息 加入参数:打印Gc日志,分析 GC日志分析工具: GCeasy 降低minor gc 和 full g ...

  3. java项目测试环境搭建

    java项目测试环境搭建 2019-03-06 13:45:26 木瓜小少年 阅读数 691更多 分类专栏: 测试   版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原 ...

  4. 2020年值得你去试试的10个React开发工具

    本文由葡萄城技术团队翻译并首发 转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. JavaScript每天都在出现大量的框架和工具,而React是除了上次我们 ...

  5. WebService创建、发布及在IIS上部署

    一.项目创建 1.     首先打开VS,这里我以VS2013为例 2.     点击“新建项目”,依次选择“Web”——>“Visual Studio 2012”——>“ASP.NET空 ...

  6. 《Java Spring框架》SpringXML配置详解

    Spring框架作为Bean的管理容器,其最经典最基础的Bean配置方式就是纯XML配置,这样做使得结构清晰明了,适合大型项目使用.Spring的XML配置虽然很繁琐,而且存在简洁的注解方式,但读懂X ...

  7. Linux下shell通用脚本启动jar(微服务)

    Linux下shell通用脚本启动jar(微服务) vim app_jar.sh #!/bin/bash #source /etc/profile # Auth:Liucx # Please chan ...

  8. 在 .NET Core 中使用 Diagnostics (Diagnostic Source) 记录跟踪信息

    前言 最新一直在忙着项目上的事情,很久没有写博客了,在这里对关注我的粉丝们说声抱歉,后面我可能更多的分享我们在微服务落地的过程中的一些经验.那么今天给大家讲一下在 .NET Core 2 中引入的全新 ...

  9. CUDA架构及对应编译参数

    NVIDIA CUDA C++ 编译器 nvcc 基于每个内核,既可以用来产生特定于体系结构的 cubin 文件,又能产生前向兼容的 PTX 版本. 每个 cubin 文件针对特定的计算能力版本,并且 ...

  10. [译]C# 7系列,Part 3: Default Literals 默认文本表达式

    原文:https://blogs.msdn.microsoft.com/mazhou/2017/06/06/c-7-series-part-3-default-literals/ C#的default ...