Sure, I was trying to pass as little code as possible in case it was obvious. Mainly so I didn’t have to clean up the code as it’s currently got loads of little things I tried commented out.
//Fragment Shader:
#version 450
#extension GL_ARB_separate_shader_objects : enable
// Output
layout (location = 0) out vec4 color;
// Input from vertex shader
layout(location = 0) in VS_OUT
{
vec3 N;
vec3 L;
vec3 V;
vec2 tex_coord;
flat int material_id;
} fs_in;
layout(binding = 2) uniform sampler2D textures[3];
layout (push_constant) uniform pushConstants_t
{
layout (offset = 0) uint drawId;
};
void main(void)
{
vec3 Kd = texture(textures[drawId], fs_in.tex_coord).xyz;
vec3 Ks = vec3(1, 1, 1);
float m = 64.0;
vec3 n = normalize(fs_in.N);
vec3 l = normalize(fs_in.L);
vec3 v = normalize(fs_in.V);
vec3 h = normalize(l + v);
vec3 Lo = vec3(0.0);
float nDotL = clamp(dot(n, l), 0.0, 1.0);
float nDotH = clamp(dot(n, h), 0.0, 1.0);
Lo = (Kd + Ks * pow(nDotH, m)) * max(nDotL, 0.1);
color = vec4(Lo, 1.0);
}
//DescriptorSet setup
VkDescriptorBufferInfo descriptorBufferInfo = {};
descriptorBufferInfo.buffer = m_sceneUniformBuffer->m_buffer;
descriptorBufferInfo.offset = 0;
descriptorBufferInfo.range = sizeof(SceneUniformData);
VkWriteDescriptorSet writeDescriptorSet[3] = {};
writeDescriptorSet[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
writeDescriptorSet[0].dstSet = m_vkDescriptorSet;
writeDescriptorSet[0].dstBinding = 0;
writeDescriptorSet[0].dstArrayElement = 0;
writeDescriptorSet[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
writeDescriptorSet[0].descriptorCount = 1;
writeDescriptorSet[0].pBufferInfo = &descriptorBufferInfo;
VkDescriptorBufferInfo descriptorBufferInfo2 = {};
descriptorBufferInfo2.buffer = scene.m_modelMatrixUniformBuffer->m_buffer;
descriptorBufferInfo2.offset = 0;
descriptorBufferInfo2.range = sizeof(ModelUniformData);
writeDescriptorSet[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
writeDescriptorSet[1].dstSet = m_vkDescriptorSet;
writeDescriptorSet[1].dstBinding = 1;
writeDescriptorSet[1].dstArrayElement = 0;
writeDescriptorSet[1].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
writeDescriptorSet[1].descriptorCount = 1;
writeDescriptorSet[1].pBufferInfo = &descriptorBufferInfo2;
VkDescriptorImageInfo *texImageInfo = static_cast<VkDescriptorImageInfo *>(alloca(sizeof(VkDescriptorImageInfo) * m_numTextures));
memset(texImageInfo, 0, sizeof(VkDescriptorImageInfo) * m_numTextures);
for (uint32_t i = 0; i < m_numTextures; i++)
{
texImageInfo[i].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
texImageInfo[i].imageView = m_textures[i]->m_vkImageView;
texImageInfo[i].sampler = m_textures[i]->m_vkSampler;
}
uint32_t texIndex = 2;
writeDescriptorSet[texIndex].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
writeDescriptorSet[texIndex].dstSet = m_vkDescriptorSet;
writeDescriptorSet[texIndex].dstBinding = 2;
writeDescriptorSet[texIndex].dstArrayElement = 0;
writeDescriptorSet[texIndex].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
writeDescriptorSet[texIndex].descriptorCount = 2;
writeDescriptorSet[texIndex].pImageInfo = texImageInfo;
vkUpdateDescriptorSets(m_vkDevice, 3, writeDescriptorSet, 0, nullptr);
//Pipeline layout.
VkDescriptorSetLayoutBinding uboLayoutBinding = {};
uboLayoutBinding.binding = 0;
uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
uboLayoutBinding.descriptorCount = 1;
uboLayoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
VkDescriptorSetLayoutBinding ubo2LayoutBinding = {};
ubo2LayoutBinding.binding = 1;
ubo2LayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
ubo2LayoutBinding.descriptorCount = 1;
ubo2LayoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
VkDescriptorSetLayoutBinding textureLayoutBinding = {};
textureLayoutBinding.binding = 2;
textureLayoutBinding.descriptorCount = 2;
textureLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
textureLayoutBinding.pImmutableSamplers = nullptr;
textureLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
VkDescriptorSetLayoutBinding bindings[] = { uboLayoutBinding, ubo2LayoutBinding, textureLayoutBinding };
VkDescriptorSetLayoutCreateInfo descriptorLayoutCreateInfo = {};
descriptorLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
descriptorLayoutCreateInfo.bindingCount = sizeof(bindings) / sizeof(bindings[0]);
descriptorLayoutCreateInfo.pBindings = bindings;
if (vkCreateDescriptorSetLayout(m_vkDevice, &descriptorLayoutCreateInfo, nullptr, &m_vkDescriptorSetLayout) != VK_SUCCESS)
{
print("failed to create descriptor layout
");
exit(1);
}
I’m happy to post more if needed, but just trying to keep things to a minimum.
If I set textureLayoutBinding.descriptorCount = 3; I get the following validation error instead when building my command buffers: ‘ERROR: validation layer: Object: 0x3b | Descriptor set 0x3b encountered the following validation error at vkCmdDrawIndexed() time: Descriptor in binding #2 at global descriptor index 4 is being used in draw but has not been updated.’
Similarly if I set writeDescriptorSet[texIndex].descriptorCount = 3; I get: ‘ERROR: validation layer: Object: 0x0 | vkUpdateDescriptorSets: required parameter pDescriptorWrites[2].pImageInfo[2].imageView specified as VK_NULL_HANDLE’