Reworked inline uniform block example

This commit is contained in:
saschawillems 2018-10-07 10:27:28 +02:00
parent f1a7e66de1
commit 367fce5b46
9 changed files with 349 additions and 302 deletions

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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);
}

Binary file not shown.

View file

@ -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);
}

Binary file not shown.

View file

@ -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 * Note: Requires a device that supports the VK_EXT_inline_uniform_block extension
* *
@ -20,81 +20,93 @@
#define GLM_FORCE_DEPTH_ZERO_TO_ONE #define GLM_FORCE_DEPTH_ZERO_TO_ONE
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <gli/gli.hpp>
#include <vulkan/vulkan.h> #include <vulkan/vulkan.h>
#include "vulkanexamplebase.h" #include "vulkanexamplebase.h"
#include "VulkanTexture.hpp" #include "VulkanBuffer.hpp"
#include "VulkanModel.hpp" #include "VulkanModel.hpp"
#define ENABLE_VALIDATION false #define ENABLE_VALIDATION false
#define OBJ_DIM 0.025f
float rnd() {
return ((float)rand() / (RAND_MAX));
}
class VulkanExample : public VulkanExampleBase class VulkanExample : public VulkanExampleBase
{ {
public: public:
bool animate = true;
vks::VertexLayout vertexLayout = vks::VertexLayout({ vks::VertexLayout vertexLayout = vks::VertexLayout({
vks::VERTEX_COMPONENT_POSITION, vks::VERTEX_COMPONENT_POSITION,
vks::VERTEX_COMPONENT_NORMAL, vks::VERTEX_COMPONENT_NORMAL,
vks::VERTEX_COMPONENT_UV, vks::VERTEX_COMPONENT_UV,
vks::VERTEX_COMPONENT_COLOR, });
});
/* vks::Model model;
[POI] This is the data structure that'll be passed using inline uniform blocks
*/
struct InlineBlockData {
glm::vec4 color;
};
struct Cube { struct Object {
struct Matrices { struct Material {
glm::mat4 projection; float roughness;
glm::mat4 view; float metallic;
glm::mat4 model; float r, g, b;
} matrices; float ambient;
InlineBlockData inlineBlockData; } material;
VkDescriptorSet descriptorSet; VkDescriptorSet descriptorSet;
vks::Texture2D texture;
vks::Buffer uniformBuffer;
glm::vec3 rotation;
}; };
std::array<Cube, 2> cubes; std::array<Object, 16> 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; VkPipelineLayout pipelineLayout;
VkPipeline pipeline;
VkDescriptorSet descriptorSet;
VkDescriptorSetLayout descriptorSetLayout; struct DescriptorSetLaysts {
VkDescriptorSetLayout scene;
VkDescriptorSetLayout object;
} descriptorSetLayouts;
VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION) VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION)
{ {
title = "Inline uniform blocks"; 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; settings.overlay = true;
camera.type = Camera::CameraType::lookat;
camera.setPerspective(60.0f, (float)width / (float)height, 0.1f, 512.0f); srand((unsigned int)time(0));
camera.setRotation(glm::vec3(0.0f, 0.0f, 0.0f));
camera.setTranslation(glm::vec3(0.0f, 0.0f, -5.0f));
/* /*
[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); enabledDeviceExtensions.push_back(VK_EXT_INLINE_UNIFORM_BLOCK_EXTENSION_NAME);
} }
~VulkanExample() ~VulkanExample()
{ {
vkDestroyPipeline(device, pipeline, nullptr); vkDestroyPipeline(device, pipeline, nullptr);
vkDestroyPipelineLayout(device, pipelineLayout, nullptr); vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr); vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.scene, nullptr);
models.cube.destroy(); vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.object, nullptr);
for (auto cube : cubes) {
cube.uniformBuffer.destroy(); model.destroy();
cube.texture.destroy();
} uniformBuffers.scene.destroy();
} }
void buildCommandBuffers() void buildCommandBuffers()
@ -102,7 +114,7 @@ public:
VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo(); VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo();
VkClearValue clearValues[2]; VkClearValue clearValues[2];
clearValues[0].color = defaultClearColor; clearValues[0].color = { { 0.0f, 0.0f, 0.0f, 1.0f } };
clearValues[1].depthStencil = { 1.0f, 0 }; clearValues[1].depthStencil = { 1.0f, 0 };
VkRenderPassBeginInfo renderPassBeginInfo = vks::initializers::renderPassBeginInfo(); VkRenderPassBeginInfo renderPassBeginInfo = vks::initializers::renderPassBeginInfo();
@ -114,15 +126,14 @@ public:
renderPassBeginInfo.clearValueCount = 2; renderPassBeginInfo.clearValueCount = 2;
renderPassBeginInfo.pClearValues = clearValues; 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]; renderPassBeginInfo.framebuffer = frameBuffers[i];
VK_CHECK_RESULT(vkBeginCommandBuffer(drawCmdBuffers[i], &cmdBufInfo)); VK_CHECK_RESULT(vkBeginCommandBuffer(drawCmdBuffers[i], &cmdBufInfo));
vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); 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); VkViewport viewport = vks::initializers::viewport((float)width, (float)height, 0.0f, 1.0f);
vkCmdSetViewport(drawCmdBuffers[i], 0, 1, &viewport); vkCmdSetViewport(drawCmdBuffers[i], 0, 1, &viewport);
@ -130,14 +141,30 @@ public:
vkCmdSetScissor(drawCmdBuffers[i], 0, 1, &scissor); vkCmdSetScissor(drawCmdBuffers[i], 0, 1, &scissor);
VkDeviceSize offsets[1] = { 0 }; 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) { // Render objects
vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &cube.descriptorSet, 0, nullptr); vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
vkCmdDrawIndexed(drawCmdBuffers[i], models.cube.indexCount, 1, 0, 0, 0); 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<uint32_t>(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<VkDescriptorSet> 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]); drawUI(drawCmdBuffers[i]);
vkCmdEndRenderPass(drawCmdBuffers[i]); vkCmdEndRenderPass(drawCmdBuffers[i]);
@ -148,184 +175,135 @@ public:
void loadAssets() void loadAssets()
{ {
models.cube.loadFromFile(getAssetPath() + "models/cube.dae", vertexLayout, 1.0f, vulkanDevice, queue); model.loadFromFile(getAssetPath() + "models/geosphere.obj", vertexLayout, OBJ_DIM, 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); // Setup random materials for every object in the scene
cubes[0].inlineBlockData.color = glm::vec4(1.0f, 0.0f, 0.0f, 1.0f); for (uint32_t i = 0; i < objects.size(); i++) {
cubes[1].inlineBlockData.color = glm::vec4(0.0f, 0.0f, 1.0f, 1.0f); 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);
}
} }
/* void setupDescriptorSetLayout()
[POI] Set up descriptor sets and set layout
*/
void setupDescriptors()
{ {
const uint32_t cubeCount = static_cast<uint32_t>(cubes.size()); // Scene
{
std::vector<VkDescriptorSetLayoutBinding> 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<VkDescriptorSetLayoutBinding> 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<VkDescriptorSetLayout> setLayouts = {
descriptorSetLayouts.scene, // Set 0 = Scene matrices
descriptorSetLayouts.object // Set 1 = Object inline uniform block
};
VkPipelineLayoutCreateInfo pipelineLayoutCI = vks::initializers::pipelineLayoutCreateInfo(setLayouts.data(), static_cast<uint32_t>(setLayouts.size()));
std::array<VkDescriptorPoolSize, 3> descriptorPoolSizes{}; std::vector<VkPushConstantRange> 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 VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCI, nullptr, &pipelineLayout));
descriptorPoolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; }
descriptorPoolSizes[0].descriptorCount = cubeCount;
void setupDescriptorSets()
{
// Pool
std::vector<VkDescriptorPoolSize> poolSizes = {
vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, (static_cast<uint32_t>(objects.size()) + 1)),
/* [POI] TODO */
// TODO: split scene and object
vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT, (static_cast<uint32_t>(objects.size()) + 1) * sizeof(Object::Material)),
};
VkDescriptorPoolCreateInfo descriptorPoolCI = vks::initializers::descriptorPoolCreateInfo(poolSizes, static_cast<uint32_t>(objects.size()) + 1);
/* /*
[POI] One inline uniform block descriptor per cube [POI] New structure that has to be chained into the descriptor pool's createinfo if you want to allocate inline uniform blocks
*/
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<uint32_t>(cubes.size());
// Create the global descriptor pool
VkDescriptorPoolCreateInfo descriptorPoolCI = {};
descriptorPoolCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
descriptorPoolCI.poolSizeCount = static_cast<uint32_t>(descriptorPoolSizes.size());
descriptorPoolCI.pPoolSizes = descriptorPoolSizes.data();
descriptorPoolCI.maxSets = static_cast<uint32_t>(descriptorPoolSizes.size());
#
/*
[POI] New structure that has to be chained into the descriptor pool create info if you want to allocate inline uniform blocks
*/ */
VkDescriptorPoolInlineUniformBlockCreateInfoEXT descriptorPoolInlineUniformBlockCreateInfo{}; VkDescriptorPoolInlineUniformBlockCreateInfoEXT descriptorPoolInlineUniformBlockCreateInfo{};
descriptorPoolInlineUniformBlockCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_INLINE_UNIFORM_BLOCK_CREATE_INFO_EXT; descriptorPoolInlineUniformBlockCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_INLINE_UNIFORM_BLOCK_CREATE_INFO_EXT;
descriptorPoolInlineUniformBlockCreateInfo.maxInlineUniformBlockBindings = 1; descriptorPoolInlineUniformBlockCreateInfo.maxInlineUniformBlockBindings = 1;
// Chain into descriptor pool create info
descriptorPoolCI.pNext = &descriptorPoolInlineUniformBlockCreateInfo; descriptorPoolCI.pNext = &descriptorPoolInlineUniformBlockCreateInfo;
VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolCI, nullptr, &descriptorPool)); VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolCI, nullptr, &descriptorPool));
/* // Sets
Descriptor set layout
*/
std::array<VkDescriptorSetLayoutBinding,3> 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) std::vector<VkWriteDescriptorSet> writeDescriptorSets = {
setLayoutBindings[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, &uniformBuffers.scene.descriptor),
setLayoutBindings[0].binding = 0; };
setLayoutBindings[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; vkUpdateDescriptorSets(device, static_cast<uint32_t>(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, nullptr);
setLayoutBindings[0].descriptorCount = 1;
/* // Objects
[POI] Binding 1: Inline uniform block for (auto &object : objects) {
*/ VkDescriptorSetAllocateInfo descriptorAllocateInfo = vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayouts.object, 1);
setLayoutBindings[1].descriptorType = VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT; VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &descriptorAllocateInfo, &object.descriptorSet));
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<uint32_t>(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<VkWriteDescriptorSet, 3> 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);
/* /*
[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{}; VkWriteDescriptorSetInlineUniformBlockEXT writeDescriptorSetInlineUniformBlock{};
writeDescriptorSetInlineUniformBlock.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK_EXT; writeDescriptorSetInlineUniformBlock.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK_EXT;
writeDescriptorSetInlineUniformBlock.dataSize = sizeof(InlineBlockData); writeDescriptorSetInlineUniformBlock.dataSize = sizeof(Object::Material);
writeDescriptorSetInlineUniformBlock.pData = &cube.inlineBlockData; // Uniform data for the inline block
// Needs to be chained to an existing write descriptor set structure writeDescriptorSetInlineUniformBlock.pData = &object.material;
writeDescriptorSets[1].pNext = &writeDescriptorSetInlineUniformBlock;
// Binding 2: Object texture /*
writeDescriptorSets[2].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; [POI] Setup the inline uniform block
writeDescriptorSets[2].dstSet = cube.descriptorSet; */
writeDescriptorSets[2].dstBinding = 2; VkWriteDescriptorSet writeDescriptorSet{};
writeDescriptorSets[2].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; writeDescriptorSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
writeDescriptorSets[2].pImageInfo = &cube.texture.descriptor; writeDescriptorSet.descriptorType = VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT;
writeDescriptorSets[2].descriptorCount = 1; 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<uint32_t>(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, nullptr); vkUpdateDescriptorSets(device, 1, &writeDescriptorSet, 0, nullptr);
} }
} }
void preparePipelines() void preparePipelines()
{ {
VkPipelineLayoutCreateInfo pipelineLayoutCI{}; // Vertex bindings an attributes
pipelineLayoutCI.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; std::vector<VkVertexInputBindingDescription> vertexInputBindings = {
pipelineLayoutCI.setLayoutCount = 1;
pipelineLayoutCI.pSetLayouts = &descriptorSetLayout;
VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCI, nullptr, &pipelineLayout));
const std::vector<VkDynamicState> 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<uint32_t>(dynamicStateEnables.size()),0);
// Vertex bindings and attributes
const std::vector<VkVertexInputBindingDescription> vertexInputBindings = {
vks::initializers::vertexInputBindingDescription(0, vertexLayout.stride(), VK_VERTEX_INPUT_RATE_VERTEX), vks::initializers::vertexInputBindingDescription(0, vertexLayout.stride(), VK_VERTEX_INPUT_RATE_VERTEX),
}; };
const std::vector<VkVertexInputAttributeDescription> vertexInputAttributes = { std::vector<VkVertexInputAttributeDescription> vertexInputAttributes = {
vks::initializers::vertexInputAttributeDescription(0, 0, VK_FORMAT_R32G32B32_SFLOAT, 0), // Location 0: Position vks::initializers::vertexInputAttributeDescription(0, 0, VK_FORMAT_R32G32B32_SFLOAT, 0),
vks::initializers::vertexInputAttributeDescription(0, 1, VK_FORMAT_R32G32B32_SFLOAT, sizeof(float) * 3), // Location 1: Normal vks::initializers::vertexInputAttributeDescription(0, 1, VK_FORMAT_R32G32B32_SFLOAT, sizeof(float) * 3),
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
}; };
VkPipelineVertexInputStateCreateInfo vertexInputState = vks::initializers::pipelineVertexInputStateCreateInfo(); VkPipelineVertexInputStateCreateInfo vertexInputState = vks::initializers::pipelineVertexInputStateCreateInfo();
vertexInputState.vertexBindingDescriptionCount = static_cast<uint32_t>(vertexInputBindings.size()); vertexInputState.vertexBindingDescriptionCount = static_cast<uint32_t>(vertexInputBindings.size());
@ -333,8 +311,18 @@ public:
vertexInputState.vertexAttributeDescriptionCount = static_cast<uint32_t>(vertexInputAttributes.size()); vertexInputState.vertexAttributeDescriptionCount = static_cast<uint32_t>(vertexInputAttributes.size());
vertexInputState.pVertexAttributeDescriptions = vertexInputAttributes.data(); vertexInputState.pVertexAttributeDescriptions = vertexInputAttributes.data();
VkGraphicsPipelineCreateInfo pipelineCreateInfoCI = vks::initializers::pipelineCreateInfo(pipelineLayout, renderPass, 0); VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCI = vks::initializers::pipelineInputAssemblyStateCreateInfo(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 0, VK_FALSE);
pipelineCreateInfoCI.pVertexInputState = &vertexInputState; 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<VkDynamicState> dynamicStateEnables = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };
VkPipelineDynamicStateCreateInfo dynamicStateCI = vks::initializers::pipelineDynamicStateCreateInfo(dynamicStateEnables);
std::array<VkPipelineShaderStageCreateInfo, 2> shaderStages;
VkGraphicsPipelineCreateInfo pipelineCreateInfoCI = vks::initializers::pipelineCreateInfo(pipelineLayout, renderPass);
pipelineCreateInfoCI.pInputAssemblyState = &inputAssemblyStateCI; pipelineCreateInfoCI.pInputAssemblyState = &inputAssemblyStateCI;
pipelineCreateInfoCI.pRasterizationState = &rasterizationStateCI; pipelineCreateInfoCI.pRasterizationState = &rasterizationStateCI;
pipelineCreateInfoCI.pColorBlendState = &colorBlendStateCI; pipelineCreateInfoCI.pColorBlendState = &colorBlendStateCI;
@ -342,54 +330,39 @@ public:
pipelineCreateInfoCI.pViewportState = &viewportStateCI; pipelineCreateInfoCI.pViewportState = &viewportStateCI;
pipelineCreateInfoCI.pDepthStencilState = &depthStencilStateCI; pipelineCreateInfoCI.pDepthStencilState = &depthStencilStateCI;
pipelineCreateInfoCI.pDynamicState = &dynamicStateCI; pipelineCreateInfoCI.pDynamicState = &dynamicStateCI;
const std::array<VkPipelineShaderStageCreateInfo, 2> 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<uint32_t>(shaderStages.size()); pipelineCreateInfoCI.stageCount = static_cast<uint32_t>(shaderStages.size());
pipelineCreateInfoCI.pStages = shaderStages.data(); 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)); VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfoCI, nullptr, &pipeline));
} }
void prepareUniformBuffers() void prepareUniformBuffers()
{ {
// Vertex shader matrix uniform buffer block 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)));
for (auto& cube : cubes) { VK_CHECK_RESULT(uniformBuffers.scene.map());
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());
}
updateUniformBuffers(); updateUniformBuffers();
} }
void updateUniformBuffers() void updateUniformBuffers()
{ {
cubes[0].matrices.model = glm::translate(glm::mat4(1.0f), glm::vec3(-2.0f, 0.0f, 0.0f)); uboMatrices.projection = camera.matrices.perspective;
cubes[1].matrices.model = glm::translate(glm::mat4(1.0f), glm::vec3( 1.5f, 0.5f, 0.0f)); uboMatrices.view = camera.matrices.view;
uboMatrices.model = glm::mat4(1.0f);
for (auto& cube : cubes) { uboMatrices.camPos = camera.position * -1.0f;
cube.matrices.projection = camera.matrices.perspective; memcpy(uniformBuffers.scene.mapped, &uboMatrices, sizeof(uboMatrices));
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));
}
} }
void draw() void draw()
{ {
VulkanExampleBase::prepareFrame(); VulkanExampleBase::prepareFrame();
submitInfo.commandBufferCount = 1; submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer]; submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer];
VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE)); VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE));
VulkanExampleBase::submitFrame(); VulkanExampleBase::submitFrame();
} }
@ -398,8 +371,9 @@ public:
VulkanExampleBase::prepare(); VulkanExampleBase::prepare();
loadAssets(); loadAssets();
prepareUniformBuffers(); prepareUniformBuffers();
setupDescriptors(); setupDescriptorSetLayout();
preparePipelines(); preparePipelines();
setupDescriptorSets();
buildCommandBuffers(); buildCommandBuffers();
prepared = true; prepared = true;
} }
@ -409,24 +383,12 @@ public:
if (!prepared) if (!prepared)
return; return;
draw(); draw();
if (animate) { if (camera.updated)
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)) {
updateUniformBuffers(); updateUniformBuffers();
}
} }
virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay) virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay)
{ {
if (overlay->header("Settings")) {
overlay->checkBox("Animate", &animate);
}
} }
}; };