From c94a4178f17e7c1edecb3d4e06e5cc521f20d32d Mon Sep 17 00:00:00 2001 From: Tobias Frisch <tfrisch@uni-koblenz.de> Date: Fri, 14 Oct 2022 18:19:34 +0200 Subject: [PATCH] Add screen-space ambient occlusion demo Signed-off-by: Tobias Frisch <tfrisch@uni-koblenz.de> --- demos/CMakeLists.txt | 1 + demos/SSAO/.gitignore | 1 + demos/SSAO/CMakeLists.txt | 15 + demos/SSAO/shaders/GBuffer.frag | 37 ++ demos/SSAO/shaders/GBuffer.vert | 27 + demos/SSAO/shaders/ambientOcclusion.frag | 84 +++ demos/SSAO/shaders/blur1D.frag | 33 ++ demos/SSAO/shaders/finalCompositing.frag | 37 ++ demos/SSAO/shaders/lighting.frag | 53 ++ demos/SSAO/shaders/lighting.vert | 33 ++ demos/SSAO/shaders/screenFill.vert | 14 + demos/SSAO/src/main.cpp | 701 +++++++++++++++++++++++ framework | 2 +- 13 files changed, 1037 insertions(+), 1 deletion(-) create mode 100644 demos/SSAO/.gitignore create mode 100644 demos/SSAO/CMakeLists.txt create mode 100644 demos/SSAO/shaders/GBuffer.frag create mode 100644 demos/SSAO/shaders/GBuffer.vert create mode 100644 demos/SSAO/shaders/ambientOcclusion.frag create mode 100644 demos/SSAO/shaders/blur1D.frag create mode 100644 demos/SSAO/shaders/finalCompositing.frag create mode 100644 demos/SSAO/shaders/lighting.frag create mode 100644 demos/SSAO/shaders/lighting.vert create mode 100644 demos/SSAO/shaders/screenFill.vert create mode 100644 demos/SSAO/src/main.cpp diff --git a/demos/CMakeLists.txt b/demos/CMakeLists.txt index 248a547..ed9ad7d 100644 --- a/demos/CMakeLists.txt +++ b/demos/CMakeLists.txt @@ -2,3 +2,4 @@ add_subdirectory(CubeMapping) add_subdirectory(InstancingDemo) add_subdirectory(NormalMapping) +add_subdirectory(SSAO) diff --git a/demos/SSAO/.gitignore b/demos/SSAO/.gitignore new file mode 100644 index 0000000..a6dcbba --- /dev/null +++ b/demos/SSAO/.gitignore @@ -0,0 +1 @@ +SSAO \ No newline at end of file diff --git a/demos/SSAO/CMakeLists.txt b/demos/SSAO/CMakeLists.txt new file mode 100644 index 0000000..964bc93 --- /dev/null +++ b/demos/SSAO/CMakeLists.txt @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 3.16) +project(SSAO) + +# setting c++ standard for the project +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# adding source files to the project +add_project(SSAO src/main.cpp) + +# including headers of dependencies and the VkCV framework +target_include_directories(SSAO SYSTEM BEFORE PRIVATE ${vkcv_includes}) + +# linking with libraries from all dependencies and the VkCV framework +target_link_libraries(SSAO ${vkcv_libraries}) diff --git a/demos/SSAO/shaders/GBuffer.frag b/demos/SSAO/shaders/GBuffer.frag new file mode 100644 index 0000000..ff16f61 --- /dev/null +++ b/demos/SSAO/shaders/GBuffer.frag @@ -0,0 +1,37 @@ +#version 450 + +//incoming data for the single textures +layout(location = 0) in vec4 passPosition; +layout(location = 1) in vec3 passNormal; +layout(location = 2) in vec2 passUVCoord; + +struct Material { + vec3 diffuse; + float alpha; +}; + +layout(set=0, binding=1) uniform materialBuffer { + Material mat; +}; + +layout(set=0, binding=2) uniform texturePropsBuffer { + int useColorTexture; +}; + +layout(set=0, binding=3) uniform texture2D colorTexture; +layout(set=0, binding=4) uniform sampler colorSampler; + +//writable textures for deferred screen space calculations +layout(location = 0) out vec4 positionOutput; +layout(location = 1) out vec4 normalOutput; +layout(location = 2) out vec4 colorOutput; + +void main() { + positionOutput = passPosition; + normalOutput = vec4(normalize(passNormal), 1); + colorOutput = vec4(mat.diffuse, mat.alpha); + + if (useColorTexture != 0) { + colorOutput = texture(sampler2D(colorTexture, colorSampler), passUVCoord); + } +} diff --git a/demos/SSAO/shaders/GBuffer.vert b/demos/SSAO/shaders/GBuffer.vert new file mode 100644 index 0000000..3d6a665 --- /dev/null +++ b/demos/SSAO/shaders/GBuffer.vert @@ -0,0 +1,27 @@ +#version 450 + +layout(location = 0) in vec3 position; +layout(location = 1) in vec3 normal; +layout(location = 2) in vec2 uv; + +layout(set=0, binding=0) uniform matrixBuffer { + mat4 viewMatrix; + mat4 projectionMatrix; +}; + +layout( push_constant ) uniform constants { + mat4 modelMatrix; +}; + +layout(location = 0) out vec4 passPosition; +layout(location = 1) out vec3 passNormal; +layout(location = 2) out vec2 passUVCoord; + +void main() { + passUVCoord = vec2(uv.x, 1.0f - uv.y); + + passPosition = viewMatrix * modelMatrix * vec4(position, 1); + gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position, 1); + + passNormal = vec3(transpose(inverse(viewMatrix * modelMatrix)) * vec4(normal, 0)); +} diff --git a/demos/SSAO/shaders/ambientOcclusion.frag b/demos/SSAO/shaders/ambientOcclusion.frag new file mode 100644 index 0000000..820a59e --- /dev/null +++ b/demos/SSAO/shaders/ambientOcclusion.frag @@ -0,0 +1,84 @@ +#version 450 + +layout(location = 0) in vec2 passUVCoord; + +layout(set=0, binding=0) uniform matrixBuffer { + mat4 viewMatrix; + mat4 projectionMatrix; +}; + +layout(set=0, binding=1) uniform texture2D positionTexture; +layout(set=0, binding=2) uniform texture2D normalTexture; +layout(set=0, binding=3) uniform sampler texSampler; + +layout( push_constant ) uniform constants { + float radius; + float quality; +}; + +layout(location = 0) out vec4 fragmentColor; + +float rand(vec2 co){ + return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453); +} + +vec3 rand3(int i, vec3 v, vec2 v2){ + float x = rand(vec2(v.x + i*3+0, v.x + ((i*3+0)*1531)%113) + v2*19789)*2 - 1.0; + float y = rand(vec2(v.y + i*3+1, v.y + ((i*3+1)*1531)%113) + v2*19789)*2 - 1.0; + float z = rand(vec2(v.z + i*3+2, v.z + ((i*3+2)*1531)%113) + v2*19789)*2 - 1.0; + return vec3(x,y,z); +} + +void main() { + vec3 pSphere[16] = vec3[]( + vec3(0.53812504, 0.18565957, -0.43192), + vec3(0.13790712, 0.24864247, 0.44301823), + vec3(0.33715037, 0.56794053, -0.005789503), + vec3(-0.6999805, -0.04511441, -0.0019965635), + vec3(0.06896307, -0.15983082, -0.85477847), + vec3(0.056099437, 0.006954967, -0.1843352), + vec3(-0.014653638, 0.14027752, 0.0762037), + vec3(0.010019933, -0.1924225, -0.034443386), + vec3(-0.35775623, -0.5301969, -0.43581226), + vec3(-0.3169221, 0.106360726, 0.015860917), + vec3(0.010350345, -0.58698344, 0.0046293875), + vec3(-0.08972908, -0.49408212, 0.3287904), + vec3(0.7119986, -0.0154690035, -0.09183723), + vec3(-0.053382345, 0.059675813, -0.5411899), + vec3(0.035267662, -0.063188605, 0.54602677), + vec3(-0.47761092, 0.2847911, -0.0271716) + ); + + vec4 position = texture(sampler2D(positionTexture, texSampler), passUVCoord); + vec3 pos = position.xyz; + vec3 normal = normalize(texture(sampler2D(normalTexture, texSampler), passUVCoord).rgb);// + vec3(0,0,0.00001)); + float d = pos.z + 0.001; + + fragmentColor = vec4(0.0, 0.0, 0.0, 0.0); + if (position.w < 0.5) { + return; + } + + float occ = 1.0; + int j=0; + + for (int i = 0; i < quality; i++) { + vec3 v = rand3(i + j, pSphere[i%16], passUVCoord); + v = sign(dot(v, normal)) * v; + v = pos + v * radius; + + vec4 diff = projectionMatrix * vec4(v, 1); + diff = (diff / diff.w) * 0.5f + 0.5f; + + vec4 td = texture(sampler2D(positionTexture, texSampler), diff.xy); + if (td.w < 0.5) { + continue; + } + + if (td.z > v.z) { + occ -= 1.0 / quality; + } + } + + fragmentColor = vec4(vec3(1.0f - occ), 1.0); +} diff --git a/demos/SSAO/shaders/blur1D.frag b/demos/SSAO/shaders/blur1D.frag new file mode 100644 index 0000000..5c61426 --- /dev/null +++ b/demos/SSAO/shaders/blur1D.frag @@ -0,0 +1,33 @@ +#version 450 + +layout(location = 0) in vec2 passUVCoord; + +layout(set=0, binding=0) uniform texture2D colorTexture; +layout(set=0, binding=1) uniform sampler colorSampler; + +layout( push_constant ) uniform constants { + float yAxis; +}; + +layout(location = 0) out vec4 fragmentColor; + +void main() { + vec4 weights = vec4(2.0, 3.0, 2.0, 1.0); + + vec4 sum = vec4(0.0, 0.0, 0.0, 0.0); + vec2 diff = vec2(1.0, 0.0); + + if (yAxis > 0.5) { + diff = vec2(0.0, 1.0); + } + + diff *= (1.0 / 800.0); + + for(int i=0; i<4; i++) + { + sum += weights[i] * texture(sampler2D(colorTexture, colorSampler), passUVCoord + i*diff); + sum += weights[i] * texture(sampler2D(colorTexture, colorSampler), passUVCoord - i*diff); + } + + fragmentColor = sum / 16.0; +} \ No newline at end of file diff --git a/demos/SSAO/shaders/finalCompositing.frag b/demos/SSAO/shaders/finalCompositing.frag new file mode 100644 index 0000000..d380540 --- /dev/null +++ b/demos/SSAO/shaders/finalCompositing.frag @@ -0,0 +1,37 @@ +#version 450 + +layout(location = 0) in vec2 passUVCoord; + +layout(set=0, binding=0) uniform texture2D lightTexture; +layout(set=0, binding=1) uniform texture2D colorTexture; +layout(set=0, binding=2) uniform texture2D ssaoTexture; +layout(set=0, binding=3) uniform sampler texSampler; + +layout( push_constant ) uniform constants { + float useLight; + float useSSAO; +}; + +layout(location = 0) out vec4 fragmentColor; + +void main() { + vec4 light = texture(sampler2D(lightTexture, texSampler), passUVCoord); + vec4 color = texture(sampler2D(colorTexture, texSampler), passUVCoord); + vec4 ssao = texture(sampler2D(ssaoTexture, texSampler), passUVCoord); + + fragmentColor = color; + + if (useLight > 0.5) { + fragmentColor *= light; + } + + if (color.a < 0.5) { + fragmentColor = vec4(0.4,0.4,0.4,1.0); + } + + if (useSSAO > 0.5) { + fragmentColor *= (ssao * 0.7 + 0.3); + } + + //fragmentColor = color; +} \ No newline at end of file diff --git a/demos/SSAO/shaders/lighting.frag b/demos/SSAO/shaders/lighting.frag new file mode 100644 index 0000000..f2f5b8d --- /dev/null +++ b/demos/SSAO/shaders/lighting.frag @@ -0,0 +1,53 @@ +#version 450 + +layout(location = 0) in vec4 passPosition; +layout(location = 1) in vec4 midPosition; + +layout(location = 2) in vec4 color; + +layout(set=0, binding=0) uniform matrixBuffer { + mat4 viewMatrix; + mat4 projectionMatrix; +}; + +layout(set=0, binding=1) uniform texture2D positionTexture; +layout(set=0, binding=2) uniform texture2D normalTexture; +layout(set=0, binding=3) uniform sampler texSampler; + +layout(set=0, binding=4) uniform resolutionBuffer { + vec2 resolution; +}; + +layout(location = 0) out vec4 lightingOutput; + +void main() { + vec2 uv = gl_FragCoord.xy / resolution; + vec4 pos = texture(sampler2D(positionTexture, texSampler), uv); + vec3 nor = texture(sampler2D(normalTexture, texSampler), uv).xyz; + + if (pos.w < 0.5) { + discard; + } + + float diffuseStrength = max(2.0f - length(pos - midPosition), 0.0f); + float specularStrength = clamp(diffuseStrength * diffuseStrength, 0.0f, 1.0f); + + if (diffuseStrength < 0) { + discard; + } + + vec3 nPosToLight = normalize(vec3(midPosition.xyz - pos.xyz)); + + vec3 reflection = normalize(reflect(-nPosToLight,nor.xyz)); + float diffuse = max(dot(nor.xyz, nPosToLight), 0); + float specular = pow(max(dot(reflection, -normalize(pos.xyz)),0),50); + + lightingOutput = vec4(passPosition.xyz - midPosition.xyz, 1.0); + lightingOutput = vec4(nor.xyz, 1.0); + + lightingOutput = color * ( + diffuseStrength * vec4(vec3(diffuse), 1) * 0.7 + + specularStrength * vec4(1) * specular + ); +} + diff --git a/demos/SSAO/shaders/lighting.vert b/demos/SSAO/shaders/lighting.vert new file mode 100644 index 0000000..8e27435 --- /dev/null +++ b/demos/SSAO/shaders/lighting.vert @@ -0,0 +1,33 @@ +#version 450 + +layout(location = 0) in vec3 position; + +layout(set=0, binding=0) uniform matrixBuffer { + mat4 viewMatrix; + mat4 projectionMatrix; +}; + +layout( push_constant ) uniform constants { + mat4 modelMatrix; +}; + +layout(location = 0) out vec4 passPosition; +layout(location = 1) out vec4 midPosition; + +layout(location = 2) out vec4 color; + +void main() { + vec3 c = (modelMatrix * vec4(0,0,0,1)).xyz; + float x = c.x + 2; + float y = c.y + 2; + float z = c.z + 2; + c = vec3(x * 2.3 + y * 5.6 + z * 4.4, x * 3.1 + y * 7.2 + z, x * 4.3 + y + z * 6.9); + c = sin(c); + c = c / 2.0 + 1.0; + c = normalize(c); + color = vec4(c, 1.0); + + passPosition = viewMatrix * modelMatrix * vec4(position, 1); + midPosition = viewMatrix * modelMatrix * vec4(0,0,0,1); + gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position, 1); +} \ No newline at end of file diff --git a/demos/SSAO/shaders/screenFill.vert b/demos/SSAO/shaders/screenFill.vert new file mode 100644 index 0000000..e32d3ef --- /dev/null +++ b/demos/SSAO/shaders/screenFill.vert @@ -0,0 +1,14 @@ +#version 450 + +vec2 positions[3] = { + vec2(0, 0), + vec2(0, 2), + vec2(2, 0) +}; + +layout(location = 0) out vec2 passUVCoord; + +void main() { + gl_Position = vec4(positions[gl_VertexIndex] * 2.0f - 1.0f, 1, 1); + passUVCoord = positions[gl_VertexIndex]; +} \ No newline at end of file diff --git a/demos/SSAO/src/main.cpp b/demos/SSAO/src/main.cpp new file mode 100644 index 0000000..9f136eb --- /dev/null +++ b/demos/SSAO/src/main.cpp @@ -0,0 +1,701 @@ + +#include <vkcv/Buffer.hpp> +#include <vkcv/Core.hpp> +#include <vkcv/DescriptorWrites.hpp> +#include <vkcv/Image.hpp> +#include <vkcv/Pass.hpp> +#include <vkcv/Sampler.hpp> +#include <vkcv/Window.hpp> +#include <vkcv/asset/asset_loader.hpp> +#include <vkcv/camera/CameraManager.hpp> +#include <vkcv/geometry/Cuboid.hpp> +#include <vkcv/geometry/Sphere.hpp> +#include <vkcv/gui/GUI.hpp> +#include <vkcv/shader/GLSLCompiler.hpp> + +struct Material { + glm::vec3 diffuse; + float alpha; +}; + +struct TextureProps { + int useColorTexture; +}; + +int main(int argc, const char** argv) { + const std::string applicationName = "SSAO"; + + vkcv::Features features; + features.requireExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); + features.requireExtensionFeature<vk::PhysicalDeviceShaderTerminateInvocationFeatures>( + VK_KHR_SHADER_TERMINATE_INVOCATION_EXTENSION_NAME, + [](vk::PhysicalDeviceShaderTerminateInvocationFeatures& features) { + features.setShaderTerminateInvocation(true); + } + ); + + vkcv::Core core = vkcv::Core::create( + applicationName, + VK_MAKE_VERSION(0, 0, 1), + { vk::QueueFlagBits::eGraphics, vk::QueueFlagBits::eTransfer }, + features + ); + + vkcv::WindowHandle windowHandle = core.createWindow(applicationName, 800, 800, true); + vkcv::Window& window = core.getWindow(windowHandle); + + vkcv::camera::CameraManager cameraManager (window); + auto camHandle = cameraManager.addCamera(vkcv::camera::ControllerType::TRACKBALL); + + cameraManager.getCamera(camHandle).setNearFar(0.1f, 100.0f); + + vkcv::geometry::Cuboid plane (glm::vec3(0.0f), glm::vec3(1.0f, 0.01f, 1.0f)); + + vkcv::geometry::Sphere sphere (glm::vec3(0.0f), 1.0f); + sphere.setResolution(20); + + vkcv::shader::GLSLCompiler compiler; + vkcv::ShaderProgram shaderProgram, lightProgram, aoProgram, blurProgram, compositeProgram; + + compiler.compileProgram( + shaderProgram, + { + { vkcv::ShaderStage::VERTEX, "shaders/GBuffer.vert" }, + { vkcv::ShaderStage::FRAGMENT, "shaders/GBuffer.frag" } + }, + nullptr + ); + + compiler.compileProgram( + lightProgram, + { + { vkcv::ShaderStage::VERTEX, "shaders/lighting.vert" }, + { vkcv::ShaderStage::FRAGMENT, "shaders/lighting.frag" } + }, + nullptr + ); + + compiler.compileProgram( + aoProgram, + { + { vkcv::ShaderStage::VERTEX, "shaders/screenFill.vert" }, + { vkcv::ShaderStage::FRAGMENT, "shaders/ambientOcclusion.frag" } + }, + nullptr + ); + + compiler.compileProgram( + blurProgram, + { + { vkcv::ShaderStage::VERTEX, "shaders/screenFill.vert" }, + { vkcv::ShaderStage::FRAGMENT, "shaders/blur1D.frag" } + }, + nullptr + ); + + compiler.compileProgram( + compositeProgram, + { + { vkcv::ShaderStage::VERTEX, "shaders/screenFill.vert" }, + { vkcv::ShaderStage::FRAGMENT, "shaders/finalCompositing.frag" } + }, + nullptr + ); + + const vkcv::PassConfig gPassConfig ({ + vkcv::AttachmentDescription( + vk::Format::eR32G32B32A32Sfloat, + vkcv::AttachmentOperation::CLEAR, + vkcv::AttachmentOperation::STORE, + vk::ClearValue(vk::ClearColorValue(std::array<float, 4>{ + 0.0f, 0.0f, 0.0f, 0.0f + })) + ), + vkcv::AttachmentDescription( + vk::Format::eR32G32B32A32Sfloat, + vkcv::AttachmentOperation::CLEAR, + vkcv::AttachmentOperation::STORE, + vk::ClearValue(vk::ClearColorValue(std::array<float, 4>{ + 0.5f, 0.5f, 0.5f, 0.5f + })) + ), + vkcv::AttachmentDescription( + core.getSwapchainFormat(window.getSwapchain()), + vkcv::AttachmentOperation::CLEAR, + vkcv::AttachmentOperation::STORE, + vk::ClearValue(vk::ClearColorValue(std::array<float, 4>{ + 1.0f, 1.0f, 1.0f, 1.0f + })) + ), + vkcv::AttachmentDescription( + vk::Format::eD32Sfloat, + vkcv::AttachmentOperation::CLEAR, + vkcv::AttachmentOperation::STORE + ) + }); + + vkcv::PassHandle gBufferPass = core.createPass(gPassConfig); + + vkcv::PassHandle gBufferPositionPass = core.createPass(vkcv::PassConfig( + { + vkcv::AttachmentDescription( + core.getSwapchainFormat(window.getSwapchain()), + vkcv::AttachmentOperation::CLEAR, + vkcv::AttachmentOperation::STORE, + vk::ClearValue(vk::ClearColorValue(std::array<float, 4>{ + 0.0f, 0.0f, 0.0f, 0.0f + })) + ), + gPassConfig.getAttachments()[1], + gPassConfig.getAttachments()[2], + gPassConfig.getAttachments()[3] + } + )); + + vkcv::PassHandle gBufferNormalPass = core.createPass(vkcv::PassConfig( + { + gPassConfig.getAttachments()[0], + vkcv::AttachmentDescription( + core.getSwapchainFormat(window.getSwapchain()), + vkcv::AttachmentOperation::CLEAR, + vkcv::AttachmentOperation::STORE, + vk::ClearValue(vk::ClearColorValue(std::array<float, 4>{ + 0.5f, 0.5f, 0.5f, 0.5f + })) + ), + gPassConfig.getAttachments()[2], + gPassConfig.getAttachments()[3] + } + )); + + vkcv::PassHandle simplePass = vkcv::passSwapchain(core, window.getSwapchain(), { + vk::Format::eUndefined + }); + + const vkcv::VertexLayout vertexLayout { + vkcv::createVertexBindings(shaderProgram.getVertexAttachments()) + }; + + const vkcv::DescriptorBindings descriptorBindings = ( + shaderProgram.getReflectedDescriptors().at(0) + ); + + auto descriptorSetLayout = core.createDescriptorSetLayout(descriptorBindings); + auto descriptorSet = core.createDescriptorSet(descriptorSetLayout); + + vkcv::GraphicsPipelineHandle gBufferPipeline = core.createGraphicsPipeline( + vkcv::GraphicsPipelineConfig( + shaderProgram, + gBufferPass, + vertexLayout, + { descriptorSetLayout } + ) + ); + + vkcv::GraphicsPipelineHandle gBufferPosPipeline = core.createGraphicsPipeline( + vkcv::GraphicsPipelineConfig( + shaderProgram, + gBufferPositionPass, + vertexLayout, + { descriptorSetLayout } + ) + ); + + vkcv::GraphicsPipelineHandle gBufferNorPipeline = core.createGraphicsPipeline( + vkcv::GraphicsPipelineConfig( + shaderProgram, + gBufferNormalPass, + vertexLayout, + { descriptorSetLayout } + ) + ); + + const vkcv::VertexLayout lightVertexLayout { + vkcv::createVertexBindings(lightProgram.getVertexAttachments()) + }; + + const vkcv::DescriptorBindings lightDescSetBindings = ( + lightProgram.getReflectedDescriptors().at(0) + ); + + auto lightDescSetLayout = core.createDescriptorSetLayout(lightDescSetBindings); + auto lightDescSet = core.createDescriptorSet(lightDescSetLayout); + + vkcv::GraphicsPipelineConfig lightPipelineConfig ( + lightProgram, + simplePass, + lightVertexLayout, + { lightDescSetLayout } + ); + + lightPipelineConfig.setBlendMode(vkcv::BlendMode::Additive); + + vkcv::GraphicsPipelineHandle lightPipeline = core.createGraphicsPipeline( + lightPipelineConfig + ); + + const vkcv::DescriptorBindings aoDescSetBindings = ( + aoProgram.getReflectedDescriptors().at(0) + ); + + auto aoDescSetLayout = core.createDescriptorSetLayout(aoDescSetBindings); + auto aoDescSet = core.createDescriptorSet(aoDescSetLayout); + + vkcv::GraphicsPipelineHandle aoPipeline = core.createGraphicsPipeline( + vkcv::GraphicsPipelineConfig( + aoProgram, + simplePass, + {}, + { aoDescSetLayout } + ) + ); + + const vkcv::DescriptorBindings blurDescSetBindings = ( + blurProgram.getReflectedDescriptors().at(0) + ); + + auto blurDescSetLayout = core.createDescriptorSetLayout(blurDescSetBindings); + auto blurDescSet = core.createDescriptorSet(blurDescSetLayout); + + vkcv::GraphicsPipelineHandle blurPipeline = core.createGraphicsPipeline( + vkcv::GraphicsPipelineConfig( + blurProgram, + simplePass, + {}, + { blurDescSetLayout } + ) + ); + + const vkcv::DescriptorBindings compositeDescSetBindings = ( + compositeProgram.getReflectedDescriptors().at(0) + ); + + auto compositeDescSetLayout = core.createDescriptorSetLayout(compositeDescSetBindings); + auto compositeDescSet = core.createDescriptorSet(compositeDescSetLayout); + + vkcv::GraphicsPipelineHandle compositePipeline = core.createGraphicsPipeline( + vkcv::GraphicsPipelineConfig( + compositeProgram, + simplePass, + {}, + { compositeDescSetLayout } + ) + ); + + auto matrixBuffer = vkcv::buffer<glm::mat4>( + core, + vkcv::BufferType::UNIFORM, + 2, + vkcv::BufferMemoryType::HOST_VISIBLE + ); + + auto materialBuffer = vkcv::buffer<Material>( + core, + vkcv::BufferType::UNIFORM, + 1 + ); + + Material material; + material.diffuse = glm::vec3(1.0f, 0.0f, 0.0f); + material.alpha = 1.0f; + materialBuffer.fill(&material, 1); + + auto texturePropsBuffer = vkcv::buffer<TextureProps>( + core, + vkcv::BufferType::UNIFORM, + 1, + vkcv::BufferMemoryType::HOST_VISIBLE + ); + + vkcv::asset::Texture cv_logo = vkcv::asset::loadTexture("../../resources/cv_logo.png"); + + vkcv::Image cv_logoImage = vkcv::image(core, vk::Format::eR8G8B8A8Unorm, cv_logo.w, cv_logo.h); + cv_logoImage.fill(cv_logo.data.data()); + + vkcv::SamplerHandle sampler = vkcv::samplerLinear(core); + + auto resolutionBuffer = vkcv::buffer<glm::vec2>( + core, + vkcv::BufferType::UNIFORM, + 1, + vkcv::BufferMemoryType::HOST_VISIBLE + ); + + int sizeX = 7, sizeZ = 7; + vkcv::PushConstants pushConstants = vkcv::pushConstants<glm::mat4>(); + + { + vkcv::DescriptorWrites writes; + writes.writeUniformBuffer(0, matrixBuffer.getHandle()); + writes.writeUniformBuffer(1, materialBuffer.getHandle()); + writes.writeUniformBuffer(2, texturePropsBuffer.getHandle()); + writes.writeSampledImage(3, cv_logoImage.getHandle()); + writes.writeSampler(4, sampler); + core.writeDescriptorSet(descriptorSet, writes); + } + + { + vkcv::DescriptorWrites writes; + writes.writeUniformBuffer(0, matrixBuffer.getHandle()); + writes.writeSampler(3, sampler); + core.writeDescriptorSet(aoDescSet, writes); + + writes.writeUniformBuffer(4, resolutionBuffer.getHandle()); + core.writeDescriptorSet(lightDescSet, writes); + } + + { + vkcv::DescriptorWrites writes; + writes.writeSampler(1, sampler); + core.writeDescriptorSet(blurDescSet, writes); + } + + { + vkcv::DescriptorWrites writes; + writes.writeSampler(3, sampler); + core.writeDescriptorSet(compositeDescSet, writes); + } + + vkcv::gui::GUI gui (core, windowHandle); + + bool useColorTexture = true; + int showBuffer = 0; + bool useBlurPass = false; + + const std::vector<const char*> showBufferNames = { + "Composition", + "Position", + "Normal", + "Color", + "Light", + "Ambient Occlusion" + }; + + float ssaoRadius = 0.2f; + float ssaoQuality = 16.0f; + + bool useLighting = true; + bool useSSAO = true; + + vkcv::InstanceDrawcall planeDrawcall (plane.generateVertexData(core)); + planeDrawcall.useDescriptorSet(0, descriptorSet); + + vkcv::InstanceDrawcall sphereDrawcall (sphere.generateVertexData(core)); + sphereDrawcall.useDescriptorSet(0, descriptorSet); + + std::vector<vkcv::InstanceDrawcall> lightDrawcalls; + lightDrawcalls.reserve(100); + + sphere.setRadius(3.0f); + vkcv::VertexData lightSphereData = sphere.generateVertexData(core); + + for (size_t i = 0; i < 100; i++) { + vkcv::InstanceDrawcall lightDrawcall (lightSphereData); + lightDrawcall.useDescriptorSet(0, lightDescSet); + lightDrawcalls.push_back(lightDrawcall); + } + + vkcv::VertexData simpleVertexData; + simpleVertexData.setCount(3); + + vkcv::InstanceDrawcall aoDrawcall (simpleVertexData); + aoDrawcall.useDescriptorSet(0, aoDescSet); + + vkcv::InstanceDrawcall blurDrawcall (simpleVertexData); + blurDrawcall.useDescriptorSet(0, blurDescSet); + + vkcv::InstanceDrawcall compositeDrawcall (simpleVertexData); + compositeDrawcall.useDescriptorSet(0, compositeDescSet); + + const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle(); + + vkcv::ImageHandle positionBuffer; + vkcv::ImageHandle normalBuffer; + vkcv::ImageHandle colorBuffer; + vkcv::ImageHandle depthBuffer; + + vkcv::ImageHandle lightBuffer; + vkcv::ImageHandle aoBuffer; + vkcv::ImageHandle blurBuffer; + + glm::mat4* mvp = matrixBuffer.map(); + TextureProps* textureProps = texturePropsBuffer.map(); + glm::vec2* res = resolutionBuffer.map(); + + core.run([&](const vkcv::WindowHandle &windowHandle, + double t, + double dt, + uint32_t swapchainWidth, + uint32_t swapchainHeight + ) { + vkcv::ImageConfig bufferConfig ( + swapchainWidth, + swapchainHeight + ); + + bufferConfig.setSupportingColorAttachment(true); + + if ((!positionBuffer) || + (swapchainWidth != core.getImageWidth(positionBuffer)) || + (swapchainHeight != core.getImageHeight(positionBuffer))) { + positionBuffer = core.createImage( + vk::Format::eR32G32B32A32Sfloat, + bufferConfig + ); + + vkcv::DescriptorWrites writes; + writes.writeSampledImage(1, positionBuffer); + core.writeDescriptorSet(lightDescSet, writes); + core.writeDescriptorSet(aoDescSet, writes); + } + + if ((!normalBuffer) || + (swapchainWidth != core.getImageWidth(normalBuffer)) || + (swapchainHeight != core.getImageHeight(normalBuffer))) { + normalBuffer = core.createImage( + vk::Format::eR32G32B32A32Sfloat, + bufferConfig + ); + + vkcv::DescriptorWrites writes; + writes.writeSampledImage(2, normalBuffer); + core.writeDescriptorSet(lightDescSet, writes); + core.writeDescriptorSet(aoDescSet, writes); + } + + if ((!colorBuffer) || + (swapchainWidth != core.getImageWidth(colorBuffer)) || + (swapchainHeight != core.getImageHeight(colorBuffer))) { + colorBuffer = core.createImage( + core.getSwapchainFormat(core.getWindow(windowHandle).getSwapchain()), + bufferConfig + ); + + vkcv::DescriptorWrites writes; + writes.writeSampledImage(1, colorBuffer); + core.writeDescriptorSet(compositeDescSet, writes); + } + + if ((!depthBuffer) || + (swapchainWidth != core.getImageWidth(depthBuffer)) || + (swapchainHeight != core.getImageHeight(depthBuffer))) { + depthBuffer = core.createImage( + vk::Format::eD32Sfloat, + vkcv::ImageConfig( + swapchainWidth, + swapchainHeight + ) + ); + } + + if ((!lightBuffer) || + (swapchainWidth != core.getImageWidth(lightBuffer)) || + (swapchainHeight != core.getImageHeight(lightBuffer))) { + lightBuffer = core.createImage( + core.getSwapchainFormat(core.getWindow(windowHandle).getSwapchain()), + bufferConfig + ); + + vkcv::DescriptorWrites writes; + writes.writeSampledImage(0, lightBuffer); + core.writeDescriptorSet(compositeDescSet, writes); + } + + if ((!aoBuffer) || + (swapchainWidth != core.getImageWidth(aoBuffer)) || + (swapchainHeight != core.getImageHeight(aoBuffer))) { + aoBuffer = core.createImage( + core.getSwapchainFormat(core.getWindow(windowHandle).getSwapchain()), + bufferConfig + ); + + vkcv::DescriptorWrites writes; + writes.writeSampledImage(2, aoBuffer); + core.writeDescriptorSet(compositeDescSet, writes); + } + + if ((!blurBuffer) || + (swapchainWidth != core.getImageWidth(blurBuffer)) || + (swapchainHeight != core.getImageHeight(blurBuffer))) { + blurBuffer = core.createImage( + core.getSwapchainFormat(core.getWindow(windowHandle).getSwapchain()), + bufferConfig + ); + + vkcv::DescriptorWrites writes; + writes.writeSampledImage(0, blurBuffer); + core.writeDescriptorSet(blurDescSet, writes); + } + + cameraManager.update(dt); + + mvp[0] = cameraManager.getActiveCamera().getView(); + mvp[1] = cameraManager.getActiveCamera().getProjection(); + + textureProps->useColorTexture = useColorTexture? 1 : 0; + + res[0] = glm::vec2(swapchainWidth, swapchainHeight); + + auto cmdStream = core.createCommandStream(vkcv::QueueType::Graphics); + + std::vector<vkcv::InstanceDrawcall> drawcalls; + drawcalls.reserve(sizeX * sizeZ + 1); + drawcalls.push_back(planeDrawcall); + + pushConstants.clear(); + pushConstants.appendDrawcall(glm::scale(glm::translate( + glm::identity<glm::mat4>(), + glm::vec3(0, -2.5f, 0) + ), glm::vec3(sizeX + 4, 1.0f, sizeZ + 4))); + + for (size_t i = 0; i < sizeX; i++) { + for (size_t j = 0; j < sizeZ; j++) { + drawcalls.push_back(sphereDrawcall); + + pushConstants.appendDrawcall(glm::scale(glm::translate( + glm::identity<glm::mat4>(), + glm::vec3( + (i * 1.2f) - (sizeX - 1) * 0.6f, + -2.0f, + (j * 1.2f) - (sizeZ - 1) * 0.6f + ) + ), glm::vec3(0.5))); + } + } + + const vkcv::ImageHandle targetImage = ( + useBlurPass? + blurBuffer : + swapchainInput + ); + + core.recordDrawcallsToCmdStream( + cmdStream, + (showBuffer == 1? + gBufferPosPipeline : (showBuffer == 2? + gBufferNorPipeline : gBufferPipeline) + ), + pushConstants, + drawcalls, + { + showBuffer == 1? targetImage : positionBuffer, + showBuffer == 2? targetImage : normalBuffer, + showBuffer == 3? targetImage : colorBuffer, + depthBuffer + }, + windowHandle + ); + + if (((showBuffer == 0) && (useLighting)) || (showBuffer == 4)) { + core.prepareImageForSampling(cmdStream, positionBuffer); + core.prepareImageForSampling(cmdStream, normalBuffer); + + pushConstants.clear(); + + const glm::mat4 lightMatrix = glm::rotate<float>( + glm::identity<glm::mat4>(), + glm::radians<float>(10.0f * static_cast<float>(t)), + glm::vec3(0.0, 1.0, 0.0) + ); + + for (size_t i = 0; i < lightDrawcalls.size(); i++) { + float x = static_cast<float>(i % 10) - 5.0f; + float y = static_cast<float>((i / 10) % 10) - 5.0f; + + pushConstants.appendDrawcall(glm::translate( + lightMatrix, + glm::vec3( + x * 1.2f, + -1.0f, + y * 1.2f + ) + )); + } + + core.recordDrawcallsToCmdStream( + cmdStream, + lightPipeline, + pushConstants, + lightDrawcalls, + { + showBuffer == 4? targetImage : lightBuffer + }, + windowHandle + ); + } + + if (((showBuffer == 0) && (useSSAO)) || (showBuffer == 5)) { + core.prepareImageForSampling(cmdStream, positionBuffer); + core.prepareImageForSampling(cmdStream, normalBuffer); + + core.recordDrawcallsToCmdStream( + cmdStream, + aoPipeline, + vkcv::pushConstants<glm::vec2>(glm::vec2(ssaoRadius, ssaoQuality)), + { aoDrawcall }, + { + showBuffer == 5? targetImage : (useBlurPass? blurBuffer : aoBuffer) + }, + windowHandle + ); + } + + if (useBlurPass) { + core.prepareImageForSampling(cmdStream, blurBuffer); + + core.recordDrawcallsToCmdStream( + cmdStream, + blurPipeline, + vkcv::pushConstants<float>(0.0f), + { blurDrawcall }, + { + showBuffer == 0? aoBuffer : swapchainInput + }, + windowHandle + ); + } + + if (showBuffer == 0) { + core.prepareImageForSampling(cmdStream, lightBuffer); + core.prepareImageForSampling(cmdStream, colorBuffer); + core.prepareImageForSampling(cmdStream, aoBuffer); + + core.recordDrawcallsToCmdStream( + cmdStream, + compositePipeline, + vkcv::pushConstants<glm::vec2>( + glm::vec2(useLighting? 1 : 0, useSSAO? 1 : 0) + ), + { compositeDrawcall }, + { + swapchainInput + }, + windowHandle + ); + } + + core.prepareSwapchainImageForPresent(cmdStream); + core.submitCommandStream(cmdStream); + + gui.beginGUI(); + ImGui::Begin("Settings"); + ImGui::SliderInt("X-Axis", &sizeX, 1, 100); + ImGui::SliderInt("Z-Axis", &sizeZ, 1, 100); + ImGui::Spacing(); + ImGui::Combo("Show buffer", &showBuffer, showBufferNames.data(), + static_cast<int>(showBufferNames.size())); + ImGui::Checkbox("Use color texture", &useColorTexture); + ImGui::Checkbox("Use blur pass", &useBlurPass); + ImGui::SliderFloat("SSAO radius", &ssaoRadius, 0.0f, 1.0f); + ImGui::SliderFloat("SSAO quality", &ssaoQuality, 1.0f, 100.0f); + ImGui::Checkbox("Composite lighting", &useLighting); + ImGui::Checkbox("Composite SSAO", &useSSAO); + ImGui::End(); + gui.endGUI(); + }); + + matrixBuffer.unmap(); + texturePropsBuffer.unmap(); + resolutionBuffer.unmap(); + return 0; +} diff --git a/framework b/framework index 393809b..b022602 160000 --- a/framework +++ b/framework @@ -1 +1 @@ -Subproject commit 393809b4e6e8c0e5fa79e8501ceb3cc31462c9fd +Subproject commit b022602d1914f87174533b5fb1a302caf8f57343 -- GitLab