diff --git a/include/vkcv/Core.hpp b/include/vkcv/Core.hpp index 4a51b24f5c978daebc5116e20b527252c8063d61..48e94aad2d0e11cd77090da824130f0d2ea286ba 100644 --- a/include/vkcv/Core.hpp +++ b/include/vkcv/Core.hpp @@ -279,5 +279,6 @@ namespace vkcv void submitCommandStream(const CommandStreamHandle handle); void prepareSwapchainImageForPresent(const CommandStreamHandle handle); void prepareImageForSampling(const CommandStreamHandle cmdStream, const ImageHandle image); + void prepareImageForStorage(const CommandStreamHandle cmdStream, const ImageHandle image); }; } diff --git a/include/vkcv/DescriptorWrites.hpp b/include/vkcv/DescriptorWrites.hpp index d67e8e3233e184b207d109e652adeca43407d7e0..c9d046566a664ffea419dad2b293e206d0b2cdc5 100644 --- a/include/vkcv/DescriptorWrites.hpp +++ b/include/vkcv/DescriptorWrites.hpp @@ -36,8 +36,8 @@ namespace vkcv { struct DescriptorWrites { std::vector<SampledImageDescriptorWrite> sampledImageWrites; std::vector<StorageImageDescriptorWrite> storageImageWrites; - std::vector<UniformBufferDescriptorWrite> uniformBufferWrites; - std::vector<StorageBufferDescriptorWrite> storageBufferWrites; - std::vector<SamplerDescriptorWrite> samplerWrites; + std::vector<UniformBufferDescriptorWrite> uniformBufferWrites; + std::vector<StorageBufferDescriptorWrite> storageBufferWrites; + std::vector<SamplerDescriptorWrite> samplerWrites; }; } \ No newline at end of file diff --git a/projects/CMakeLists.txt b/projects/CMakeLists.txt index ccbdaf4101c5dabb3e9d43788e255eab85ad5776..472597e0f4a90de09692f93c62944f7b60c9b753 100644 --- a/projects/CMakeLists.txt +++ b/projects/CMakeLists.txt @@ -1,5 +1,6 @@ # Add new projects/examples here: +add_subdirectory(bloom) add_subdirectory(first_triangle) add_subdirectory(first_mesh) add_subdirectory(cmd_sync_test) \ No newline at end of file diff --git a/projects/bloom/.gitignore b/projects/bloom/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..3643183e0628e666abab193e1dd1d92c1774ac61 --- /dev/null +++ b/projects/bloom/.gitignore @@ -0,0 +1 @@ +bloom \ No newline at end of file diff --git a/projects/bloom/CMakeLists.txt b/projects/bloom/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..bcd8827f98b479d7444eaa9f0628e8de569f7a8d --- /dev/null +++ b/projects/bloom/CMakeLists.txt @@ -0,0 +1,28 @@ +cmake_minimum_required(VERSION 3.16) +project(bloom) + +# setting c++ standard for the project +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# this should fix the execution path to load local files from the project +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + +# adding source files to the project +add_executable(bloom src/main.cpp) + +# this should fix the execution path to load local files from the project (for MSVC) +if(MSVC) + set_target_properties(bloom PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) + set_target_properties(bloom PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) + + # in addition to setting the output directory, the working directory has to be set + # by default visual studio sets the working directory to the build directory, when using the debugger + set_target_properties(bloom PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) +endif() + +# including headers of dependencies and the VkCV framework +target_include_directories(bloom SYSTEM BEFORE PRIVATE ${vkcv_include} ${vkcv_includes} ${vkcv_asset_loader_include} ${vkcv_camera_include}) + +# linking with libraries from all dependencies and the VkCV framework +target_link_libraries(bloom vkcv ${vkcv_libraries} vkcv_asset_loader ${vkcv_asset_loader_libraries} vkcv_camera) diff --git a/projects/bloom/resources/cube/boards2_vcyc_jpg.jpg b/projects/bloom/resources/cube/boards2_vcyc_jpg.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2636039e272289c0fba3fa2d88a060b857501248 --- /dev/null +++ b/projects/bloom/resources/cube/boards2_vcyc_jpg.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cca33a6e58ddd1b37a6e6853a9aa0e7b15ca678937119194752393dd2a0a0564 +size 1192476 diff --git a/projects/bloom/resources/cube/cube.bin b/projects/bloom/resources/cube/cube.bin new file mode 100644 index 0000000000000000000000000000000000000000..3303cd8635848bee18e10ab8754d5e4e7218db92 --- /dev/null +++ b/projects/bloom/resources/cube/cube.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9bb9b6b8bbe50a0aaa517057f245ee844f80afa7426dacb2aed4128f71629ce4 +size 840 diff --git a/projects/bloom/resources/cube/cube.blend b/projects/bloom/resources/cube/cube.blend new file mode 100644 index 0000000000000000000000000000000000000000..62ccb2c742094bcfb5ed194ab905bffae86bfd65 --- /dev/null +++ b/projects/bloom/resources/cube/cube.blend @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a6c1e245f259c610528c9485db6688928faac0ab2addee9e3c2dde7740e4dd09 +size 774920 diff --git a/projects/bloom/resources/cube/cube.blend1 b/projects/bloom/resources/cube/cube.blend1 new file mode 100644 index 0000000000000000000000000000000000000000..13f21dcca218d7bc7a07a8a9682b5e1d9e607736 --- /dev/null +++ b/projects/bloom/resources/cube/cube.blend1 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f4496f423569b8ca81f3b3a55fad00f925557e0193fb9dbe6cdce7e71fb48f7b +size 774920 diff --git a/projects/bloom/resources/cube/cube.glb b/projects/bloom/resources/cube/cube.glb new file mode 100644 index 0000000000000000000000000000000000000000..66a42c65e71dcf375e04cc378256024dd3c7834d --- /dev/null +++ b/projects/bloom/resources/cube/cube.glb @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:198568b715f397d78f7c358c0f709a419e7fd677e54cdec7c19f71b5ed264897 +size 1194508 diff --git a/projects/bloom/resources/cube/cube.gltf b/projects/bloom/resources/cube/cube.gltf new file mode 100644 index 0000000000000000000000000000000000000000..428176144843dd06c78fe1d11a6392a0ea02b22d --- /dev/null +++ b/projects/bloom/resources/cube/cube.gltf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f82f455647a84ca6242882ae26a79a499d3ce594f8de317ab89488c5b79721ac +size 2823 diff --git a/projects/bloom/resources/shaders/blur.comp b/projects/bloom/resources/shaders/blur.comp new file mode 100644 index 0000000000000000000000000000000000000000..d7fcfb3c21f2f545c90f65d3a22e66362ab6dab9 --- /dev/null +++ b/projects/bloom/resources/shaders/blur.comp @@ -0,0 +1,17 @@ +# version 450 +layout(local_size_x = 8, local_size_y = 8) in; + +layout(set=0, binding=0) uniform texture2D offscreenAttachment; +layout(set=0, binding=1) uniform sampler offscreenSampler; +layout(r11f_g11f_b10f, set=0, binding=2) uniform writeonly image2D blurAttachment; + +void main() +{ + ivec2 pixel_coords = ivec2(gl_GlobalInvocationID.xy); + vec2 uv = vec2(pixel_coords) / imageSize(blurAttachment); + + // TODO: BLUR + + + imageStore(blurAttachment, pixel_coords, vec4(1.0, 0.0 ,0.0, 0.0)); +} \ No newline at end of file diff --git a/projects/bloom/resources/shaders/blur_comp.spv b/projects/bloom/resources/shaders/blur_comp.spv new file mode 100644 index 0000000000000000000000000000000000000000..565eab96c0b2c554556077dee67d21ed92f42764 Binary files /dev/null and b/projects/bloom/resources/shaders/blur_comp.spv differ diff --git a/projects/bloom/resources/shaders/compile.bat b/projects/bloom/resources/shaders/compile.bat new file mode 100644 index 0000000000000000000000000000000000000000..5fecf915079df6cf230254ef2c1755c953d826b1 --- /dev/null +++ b/projects/bloom/resources/shaders/compile.bat @@ -0,0 +1,11 @@ +%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 + +%VULKAN_SDK%\Bin32\glslc.exe quad.vert -o quad_vert.spv +%VULKAN_SDK%\Bin32\glslc.exe quad.frag -o quad_frag.spv + +%VULKAN_SDK%\Bin32\glslc.exe blur.comp -o blur_comp.spv +pause \ No newline at end of file diff --git a/projects/bloom/resources/shaders/frag.spv b/projects/bloom/resources/shaders/frag.spv new file mode 100644 index 0000000000000000000000000000000000000000..ba47f91cdfcd1ecd824614f23d424b0a510ac1c7 Binary files /dev/null and b/projects/bloom/resources/shaders/frag.spv differ diff --git a/projects/bloom/resources/shaders/quad.frag b/projects/bloom/resources/shaders/quad.frag new file mode 100644 index 0000000000000000000000000000000000000000..14bacc9508c783b9d336c1ebc720cdafd5e044b7 --- /dev/null +++ b/projects/bloom/resources/shaders/quad.frag @@ -0,0 +1,15 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) in vec2 inUV; + +layout(location = 0) out vec3 outColor; + +layout(set=0, binding=0) uniform texture2D renderAttachment; +layout(set=0, binding=1) uniform texture2D blurAttachment; +layout(set=0, binding=2) uniform sampler samp; + +void main() +{ + outColor = texture(sampler2D(renderAttachment, samp), inUV).rgb; +} \ No newline at end of file diff --git a/projects/bloom/resources/shaders/quad.vert b/projects/bloom/resources/shaders/quad.vert new file mode 100644 index 0000000000000000000000000000000000000000..a5d520084e8afd1110f6b4535754a0988dfc7cee --- /dev/null +++ b/projects/bloom/resources/shaders/quad.vert @@ -0,0 +1,12 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) in vec3 inPosition; + +layout(location = 0) out vec2 outUV; + +void main() +{ + outUV = inPosition.xy; + gl_Position = vec4(inPosition, 1.0); +} \ No newline at end of file diff --git a/projects/bloom/resources/shaders/quad_frag.spv b/projects/bloom/resources/shaders/quad_frag.spv new file mode 100644 index 0000000000000000000000000000000000000000..86f9763845401abb1f01879b58b234ffb5904efc Binary files /dev/null and b/projects/bloom/resources/shaders/quad_frag.spv differ diff --git a/projects/bloom/resources/shaders/quad_vert.spv b/projects/bloom/resources/shaders/quad_vert.spv new file mode 100644 index 0000000000000000000000000000000000000000..c9c7a116497ce2098b9854b538d07fd99a77e383 Binary files /dev/null and b/projects/bloom/resources/shaders/quad_vert.spv differ diff --git a/projects/bloom/resources/shaders/shader.frag b/projects/bloom/resources/shaders/shader.frag new file mode 100644 index 0000000000000000000000000000000000000000..1c97a68808af11765fa6bf8a535218a8a2b14a77 --- /dev/null +++ b/projects/bloom/resources/shaders/shader.frag @@ -0,0 +1,46 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +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() { + /* + 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 = passNormal; +} \ No newline at end of file diff --git a/projects/bloom/resources/shaders/shader.vert b/projects/bloom/resources/shaders/shader.vert new file mode 100644 index 0000000000000000000000000000000000000000..0ab82c203806356d0f35dc52c0a6988b286d90d1 --- /dev/null +++ b/projects/bloom/resources/shaders/shader.vert @@ -0,0 +1,22 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) in vec3 inPosition; +layout(location = 1) in vec3 inNormal; +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/bloom/resources/shaders/shadow.frag b/projects/bloom/resources/shaders/shadow.frag new file mode 100644 index 0000000000000000000000000000000000000000..848f853f556660b4900b5db7fb6fc98d57c1cd5b --- /dev/null +++ b/projects/bloom/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/bloom/resources/shaders/shadow.vert b/projects/bloom/resources/shaders/shadow.vert new file mode 100644 index 0000000000000000000000000000000000000000..e0f41d42d575fa64fedbfa04adf89ac0f4aeebe8 --- /dev/null +++ b/projects/bloom/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/bloom/resources/shaders/shadow_frag.spv b/projects/bloom/resources/shaders/shadow_frag.spv new file mode 100644 index 0000000000000000000000000000000000000000..6be3bd2518a3b1f234e39aea2503ba86cfb3314b Binary files /dev/null and b/projects/bloom/resources/shaders/shadow_frag.spv differ diff --git a/projects/bloom/resources/shaders/shadow_vert.spv b/projects/bloom/resources/shaders/shadow_vert.spv new file mode 100644 index 0000000000000000000000000000000000000000..afaa0824ee9be2c22209d611943c6512587dce24 Binary files /dev/null and b/projects/bloom/resources/shaders/shadow_vert.spv differ diff --git a/projects/bloom/resources/shaders/vert.spv b/projects/bloom/resources/shaders/vert.spv new file mode 100644 index 0000000000000000000000000000000000000000..5e514eef5983927316465679af5461f507497130 Binary files /dev/null and b/projects/bloom/resources/shaders/vert.spv differ diff --git a/projects/bloom/src/main.cpp b/projects/bloom/src/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e33f603bb92fc58a5ebff6fb042a8ab6a9a7d59f --- /dev/null +++ b/projects/bloom/src/main.cpp @@ -0,0 +1,428 @@ +#include <iostream> +#include <vkcv/Core.hpp> +#include <GLFW/glfw3.h> +#include <vkcv/camera/CameraManager.hpp> +#include <chrono> +#include <vkcv/asset/asset_loader.hpp> + +int main(int argc, const char** argv) { + const char* applicationName = "First Mesh"; + + uint32_t windowWidth = 800; + uint32_t windowHeight = 600; + + vkcv::Window window = vkcv::Window::create( + applicationName, + windowWidth, + windowHeight, + true + ); + + 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(); + + vkcv::Core core = vkcv::Core::create( + window, + applicationName, + VK_MAKE_VERSION(0, 0, 1), + { vk::QueueFlagBits::eTransfer,vk::QueueFlagBits::eGraphics, vk::QueueFlagBits::eCompute }, + {}, + { "VK_KHR_swapchain" } + ); + + + // ATTACHMENTS + const vkcv::AttachmentDescription offscreenAttachment( + vkcv::AttachmentOperation::STORE, + vkcv::AttachmentOperation::CLEAR, + vk::Format::eB10G11R11UfloatPack32 + ); + + const vkcv::AttachmentDescription shadowAttachment( + vkcv::AttachmentOperation::STORE, + vkcv::AttachmentOperation::CLEAR, + vk::Format::eD16Unorm + ); + + const vkcv::AttachmentDescription depthAttachment( + vkcv::AttachmentOperation::STORE, + vkcv::AttachmentOperation::CLEAR, + vk::Format::eD32Sfloat + ); + + const vkcv::AttachmentDescription presentAttachment( + vkcv::AttachmentOperation::STORE, + vkcv::AttachmentOperation::CLEAR, + core.getSwapchainImageFormat() + ); + + // RENDER PASSES + const vkcv::PassConfig shadowPassConfig({shadowAttachment}); + const vkcv::PassHandle shadowPassHandle = core.createPass(shadowPassConfig); + + const vkcv::PassConfig meshPassDefinition({ offscreenAttachment, depthAttachment }); + const vkcv::PassHandle meshPassHandle = core.createPass(meshPassDefinition); + + const vkcv::PassConfig screenQuadPassConfig({presentAttachment}); + const vkcv::PassHandle screenQuadPassHandle = core.createPass(screenQuadPassConfig); + + if (!shadowPassHandle || !meshPassHandle || !screenQuadPassHandle) + { + std::cout << "Error. Could not create render passes. Exiting." << std::endl; + return EXIT_FAILURE; + } + + + // SHADERS + vkcv::ShaderProgram shadowProgram; + shadowProgram.addShader(vkcv::ShaderStage::VERTEX, "resources/shaders/shadow_vert.spv"); + shadowProgram.addShader(vkcv::ShaderStage::FRAGMENT, "resources/shaders/shadow_frag.spv"); + + vkcv::ShaderProgram meshProgram{}; + meshProgram.addShader(vkcv::ShaderStage::VERTEX, std::filesystem::path("resources/shaders/vert.spv")); + meshProgram.addShader(vkcv::ShaderStage::FRAGMENT, std::filesystem::path("resources/shaders/frag.spv")); + + vkcv::ShaderProgram bloomComputeProgram{}; + bloomComputeProgram.addShader(vkcv::ShaderStage::COMPUTE, std::filesystem::path("resources/shaders/blur_comp.spv")); + + vkcv::ShaderProgram screenQuadProgram{}; + screenQuadProgram.addShader(vkcv::ShaderStage::VERTEX, "resources/shaders/quad_vert.spv"); + screenQuadProgram.addShader(vkcv::ShaderStage::FRAGMENT, "resources/shaders/quad_frag.spv"); + + + vkcv::asset::Mesh mesh; + + const char* path = argc > 1 ? argv[1] : "resources/cube/cube.gltf"; + int result = vkcv::asset::loadMesh(path, mesh); + + if (result == 1) { + std::cout << "Mesh loading successful!" << std::endl; + } + else { + std::cout << "Mesh loading failed: " << result << std::endl; + return 1; + } + assert(mesh.vertexGroups.size() > 0); + + auto& attributes = mesh.vertexGroups[0].vertexBuffer.attributes; + + std::sort(attributes.begin(), attributes.end(), [](const vkcv::asset::VertexAttribute& x, const vkcv::asset::VertexAttribute& y) { + return static_cast<uint32_t>(x.type) < static_cast<uint32_t>(y.type); + }); + + // MESH INDEX/VERTEX BUFFER + auto meshVertexBuffer = core.createBuffer<uint8_t>( + vkcv::BufferType::VERTEX, + mesh.vertexGroups[0].vertexBuffer.data.size(), + vkcv::BufferMemoryType::DEVICE_LOCAL + ); + meshVertexBuffer.fill(mesh.vertexGroups[0].vertexBuffer.data); + + auto meshIndexBuffer = core.createBuffer<uint8_t>( + vkcv::BufferType::INDEX, + mesh.vertexGroups[0].indexBuffer.data.size(), + vkcv::BufferMemoryType::DEVICE_LOCAL + ); + meshIndexBuffer.fill(mesh.vertexGroups[0].indexBuffer.data); + + // MESH VERTEX LAYOUT + const std::vector<vkcv::VertexBufferBinding> meshVertexBufferBindings = { + vkcv::VertexBufferBinding(attributes[0].offset, meshVertexBuffer.getVulkanHandle()), + vkcv::VertexBufferBinding(attributes[1].offset, meshVertexBuffer.getVulkanHandle()), + vkcv::VertexBufferBinding(attributes[2].offset, meshVertexBuffer.getVulkanHandle()) }; + + const std::vector<vkcv::VertexAttachment> meshVertexAttachments = meshProgram.getVertexAttachments(); + std::vector<vkcv::VertexBinding> meshBindings; + for (size_t i = 0; i < meshVertexAttachments.size(); i++) { + meshBindings.push_back(vkcv::VertexBinding(i, { meshVertexAttachments[i] })); + } + const vkcv::VertexLayout meshVertexLayout(meshBindings); + + const vkcv::Mesh loadedMesh(meshVertexBufferBindings, meshIndexBuffer.getVulkanHandle(), mesh.vertexGroups[0].numIndices); + + // QUAD INDEX/VERTEX BUFFER + const std::vector<float> quadFloats = {-1.0f, 1.0f, 0.0f, // Left Bottom + 1.0f, 1.0f, 0.0f, // Right Bottom + -1.0f, -1.0f, 0.0f, // Left Top + 1.0f, -1.0f, 0.0f}; // Right Top + + const std::vector<uint8_t> quadIndices = {0, 1, 2, + 2, 1, 3}; + + auto quadVertexBuffer = core.createBuffer<float>( + vkcv::BufferType::VERTEX, + quadFloats.size(), + vkcv::BufferMemoryType::DEVICE_LOCAL); + quadVertexBuffer.fill(quadFloats); + + auto quadIndexBuffer = core.createBuffer<uint8_t>( + vkcv::BufferType::INDEX, + quadIndices.size(), + vkcv::BufferMemoryType::DEVICE_LOCAL); + quadIndexBuffer.fill(quadIndices); + + // SCREEN QUAD VERTEX LAYOUT + const std::vector<vkcv::VertexBufferBinding> quadVertexBufferBindings = { + vkcv::VertexBufferBinding(0, quadVertexBuffer.getVulkanHandle()) + }; + const vkcv::VertexBinding quadBinding(0, screenQuadProgram.getVertexAttachments()); + const vkcv::VertexLayout quadLayout({quadBinding}); + + const vkcv::Mesh loadedQuad(quadVertexBufferBindings, quadIndexBuffer.getVulkanHandle(), quadIndices.size()); + + // RESOURCES + vkcv::Image meshTexture = core.createImage(vk::Format::eR8G8B8A8Srgb, mesh.texture_hack.w, mesh.texture_hack.h); + meshTexture.fill(mesh.texture_hack.img); + const vkcv::ImageHandle meshTextureHandle = meshTexture.getHandle(); + + vkcv::ImageHandle depthBufferHandle = core.createImage(vk::Format::eD32Sfloat, windowWidth, windowHeight).getHandle(); + + vkcv::Image offscreenImage = core.createImage(vk::Format::eB10G11R11UfloatPack32, windowWidth, windowHeight, 1); + vkcv::ImageHandle bloomImageHandle = core.createImage(vk::Format::eB10G11R11UfloatPack32, windowWidth, windowHeight, 1).getHandle(); + + const vkcv::ImageHandle swapchainHandle = vkcv::ImageHandle::createSwapchainImageHandle(); + + + const vkcv::ImageHandle shadowMapHandle = core.createImage(vk::Format::eD16Unorm, 1024, 1024, 1).getHandle(); + + const vkcv::SamplerHandle linearSampler = core.createSampler( + vkcv::SamplerFilterType::LINEAR, + vkcv::SamplerFilterType::LINEAR, + vkcv::SamplerMipmapMode::LINEAR, + vkcv::SamplerAddressMode::REPEAT + ); + + const vkcv::SamplerHandle shadowSampler = core.createSampler( + vkcv::SamplerFilterType::NEAREST, + vkcv::SamplerFilterType::NEAREST, + vkcv::SamplerMipmapMode::NEAREST, + vkcv::SamplerAddressMode::CLAMP_TO_EDGE + ); + + + struct LightInfo { + glm::vec3 direction; + float padding; + glm::mat4 lightMatrix; + }; + LightInfo lightInfo{}; + vkcv::Buffer lightBuffer = core.createBuffer<LightInfo>(vkcv::BufferType::UNIFORM, sizeof(glm::vec3)); + + // PIPELINES & DESCRIPTOR STUFF + const std::vector<vkcv::DescriptorBinding> meshDescriptorBindings = { meshProgram.getReflectedDescriptors()[0] }; + const vkcv::DescriptorSetHandle meshDescriptorSet = core.createDescriptorSet(meshDescriptorBindings); + const vkcv::DescriptorSetUsage meshDescriptorUsage(0, core.getDescriptorSet(meshDescriptorSet).vulkanHandle); + + vkcv::DescriptorWrites meshDescriptorWrites; + meshDescriptorWrites.sampledImageWrites = { + vkcv::SampledImageDescriptorWrite(0, meshTextureHandle), + vkcv::SampledImageDescriptorWrite(3, shadowMapHandle) }; + meshDescriptorWrites.samplerWrites = { + vkcv::SamplerDescriptorWrite(1, linearSampler), + vkcv::SamplerDescriptorWrite(4, shadowSampler) }; + meshDescriptorWrites.uniformBufferWrites = { vkcv::UniformBufferDescriptorWrite(2, lightBuffer.getHandle()) }; + core.writeDescriptorSet(meshDescriptorSet, meshDescriptorWrites); + + const vkcv::PipelineConfig meshPipelineConfig( + meshProgram, + windowWidth, + windowHeight, + meshPassHandle, + {meshVertexLayout}, + { core.getDescriptorSet(meshDescriptorSet).layout }, + true); + vkcv::PipelineHandle meshPipelineHandle = core.createGraphicsPipeline(meshPipelineConfig); + + // -- + + const vkcv::PipelineConfig shadowPipeConfig( + shadowProgram, + 1024, + 1024, + shadowPassHandle, + {meshVertexLayout}, + {}, + false); + const vkcv::PipelineHandle shadowPipelineHandle = core.createGraphicsPipeline(shadowPipeConfig); + + // -- + + const std::vector<vkcv::DescriptorBinding> bloomSetBindings = bloomComputeProgram.getReflectedDescriptors()[0]; + const vkcv::DescriptorSetHandle bloomSetHandle = core.createDescriptorSet(bloomSetBindings); + const vkcv::DescriptorSetUsage bloomSetUsage(0, core.getDescriptorSet(bloomSetHandle).vulkanHandle); + + vkcv::DescriptorWrites bloomSetWrites; + bloomSetWrites.sampledImageWrites = {vkcv::SampledImageDescriptorWrite(0, offscreenImage.getHandle())}; + bloomSetWrites.samplerWrites = {vkcv::SamplerDescriptorWrite(1, linearSampler)}; + bloomSetWrites.storageImageWrites = {vkcv::StorageImageDescriptorWrite(2, bloomImageHandle)}; + core.writeDescriptorSet(bloomSetHandle, bloomSetWrites); + vkcv::PipelineHandle bloomComputePipelineHandle = core.createComputePipeline(bloomComputeProgram, {core.getDescriptorSet(bloomSetHandle).layout}); + + // -- + const std::vector<vkcv::DescriptorBinding> screenQuadBindings = { screenQuadProgram.getReflectedDescriptors()[0] }; + const vkcv::DescriptorSetHandle screenQuadSet = core.createDescriptorSet(screenQuadBindings); + const vkcv::DescriptorSetUsage screenQuadDescriptorUsage(0, core.getDescriptorSet(screenQuadSet).vulkanHandle); + + vkcv::DescriptorWrites screenQuadSetDescriptorWrites; + screenQuadSetDescriptorWrites.sampledImageWrites = { + vkcv::SampledImageDescriptorWrite(0, offscreenImage.getHandle()), + vkcv::SampledImageDescriptorWrite(1, bloomImageHandle) }; + screenQuadSetDescriptorWrites.samplerWrites = { + vkcv::SamplerDescriptorWrite(2, linearSampler) }; + core.writeDescriptorSet(screenQuadSet, screenQuadSetDescriptorWrites); + + const vkcv::PipelineConfig screenQuadConfig( + screenQuadProgram, + windowWidth, + windowHeight, + screenQuadPassHandle, + {quadLayout}, + { core.getDescriptorSet(meshDescriptorSet).layout }, + true); + vkcv::PipelineHandle screenQuadPipelineHandle = core.createGraphicsPipeline(screenQuadConfig); + + if (!meshPipelineHandle || !shadowPipelineHandle || !bloomComputePipelineHandle) { + std::cout << "Error. Could not create graphics pipeline. Exiting." << std::endl; + return EXIT_FAILURE; + } + + // DRAWCALLS AND MVP STUFF + + const std::vector<glm::vec3> cubeTranslations = { + 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, -5.f, 0.f) + }; + + std::vector<glm::mat4> modelMatrices; + std::vector<vkcv::DrawcallInfo> meshDrawcalls; + std::vector<vkcv::DrawcallInfo> shadowDrawcalls; + for (const auto& translationVec : cubeTranslations) { + modelMatrices.push_back(glm::translate(glm::mat4(1.f), translationVec)); + meshDrawcalls.push_back(vkcv::DrawcallInfo(loadedMesh, { meshDescriptorUsage })); + shadowDrawcalls.push_back(vkcv::DrawcallInfo(loadedMesh, {})); + } + + vkcv::DrawcallInfo quadDrawcall(loadedQuad, {screenQuadDescriptorUsage}); + + 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; + + + auto start = std::chrono::system_clock::now(); + const auto appStartTime = start; + while (window.isWindowOpen()) { + vkcv::Window::pollEvents(); + + uint32_t swapchainWidth, swapchainHeight; + if (!core.beginFrame(swapchainWidth, swapchainHeight)) { + continue; + } + if ((swapchainWidth != windowWidth) || ((swapchainHeight != windowHeight))) { + depthBufferHandle = core.createImage(vk::Format::eD32Sfloat, swapchainWidth, swapchainHeight).getHandle(); + + windowWidth = swapchainWidth; + windowHeight = swapchainHeight; + } + + auto end = std::chrono::system_clock::now(); + auto deltatime = std::chrono::duration_cast<std::chrono::microseconds>(end - start); + start = end; + cameraManager.getCamera().updateView(deltatime.count() * 0.000001); + + const float sunTheta = std::chrono::duration_cast<std::chrono::milliseconds>(end - appStartTime).count() * 0.001f; + lightInfo.direction = glm::normalize(glm::vec3(std::cos(sunTheta), 1, std::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) { + mainPassMatrices.push_back({ viewProjectionCamera * m, m }); + mvpLight.push_back(lightInfo.lightMatrix* m); + } + + vkcv::PushConstantData pushConstantData((void*)mainPassMatrices.data(), 2 * sizeof(glm::mat4)); + + vkcv::PushConstantData shadowPushConstantData((void*)mvpLight.data(), sizeof(glm::mat4)); + + auto cmdStream = core.createCommandStream(vkcv::QueueType::Graphics); + + // shadow map pass + core.recordDrawcallsToCmdStream( + cmdStream, + shadowPassHandle, + shadowPipelineHandle, + shadowPushConstantData, + shadowDrawcalls, + { shadowMapHandle }); + + core.prepareImageForSampling(cmdStream, shadowMapHandle); + + // offscreen render pass + core.recordDrawcallsToCmdStream( + cmdStream, + meshPassHandle, + meshPipelineHandle, + pushConstantData, + meshDrawcalls, + {offscreenImage.getHandle(), depthBufferHandle}); + + + core.prepareImageForSampling(cmdStream, offscreenImage.getHandle()); + //core.prepareImageForStorage(cmdStream, bloomAttachment.getHandle()); + + // compute blur pass + const std::array<uint32_t, 3> dispatchCount = {windowWidth, windowHeight, 0}; + /* + core.recordComputeDispatchToCmdStream( + cmdStream, + bloomComputePipeline, + dispatchCount.data(), + {bloomSetUsage}, + vkcv::PushConstantData(nullptr, 0)); + */ + // final compositing screen quad pass + core.recordDrawcallsToCmdStream( + cmdStream, + screenQuadPassHandle, + screenQuadPipelineHandle, + vkcv::PushConstantData(nullptr, 0), + {quadDrawcall}, + {swapchainHandle} + ); + + core.prepareSwapchainImageForPresent(cmdStream); + core.submitCommandStream(cmdStream); + + core.endFrame(); + } + + return 0; +} diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp index 44e7111e1f4941ef2f0f8114ac788d7db4a13b5a..6490067067dcf7a600e66a52d6a25f5aa5eae2a5 100644 --- a/src/vkcv/Core.cpp +++ b/src/vkcv/Core.cpp @@ -507,4 +507,10 @@ namespace vkcv m_ImageManager->recordImageLayoutTransition(image, vk::ImageLayout::eShaderReadOnlyOptimal, cmdBuffer); }, nullptr); } + + void Core::prepareImageForStorage(const CommandStreamHandle cmdStream, const ImageHandle image) { + recordCommandsToStream(cmdStream, [image, this](const vk::CommandBuffer cmdBuffer) { + m_ImageManager->recordImageLayoutTransition(image, vk::ImageLayout::eGeneral, cmdBuffer); + }, nullptr); + } }