diff --git a/data/shaders/inlineuniformblocks/cube.frag b/data/shaders/inlineuniformblocks/cube.frag deleted file mode 100644 index f00d3d99..00000000 --- a/data/shaders/inlineuniformblocks/cube.frag +++ /dev/null @@ -1,23 +0,0 @@ -#version 450 - -layout (set = 0, binding = 2) uniform sampler2D samplerColorMap; - -layout (location = 0) in vec3 inNormal; -layout (location = 1) in vec3 inColor; -layout (location = 2) in vec2 inUV; -layout (location = 3) in vec3 inViewVec; -layout (location = 4) in vec3 inLightVec; - -layout (location = 0) out vec4 outFragColor; - -void main() -{ - vec3 color = texture(samplerColorMap, inUV).rgb * inColor; - - vec3 N = normalize(inNormal); - vec3 L = normalize(inLightVec); - vec3 V = normalize(inViewVec); - vec3 R = reflect(-L, N); - float diffuse = max(dot(N, L), 0.1); - outFragColor = vec4(color * diffuse, 1.0); -} \ No newline at end of file diff --git a/data/shaders/inlineuniformblocks/cube.frag.spv b/data/shaders/inlineuniformblocks/cube.frag.spv deleted file mode 100644 index 2acb5f85..00000000 Binary files a/data/shaders/inlineuniformblocks/cube.frag.spv and /dev/null differ diff --git a/data/shaders/inlineuniformblocks/cube.vert b/data/shaders/inlineuniformblocks/cube.vert deleted file mode 100644 index 2c180b7e..00000000 --- a/data/shaders/inlineuniformblocks/cube.vert +++ /dev/null @@ -1,40 +0,0 @@ -#version 450 - -layout (location = 0) in vec3 inPos; -layout (location = 1) in vec3 inNormal; -layout (location = 2) in vec2 inUV; -layout (location = 3) in vec3 inColor; - -layout (set = 0, binding = 0) uniform UBOMatrices { - mat4 projection; - mat4 view; - mat4 model; -} uboMatrices; - -layout (set = 0, binding = 1) uniform UniformInline { - vec4 color; -} uniformInline; - -layout (location = 0) out vec3 outNormal; -layout (location = 1) out vec3 outColor; -layout (location = 2) out vec2 outUV; -layout (location = 3) out vec3 outViewVec; -layout (location = 4) out vec3 outLightVec; - -out gl_PerVertex { - vec4 gl_Position; -}; - -void main() -{ - outColor = inColor * uniformInline.color.rgb; - outUV = inUV; - gl_Position = uboMatrices.projection * uboMatrices.view * uboMatrices.model * vec4(inPos.xyz, 1.0); - - vec4 pos = uboMatrices.model * vec4(inPos, 1.0); - outNormal = mat3(transpose(inverse(uboMatrices.model))) * normalize(inNormal); - vec3 lightPos = vec3(0.0f, -25.0f, 25.0f); - vec3 lPos = mat3(uboMatrices.model) * lightPos.xyz; - outLightVec = lPos - pos.xyz; - outViewVec = -pos.xyz; -} \ No newline at end of file diff --git a/data/shaders/inlineuniformblocks/cube.vert.spv b/data/shaders/inlineuniformblocks/cube.vert.spv deleted file mode 100644 index b65d53cd..00000000 Binary files a/data/shaders/inlineuniformblocks/cube.vert.spv and /dev/null differ diff --git a/data/shaders/inlineuniformblocks/pbr.frag b/data/shaders/inlineuniformblocks/pbr.frag new file mode 100644 index 00000000..6c237e76 --- /dev/null +++ b/data/shaders/inlineuniformblocks/pbr.frag @@ -0,0 +1,116 @@ +#version 450 + +layout (location = 0) in vec3 inWorldPos; +layout (location = 1) in vec3 inNormal; + +layout (set = 0, binding = 0) uniform UBO +{ + mat4 projection; + mat4 model; + mat4 view; + vec3 camPos; +} ubo; + +// Inline uniform block +layout (set = 1, binding = 0) uniform UniformInline { + float roughness; + float metallic; + float r; + float g; + float b; + float ambient; +} material; + +layout (location = 0) out vec4 outColor; + +const float PI = 3.14159265359; + +vec3 materialcolor() +{ + return vec3(material.r, material.g, material.b); +} + +// Normal Distribution function -------------------------------------- +float D_GGX(float dotNH, float roughness) +{ + float alpha = roughness * roughness; + float alpha2 = alpha * alpha; + float denom = dotNH * dotNH * (alpha2 - 1.0) + 1.0; + return (alpha2)/(PI * denom*denom); +} + +// Geometric Shadowing function -------------------------------------- +float G_SchlicksmithGGX(float dotNL, float dotNV, float roughness) +{ + float r = (roughness + 1.0); + float k = (r*r) / 8.0; + float GL = dotNL / (dotNL * (1.0 - k) + k); + float GV = dotNV / (dotNV * (1.0 - k) + k); + return GL * GV; +} + +// Fresnel function ---------------------------------------------------- +vec3 F_Schlick(float cosTheta, float metallic) +{ + vec3 F0 = mix(vec3(0.04), materialcolor(), metallic); // * material.specular + vec3 F = F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0); + return F; +} + +// Specular BRDF composition -------------------------------------------- + +vec3 BRDF(vec3 L, vec3 V, vec3 N, float metallic, float roughness) +{ + // Precalculate vectors and dot products + vec3 H = normalize (V + L); + float dotNV = clamp(dot(N, V), 0.0, 1.0); + float dotNL = clamp(dot(N, L), 0.0, 1.0); + float dotLH = clamp(dot(L, H), 0.0, 1.0); + float dotNH = clamp(dot(N, H), 0.0, 1.0); + + // Light color fixed + vec3 lightColor = vec3(1.0); + + vec3 color = vec3(0.0); + + if (dotNL > 0.0) + { + float rroughness = max(0.05, roughness); + // D = Normal distribution (Distribution of the microfacets) + float D = D_GGX(dotNH, rroughness); + // G = Geometric shadowing term (Microfacets shadowing) + float G = G_SchlicksmithGGX(dotNL, dotNV, rroughness); + // F = Fresnel factor (Reflectance depending on angle of incidence) + vec3 F = F_Schlick(dotNV, metallic); + + vec3 spec = D * F * G / (4.0 * dotNL * dotNV); + + color += spec * dotNL * lightColor; + } + + return color; +} + +// ---------------------------------------------------------------------------- +void main() +{ + vec3 N = normalize(inNormal); + vec3 V = normalize(ubo.camPos - inWorldPos); + + float roughness = material.roughness; + + // Specular contribution + vec3 lightPos = vec3(0.0f, 0.0f, 10.0f); + vec3 Lo = vec3(0.0); + vec3 L = normalize(lightPos.xyz - inWorldPos); + Lo += BRDF(L, V, N, material.metallic, roughness); + + // Combine with ambient + vec3 color = materialcolor() * material.ambient; + color += Lo; + + // Gamma correct + color = pow(color, vec3(0.4545)); + + outColor = vec4(color, 1.0); +} \ No newline at end of file diff --git a/data/shaders/inlineuniformblocks/pbr.frag.spv b/data/shaders/inlineuniformblocks/pbr.frag.spv new file mode 100644 index 00000000..f4200da8 Binary files /dev/null and b/data/shaders/inlineuniformblocks/pbr.frag.spv differ diff --git a/data/shaders/inlineuniformblocks/pbr.vert b/data/shaders/inlineuniformblocks/pbr.vert new file mode 100644 index 00000000..a1b542a5 --- /dev/null +++ b/data/shaders/inlineuniformblocks/pbr.vert @@ -0,0 +1,32 @@ +#version 450 + +layout (location = 0) in vec3 inPos; +layout (location = 1) in vec3 inNormal; + +layout (set = 0, binding = 0) uniform UBO +{ + mat4 projection; + mat4 model; + mat4 view; + vec3 camPos; +} ubo; + +layout (location = 0) out vec3 outWorldPos; +layout (location = 1) out vec3 outNormal; + +layout(push_constant) uniform PushConsts { + vec3 objPos; +} pushConsts; + +out gl_PerVertex +{ + vec4 gl_Position; +}; + +void main() +{ + vec3 locPos = vec3(ubo.model * vec4(inPos, 1.0)); + outWorldPos = locPos + pushConsts.objPos; + outNormal = mat3(ubo.model) * inNormal; + gl_Position = ubo.projection * ubo.view * vec4(outWorldPos, 1.0); +} diff --git a/data/shaders/inlineuniformblocks/pbr.vert.spv b/data/shaders/inlineuniformblocks/pbr.vert.spv new file mode 100644 index 00000000..84274aa1 Binary files /dev/null and b/data/shaders/inlineuniformblocks/pbr.vert.spv differ diff --git a/examples/inlineuniformblocks/inlineuniformblocks.cpp b/examples/inlineuniformblocks/inlineuniformblocks.cpp index bdb7114f..5ec5161a 100644 --- a/examples/inlineuniformblocks/inlineuniformblocks.cpp +++ b/examples/inlineuniformblocks/inlineuniformblocks.cpp @@ -1,5 +1,5 @@ /* -* Vulkan Example - Using inline uniform blocks for passing data to shader stages +* Vulkan Example - Using inline uniform blocks for passing data to shader stages at descriptor setup * Note: Requires a device that supports the VK_EXT_inline_uniform_block extension * @@ -20,81 +20,93 @@ #define GLM_FORCE_DEPTH_ZERO_TO_ONE #include #include -#include + +#include #include #include "vulkanexamplebase.h" -#include "VulkanTexture.hpp" +#include "VulkanBuffer.hpp" #include "VulkanModel.hpp" #define ENABLE_VALIDATION false +#define OBJ_DIM 0.025f + +float rnd() { + return ((float)rand() / (RAND_MAX)); +} class VulkanExample : public VulkanExampleBase { public: - bool animate = true; - vks::VertexLayout vertexLayout = vks::VertexLayout({ vks::VERTEX_COMPONENT_POSITION, vks::VERTEX_COMPONENT_NORMAL, vks::VERTEX_COMPONENT_UV, - vks::VERTEX_COMPONENT_COLOR, - }); + }); - /* - [POI] This is the data structure that'll be passed using inline uniform blocks - */ - struct InlineBlockData { - glm::vec4 color; - }; + vks::Model model; - struct Cube { - struct Matrices { - glm::mat4 projection; - glm::mat4 view; - glm::mat4 model; - } matrices; - InlineBlockData inlineBlockData; + struct Object { + struct Material { + float roughness; + float metallic; + float r, g, b; + float ambient; + } material; VkDescriptorSet descriptorSet; - vks::Texture2D texture; - vks::Buffer uniformBuffer; - glm::vec3 rotation; }; - std::array cubes; + std::array objects; + + struct { + vks::Buffer scene; + } uniformBuffers; + + struct UBOMatrices { + glm::mat4 projection; + glm::mat4 model; + glm::mat4 view; + glm::vec3 camPos; + } uboMatrices; - struct Models { - vks::Model cube; - } models; - - VkPipeline pipeline; VkPipelineLayout pipelineLayout; + VkPipeline pipeline; + VkDescriptorSet descriptorSet; - VkDescriptorSetLayout descriptorSetLayout; + struct DescriptorSetLaysts { + VkDescriptorSetLayout scene; + VkDescriptorSetLayout object; + } descriptorSetLayouts; VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION) { title = "Inline uniform blocks"; + camera.type = Camera::CameraType::firstperson; + camera.setPosition(glm::vec3(0.0f, 0.0f, -10.0f)); + camera.setRotation(glm::vec3(0.0, 0.0f, 0.0f)); + camera.setPerspective(60.0f, (float)width / (float)height, 0.1f, 256.0f); + camera.movementSpeed = 4.0f; + camera.rotationSpeed = 0.25f; settings.overlay = true; - camera.type = Camera::CameraType::lookat; - camera.setPerspective(60.0f, (float)width / (float)height, 0.1f, 512.0f); - camera.setRotation(glm::vec3(0.0f, 0.0f, 0.0f)); - camera.setTranslation(glm::vec3(0.0f, 0.0f, -5.0f)); + + srand((unsigned int)time(0)); + /* - [POI] Enable extension required for conditional rendering - */ + [POI] Enable extensions required for inline uniform blocks + */ enabledDeviceExtensions.push_back(VK_EXT_INLINE_UNIFORM_BLOCK_EXTENSION_NAME); } ~VulkanExample() { vkDestroyPipeline(device, pipeline, nullptr); + vkDestroyPipelineLayout(device, pipelineLayout, nullptr); - vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr); - models.cube.destroy(); - for (auto cube : cubes) { - cube.uniformBuffer.destroy(); - cube.texture.destroy(); - } + vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.scene, nullptr); + vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.object, nullptr); + + model.destroy(); + + uniformBuffers.scene.destroy(); } void buildCommandBuffers() @@ -102,7 +114,7 @@ public: VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo(); VkClearValue clearValues[2]; - clearValues[0].color = defaultClearColor; + clearValues[0].color = { { 0.0f, 0.0f, 0.0f, 1.0f } }; clearValues[1].depthStencil = { 1.0f, 0 }; VkRenderPassBeginInfo renderPassBeginInfo = vks::initializers::renderPassBeginInfo(); @@ -114,15 +126,14 @@ public: renderPassBeginInfo.clearValueCount = 2; renderPassBeginInfo.pClearValues = clearValues; - for (int32_t i = 0; i < drawCmdBuffers.size(); ++i) { + for (int32_t i = 0; i < drawCmdBuffers.size(); ++i) + { renderPassBeginInfo.framebuffer = frameBuffers[i]; VK_CHECK_RESULT(vkBeginCommandBuffer(drawCmdBuffers[i], &cmdBufInfo)); vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); - VkViewport viewport = vks::initializers::viewport((float)width, (float)height, 0.0f, 1.0f); vkCmdSetViewport(drawCmdBuffers[i], 0, 1, &viewport); @@ -130,14 +141,30 @@ public: vkCmdSetScissor(drawCmdBuffers[i], 0, 1, &scissor); VkDeviceSize offsets[1] = { 0 }; - vkCmdBindVertexBuffers(drawCmdBuffers[i], 0, 1, &models.cube.vertices.buffer, offsets); - vkCmdBindIndexBuffer(drawCmdBuffers[i], models.cube.indices.buffer, 0, VK_INDEX_TYPE_UINT32); - for (auto cube : cubes) { - vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &cube.descriptorSet, 0, nullptr); - vkCmdDrawIndexed(drawCmdBuffers[i], models.cube.indexCount, 1, 0, 0, 0); + // Render objects + vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); + vkCmdBindVertexBuffers(drawCmdBuffers[i], 0, 1, &model.vertices.buffer, offsets); + vkCmdBindIndexBuffer(drawCmdBuffers[i], model.indices.buffer, 0, VK_INDEX_TYPE_UINT32); + + uint32_t objcount = static_cast(objects.size()); + for (uint32_t x = 0; x < objcount; x++) { + /* + [POI] Bind descriptor sets + Set 0 = Scene matrices: + Set 1 = Object inline uniform block (In shader pbr.frag: layout (set = 1, binding = 0) uniform UniformInline ... ) + */ + std::vector descriptorSets = { + descriptorSet, + objects[x].descriptorSet + }; + vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 2, descriptorSets.data(), 0, nullptr); + + glm::vec3 pos = glm::vec3(sin(glm::radians(x * (360.0f / objcount))), cos(glm::radians(x * (360.0f / objcount))), 0.0f) * 3.5f; + + vkCmdPushConstants(drawCmdBuffers[i], pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(glm::vec3), &pos); + vkCmdDrawIndexed(drawCmdBuffers[i], model.indexCount, 1, 0, 0, 0); } - drawUI(drawCmdBuffers[i]); vkCmdEndRenderPass(drawCmdBuffers[i]); @@ -148,184 +175,135 @@ public: void loadAssets() { - models.cube.loadFromFile(getAssetPath() + "models/cube.dae", vertexLayout, 1.0f, vulkanDevice, queue); - cubes[0].texture.loadFromFile(getAssetPath() + "textures/crate01_color_height_rgba.ktx", VK_FORMAT_R8G8B8A8_UNORM, vulkanDevice, queue); - cubes[1].texture.loadFromFile(getAssetPath() + "textures/crate02_color_height_rgba.ktx", VK_FORMAT_R8G8B8A8_UNORM, vulkanDevice, queue); - cubes[0].inlineBlockData.color = glm::vec4(1.0f, 0.0f, 0.0f, 1.0f); - cubes[1].inlineBlockData.color = glm::vec4(0.0f, 0.0f, 1.0f, 1.0f); + model.loadFromFile(getAssetPath() + "models/geosphere.obj", vertexLayout, OBJ_DIM, vulkanDevice, queue); + + // Setup random materials for every object in the scene + for (uint32_t i = 0; i < objects.size(); i++) { + objects[i].material.r = rnd(); + objects[i].material.g = rnd(); + objects[i].material.b = rnd(); + objects[i].material.ambient = 0.05f; + objects[i].material.roughness = glm::clamp(rnd(), 0.005f, 1.0f); + objects[i].material.metallic = glm::clamp(rnd(), 0.005f, 1.0f); + } } - /* - [POI] Set up descriptor sets and set layout - */ - void setupDescriptors() + void setupDescriptorSetLayout() { - const uint32_t cubeCount = static_cast(cubes.size()); + // Scene + { + std::vector setLayoutBindings = { + vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0), + vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_FRAGMENT_BIT, 1), + }; + VkDescriptorSetLayoutCreateInfo descriptorLayoutCI = vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings); + VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayoutCI, nullptr, &descriptorSetLayouts.scene)); + } + + // Objects + { + std::vector setLayoutBindings = { + /* + [POI] Setup inline uniform block for set 0 at binding 2 (see vertex shader) + Descriptor count for an inline uniform block contains data sizes of the block (last parameter) + */ + vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(Object::Material)), + }; + VkDescriptorSetLayoutCreateInfo descriptorLayoutCI = vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings); + VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayoutCI, nullptr, &descriptorSetLayouts.object)); + } /* - Descriptor pool + [POI] Pipeline layout */ + std::vector setLayouts = { + descriptorSetLayouts.scene, // Set 0 = Scene matrices + descriptorSetLayouts.object // Set 1 = Object inline uniform block + }; + VkPipelineLayoutCreateInfo pipelineLayoutCI = vks::initializers::pipelineLayoutCreateInfo(setLayouts.data(), static_cast(setLayouts.size())); - std::array descriptorPoolSizes{}; + std::vector pushConstantRanges = { + vks::initializers::pushConstantRange(VK_SHADER_STAGE_VERTEX_BIT, sizeof(glm::vec3), 0), + }; + pipelineLayoutCI.pushConstantRangeCount = 1; + pipelineLayoutCI.pPushConstantRanges = pushConstantRanges.data(); - // One uniform buffer descriptor per cube - descriptorPoolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - descriptorPoolSizes[0].descriptorCount = cubeCount; + VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCI, nullptr, &pipelineLayout)); + } + + void setupDescriptorSets() + { + // Pool + std::vector poolSizes = { + vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, (static_cast(objects.size()) + 1)), + /* [POI] TODO */ + // TODO: split scene and object + vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT, (static_cast(objects.size()) + 1) * sizeof(Object::Material)), + }; + VkDescriptorPoolCreateInfo descriptorPoolCI = vks::initializers::descriptorPoolCreateInfo(poolSizes, static_cast(objects.size()) + 1); /* - [POI] One inline uniform block descriptor per cube - */ - descriptorPoolSizes[1].type = VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT; - // Descriptor count for inline uniform blocks contains the combined data sizes of all inline uniform blocks used from this pool - descriptorPoolSizes[1].descriptorCount = cubeCount * sizeof(InlineBlockData); - - // One combined image samples per cube - descriptorPoolSizes[2].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - descriptorPoolSizes[2].descriptorCount = static_cast(cubes.size()); - - // Create the global descriptor pool - - VkDescriptorPoolCreateInfo descriptorPoolCI = {}; - descriptorPoolCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - descriptorPoolCI.poolSizeCount = static_cast(descriptorPoolSizes.size()); - descriptorPoolCI.pPoolSizes = descriptorPoolSizes.data(); - descriptorPoolCI.maxSets = static_cast(descriptorPoolSizes.size()); -# - /* - [POI] New structure that has to be chained into the descriptor pool create info if you want to allocate inline uniform blocks + [POI] New structure that has to be chained into the descriptor pool's createinfo if you want to allocate inline uniform blocks */ VkDescriptorPoolInlineUniformBlockCreateInfoEXT descriptorPoolInlineUniformBlockCreateInfo{}; descriptorPoolInlineUniformBlockCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_INLINE_UNIFORM_BLOCK_CREATE_INFO_EXT; descriptorPoolInlineUniformBlockCreateInfo.maxInlineUniformBlockBindings = 1; - // Chain into descriptor pool create info descriptorPoolCI.pNext = &descriptorPoolInlineUniformBlockCreateInfo; - + VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolCI, nullptr, &descriptorPool)); - /* - Descriptor set layout - */ + // Sets - std::array setLayoutBindings{}; + // Scene + VkDescriptorSetAllocateInfo descriptorAllocateInfo = vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayouts.scene, 1); + VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &descriptorAllocateInfo, &descriptorSet)); - // Binding 0: Uniform buffers (used to pass matrices) - setLayoutBindings[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - setLayoutBindings[0].binding = 0; - setLayoutBindings[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; - setLayoutBindings[0].descriptorCount = 1; + std::vector writeDescriptorSets = { + vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, &uniformBuffers.scene.descriptor), + }; + vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, nullptr); - /* - [POI] Binding 1: Inline uniform block - */ - setLayoutBindings[1].descriptorType = VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT; - setLayoutBindings[1].binding = 1; - setLayoutBindings[1].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; - // Descriptor count for an inline uniform block contains data sizes of the block - setLayoutBindings[1].descriptorCount = sizeof(InlineBlockData); - - // Binding 2: Combined image sampler (used to pass per object texture information) - setLayoutBindings[2].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - setLayoutBindings[2].binding = 2; - setLayoutBindings[2].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - setLayoutBindings[2].descriptorCount = 1; - - // Create the descriptor set layout - VkDescriptorSetLayoutCreateInfo descriptorLayoutCI{}; - descriptorLayoutCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - descriptorLayoutCI.bindingCount = static_cast(setLayoutBindings.size()); - descriptorLayoutCI.pBindings = setLayoutBindings.data(); - - VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayoutCI, nullptr, &descriptorSetLayout)); - - /* - Descriptor sets - */ - - for (auto &cube: cubes) { - - // Allocates an empty descriptor set without actual descriptors from the pool using the set layout - VkDescriptorSetAllocateInfo allocateInfo{}; - allocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - allocateInfo.descriptorPool = descriptorPool; - allocateInfo.descriptorSetCount = 1; - allocateInfo.pSetLayouts = &descriptorSetLayout; - VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocateInfo, &cube.descriptorSet)); - - // Update the descriptor set with the actual descriptors matching shader bindings set in the layout - - std::array writeDescriptorSets{}; - - // Binding 0: Object matrices Uniform buffer - writeDescriptorSets[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - writeDescriptorSets[0].dstSet = cube.descriptorSet; - writeDescriptorSets[0].dstBinding = 0; - writeDescriptorSets[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - writeDescriptorSets[0].pBufferInfo = &cube.uniformBuffer.descriptor; - writeDescriptorSets[0].descriptorCount = 1; - - /* - [POI] Binding 1: Inline uniform block - */ - writeDescriptorSets[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - writeDescriptorSets[1].dstSet = cube.descriptorSet; - writeDescriptorSets[1].dstBinding = 1; - writeDescriptorSets[1].descriptorType = VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT; - // The dstArrayElement member can be used to define an offset for inline uniform blocks - writeDescriptorSets[1].dstArrayElement = 0; - // TODO: API-Design from hell - writeDescriptorSets[1].descriptorCount = sizeof(glm::vec4); + // Objects + for (auto &object : objects) { + VkDescriptorSetAllocateInfo descriptorAllocateInfo = vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayouts.object, 1); + VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &descriptorAllocateInfo, &object.descriptorSet)); /* - [POI] New structure that defines size and data of the inline uniform block + [POI] New structure that defines size and data of the inline uniform block needs to be chained into the write descriptor set + We will be using this inline uniform block to pass per-object material information to the fragment shader */ VkWriteDescriptorSetInlineUniformBlockEXT writeDescriptorSetInlineUniformBlock{}; writeDescriptorSetInlineUniformBlock.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK_EXT; - writeDescriptorSetInlineUniformBlock.dataSize = sizeof(InlineBlockData); - writeDescriptorSetInlineUniformBlock.pData = &cube.inlineBlockData; - // Needs to be chained to an existing write descriptor set structure - writeDescriptorSets[1].pNext = &writeDescriptorSetInlineUniformBlock; + writeDescriptorSetInlineUniformBlock.dataSize = sizeof(Object::Material); + // Uniform data for the inline block + writeDescriptorSetInlineUniformBlock.pData = &object.material; - // Binding 2: Object texture - writeDescriptorSets[2].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - writeDescriptorSets[2].dstSet = cube.descriptorSet; - writeDescriptorSets[2].dstBinding = 2; - writeDescriptorSets[2].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - writeDescriptorSets[2].pImageInfo = &cube.texture.descriptor; - writeDescriptorSets[2].descriptorCount = 1; + /* + [POI] Setup the inline uniform block + */ + VkWriteDescriptorSet writeDescriptorSet{}; + writeDescriptorSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writeDescriptorSet.descriptorType = VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT; + writeDescriptorSet.dstSet = object.descriptorSet; + writeDescriptorSet.dstBinding = 0; + // Descriptor count for an inline uniform block contains data sizes of the block(last parameter) + writeDescriptorSet.descriptorCount = sizeof(Object::Material); + // Chain inline uniform block structure + writeDescriptorSet.pNext = &writeDescriptorSetInlineUniformBlock; - vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, nullptr); + vkUpdateDescriptorSets(device, 1, &writeDescriptorSet, 0, nullptr); } - } void preparePipelines() { - VkPipelineLayoutCreateInfo pipelineLayoutCI{}; - pipelineLayoutCI.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; - pipelineLayoutCI.setLayoutCount = 1; - pipelineLayoutCI.pSetLayouts = &descriptorSetLayout; - VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCI, nullptr, &pipelineLayout)); - - const std::vector dynamicStateEnables = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR }; - - VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCI = vks::initializers::pipelineInputAssemblyStateCreateInfo(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 0, VK_FALSE); - VkPipelineRasterizationStateCreateInfo rasterizationStateCI = vks::initializers::pipelineRasterizationStateCreateInfo(VK_POLYGON_MODE_FILL, VK_CULL_MODE_BACK_BIT, VK_FRONT_FACE_CLOCKWISE, 0); - VkPipelineColorBlendAttachmentState blendAttachmentState = vks::initializers::pipelineColorBlendAttachmentState(0xf, VK_FALSE); - VkPipelineColorBlendStateCreateInfo colorBlendStateCI = vks::initializers::pipelineColorBlendStateCreateInfo(1, &blendAttachmentState); - VkPipelineDepthStencilStateCreateInfo depthStencilStateCI = vks::initializers::pipelineDepthStencilStateCreateInfo(VK_TRUE, VK_TRUE, VK_COMPARE_OP_LESS_OR_EQUAL); - VkPipelineViewportStateCreateInfo viewportStateCI = vks::initializers::pipelineViewportStateCreateInfo(1, 1, 0); - VkPipelineMultisampleStateCreateInfo multisampleStateCI = vks::initializers::pipelineMultisampleStateCreateInfo(VK_SAMPLE_COUNT_1_BIT, 0); - VkPipelineDynamicStateCreateInfo dynamicStateCI = vks::initializers::pipelineDynamicStateCreateInfo(dynamicStateEnables.data(), static_cast(dynamicStateEnables.size()),0); - - // Vertex bindings and attributes - const std::vector vertexInputBindings = { + // Vertex bindings an attributes + std::vector vertexInputBindings = { vks::initializers::vertexInputBindingDescription(0, vertexLayout.stride(), VK_VERTEX_INPUT_RATE_VERTEX), }; - const std::vector vertexInputAttributes = { - vks::initializers::vertexInputAttributeDescription(0, 0, VK_FORMAT_R32G32B32_SFLOAT, 0), // Location 0: Position - vks::initializers::vertexInputAttributeDescription(0, 1, VK_FORMAT_R32G32B32_SFLOAT, sizeof(float) * 3), // Location 1: Normal - vks::initializers::vertexInputAttributeDescription(0, 2, VK_FORMAT_R32G32_SFLOAT, sizeof(float) * 6), // Location 2: UV - vks::initializers::vertexInputAttributeDescription(0, 3, VK_FORMAT_R32G32B32_SFLOAT, sizeof(float) * 8), // Location 3: Color + std::vector vertexInputAttributes = { + vks::initializers::vertexInputAttributeDescription(0, 0, VK_FORMAT_R32G32B32_SFLOAT, 0), + vks::initializers::vertexInputAttributeDescription(0, 1, VK_FORMAT_R32G32B32_SFLOAT, sizeof(float) * 3), }; VkPipelineVertexInputStateCreateInfo vertexInputState = vks::initializers::pipelineVertexInputStateCreateInfo(); vertexInputState.vertexBindingDescriptionCount = static_cast(vertexInputBindings.size()); @@ -333,8 +311,18 @@ public: vertexInputState.vertexAttributeDescriptionCount = static_cast(vertexInputAttributes.size()); vertexInputState.pVertexAttributeDescriptions = vertexInputAttributes.data(); - VkGraphicsPipelineCreateInfo pipelineCreateInfoCI = vks::initializers::pipelineCreateInfo(pipelineLayout, renderPass, 0); - pipelineCreateInfoCI.pVertexInputState = &vertexInputState; + VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCI = vks::initializers::pipelineInputAssemblyStateCreateInfo(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 0, VK_FALSE); + VkPipelineRasterizationStateCreateInfo rasterizationStateCI = vks::initializers::pipelineRasterizationStateCreateInfo(VK_POLYGON_MODE_FILL, VK_CULL_MODE_FRONT_BIT, VK_FRONT_FACE_COUNTER_CLOCKWISE); + VkPipelineColorBlendAttachmentState blendAttachmentState = vks::initializers::pipelineColorBlendAttachmentState(0xf, VK_FALSE); + VkPipelineColorBlendStateCreateInfo colorBlendStateCI = vks::initializers::pipelineColorBlendStateCreateInfo(1, &blendAttachmentState); + VkPipelineDepthStencilStateCreateInfo depthStencilStateCI = vks::initializers::pipelineDepthStencilStateCreateInfo(VK_TRUE, VK_TRUE, VK_COMPARE_OP_LESS_OR_EQUAL); + VkPipelineViewportStateCreateInfo viewportStateCI = vks::initializers::pipelineViewportStateCreateInfo(1, 1); + VkPipelineMultisampleStateCreateInfo multisampleStateCI = vks::initializers::pipelineMultisampleStateCreateInfo(VK_SAMPLE_COUNT_1_BIT); + std::vector dynamicStateEnables = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR }; + VkPipelineDynamicStateCreateInfo dynamicStateCI = vks::initializers::pipelineDynamicStateCreateInfo(dynamicStateEnables); + std::array shaderStages; + + VkGraphicsPipelineCreateInfo pipelineCreateInfoCI = vks::initializers::pipelineCreateInfo(pipelineLayout, renderPass); pipelineCreateInfoCI.pInputAssemblyState = &inputAssemblyStateCI; pipelineCreateInfoCI.pRasterizationState = &rasterizationStateCI; pipelineCreateInfoCI.pColorBlendState = &colorBlendStateCI; @@ -342,54 +330,39 @@ public: pipelineCreateInfoCI.pViewportState = &viewportStateCI; pipelineCreateInfoCI.pDepthStencilState = &depthStencilStateCI; pipelineCreateInfoCI.pDynamicState = &dynamicStateCI; - - const std::array shaderStages = { - loadShader(getAssetPath() + "shaders/inlineuniformblocks/cube.vert.spv", VK_SHADER_STAGE_VERTEX_BIT), - loadShader(getAssetPath() + "shaders/inlineuniformblocks/cube.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT) - }; - pipelineCreateInfoCI.stageCount = static_cast(shaderStages.size()); pipelineCreateInfoCI.pStages = shaderStages.data(); + pipelineCreateInfoCI.pVertexInputState = &vertexInputState; + shaderStages[0] = loadShader(getAssetPath() + "shaders/inlineuniformblocks/pbr.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); + shaderStages[1] = loadShader(getAssetPath() + "shaders/inlineuniformblocks/pbr.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfoCI, nullptr, &pipeline)); } void prepareUniformBuffers() { - // Vertex shader matrix uniform buffer block - for (auto& cube : cubes) { - VK_CHECK_RESULT(vulkanDevice->createBuffer( - VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, - &cube.uniformBuffer, - sizeof(Cube::Matrices))); - VK_CHECK_RESULT(cube.uniformBuffer.map()); - } - + VK_CHECK_RESULT(vulkanDevice->createBuffer(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &uniformBuffers.scene, sizeof(uboMatrices))); + VK_CHECK_RESULT(uniformBuffers.scene.map()); updateUniformBuffers(); } void updateUniformBuffers() { - cubes[0].matrices.model = glm::translate(glm::mat4(1.0f), glm::vec3(-2.0f, 0.0f, 0.0f)); - cubes[1].matrices.model = glm::translate(glm::mat4(1.0f), glm::vec3( 1.5f, 0.5f, 0.0f)); - - for (auto& cube : cubes) { - cube.matrices.projection = camera.matrices.perspective; - cube.matrices.view = camera.matrices.view; - cube.matrices.model = glm::rotate(cube.matrices.model, glm::radians(cube.rotation.x), glm::vec3(1.0f, 0.0f, 0.0f)); - cube.matrices.model = glm::rotate(cube.matrices.model, glm::radians(cube.rotation.y), glm::vec3(0.0f, 1.0f, 0.0f)); - cube.matrices.model = glm::rotate(cube.matrices.model, glm::radians(cube.rotation.z), glm::vec3(0.0f, 0.0f, 1.0f)); - memcpy(cube.uniformBuffer.mapped, &cube.matrices, sizeof(cube.matrices)); - } + uboMatrices.projection = camera.matrices.perspective; + uboMatrices.view = camera.matrices.view; + uboMatrices.model = glm::mat4(1.0f); + uboMatrices.camPos = camera.position * -1.0f; + memcpy(uniformBuffers.scene.mapped, &uboMatrices, sizeof(uboMatrices)); } void draw() { VulkanExampleBase::prepareFrame(); + submitInfo.commandBufferCount = 1; submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer]; VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE)); + VulkanExampleBase::submitFrame(); } @@ -398,8 +371,9 @@ public: VulkanExampleBase::prepare(); loadAssets(); prepareUniformBuffers(); - setupDescriptors(); + setupDescriptorSetLayout(); preparePipelines(); + setupDescriptorSets(); buildCommandBuffers(); prepared = true; } @@ -409,24 +383,12 @@ public: if (!prepared) return; draw(); - if (animate) { - cubes[0].rotation.x += 2.5f * frameTimer; - if (cubes[0].rotation.x > 360.0f) - cubes[0].rotation.x -= 360.0f; - cubes[1].rotation.y += 2.0f * frameTimer; - if (cubes[1].rotation.x > 360.0f) - cubes[1].rotation.x -= 360.0f; - } - if ((camera.updated) || (animate)) { + if (camera.updated) updateUniformBuffers(); - } } virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay) { - if (overlay->header("Settings")) { - overlay->checkBox("Animate", &animate); - } } };