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