操作系統(tǒng):Windows8.1
顯卡:Nivida GTX965M
開發(fā)工具:Visual Studio 2017
Introduction
我們在教程的uniform 緩沖區(qū)中首次了解了描述符。在本章節(jié)我們會看到一種新的描述符類型:combined image sampler 組合圖像取樣器。該描述符使著色器可以通過像上一章創(chuàng)建的采樣器對象來訪問圖像資源。
我們將首先修改描述符布局,描述符對象池和描述符集合,以包括這樣一個組合的圖像采樣器描述符。完成之后,我們會添加紋理貼圖坐標(biāo)到Vertex數(shù)據(jù)中,并修改片段著色器從紋理中讀取顏色,而不是內(nèi)插頂點(diǎn)顏色。
Updating the descriptors
瀏覽到createDesriptorSetLayout函數(shù),并為組合圖像采樣器描述符添加一個VkDescriptorSetLayoutBinding。我們將簡單的在uniform buffer之后進(jìn)行版定操作。
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();
確保stageFlags正確設(shè)置,指定我們打算在片段著色器中使用組合圖像采樣器描述符。這就是片段顏色最終被確定的地方??梢栽陧旤c(diǎn)著色器中使用紋理采樣,比如,通過高度圖 heightmap 動態(tài)的變形頂點(diǎn)的網(wǎng)格。
如果你開啟validation layers運(yùn)行程序,你將會看到它引起了描述符對象池不能使用這個布局分配描述符集合,因?yàn)樗鼪]有任何組合圖像采樣器描述符。來到createDescriptorPool函數(shù),以包含此描述符的VkDescriptorPoolSize:
std::array<VkDescriptorPoolSize, 2> poolSizes = {}; poolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; poolSizes[0].descriptorCount = 1; poolSizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; poolSizes[1].descriptorCount = 1; 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 = 1;
最后一步是將實(shí)際的圖像和采樣器資源綁定到描述符集合中的具體描述符。來到createDescriptorSet函數(shù)。
VkDescriptorImageInfo imageInfo = {}; imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; imageInfo.imageView = textureImageView; imageInfo.sampler = textureSampler;
組合圖像采樣器結(jié)構(gòu)體的資源必須在VkDescriptorImageInfo結(jié)構(gòu)進(jìn)行指定。就像在VkDescriptorBufferInfo結(jié)構(gòu)體中指定一個 uniform buffer descriptor 緩沖區(qū)資源一樣。這是上一章節(jié)中的對象匯集的代碼段。
std::array<VkWriteDescriptorSet, 2> descriptorWrites = {}; descriptorWrites[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; descriptorWrites[0].dstSet = descriptorSet; 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 = descriptorSet; 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);
描述符必須與此圖像信息一起更新,就像緩沖區(qū)一樣。這次我們使用pImageInfo數(shù)組代替pBufferInfo。描述符現(xiàn)在可以被著色器使用!
Texture coordinates
紋理映射的一個重要組成部分仍然缺少,這是每個頂點(diǎn)的實(shí)際坐標(biāo)。坐標(biāo)決定如何實(shí)際的映射到幾何圖形上。
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; } };
修改Vertex結(jié)構(gòu)體包含vec2結(jié)構(gòu)用于紋理坐標(biāo)。確保加入VkVertexInputAttributeDescription結(jié)構(gòu)體,如此我們就可以在頂點(diǎn)著色器中訪問紋理UV坐標(biāo)數(shù)據(jù)。這是必要的,以便能夠?qū)⑺鼈儌鬟f到片段著色器,以便在正方形的表面進(jìn)行插值處理。
const std::vector<Vertex> vertices = { {{-0.5f, -0.5f}, {1.0f, 0.0f, 0.0f}, {0.0f, 0.0f}}, {{0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}, {1.0f, 0.0f}}, {{0.5f, 0.5f}, {0.0f, 0.0f, 1.0f}, {1.0f, 1.0f}}, {{-0.5f, 0.5f}, {1.0f, 1.0f, 1.0f}, {0.0f, 1.0f}} };
在本教程中,使用坐標(biāo)從左上角 0,0 到右下角的 1,1 來映射紋理,從而簡單的填充矩形。在這里可以嘗試各種坐標(biāo)。嘗試使用低于 0 或者 1 以上的坐標(biāo)來查看尋址模式的不同表現(xiàn)。
Shaders
最后一步是修改著色器從紋理中采樣顏色。我們首先需要修改頂點(diǎn)著色器,傳遞紋理坐標(biāo)到片段著色器。
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; }
就像每個頂點(diǎn)的顏色,fragTexCoord值通過光柵化平滑的插值到矩形區(qū)域內(nèi)。我們可以通過使片段著色器輸出的紋理坐標(biāo)為顏色來可視化看到這些:
#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); }
現(xiàn)在應(yīng)該可以看到如下圖所示的效果。不要忘記重新編譯著色器!
綠色通道代表水平坐標(biāo),紅色通道代表垂直坐標(biāo)。黑色和黃色角確認(rèn)了紋理坐標(biāo)正確的從 0,0 到 1,1 進(jìn)行插值填充到方形中。使用顏色可視化在著色器中編程等價于 printf 調(diào)試,除此之外沒有更好的方法!
組合圖像采樣器描述符在GLSL中通過采樣器 uniform代替。在片段著色器中引用它:
layout(binding = 1) uniform sampler2D texSampler;
對于其他圖像有等價的 sampler1D 和 sampler3D 類型。確保正確的綁定操作。
void main() { outColor = texture(texSampler, fragTexCoord); }
紋理采用內(nèi)置的 texture 函數(shù)進(jìn)行采樣。它需要使用 sampler 和 坐標(biāo)作為參數(shù)。采樣器在后臺自動處理過濾和變化功能。你應(yīng)該可以看到紋理貼圖在方形上:
嘗試修改尋址模式放大大于 1 來觀測效果。比如,下面的片段著色器輸出的結(jié)果使用VK_SAMPLER_ADDRESS_MODE_REPEAT:
void main() { outColor = texture(texSampler, fragTexCoord * 2.0); }
還可以使用頂點(diǎn)顏色來處理紋理顏色:
void main() { outColor = vec4(fragColor * texture(texSampler, fragTexCoord).rgb, 1.0); }
將RGB和alha通道分離開,以便不分離alpha通道。
現(xiàn)在已經(jīng)知道如何在著色器中訪問圖像!當(dāng)與幀緩沖區(qū)中的圖像進(jìn)行結(jié)合時,這是一個非常有效的技術(shù)。你可以看到這些圖像作為輸入實(shí)現(xiàn)很酷的效果,比如 post-processing和3D世界攝像機(jī)顯示。
http://www.cnblogs.com/heitao/p/7144652.html