我将使用的一些网格并不总是有DiffuseMap或SpecularMap。当我试图加载一些没有漫反射和镜面图的东西时,程序崩溃了,因为在DiffuseMap.ImageViewSpecularMap.ImageView中没有任何东西,因为它没有指向任何东西。如果我尝试将imageeviewsample设置为VK_NULL_HANDLE,程序会给我这样的结果,并且在vkUpdateDescriptorSets时崩溃。
Validation Layer: Invalid VkImageView Object 0x0. The Vulkan spec states: If descriptorType is VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, or VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, the imageView and imageLayout members of each element of pImageInfo must be a valid VkImageView and VkImageLayout, respectively (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkWriteDescriptorSet-descriptorType-00326)
然后如果我试着把绑定设置为null,我就会得到这样的结果。
Validation Layer: vkUpdateDescriptorSets: required parameter pDescriptorWrites[2].dstSet specified as VK_NULL_HANDLE
验证层。Cannot call vkUpdateDescriptorSets() on VkDescriptorSet 0x0[] that has not been allocated.
这是现在基础代码的样子。这是定义描述符集的区域,以便更容易看到发生了什么。
void Mesh::CreateDescriptorSets(VulkanRenderer& Renderer)
{
BaseMesh::CreateDescriptorSets(Renderer, *GetDescriptorSetLayout(Renderer));
VkDescriptorImageInfo DiffuseMap = {};
DiffuseMap.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
DiffuseMap.imageView = TextureList[0].textureImageView;
DiffuseMap.sampler = TextureList[0].textureSampler;
VkDescriptorImageInfo SpecularMap = {};
SpecularMap.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
SpecularMap.imageView = TextureList[1].textureImageView;
SpecularMap.sampler = TextureList[1].textureSampler;
for (size_t i = 0; i < GetSwapChainImageCount(Renderer); i++)
{
VkDescriptorBufferInfo PositionInfo = {};
PositionInfo.buffer = uniformBuffers[i];
PositionInfo.offset = 0;
PositionInfo.range = sizeof(UniformBufferObject);
VkDescriptorBufferInfo AmbiantLightInfo = {};
AmbiantLightInfo.buffer = AmbientLightUniformBuffers[i];
AmbiantLightInfo.offset = 0;
AmbiantLightInfo.range = sizeof(AmbientLightUniformBuffer);
VkDescriptorBufferInfo LightInfo = {};
LightInfo.buffer = LighterUniformBuffers[i];
LightInfo.offset = 0;
LightInfo.range = sizeof(Lighter);
std::array<WriteDescriptorSetInfo, 5> WriteDescriptorInfo = {};
WriteDescriptorInfo[0].DstBinding = 0;
WriteDescriptorInfo[0].DstSet = descriptorSets[i];
WriteDescriptorInfo[0].DescriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
WriteDescriptorInfo[0].DescriptorBufferInfo = PositionInfo;
WriteDescriptorInfo[1].DstBinding = 1;
WriteDescriptorInfo[1].DstSet = descriptorSets[i];
WriteDescriptorInfo[1].DescriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
WriteDescriptorInfo[1].DescriptorImageInfo = DiffuseMap;
WriteDescriptorInfo[2].DstBinding = 2;
WriteDescriptorInfo[2].DstSet = descriptorSets[i];
WriteDescriptorInfo[2].DescriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
WriteDescriptorInfo[2].DescriptorImageInfo = SpecularMap;
WriteDescriptorInfo[3].DstBinding = 3;
WriteDescriptorInfo[3].DstSet = descriptorSets[i];
WriteDescriptorInfo[3].DescriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
WriteDescriptorInfo[3].DescriptorBufferInfo = AmbiantLightInfo;
WriteDescriptorInfo[4].DstBinding = 4;
WriteDescriptorInfo[4].DstSet = descriptorSets[i];
WriteDescriptorInfo[4].DescriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
WriteDescriptorInfo[4].DescriptorBufferInfo = LightInfo;
Mesh::CreateDescriptorSetsData(Renderer, std::vector<WriteDescriptorSetInfo>(WriteDescriptorInfo.begin(), WriteDescriptorInfo.end()));
}
}
在Vulkan 1.2之前,Vulkan并不能识别描述符为 "空 "的可能性。当创建一个描述符集时,描述符(大部分)是未初始化的。只要消耗它的流水线不使用未初始化的描述符,那么拥有一个未初始化描述符的集合是可以的。静态 使用描述符。由于你大概是想对有漫射贴图的对象和没有漫射贴图的对象使用相同的流水线,所以你的着色器根据你提供的变量从图像中读取。这代表了对描述符的静态使用,所以你需要一个图像在那里。
处理这个问题的典型方法是创建一个格式合理的小图像,并将其塞入描述符中。你可以将同样的图像用于基本上任何你想使用的 "空 "纹理。
作为Vulkan 1.2的一部分。VK_EXT_description_indexor_indexing. 扩展推广到核心,允许部分绑定描述符的可能性。基本上,如果 descriptorBindingPartiallyBound
功能是可用的,并且是被请求的,那么您可以使用描述符集来分配一个描述符集。VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT
位,这意味着只要不动态使用,就可以不定义描述符。这意味着,只要不动态地使用一个描述符,就可以不定义它。
所以,你根本不会为该描述符写一个值。
当然,这需要1.2(或上述扩展),以及请求该功能。