From fe4da00f1b8dcb8d39c10a5123c5df9fd96055d1 Mon Sep 17 00:00:00 2001 From: Alexander Gauggel <agauggel@uni-koblenz.de> Date: Tue, 3 Aug 2021 16:30:08 +0200 Subject: [PATCH] [#106] Add skybox --- .../resources/models/cube.bin | 3 + .../resources/models/cube.gltf | 3 + .../shaders/{shader.frag => mesh.frag} | 0 .../shaders/{shader.vert => mesh.vert} | 0 .../resources/shaders/sky.frag | 8 + .../resources/shaders/sky.vert | 13 + projects/indirect_dispatch/src/App.cpp | 32 ++- projects/indirect_dispatch/src/App.hpp | 7 +- projects/indirect_dispatch/src/AppSetup.cpp | 245 ++++++++++-------- projects/indirect_dispatch/src/AppSetup.hpp | 26 +- 10 files changed, 217 insertions(+), 120 deletions(-) create mode 100644 projects/indirect_dispatch/resources/models/cube.bin create mode 100644 projects/indirect_dispatch/resources/models/cube.gltf rename projects/indirect_dispatch/resources/shaders/{shader.frag => mesh.frag} (100%) rename projects/indirect_dispatch/resources/shaders/{shader.vert => mesh.vert} (100%) create mode 100644 projects/indirect_dispatch/resources/shaders/sky.frag create mode 100644 projects/indirect_dispatch/resources/shaders/sky.vert diff --git a/projects/indirect_dispatch/resources/models/cube.bin b/projects/indirect_dispatch/resources/models/cube.bin new file mode 100644 index 00000000..48295ae1 --- /dev/null +++ b/projects/indirect_dispatch/resources/models/cube.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0c9795a04850906951d977716160cae68a1555ee0b4f5c719c00c5d3314ac280 +size 648 diff --git a/projects/indirect_dispatch/resources/models/cube.gltf b/projects/indirect_dispatch/resources/models/cube.gltf new file mode 100644 index 00000000..d6b80705 --- /dev/null +++ b/projects/indirect_dispatch/resources/models/cube.gltf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2418009f665c0862617868de1dc4ff29533c1203956d8ea90c5eee2f50a517e8 +size 2270 diff --git a/projects/indirect_dispatch/resources/shaders/shader.frag b/projects/indirect_dispatch/resources/shaders/mesh.frag similarity index 100% rename from projects/indirect_dispatch/resources/shaders/shader.frag rename to projects/indirect_dispatch/resources/shaders/mesh.frag diff --git a/projects/indirect_dispatch/resources/shaders/shader.vert b/projects/indirect_dispatch/resources/shaders/mesh.vert similarity index 100% rename from projects/indirect_dispatch/resources/shaders/shader.vert rename to projects/indirect_dispatch/resources/shaders/mesh.vert diff --git a/projects/indirect_dispatch/resources/shaders/sky.frag b/projects/indirect_dispatch/resources/shaders/sky.frag new file mode 100644 index 00000000..efc0e03b --- /dev/null +++ b/projects/indirect_dispatch/resources/shaders/sky.frag @@ -0,0 +1,8 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) out vec3 outColor; + +void main() { + outColor = vec3(0, 0.2, 0.9); +} \ No newline at end of file diff --git a/projects/indirect_dispatch/resources/shaders/sky.vert b/projects/indirect_dispatch/resources/shaders/sky.vert new file mode 100644 index 00000000..44b48cd7 --- /dev/null +++ b/projects/indirect_dispatch/resources/shaders/sky.vert @@ -0,0 +1,13 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) in vec3 inPosition; + +layout( push_constant ) uniform constants{ + mat4 viewProjection; +}; + +void main() { + gl_Position = viewProjection * vec4(inPosition, 0.0); + gl_Position.w = gl_Position.z; +} \ No newline at end of file diff --git a/projects/indirect_dispatch/src/App.cpp b/projects/indirect_dispatch/src/App.cpp index b95c0f36..47f4a2b7 100644 --- a/projects/indirect_dispatch/src/App.cpp +++ b/projects/indirect_dispatch/src/App.cpp @@ -25,10 +25,16 @@ App::App() : bool App::initialize() { - if (!loadMeshGraphicPass(m_core, &m_meshPassHandles)) + if (!loadMeshPass(m_core, &m_meshPassHandles)) return false; - if (!loadSphereMesh(m_core, &m_sphereMesh)) + if (!loadSkyPass(m_core, &m_skyPassHandles)) + return false; + + if (!loadMesh(m_core, "resources/models/sphere.gltf", & m_sphereMesh)) + return false; + + if (!loadMesh(m_core, "resources/models/cube.gltf", &m_cubeMesh)) return false; m_renderTargets = createRenderTargets(m_core, m_windowWidth, m_windowHeight); @@ -52,6 +58,7 @@ void App::run() { auto frameStartTime = std::chrono::system_clock::now(); const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle(); const vkcv::DrawcallInfo sphereDrawcall(m_sphereMesh.mesh, {}, 1); + const vkcv::DrawcallInfo cubeDrawcall(m_cubeMesh.mesh, {}, 1); while (m_window.isWindowOpen()) { vkcv::Window::pollEvents(); @@ -76,22 +83,33 @@ void App::run() { frameStartTime = frameEndTime; m_cameraManager.update(0.000001 * static_cast<double>(deltatime.count())); - const glm::mat4 mvp = m_cameraManager.getActiveCamera().getMVP(); - - vkcv::PushConstants pushConstants(sizeof(glm::mat4)); - pushConstants.appendDrawcall(mvp); + const glm::mat4 viewProjection = m_cameraManager.getActiveCamera().getMVP(); const std::vector<vkcv::ImageHandle> renderTargets = { swapchainInput, m_renderTargets.depthBuffer }; const vkcv::CommandStreamHandle cmdStream = m_core.createCommandStream(vkcv::QueueType::Graphics); + vkcv::PushConstants meshPushConstants(sizeof(glm::mat4)); + meshPushConstants.appendDrawcall(viewProjection); + m_core.recordDrawcallsToCmdStream( cmdStream, m_meshPassHandles.renderPass, m_meshPassHandles.pipeline, - pushConstants, + meshPushConstants, { sphereDrawcall }, renderTargets); + vkcv::PushConstants skyPushConstants(sizeof(glm::mat4)); + skyPushConstants.appendDrawcall(viewProjection); + + m_core.recordDrawcallsToCmdStream( + cmdStream, + m_skyPassHandles.renderPass, + m_skyPassHandles.pipeline, + skyPushConstants, + { cubeDrawcall }, + renderTargets); + m_core.prepareSwapchainImageForPresent(cmdStream); m_core.submitCommandStream(cmdStream); m_core.endFrame(); diff --git a/projects/indirect_dispatch/src/App.hpp b/projects/indirect_dispatch/src/App.hpp index d4b5387f..06697176 100644 --- a/projects/indirect_dispatch/src/App.hpp +++ b/projects/indirect_dispatch/src/App.hpp @@ -19,8 +19,11 @@ private: vkcv::Core m_core; vkcv::camera::CameraManager m_cameraManager; - MeshResources m_sphereMesh; - GraphicPassHandles m_meshPassHandles; + MeshResources m_sphereMesh; + MeshResources m_cubeMesh; + + GraphicPassHandles m_meshPassHandles; + GraphicPassHandles m_skyPassHandles; RenderTargets m_renderTargets; }; \ No newline at end of file diff --git a/projects/indirect_dispatch/src/AppSetup.cpp b/projects/indirect_dispatch/src/AppSetup.cpp index ab14c181..db7f689f 100644 --- a/projects/indirect_dispatch/src/AppSetup.cpp +++ b/projects/indirect_dispatch/src/AppSetup.cpp @@ -3,128 +3,167 @@ #include <vkcv/asset/asset_loader.hpp> #include <vkcv/shader/GLSLCompiler.hpp> -bool loadSphereMesh(vkcv::Core& core, MeshResources* outMesh) { - assert(outMesh); +bool loadMesh(vkcv::Core& core, const std::filesystem::path& path, MeshResources* outMesh) { + assert(outMesh); - vkcv::asset::Scene sphereScene; - const int meshLoadResult = vkcv::asset::loadScene("resources/models/Sphere.gltf", sphereScene); + vkcv::asset::Scene scene; + const int meshLoadResult = vkcv::asset::loadScene(path.string(), scene); - if (meshLoadResult != 1) { - vkcv_log(vkcv::LogLevel::ERROR, "Mesh loading failed"); - return false; - } + if (meshLoadResult != 1) { + vkcv_log(vkcv::LogLevel::ERROR, "Mesh loading failed"); + return false; + } - if (sphereScene.meshes.size() < 1) { - vkcv_log(vkcv::LogLevel::ERROR, "Sphere mesh scene does not contain any vertex groups"); - return false; - } - assert(!sphereScene.vertexGroups.empty()); + if (scene.meshes.size() < 1) { + vkcv_log(vkcv::LogLevel::ERROR, "Cube mesh scene does not contain any vertex groups"); + return false; + } + assert(!scene.vertexGroups.empty()); - auto& sphereVertexData = sphereScene.vertexGroups[0].vertexBuffer; - auto& sphereIndexData = sphereScene.vertexGroups[0].indexBuffer; + auto& vertexData = scene.vertexGroups[0].vertexBuffer; + auto& indexData = scene.vertexGroups[0].indexBuffer; - vkcv::Buffer vertexBuffer = core.createBuffer<uint8_t>( - vkcv::BufferType::VERTEX, - sphereVertexData.data.size(), - vkcv::BufferMemoryType::DEVICE_LOCAL); + vkcv::Buffer vertexBuffer = core.createBuffer<uint8_t>( + vkcv::BufferType::VERTEX, + vertexData.data.size(), + vkcv::BufferMemoryType::DEVICE_LOCAL); - vkcv::Buffer indexBuffer = core.createBuffer<uint8_t>( - vkcv::BufferType::INDEX, - sphereIndexData.data.size(), - vkcv::BufferMemoryType::DEVICE_LOCAL); + vkcv::Buffer indexBuffer = core.createBuffer<uint8_t>( + vkcv::BufferType::INDEX, + indexData.data.size(), + vkcv::BufferMemoryType::DEVICE_LOCAL); - vertexBuffer.fill(sphereVertexData.data); - indexBuffer.fill(sphereIndexData.data); + vertexBuffer.fill(vertexData.data); + indexBuffer.fill(indexData.data); - outMesh->vertexBuffer = vertexBuffer.getHandle(); - outMesh->indexBuffer = indexBuffer.getHandle(); + outMesh->vertexBuffer = vertexBuffer.getHandle(); + outMesh->indexBuffer = indexBuffer.getHandle(); - auto& attributes = sphereVertexData.attributes; + auto& attributes = vertexData.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); - }); + 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); + }); - const std::vector<vkcv::VertexBufferBinding> vertexBufferBindings = { - vkcv::VertexBufferBinding(static_cast<vk::DeviceSize>(attributes[0].offset), vertexBuffer.getVulkanHandle()), - vkcv::VertexBufferBinding(static_cast<vk::DeviceSize>(attributes[1].offset), vertexBuffer.getVulkanHandle()) }; + const std::vector<vkcv::VertexBufferBinding> vertexBufferBindings = { + vkcv::VertexBufferBinding(static_cast<vk::DeviceSize>(attributes[0].offset), vertexBuffer.getVulkanHandle()), + vkcv::VertexBufferBinding(static_cast<vk::DeviceSize>(attributes[1].offset), vertexBuffer.getVulkanHandle()) }; - outMesh->mesh = vkcv::Mesh(vertexBufferBindings, indexBuffer.getVulkanHandle(), sphereScene.vertexGroups[0].numIndices); + outMesh->mesh = vkcv::Mesh(vertexBufferBindings, indexBuffer.getVulkanHandle(), scene.vertexGroups[0].numIndices); - return true; + return true; } -bool loadMeshGraphicPass(vkcv::Core& core, GraphicPassHandles* outPassHandles) { - assert(outPassHandles); - - const vkcv::AttachmentDescription present_color_attachment( - vkcv::AttachmentOperation::STORE, - vkcv::AttachmentOperation::CLEAR, - core.getSwapchain().getFormat()); - - const vkcv::AttachmentDescription depth_attachment( - vkcv::AttachmentOperation::STORE, - vkcv::AttachmentOperation::CLEAR, - AppConfig::depthBufferFormat); - - vkcv::PassConfig meshPassDefinition({ present_color_attachment, depth_attachment }); - outPassHandles->renderPass = core.createPass(meshPassDefinition); - - if (!outPassHandles->renderPass) { - vkcv_log(vkcv::LogLevel::ERROR, "Error: Could not create renderpass"); - return false; - } - - vkcv::ShaderProgram meshProgram; - vkcv::shader::GLSLCompiler compiler; - - compiler.compile(vkcv::ShaderStage::VERTEX, std::filesystem::path("resources/shaders/shader.vert"), - [&meshProgram](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { - meshProgram.addShader(shaderStage, path); - }); - - compiler.compile(vkcv::ShaderStage::FRAGMENT, std::filesystem::path("resources/shaders/shader.frag"), - [&meshProgram](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { - meshProgram.addShader(shaderStage, path); - }); - - const std::vector<vkcv::VertexAttachment> vertexAttachments = meshProgram.getVertexAttachments(); - std::vector<vkcv::VertexBinding> bindings; - for (size_t i = 0; i < vertexAttachments.size(); i++) { - bindings.push_back(vkcv::VertexBinding(i, { vertexAttachments[i] })); - } - - const vkcv::VertexLayout meshVertexLayout(bindings); - - const vkcv::PipelineConfig meshPipelineConfig{ - meshProgram, - UINT32_MAX, - UINT32_MAX, - outPassHandles->renderPass, - { meshVertexLayout }, - {}, - true }; - outPassHandles->pipeline = core.createGraphicsPipeline(meshPipelineConfig); - - if (!outPassHandles->pipeline) { - vkcv_log(vkcv::LogLevel::ERROR, "Error: Could not create graphics pipeline"); - return false; - } - - return true; +bool loadGraphicPass( + vkcv::Core& core, + const std::filesystem::path vertexPath, + const std::filesystem::path fragmentPath, + const vkcv::PassConfig& passConfig, + GraphicPassHandles* outPassHandles) { + + assert(outPassHandles); + + outPassHandles->renderPass = core.createPass(passConfig); + + if (!outPassHandles->renderPass) { + vkcv_log(vkcv::LogLevel::ERROR, "Error: Could not create renderpass"); + return false; + } + + vkcv::ShaderProgram shaderProgram; + vkcv::shader::GLSLCompiler compiler; + + compiler.compile(vkcv::ShaderStage::VERTEX, vertexPath, + [&shaderProgram](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { + shaderProgram.addShader(shaderStage, path); + }); + + compiler.compile(vkcv::ShaderStage::FRAGMENT, fragmentPath, + [&shaderProgram](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { + shaderProgram.addShader(shaderStage, path); + }); + + const std::vector<vkcv::VertexAttachment> vertexAttachments = shaderProgram.getVertexAttachments(); + std::vector<vkcv::VertexBinding> bindings; + for (size_t i = 0; i < vertexAttachments.size(); i++) { + bindings.push_back(vkcv::VertexBinding(i, { vertexAttachments[i] })); + } + + const vkcv::VertexLayout vertexLayout(bindings); + + const vkcv::PipelineConfig pipelineConfig{ + shaderProgram, + UINT32_MAX, + UINT32_MAX, + outPassHandles->renderPass, + { vertexLayout }, + {}, + true }; + outPassHandles->pipeline = core.createGraphicsPipeline(pipelineConfig); + + if (!outPassHandles->pipeline) { + vkcv_log(vkcv::LogLevel::ERROR, "Error: Could not create graphics pipeline"); + return false; + } + + return true; +} + +bool loadMeshPass(vkcv::Core& core, GraphicPassHandles* outHandles) { + + assert(outHandles); + + vkcv::AttachmentDescription colorAttachment( + vkcv::AttachmentOperation::STORE, + vkcv::AttachmentOperation::CLEAR, + core.getSwapchain().getFormat()); + + vkcv::AttachmentDescription depthAttachment( + vkcv::AttachmentOperation::STORE, + vkcv::AttachmentOperation::CLEAR, + AppConfig::depthBufferFormat); + + return loadGraphicPass( + core, + "resources/shaders/mesh.vert", + "resources/shaders/mesh.frag", + vkcv::PassConfig({ colorAttachment, depthAttachment }), + outHandles); +} + +bool loadSkyPass(vkcv::Core& core, GraphicPassHandles* outHandles) { + + assert(outHandles); + + vkcv::AttachmentDescription colorAttachment( + vkcv::AttachmentOperation::STORE, + vkcv::AttachmentOperation::LOAD, + core.getSwapchain().getFormat()); + + vkcv::AttachmentDescription depthAttachment( + vkcv::AttachmentOperation::DONT_CARE, + vkcv::AttachmentOperation::LOAD, + AppConfig::depthBufferFormat); + + return loadGraphicPass( + core, + "resources/shaders/sky.vert", + "resources/shaders/sky.frag", + vkcv::PassConfig({ colorAttachment, depthAttachment }), + outHandles); } RenderTargets createRenderTargets(vkcv::Core& core, const uint32_t width, const uint32_t height) { - RenderTargets targets; + RenderTargets targets; - targets.depthBuffer = core.createImage( - AppConfig::depthBufferFormat, - width, - height, - 1, - false).getHandle(); + targets.depthBuffer = core.createImage( + AppConfig::depthBufferFormat, + width, + height, + 1, + false).getHandle(); - return targets; + return targets; } \ No newline at end of file diff --git a/projects/indirect_dispatch/src/AppSetup.hpp b/projects/indirect_dispatch/src/AppSetup.hpp index 1436d134..f388ede2 100644 --- a/projects/indirect_dispatch/src/AppSetup.hpp +++ b/projects/indirect_dispatch/src/AppSetup.hpp @@ -2,21 +2,31 @@ #include <vkcv/Core.hpp> struct RenderTargets { - vkcv::ImageHandle depthBuffer; + vkcv::ImageHandle depthBuffer; }; struct GraphicPassHandles { - vkcv::PipelineHandle pipeline; - vkcv::PassHandle renderPass; + vkcv::PipelineHandle pipeline; + vkcv::PassHandle renderPass; }; struct MeshResources { - vkcv::Mesh mesh; - vkcv::BufferHandle vertexBuffer; - vkcv::BufferHandle indexBuffer; + vkcv::Mesh mesh; + vkcv::BufferHandle vertexBuffer; + vkcv::BufferHandle indexBuffer; }; -bool loadSphereMesh(vkcv::Core& core, MeshResources* outMesh); -bool loadMeshGraphicPass(vkcv::Core& core, GraphicPassHandles* outPassHandles); +// loads position and normal of the first mesh in a scene +bool loadMesh(vkcv::Core& core, const std::filesystem::path& path, MeshResources* outMesh); + +bool loadGraphicPass( + vkcv::Core& core, + const std::filesystem::path vertexPath, + const std::filesystem::path fragmentPath, + const vkcv::PassConfig& passConfig, + GraphicPassHandles* outPassHandles); + +bool loadMeshPass(vkcv::Core& core, GraphicPassHandles* outHandles); +bool loadSkyPass (vkcv::Core& core, GraphicPassHandles* outHandles); RenderTargets createRenderTargets(vkcv::Core& core, const uint32_t width, const uint32_t height); \ No newline at end of file -- GitLab