diff --git a/include/vkcv/Core.hpp b/include/vkcv/Core.hpp index 01e59191af54d0562a9b834d52f96050d0499136..8a165adf43561b1204490a12afa00d2a3fabdbf4 100644 --- a/include/vkcv/Core.hpp +++ b/include/vkcv/Core.hpp @@ -258,5 +258,6 @@ namespace vkcv void submitCommandStream(const CommandStreamHandle handle); void prepareSwapchainImageForPresent(const CommandStreamHandle handle); + void prepareImageForSampling(const CommandStreamHandle cmdStream, const ImageHandle image); }; } diff --git a/include/vkcv/PipelineConfig.hpp b/include/vkcv/PipelineConfig.hpp index f464997b8985c5750aac34d19f4cd71eb20bd403..7dc6f2200db7efc1abdddab81145daec27540c49 100644 --- a/include/vkcv/PipelineConfig.hpp +++ b/include/vkcv/PipelineConfig.hpp @@ -27,7 +27,7 @@ namespace vkcv { const ShaderProgram& shaderProgram, uint32_t width, uint32_t height, - PassHandle &passHandle, + const PassHandle &passHandle, const std::vector<VertexAttribute> &vertexAttributes, const std::vector<vk::DescriptorSetLayout> &descriptorLayouts, bool useDynamicViewport); diff --git a/include/vkcv/ShaderProgram.hpp b/include/vkcv/ShaderProgram.hpp index ef5d1f00ea3eeb97d97d8824439ded1ed326f33c..459125bbd3208ffb40815e1e3fd4c9615ce21724 100644 --- a/include/vkcv/ShaderProgram.hpp +++ b/include/vkcv/ShaderProgram.hpp @@ -58,10 +58,12 @@ namespace vkcv { void reflectShader(ShaderStage shaderStage); const VertexLayout &getVertexLayout() const; + size_t getPushConstantSize() const; private: std::unordered_map<ShaderStage, Shader> m_Shaders; VertexLayout m_VertexLayout; + size_t m_pushConstantSize = 0; }; } diff --git a/projects/cmd_sync_test/resources/shaders/compile.bat b/projects/cmd_sync_test/resources/shaders/compile.bat index b4521235c40fe5fb163bab874560c2f219b7517f..516c2f2f78001e1a5d182356e7c3fe82d66a45ee 100644 --- a/projects/cmd_sync_test/resources/shaders/compile.bat +++ b/projects/cmd_sync_test/resources/shaders/compile.bat @@ -1,3 +1,5 @@ %VULKAN_SDK%\Bin32\glslc.exe shader.vert -o vert.spv %VULKAN_SDK%\Bin32\glslc.exe shader.frag -o frag.spv +%VULKAN_SDK%\Bin32\glslc.exe shadow.vert -o shadow_vert.spv +%VULKAN_SDK%\Bin32\glslc.exe shadow.frag -o shadow_frag.spv pause \ No newline at end of file diff --git a/projects/cmd_sync_test/resources/shaders/frag.spv b/projects/cmd_sync_test/resources/shaders/frag.spv index 087e4e22fb2fcec27d99b3ff2aa1a705fe755796..ff3110571871d65ce119dc6c5006e7e67aa53546 100644 Binary files a/projects/cmd_sync_test/resources/shaders/frag.spv and b/projects/cmd_sync_test/resources/shaders/frag.spv differ diff --git a/projects/cmd_sync_test/resources/shaders/shader.frag b/projects/cmd_sync_test/resources/shaders/shader.frag index 71a1de69c57c0d7b7d4665095410e7acaf8dbd62..95f1b3319e1ca5c7c34ff94e5e7198819c0233c1 100644 --- a/projects/cmd_sync_test/resources/shaders/shader.frag +++ b/projects/cmd_sync_test/resources/shaders/shader.frag @@ -3,12 +3,42 @@ layout(location = 0) in vec3 passNormal; layout(location = 1) in vec2 passUV; +layout(location = 2) in vec3 passPos; layout(location = 0) out vec3 outColor; layout(set=0, binding=0) uniform texture2D meshTexture; layout(set=0, binding=1) uniform sampler textureSampler; +layout(set=0, binding=2) uniform sunBuffer { + vec3 L; float padding; + mat4 lightMatrix; +}; +layout(set=0, binding=3) uniform texture2D shadowMap; +layout(set=0, binding=4) uniform sampler shadowMapSampler; + +float shadowTest(vec3 worldPos){ + vec4 lightPos = lightMatrix * vec4(worldPos, 1); + lightPos /= lightPos.w; + lightPos.xy = lightPos.xy * 0.5 + 0.5; + + if(any(lessThan(lightPos.xy, vec2(0))) || any(greaterThan(lightPos.xy, vec2(1)))){ + return 1; + } + + lightPos.z = clamp(lightPos.z, 0, 1); + + float shadowMapSample = texture(sampler2D(shadowMap, shadowMapSampler), lightPos.xy).r; + float bias = 0.01f; + shadowMapSample += bias; + return shadowMapSample < lightPos.z ? 0 : 1; +} void main() { - outColor = texture(sampler2D(meshTexture, textureSampler), passUV).rgb; + vec3 N = normalize(passNormal); + vec3 sunColor = vec3(1); + vec3 sun = sunColor * clamp(dot(N, L), 0, 1); + sun *= shadowTest(passPos); + vec3 ambient = vec3(0.1); + vec3 albedo = texture(sampler2D(meshTexture, textureSampler), passUV).rgb; + outColor = albedo * (sun + ambient); } \ No newline at end of file diff --git a/projects/cmd_sync_test/resources/shaders/shader.vert b/projects/cmd_sync_test/resources/shaders/shader.vert index 76855152253b48b7400f016d063ed4f0e507435e..0ab82c203806356d0f35dc52c0a6988b286d90d1 100644 --- a/projects/cmd_sync_test/resources/shaders/shader.vert +++ b/projects/cmd_sync_test/resources/shaders/shader.vert @@ -7,13 +7,16 @@ layout(location = 2) in vec2 inUV; layout(location = 0) out vec3 passNormal; layout(location = 1) out vec2 passUV; +layout(location = 2) out vec3 passPos; layout( push_constant ) uniform constants{ mat4 mvp; + mat4 model; }; void main() { gl_Position = mvp * vec4(inPosition, 1.0); passNormal = inNormal; passUV = inUV; + passPos = (model * vec4(inPosition, 1)).xyz; } \ No newline at end of file diff --git a/projects/cmd_sync_test/resources/shaders/shadow.frag b/projects/cmd_sync_test/resources/shaders/shadow.frag new file mode 100644 index 0000000000000000000000000000000000000000..848f853f556660b4900b5db7fb6fc98d57c1cd5b --- /dev/null +++ b/projects/cmd_sync_test/resources/shaders/shadow.frag @@ -0,0 +1,6 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +void main() { + +} \ No newline at end of file diff --git a/projects/cmd_sync_test/resources/shaders/shadow.vert b/projects/cmd_sync_test/resources/shaders/shadow.vert new file mode 100644 index 0000000000000000000000000000000000000000..e0f41d42d575fa64fedbfa04adf89ac0f4aeebe8 --- /dev/null +++ b/projects/cmd_sync_test/resources/shaders/shadow.vert @@ -0,0 +1,12 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) in vec3 inPosition; + +layout( push_constant ) uniform constants{ + mat4 mvp; +}; + +void main() { + gl_Position = mvp * vec4(inPosition, 1.0); +} \ No newline at end of file diff --git a/projects/cmd_sync_test/resources/shaders/shadow_frag.spv b/projects/cmd_sync_test/resources/shaders/shadow_frag.spv new file mode 100644 index 0000000000000000000000000000000000000000..6be3bd2518a3b1f234e39aea2503ba86cfb3314b Binary files /dev/null and b/projects/cmd_sync_test/resources/shaders/shadow_frag.spv differ diff --git a/projects/cmd_sync_test/resources/shaders/shadow_vert.spv b/projects/cmd_sync_test/resources/shaders/shadow_vert.spv new file mode 100644 index 0000000000000000000000000000000000000000..afaa0824ee9be2c22209d611943c6512587dce24 Binary files /dev/null and b/projects/cmd_sync_test/resources/shaders/shadow_vert.spv differ diff --git a/projects/cmd_sync_test/resources/shaders/vert.spv b/projects/cmd_sync_test/resources/shaders/vert.spv index 374c023e14b351eb43cbcda5951cbb8b3d6f96a1..5e514eef5983927316465679af5461f507497130 100644 Binary files a/projects/cmd_sync_test/resources/shaders/vert.spv and b/projects/cmd_sync_test/resources/shaders/vert.spv differ diff --git a/projects/cmd_sync_test/src/main.cpp b/projects/cmd_sync_test/src/main.cpp index c3455be6dadb8f8c0ffd34e52080c80570b3ee58..d28adb371fd7e58487abae3f8d39ed5507481f92 100644 --- a/projects/cmd_sync_test/src/main.cpp +++ b/projects/cmd_sync_test/src/main.cpp @@ -20,6 +20,7 @@ int main(int argc, const char** argv) { vkcv::CameraManager cameraManager(window, windowWidth, windowHeight); cameraManager.getCamera().setPosition(glm::vec3(0.f, 0.f, 3.f)); + cameraManager.getCamera().setNearFar(0.1, 30); window.initEvents(); @@ -103,8 +104,11 @@ int main(int argc, const char** argv) { triangleShaderProgram.reflectShader(vkcv::ShaderStage::FRAGMENT); std::vector<vkcv::DescriptorBinding> descriptorBindings = { - vkcv::DescriptorBinding(vkcv::DescriptorType::IMAGE_SAMPLED, 1, vkcv::ShaderStage::FRAGMENT), - vkcv::DescriptorBinding(vkcv::DescriptorType::SAMPLER, 1, vkcv::ShaderStage::FRAGMENT)}; + vkcv::DescriptorBinding(vkcv::DescriptorType::IMAGE_SAMPLED, 1, vkcv::ShaderStage::FRAGMENT), + vkcv::DescriptorBinding(vkcv::DescriptorType::SAMPLER, 1, vkcv::ShaderStage::FRAGMENT), + vkcv::DescriptorBinding(vkcv::DescriptorType::UNIFORM_BUFFER, 1, vkcv::ShaderStage::FRAGMENT), + vkcv::DescriptorBinding(vkcv::DescriptorType::IMAGE_SAMPLED, 1, vkcv::ShaderStage::FRAGMENT) , + vkcv::DescriptorBinding(vkcv::DescriptorType::SAMPLER, 1, vkcv::ShaderStage::FRAGMENT) }; vkcv::DescriptorSetHandle descriptorSet = core.createDescriptorSet(descriptorBindings); const vkcv::PipelineConfig trianglePipelineDefinition( @@ -132,10 +136,12 @@ int main(int argc, const char** argv) { vkcv::SamplerAddressMode::REPEAT ); - vkcv::DescriptorWrites setWrites; - setWrites.sampledImageWrites = { vkcv::SampledImageDescriptorWrite(0, texture.getHandle()) }; - setWrites.samplerWrites = { vkcv::SamplerDescriptorWrite(1, sampler) }; - core.writeResourceDescription(descriptorSet, 0, setWrites); + vkcv::SamplerHandle shadowSampler = core.createSampler( + vkcv::SamplerFilterType::NEAREST, + vkcv::SamplerFilterType::NEAREST, + vkcv::SamplerMipmapMode::NEAREST, + vkcv::SamplerAddressMode::CLAMP_TO_EDGE + ); vkcv::ImageHandle depthBuffer = core.createImage(vk::Format::eD32Sfloat, windowWidth, windowHeight).getHandle(); @@ -147,19 +153,69 @@ int main(int argc, const char** argv) { glm::vec3( 0.f, -2.f, 0.f), glm::vec3( 3.f, 0.f, 0.f), glm::vec3(-3.f, 0.f, 0.f), - glm::vec3( 0.f, 2.f, 0.f) + glm::vec3( 0.f, 2.f, 0.f), + glm::vec3( 0.f, -5.f, 0.f) }; std::vector<glm::mat4> modelMatrices; std::vector<vkcv::DrawcallInfo> drawcalls; + std::vector<vkcv::DrawcallInfo> shadowDrawcalls; for (const auto& position : instancePositions) { modelMatrices.push_back(glm::translate(glm::mat4(1.f), position)); drawcalls.push_back(vkcv::DrawcallInfo(loadedMesh, { descriptorUsage })); + shadowDrawcalls.push_back(vkcv::DrawcallInfo(loadedMesh, {})); } - std::vector<glm::mat4> mvpMatrices; + modelMatrices.back() *= glm::scale(glm::mat4(1.f), glm::vec3(10.f, 1.f, 10.f)); + + std::vector<std::array<glm::mat4, 2>> mainPassMatrices; + std::vector<glm::mat4> mvpLight; + + vkcv::ShaderProgram shadowShader; + shadowShader.addShader(vkcv::ShaderStage::VERTEX, "resources/shaders/shadow_vert.spv"); + shadowShader.addShader(vkcv::ShaderStage::FRAGMENT, "resources/shaders/shadow_frag.spv"); + shadowShader.reflectShader(vkcv::ShaderStage::VERTEX); + shadowShader.reflectShader(vkcv::ShaderStage::FRAGMENT); + + const vk::Format shadowMapFormat = vk::Format::eD16Unorm; + const std::vector<vkcv::AttachmentDescription> shadowAttachments = { + vkcv::AttachmentDescription(vkcv::AttachmentOperation::STORE, vkcv::AttachmentOperation::CLEAR, shadowMapFormat) + }; + const vkcv::PassConfig shadowPassConfig(shadowAttachments); + const vkcv::PassHandle shadowPass = core.createPass(shadowPassConfig); + + const uint32_t shadowMapResolution = 1024; + const vkcv::Image shadowMap = core.createImage(shadowMapFormat, shadowMapResolution, shadowMapResolution, 1); + const vkcv::PipelineConfig shadowPipeConfig( + shadowShader, + shadowMapResolution, + shadowMapResolution, + shadowPass, + attributes, + {}, + false); + const vkcv::PipelineHandle shadowPipe = core.createGraphicsPipeline(shadowPipeConfig); + + struct LightInfo { + glm::vec3 direction; + float padding; + glm::mat4 lightMatrix; + }; + LightInfo lightInfo; + vkcv::Buffer lightBuffer = core.createBuffer<LightInfo>(vkcv::BufferType::UNIFORM, sizeof(glm::vec3)); + + vkcv::DescriptorWrites setWrites; + setWrites.sampledImageWrites = { + vkcv::SampledImageDescriptorWrite(0, texture.getHandle()), + vkcv::SampledImageDescriptorWrite(3, shadowMap.getHandle()) }; + setWrites.samplerWrites = { + vkcv::SamplerDescriptorWrite(1, sampler), + vkcv::SamplerDescriptorWrite(4, shadowSampler) }; + setWrites.uniformBufferWrites = { vkcv::UniformBufferDescriptorWrite(2, lightBuffer.getHandle()) }; + core.writeResourceDescription(descriptorSet, 0, setWrites); auto start = std::chrono::system_clock::now(); + const auto appStartTime = start; while (window.isWindowOpen()) { vkcv::Window::pollEvents(); @@ -180,16 +236,54 @@ int main(int argc, const char** argv) { start = end; cameraManager.getCamera().updateView(std::chrono::duration<double>(deltatime).count()); - const glm::mat4 viewProjection = cameraManager.getCamera().getProjection() * cameraManager.getCamera().getView(); - mvpMatrices.clear(); + const float sunTheta = (end - appStartTime).count() * 0.0000001; + lightInfo.direction = glm::normalize(glm::vec3(cos(sunTheta), 1, sin(sunTheta))); + + const float shadowProjectionSize = 5.f; + glm::mat4 projectionLight = glm::ortho( + -shadowProjectionSize, + shadowProjectionSize, + -shadowProjectionSize, + shadowProjectionSize, + -shadowProjectionSize, + shadowProjectionSize); + + glm::mat4 vulkanCorrectionMatrix(1.f); + vulkanCorrectionMatrix[2][2] = 0.5; + vulkanCorrectionMatrix[3][2] = 0.5; + projectionLight = vulkanCorrectionMatrix * projectionLight; + + const glm::mat4 viewLight = glm::lookAt(glm::vec3(0), -lightInfo.direction, glm::vec3(0, -1, 0)); + + lightInfo.lightMatrix = projectionLight * viewLight; + lightBuffer.fill({ lightInfo }); + + const glm::mat4 viewProjectionCamera = cameraManager.getCamera().getProjection() * cameraManager.getCamera().getView(); + + mainPassMatrices.clear(); + mvpLight.clear(); for (const auto& m : modelMatrices) { - mvpMatrices.push_back(viewProjection * m); + mainPassMatrices.push_back({ viewProjectionCamera * m, m }); + mvpLight.push_back(lightInfo.lightMatrix* m); } - vkcv::PushConstantData pushConstantData((void*)mvpMatrices.data(), sizeof(glm::mat4)); - const std::vector<vkcv::ImageHandle> renderTargets = { swapchainInput, depthBuffer }; + + vkcv::PushConstantData pushConstantData((void*)mainPassMatrices.data(), 2 * sizeof(glm::mat4)); + const std::vector<vkcv::ImageHandle> renderTargets = { swapchainInput, depthBuffer }; + + vkcv::PushConstantData shadowPushConstantData((void*)mvpLight.data(), sizeof(glm::mat4)); auto cmdStream = core.createCommandStream(vkcv::QueueType::Graphics); + core.recordDrawcallsToCmdStream( + cmdStream, + shadowPass, + shadowPipe, + shadowPushConstantData, + shadowDrawcalls, + { shadowMap.getHandle() }); + + core.prepareImageForSampling(cmdStream, shadowMap.getHandle()); + core.recordDrawcallsToCmdStream( cmdStream, trianglePass, diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp index 908cb617052e67f9ffb62775845ff8e861300d66..9ed83d2a224119bd20fcfc81c5720b425de06bb6 100644 --- a/src/vkcv/Core.cpp +++ b/src/vkcv/Core.cpp @@ -375,7 +375,9 @@ namespace vkcv const FinishCommandFunction &finish) { m_CommandStreamManager->recordCommandsToStream(cmdStreamHandle, record); - m_CommandStreamManager->addFinishCallbackToStream(cmdStreamHandle, finish); + if (finish) { + m_CommandStreamManager->addFinishCallbackToStream(cmdStreamHandle, finish); + } } void Core::submitCommandStream(const CommandStreamHandle handle) { @@ -457,4 +459,10 @@ namespace vkcv recordSwapchainImageLayoutTransition(cmdBuffer, vk::ImageLayout::ePresentSrcKHR); }); } + + void Core::prepareImageForSampling(const CommandStreamHandle cmdStream, const ImageHandle image) { + recordCommandsToStream(cmdStream, [image, this](const vk::CommandBuffer cmdBuffer) { + m_ImageManager->recordImageLayoutTransition(image, vk::ImageLayout::eShaderReadOnlyOptimal, cmdBuffer); + }, nullptr); + } } diff --git a/src/vkcv/PipelineConfig.cpp b/src/vkcv/PipelineConfig.cpp index 14259245272140d0e5b180c3c1f8c2614881a402..ad8437ca2a6c07862f66485c74c89ccba0d69ebe 100644 --- a/src/vkcv/PipelineConfig.cpp +++ b/src/vkcv/PipelineConfig.cpp @@ -9,13 +9,13 @@ namespace vkcv { PipelineConfig::PipelineConfig( - const ShaderProgram& shaderProgram, - uint32_t width, - uint32_t height, - PassHandle &passHandle, - const std::vector<VertexAttribute> &vertexAttributes, - const std::vector<vk::DescriptorSetLayout> &descriptorLayouts, - bool useDynamicViewport) + const ShaderProgram& shaderProgram, + uint32_t width, + uint32_t height, + const PassHandle &passHandle, + const std::vector<VertexAttribute> &vertexAttributes, + const std::vector<vk::DescriptorSetLayout> &descriptorLayouts, + bool useDynamicViewport) : m_ShaderProgram(shaderProgram), m_Height(height), diff --git a/src/vkcv/PipelineManager.cpp b/src/vkcv/PipelineManager.cpp index 9afa2bc90dc5bdbaf88deee9de8b4ff71d436641..28a64a243b9a7a8fc9372409ef3783901219c868 100644 --- a/src/vkcv/PipelineManager.cpp +++ b/src/vkcv/PipelineManager.cpp @@ -174,7 +174,7 @@ namespace vkcv { 1.f,1.f,1.f,1.f } ); - const size_t matrixPushConstantSize = 4 * 4 * sizeof(float); + const size_t matrixPushConstantSize = config.m_ShaderProgram.getPushConstantSize(); const vk::PushConstantRange pushConstantRange(vk::ShaderStageFlagBits::eAll, 0, matrixPushConstantSize); // pipeline layout diff --git a/src/vkcv/ShaderProgram.cpp b/src/vkcv/ShaderProgram.cpp index 5185b8b402eae5cd514689ba51a06e1a437271bf..3eea7ed21d99af2768d48e62af47cbdef94c7ef1 100644 --- a/src/vkcv/ShaderProgram.cpp +++ b/src/vkcv/ShaderProgram.cpp @@ -5,6 +5,7 @@ */ #include "vkcv/ShaderProgram.hpp" +#include <algorithm> namespace vkcv { /** @@ -128,9 +129,19 @@ namespace vkcv { m_VertexLayout = VertexLayout(inputVec); } + for (const auto &pushConstantBuffer : resources.push_constant_buffers) { + for (const auto &range : comp.get_active_buffer_ranges(pushConstantBuffer.id)) { + const size_t size = range.range + range.offset; + m_pushConstantSize = std::max(m_pushConstantSize, size); + } + } } const VertexLayout& ShaderProgram::getVertexLayout() const{ return m_VertexLayout; } + + size_t ShaderProgram::getPushConstantSize() const { + return m_pushConstantSize; + } }