diff --git a/include/light.h b/include/light.h new file mode 100644 index 0000000..65c1459 --- /dev/null +++ b/include/light.h @@ -0,0 +1,9 @@ +#pragma once + +#include + +class Light { +public: + glm::vec3 position; + glm::vec3 color = glm::vec3(1); +}; diff --git a/include/world.h b/include/world.h index 6c3c802..15af9ea 100644 --- a/include/world.h +++ b/include/world.h @@ -3,8 +3,10 @@ #include class Mesh; +class Light; class World { public: std::vector meshes; + std::vector lights; }; diff --git a/include/worldpass.h b/include/worldpass.h index 25d14c9..075f319 100644 --- a/include/worldpass.h +++ b/include/worldpass.h @@ -19,12 +19,22 @@ public: private: void createRenderPass(); + void createDescriptorSetLayout(); void createPipeline(); - + void createUniformBuffer(); + void createDescriptorSet(); + VkRenderPass renderPass_ = nullptr; - + + VkDescriptorSetLayout setLayout_ = nullptr; + VkPipelineLayout pipelineLayout_ = nullptr; VkPipeline pipeline_ = nullptr; + + VkDeviceMemory lightMemory_ = nullptr; + VkBuffer lightBuffer_ = nullptr; + + VkDescriptorSet descriptorSet_ = nullptr; Renderer& renderer_; }; diff --git a/shaders/triangle.frag b/shaders/triangle.frag index f43ff2b..d5709bf 100644 --- a/shaders/triangle.frag +++ b/shaders/triangle.frag @@ -5,10 +5,24 @@ layout(location = 1) in vec3 inNormal; layout(location = 0) out vec4 outColor; +struct Light { + vec4 position; + vec3 color; +}; + +layout(binding = 0) uniform Lights { + Light lights[32]; +}; + void main() { - const vec3 norm = normalize(inNormal); - const vec3 lightDir = normalize(vec3(5) - inFragPos); + vec3 diffuse = vec3(0); + for(int i = 0; i < 32; i++) { + const vec3 norm = normalize(inNormal); + const vec3 lightDir = normalize(lights[i].position.xyz - inFragPos); + + const float diff = max(dot(norm, lightDir), 0.0); + diffuse += vec3(diff) * lights[i].color; + } - const float diff = max(dot(norm, lightDir), 0.0); - outColor = vec4(vec3(0.1) + vec3(diff), 1.0); + outColor = vec4(vec3(0.1) + diffuse, 1.0); } diff --git a/src/main.cpp b/src/main.cpp index 8610d83..ea82130 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -12,6 +12,7 @@ #include "platform.h" #include "world.h" #include "mesh.h" +#include "light.h" SDL_Window* window = nullptr; @@ -138,6 +139,11 @@ int main(int, char*[]) { World world; world.meshes.push_back(mesh); + + Light* light = new Light(); + light->position.y = 5; + + world.lights.push_back(light); bool running = true; while(running) { diff --git a/src/renderer.cpp b/src/renderer.cpp index b69500c..44772bd 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "platform.h" #include "mesh.h" @@ -51,7 +52,7 @@ void Renderer::render(World& world, RenderTarget* target) { vkWaitForFences(device_, 1, &target->fences[target->currentImage], true, UINT64_MAX); vkResetFences(device_, 1, &target->fences[target->currentImage]); - + const VkCommandBuffer commandBuffer = target->commandBuffers[target->currentImage]; VkCommandBufferBeginInfo beginInfo = {}; @@ -599,15 +600,16 @@ void Renderer::createPresentationRenderPass() { } void Renderer::createDescriptorPool() { - VkDescriptorPoolSize poolSize = {}; - poolSize.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - poolSize.descriptorCount = 15; + const std::array poolSizes = { + VkDescriptorPoolSize{VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 15}, + VkDescriptorPoolSize{VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 15} + }; VkDescriptorPoolCreateInfo poolInfo = {}; poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; poolInfo.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; - poolInfo.poolSizeCount = 1; - poolInfo.pPoolSizes = &poolSize; + poolInfo.poolSizeCount = poolSizes.size(); + poolInfo.pPoolSizes = poolSizes.data(); poolInfo.maxSets = 15; vkCreateDescriptorPool(device_, &poolInfo, nullptr, &descriptorPool_); diff --git a/src/worldpass.cpp b/src/worldpass.cpp index 920e019..c056a3f 100644 --- a/src/worldpass.cpp +++ b/src/worldpass.cpp @@ -6,10 +6,14 @@ #include "renderer.h" #include "world.h" #include "mesh.h" +#include "light.h" WorldPass::WorldPass(Renderer& renderer) : renderer_(renderer) { createRenderPass(); + createDescriptorSetLayout(); createPipeline(); + createUniformBuffer(); + createDescriptorSet(); } WorldPass::~WorldPass() { @@ -20,6 +24,23 @@ WorldPass::~WorldPass() { } void WorldPass::render(VkCommandBuffer commandBuffer, World& world, RenderTarget* target) { + struct ShaderLight { + glm::vec4 position; + glm::vec3 color; + }; + + ShaderLight* data; + vkMapMemory(renderer_.getDevice(), lightMemory_, 0, sizeof(float) * (4 + 3) * 32, 0, (void**)&data); + + for(size_t i = 0; i < world.lights.size(); i++) { + data->position = glm::vec4(world.lights[i]->position, 0.0); + data->color = world.lights[i]->color; + + data++; + } + + vkUnmapMemory(renderer_.getDevice(), lightMemory_); + VkClearValue clearColor = {}; VkRenderPassBeginInfo renderPassBeginInfo = {}; @@ -33,7 +54,8 @@ void WorldPass::render(VkCommandBuffer commandBuffer, World& world, RenderTarget vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_); - + vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout_, 0, 1, &descriptorSet_, 0, nullptr); + for(const auto& mesh : world.meshes) { glm::mat4 mvp; mvp = glm::perspective(glm::radians(75.0f), (float)target->extent.width / target->extent.height, 0.1f, 100.0f); @@ -80,6 +102,20 @@ void WorldPass::createRenderPass() { vkCreateRenderPass(renderer_.getDevice(), &renderPassInfo, nullptr, &renderPass_); } +void WorldPass::createDescriptorSetLayout() { + VkDescriptorSetLayoutBinding lightBufferBinding = {}; + lightBufferBinding.descriptorCount = 1; + lightBufferBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + lightBufferBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + + VkDescriptorSetLayoutCreateInfo createInfo = {}; + createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + createInfo.bindingCount = 1; + createInfo.pBindings = &lightBufferBinding; + + vkCreateDescriptorSetLayout(renderer_.getDevice(), &createInfo, nullptr, &setLayout_); +} + void WorldPass::createPipeline() { VkShaderModule vertShaderModule = renderer_.createShader("triangle.vert.spv"); VkShaderModule fragShaderModule = renderer_.createShader("triangle.frag.spv"); @@ -166,6 +202,8 @@ void WorldPass::createPipeline() { VkPipelineLayoutCreateInfo pipelineLayoutInfo = {}; pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipelineLayoutInfo.setLayoutCount = 1; + pipelineLayoutInfo.pSetLayouts = &setLayout_; pipelineLayoutInfo.pushConstantRangeCount = 1; pipelineLayoutInfo.pPushConstantRanges = &mvpPushConstant; @@ -190,3 +228,55 @@ void WorldPass::createPipeline() { vkDestroyShaderModule(renderer_.getDevice(), fragShaderModule, nullptr); vkDestroyShaderModule(renderer_.getDevice(), vertShaderModule, nullptr); } + +void WorldPass::createUniformBuffer() { + VkBufferCreateInfo bufferInfo = {}; + bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + bufferInfo.size = sizeof(float) * (4 + 3) * 32; + bufferInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; + bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + vkCreateBuffer(renderer_.getDevice(), &bufferInfo, nullptr, &lightBuffer_); + + VkMemoryRequirements memRequirements; + vkGetBufferMemoryRequirements(renderer_.getDevice(), lightBuffer_, &memRequirements); + + VkMemoryAllocateInfo allocInfo = {}; + allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + allocInfo.allocationSize = memRequirements.size; + allocInfo.memoryTypeIndex = renderer_.findMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + + vkAllocateMemory(renderer_.getDevice(), &allocInfo, nullptr, &lightMemory_); + vkBindBufferMemory(renderer_.getDevice(), lightBuffer_, lightMemory_, 0); +} + +void WorldPass::createDescriptorSet() { + VkDescriptorSetAllocateInfo allocInfo = {}; + allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + allocInfo.descriptorPool = renderer_.getDescriptorPool(); + allocInfo.descriptorSetCount = 1; + allocInfo.pSetLayouts = &setLayout_; + + vkAllocateDescriptorSets(renderer_.getDevice(), &allocInfo, &descriptorSet_); + + VkDescriptorBufferInfo bufferInfo = {}; + bufferInfo.buffer = lightBuffer_; + bufferInfo.range = sizeof(float) * (4 + 3) * 32; + + VkWriteDescriptorSet descriptorWrite = {}; + descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descriptorWrite.descriptorCount = 1; + descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + descriptorWrite.dstSet = descriptorSet_; + descriptorWrite.pBufferInfo = &bufferInfo; + + vkUpdateDescriptorSets(renderer_.getDevice(), 1, &descriptorWrite, 0, nullptr); + + float* data; + vkMapMemory(renderer_.getDevice(), lightMemory_, 0, sizeof(float) * (4 + 3) * 32, 0, (void**)&data); + + for(uint32_t i = 0; i < (4 + 3) * 32; i++) + data[i] = 0.0f; + + vkUnmapMemory(renderer_.getDevice(), lightMemory_); +}