Atualizando os descritores
Agora precisamos atualizar os descritores. Para isso, navegamos até a função createDescriptorSetLayout
e adicionamos um VkDescriptorSetLayoutBinding
para um descritor de uniform buffer. Vamos simplesmente colocá-lo na ligação após o descritor de sampler e imagem combinados:
VkDescriptorSetLayoutBinding uboLayoutBinding = {};
uboLayoutBinding.binding = 1;
uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
uboLayoutBinding.descriptorCount = 1;
uboLayoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
uboLayoutBinding.pImmutableSamplers = nullptr;
std::array<VkDescriptorSetLayoutBinding, 2> bindings =
{samplerLayoutBinding, uboLayoutBinding};
VkDescriptorSetLayoutCreateInfo layoutInfo = {};
layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
layoutInfo.bindingCount =
static_cast<uint32_t>(bindings.size());
layoutInfo.pBindings = bindings.data();
Definimos o campo stageFlags
para VK_SHADER_STAGE_VERTEX_BIT
indicando que pretendemos usar o descritor de uniform buffer no vertex shader.
Agora, vamos à função createDescriptorPool
e modificamos-a para incluir um VkDescriptorPoolSize
para esse descritor:
std::array<VkDescriptorPoolSize, 2> poolSizes = {};
poolSizes[0].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
poolSizes[0].descriptorCount = 1;
poolSizes[1].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
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 = static_cast<uint32_t>(poolSizes.size());
A etapa final é vincular o recurso do uniform buffer aos descritores no conjunto de descritores. Para isso, modificamos a função createDescriptorSets
.
VkDescriptorImageInfo descriptorImageInfo = {};
descriptorImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
descriptorImageInfo.imageView = m_object->textureImageView;
descriptorImageInfo.sampler = m_textureSampler;
VkDescriptorBufferInfo bufferInfo = {};
bufferInfo.buffer = m_object->uniformBuffer;
bufferInfo.offset = 0;
bufferInfo.range = sizeof(UniformBufferObject);
O recurso de buffer para um descritor de uniform buffer deve ser especificado em uma estrutura VkDescriptorBufferInfo
, assim como os recursos de imagem e sampler são especificados em uma estrutura VkDescriptorImageInfo
. É aqui que os objetos do capítulo anterior se reúnem.
std::array<VkWriteDescriptorSet, 2> descriptorWrites = {};
descriptorWrites[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptorWrites[0].dstSet = m_object->descriptorSet;
descriptorWrites[0].dstBinding = 0;
descriptorWrites[0].dstArrayElement = 0;
descriptorWrites[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
descriptorWrites[0].descriptorCount = 1;
descriptorWrites[0].pImageInfo = &descriptorImageInfo;
descriptorWrites[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptorWrites[1].dstSet = m_object->descriptorSet;
descriptorWrites[1].dstBinding = 1;
descriptorWrites[1].dstArrayElement = 0;
descriptorWrites[1].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
descriptorWrites[1].descriptorCount = 1;
descriptorWrites[1].pBufferInfo = &bufferInfo;
m_deviceFunctions->vkUpdateDescriptorSets(
device,
descriptorWrites.size(),
descriptorWrites.data(),
0,
nullptr
);
Os descritores devem ser atualizados com essas informações do buffer, assim como a imagem. Desta vez, estamos usando o campo pBufferInfo
em vez de pImageInfo
. Agora os descritores estão prontos para serem usados pelos shaders.
Se executarmos nos programa agora, notaremos que infelizmente nada é visível. O problema é que, devido ao rotação em Y
que fizemos na matriz de projeção, os vértices agora estão sendo desenhados no sentido anti-horário, em vez de no sentido horário. Isso faz com que a seleção da face posterior (backface culling) seja ativada e evita que qualquer geometria seja desenhada. Para corrigir isso, devemos ir à função initPipeline
e modificar frontFace
em VkPipelineRasterizationStateCreateInfo
para VK_FRONT_FACE_COUNTER_CLOCKWISE
:
rasterizationInfo.cullMode = VK_CULL_MODE_BACK_BIT;
rasterizationInfo.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
Ser executarmos nosso programa novamente, devemos ver o mesmo que mostrado na Figura 9. O retângulo mudou para um quadrado porque a matriz de projeção agora corrige a proporção de tela. A função updateUniformBuffer
cuida do redimensionamento da tela, portanto, não precisamos recriar o conjunto de descritor quando o tamanho da janela for alterado.
