diff --git a/config/Sources.cmake b/config/Sources.cmake
index 3254368f17d92549800af7ecb614b179df1ba16f..ac49dac1a030be3b3dff1c4f6dc3339b1baca422 100644
--- a/config/Sources.cmake
+++ b/config/Sources.cmake
@@ -53,7 +53,7 @@ set(vkcv_sources
         
         ${vkcv_source}/vkcv/Framebuffer.hpp
         ${vkcv_source}/vkcv/Framebuffer.cpp
-		
+
 		${vkcv_include}/vkcv/VertexLayout.hpp
 		${vkcv_source}/vkcv/VertexLayout.cpp
 
diff --git a/include/vkcv/Core.hpp b/include/vkcv/Core.hpp
index 66db4776d053352d8ccb2eea5e09c3fb77b68561..ab0d2aca0eccbd3c6adfea191cefa2c63623b0b9 100644
--- a/include/vkcv/Core.hpp
+++ b/include/vkcv/Core.hpp
@@ -186,8 +186,9 @@ namespace vkcv
 		/**
 		 * @brief render a beautiful triangle
 		*/
-		void renderTriangle(const PassHandle renderpassHandle, const PipelineHandle pipelineHandle,
-			const int width, const int height, const size_t pushConstantSize, const void* pushConstantData);
+		void renderMesh(const PassHandle renderpassHandle, const PipelineHandle pipelineHandle,
+			const int width, const int height, const size_t pushConstantSize, const void* pushConstantData, 
+			const BufferHandle vertexBuffer, const BufferHandle indexBuffer, const size_t indexCount);
 
 		/**
 		 * @brief end recording and present image
diff --git a/include/vkcv/PipelineConfig.hpp b/include/vkcv/PipelineConfig.hpp
index 1ad6be8d1979c8a89f7de9dbe24ff13b5f5bb3fa..26ad7053d5a732968093b0f8ffb2c23a0d70255d 100644
--- a/include/vkcv/PipelineConfig.hpp
+++ b/include/vkcv/PipelineConfig.hpp
@@ -1,12 +1,10 @@
+#pragma once
 /**
  * @authors Mara Vogt, Mark Mints
  * @file src/vkcv/Pipeline.hpp
  * @brief Pipeline class to handle shader stages
  */
 
-#ifndef VKCV_PIPELINECONFIG_HPP
-#define VKCV_PIPELINECONFIG_HPP
-
 #include <vector>
 #include <cstdint>
 #include "vkcv/Handles.hpp"
@@ -39,5 +37,4 @@ namespace vkcv {
         PassHandle m_PassHandle;
     };
 
-}
-#endif //VKCV_PIPELINECONFIG_HPP
+}
\ No newline at end of file
diff --git a/include/vkcv/VertexLayout.hpp b/include/vkcv/VertexLayout.hpp
index f9579b5d7dfa8127d592532f55fd569cacb505c9..fceaa9cf5498f068b5c767534be0957fed96a033 100644
--- a/include/vkcv/VertexLayout.hpp
+++ b/include/vkcv/VertexLayout.hpp
@@ -3,6 +3,7 @@
 #include <unordered_map>
 #include <vector>
 #include <iostream>
+#include <vulkan/vulkan.hpp>
 
 namespace vkcv{
     enum class VertexFormat{
@@ -33,5 +34,6 @@ namespace vkcv{
         uint32_t stride;
     };
 
-
+	// currently assuming default 32 bit formats, no lower precision or normalized variants supported
+	vk::Format vertexFormatToVulkanFormat(const VertexFormat format);
 }
\ No newline at end of file
diff --git a/projects/first_mesh/CMakeLists.txt b/projects/first_mesh/CMakeLists.txt
index ae9c5604cb83c6f3a16773e896521117460839f7..eb0f028db38707272f9fbcf61662633f2868eedc 100644
--- a/projects/first_mesh/CMakeLists.txt
+++ b/projects/first_mesh/CMakeLists.txt
@@ -22,7 +22,7 @@ if(MSVC)
 endif()
 
 # including headers of dependencies and the VkCV framework
-target_include_directories(first_mesh SYSTEM BEFORE PRIVATE ${vkcv_include} ${vkcv_includes} ${vkcv_asset_loader_include})
+target_include_directories(first_mesh 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(first_mesh vkcv ${vkcv_libraries} vkcv_asset_loader ${vkcv_asset_loader_libraries})
+target_link_libraries(first_mesh vkcv ${vkcv_libraries} vkcv_asset_loader ${vkcv_asset_loader_libraries} vkcv_camera)
diff --git a/projects/first_mesh/resources/shaders/compile.bat b/projects/first_mesh/resources/shaders/compile.bat
new file mode 100644
index 0000000000000000000000000000000000000000..b4521235c40fe5fb163bab874560c2f219b7517f
--- /dev/null
+++ b/projects/first_mesh/resources/shaders/compile.bat
@@ -0,0 +1,3 @@
+%VULKAN_SDK%\Bin32\glslc.exe shader.vert -o vert.spv
+%VULKAN_SDK%\Bin32\glslc.exe shader.frag -o frag.spv
+pause
\ No newline at end of file
diff --git a/projects/first_mesh/resources/shaders/frag.spv b/projects/first_mesh/resources/shaders/frag.spv
new file mode 100644
index 0000000000000000000000000000000000000000..cb13e606fc0041e24ff6a63c0ec7dcca466732aa
Binary files /dev/null and b/projects/first_mesh/resources/shaders/frag.spv differ
diff --git a/projects/first_mesh/resources/shaders/shader.frag b/projects/first_mesh/resources/shaders/shader.frag
new file mode 100644
index 0000000000000000000000000000000000000000..d26446a73020111695aa2c86166205796dfa5e44
--- /dev/null
+++ b/projects/first_mesh/resources/shaders/shader.frag
@@ -0,0 +1,9 @@
+#version 450
+#extension GL_ARB_separate_shader_objects : enable
+
+layout(location = 0) in vec3 fragColor;
+layout(location = 0) out vec4 outColor;
+
+void main()	{
+	outColor = vec4(fragColor, 1.0);
+}
\ No newline at end of file
diff --git a/projects/first_mesh/resources/shaders/shader.vert b/projects/first_mesh/resources/shaders/shader.vert
new file mode 100644
index 0000000000000000000000000000000000000000..e6c0e3d6bafda35e90a6bfd849a211e2b6de0f9c
--- /dev/null
+++ b/projects/first_mesh/resources/shaders/shader.vert
@@ -0,0 +1,27 @@
+#version 450
+#extension GL_ARB_separate_shader_objects : enable
+
+layout(location = 0) in vec3 position;
+
+layout(location = 0) out vec3 fragColor;
+
+layout( push_constant ) uniform constants{
+    mat4 mvp;
+};
+
+void main()	{
+    vec3 positions[3] = {
+        vec3(-0.5, 0.5, -1),
+        vec3( 0.5, 0.5, -1),
+        vec3(0, -0.5, -1)
+    };
+    
+    vec3 colors[3] = {
+        vec3(1, 0, 0),
+        vec3(0, 1, 0),
+        vec3(0, 0, 1)
+    };
+
+	gl_Position = mvp * vec4(position, 1.0);
+	fragColor = colors[gl_VertexIndex % 3];
+}
\ No newline at end of file
diff --git a/projects/first_mesh/resources/shaders/vert.spv b/projects/first_mesh/resources/shaders/vert.spv
new file mode 100644
index 0000000000000000000000000000000000000000..74722f38ff0584d51d4a966c748b69a4d3f1d3cb
Binary files /dev/null and b/projects/first_mesh/resources/shaders/vert.spv differ
diff --git a/projects/first_mesh/src/main.cpp b/projects/first_mesh/src/main.cpp
index b37429e1f7080b70aaab514125f86fbe03f329b5..e1cbc40e747f9f68e44db6ea9ca3dcd556148a4b 100644
--- a/projects/first_mesh/src/main.cpp
+++ b/projects/first_mesh/src/main.cpp
@@ -1,76 +1,101 @@
 #include <iostream>
-#include <stdio.h>
+#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";
+
+	const int windowWidth = 800;
+	const int windowHeight = 600;
+	vkcv::Window window = vkcv::Window::create(
+		applicationName,
+		windowWidth,
+		windowHeight,
+		false
+	);
+
+	vkcv::CameraManager cameraManager(window, windowWidth, windowHeight);
+
+	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" }
+	);
+
 	vkcv::asset::Mesh mesh;
-	
-	const char *path = argc > 1 ? argv[1] : "resources/cube/cube.gltf";
+
+	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 {
+	}
+	else {
 		std::cout << "Mesh loading failed: " << result << std::endl;
 		return 1;
 	}
 
-	/* Demonstration of how to use the vkcv::asset::Mesh struct. */
-	const char *primitive_modes[] = {
-		"points", "lines", "line loop", "line strip", "triangles",
-		"triangle strip", "triangle fan"
-	};
-	const char *primitive_types[] = {
-		"unknown", "position", "normal", "texcoord0"
-	};
-	printf("Mesh %s (%s) has %lu vertex group(s) and %lu material(s):\n",
-			mesh.name.c_str(), path, mesh.vertexGroups.size(),
-			mesh.materials.size());
-	for (size_t i = 0; i < mesh.vertexGroups.size(); i++) {
-		printf("--- vertex group %lu ---\n", i);
-		const auto &vg = mesh.vertexGroups[i];
-		printf("primitive mode: %d (%s)\n", vg.mode,
-				primitive_modes[vg.mode]);
-		printf("index buffer: %lu bytes for %lu indices ",
-				vg.indexBuffer.data.size(), vg.numIndices);
-		const auto itype = vg.indexBuffer.type;
-		printf("(%s @ %p)\n",
-				itype == vkcv::asset::UINT32 ? "UINT32" :
-				itype == vkcv::asset::UINT16 ? "UINT16" :
-				"UINT8", vg.indexBuffer.data.data());
-		printf("\tindices: ");
-		const size_t n = vg.numIndices;
-		if (vg.indexBuffer.type == vkcv::asset::UINT32) {
-			uint32_t *idx = (uint32_t*)vg.indexBuffer.data.data();
-			for (size_t j = 0; j < n; j++) printf("%u ", idx[j]);
-		} else
-		if (vg.indexBuffer.type == vkcv::asset::UINT16) {
-			uint16_t *idx = (uint16_t*)vg.indexBuffer.data.data();
-			for (size_t j = 0; j < n; j++) printf("%u ", idx[j]);
-		} else
-		if (vg.indexBuffer.type == vkcv::asset::UINT8) {
-			uint8_t *idx = (uint8_t*)vg.indexBuffer.data.data();
-			for (size_t j = 0; j < n; j++) printf("%u ", idx[j]);
-		} else {
-			fprintf(stderr, "ERROR Invalid IndexType: %d\n",
-					vg.indexBuffer.type);
-			return 0;
-		}
-		printf("\n");
-		printf("vertex buffer: %lu bytes for %lu vertices with %lu "
-				"attributes (starting at %p)\n",
-				vg.vertexBuffer.data.size(), vg.numVertices,
-				vg.vertexBuffer.attributes.size(),
-				vg.vertexBuffer.data.data());
-		printf("attributes:\toffset\tlength\tstride\tcomponents\n");
-		for (const auto att : vg.vertexBuffer.attributes) {
-			printf("%11s\t%u\t%u\t%u\t%hhux%hu\n",
-					primitive_types[att.type],
-					att.offset, att.length, att.stride,
-					att.componentCount, att.componentType);
-		}
+	assert(mesh.vertexGroups.size() > 0);
+	const size_t vertexBufferSize = mesh.vertexGroups[0].vertexBuffer.data.size();
+	auto vertexBuffer = core.createBuffer<uint8_t>(vkcv::BufferType::VERTEX, vertexBufferSize, vkcv::BufferMemoryType::DEVICE_LOCAL);
+	vertexBuffer.fill(mesh.vertexGroups[0].vertexBuffer.data.data(), vertexBufferSize);
+
+	const size_t indexBufferSize = mesh.vertexGroups[0].indexBuffer.data.size();
+	auto indexBuffer = core.createBuffer<uint8_t>(vkcv::BufferType::INDEX, indexBufferSize, vkcv::BufferMemoryType::DEVICE_LOCAL);
+	indexBuffer.fill(mesh.vertexGroups[0].indexBuffer.data.data(), indexBufferSize);
+
+	// an example attachment for passes that output to the window
+	const vkcv::AttachmentDescription present_color_attachment(
+		vkcv::AttachmentLayout::UNDEFINED,
+		vkcv::AttachmentLayout::COLOR_ATTACHMENT,
+		vkcv::AttachmentLayout::PRESENTATION,
+		vkcv::AttachmentOperation::STORE,
+		vkcv::AttachmentOperation::CLEAR,
+		core.getSwapchainImageFormat());
+
+	vkcv::PassConfig trianglePassDefinition({ present_color_attachment });
+	vkcv::PassHandle trianglePass = core.createPass(trianglePassDefinition);
+
+	if (!trianglePass) {
+		std::cout << "Error. Could not create renderpass. Exiting." << std::endl;
+		return EXIT_FAILURE;
 	}
+
+	vkcv::ShaderProgram triangleShaderProgram{};
+	triangleShaderProgram.addShader(vkcv::ShaderStage::VERTEX, std::filesystem::path("resources/shaders/vert.spv"));
+	triangleShaderProgram.addShader(vkcv::ShaderStage::FRAGMENT, std::filesystem::path("resources/shaders/frag.spv"));
+	triangleShaderProgram.reflectShader(vkcv::ShaderStage::VERTEX);
+	triangleShaderProgram.reflectShader(vkcv::ShaderStage::FRAGMENT);
+
+	const vkcv::PipelineConfig trianglePipelineDefinition(triangleShaderProgram, windowWidth, windowHeight, trianglePass);
+	vkcv::PipelineHandle trianglePipeline = core.createGraphicsPipeline(trianglePipelineDefinition);
 	
+	if (!trianglePipeline) {
+		std::cout << "Error. Could not create graphics pipeline. Exiting." << std::endl;
+		return EXIT_FAILURE;
+	}
+
+	auto start = std::chrono::system_clock::now();
+	while (window.isWindowOpen()) {
+		core.beginFrame();
+		window.pollEvents();
+		auto end = std::chrono::system_clock::now();
+		auto deltatime = end - start;
+		start = end;
+		cameraManager.getCamera().updateView(std::chrono::duration<double>(deltatime).count());
+		const glm::mat4 mvp = cameraManager.getCamera().getProjection() * cameraManager.getCamera().getView();
+
+		core.renderMesh(trianglePass, trianglePipeline, windowWidth, windowHeight, sizeof(mvp), &mvp, vertexBuffer.getHandle(), indexBuffer.getHandle(), mesh.vertexGroups[0].numIndices);
+		core.endFrame();
+	}
 	return 0;
 }
diff --git a/projects/first_triangle/src/main.cpp b/projects/first_triangle/src/main.cpp
index 78502661a5932804d622ffb25edc7cbd6828bfa4..8fcbf76f10e5749435c0fb4c8f3b5d04418bd471 100644
--- a/projects/first_triangle/src/main.cpp
+++ b/projects/first_triangle/src/main.cpp
@@ -40,15 +40,19 @@ int main(int argc, const char** argv) {
 	
 	const size_t n = 5027;
 	
-	auto buffer = core.createBuffer<vec3>(vkcv::BufferType::VERTEX, n, vkcv::BufferMemoryType::DEVICE_LOCAL);
-	vec3 vec_data [n];
-	
+	auto testBuffer = core.createBuffer<vec3>(vkcv::BufferType::VERTEX, n, vkcv::BufferMemoryType::DEVICE_LOCAL);
+	vec3 vec_data[n];
+
 	for (size_t i = 0; i < n; i++) {
 		vec_data[i] = { 42, static_cast<float>(i), 7 };
 	}
-	
-	buffer.fill(vec_data);
-	
+
+	testBuffer.fill(vec_data);
+
+	auto triangleIndexBuffer = core.createBuffer<uint16_t>(vkcv::BufferType::INDEX, n, vkcv::BufferMemoryType::DEVICE_LOCAL);
+	uint16_t indices[3] = { 0, 1, 2 };
+	triangleIndexBuffer.fill(&indices[0], sizeof(indices));
+
 	/*vec3* m = buffer.map();
 	m[0] = { 0, 0, 0 };
 	m[1] = { 0, 0, 0 };
@@ -143,7 +147,7 @@ int main(int argc, const char** argv) {
         cameraManager.getCamera().updateView(std::chrono::duration<double>(deltatime).count());
 		const glm::mat4 mvp = cameraManager.getCamera().getProjection() * cameraManager.getCamera().getView();
 
-	    core.renderTriangle(trianglePass, trianglePipeline, windowWidth, windowHeight, sizeof(mvp), &mvp);
+	    core.renderMesh(trianglePass, trianglePipeline, windowWidth, windowHeight, sizeof(mvp), &mvp, testBuffer.getHandle(), triangleIndexBuffer.getHandle(), 3);
 	    core.endFrame();
 	}
 	return 0;
diff --git a/src/vkcv/BufferManager.cpp b/src/vkcv/BufferManager.cpp
index afff7d4b3e3fc78a6dbb7535162857f21812721c..e27338d837e89b5a9442c4ba2dff2061bf0e0f53 100644
--- a/src/vkcv/BufferManager.cpp
+++ b/src/vkcv/BufferManager.cpp
@@ -69,6 +69,9 @@ namespace vkcv {
 			case BufferType::STAGING:
 				usageFlags = vk::BufferUsageFlagBits::eTransferSrc;
 				break;
+			case BufferType::INDEX:
+				usageFlags = vk::BufferUsageFlagBits::eIndexBuffer;
+				break;
 			default:
 				// TODO: maybe an issue
 				break;
diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp
index 0ee414fb974676b1d2df820e69218f5bb247341b..13800254d78cb679c81d58a003089aa961986937 100644
--- a/src/vkcv/Core.cpp
+++ b/src/vkcv/Core.cpp
@@ -162,8 +162,9 @@ namespace vkcv
 		destroyTemporaryFramebuffers();
 	}
 
-	void Core::renderTriangle(const PassHandle renderpassHandle, const PipelineHandle pipelineHandle, 
-		const int width, const int height, const size_t pushConstantSize, const void *pushConstantData) {
+	void Core::renderMesh(const PassHandle renderpassHandle, const PipelineHandle pipelineHandle, 
+		const int width, const int height, const size_t pushConstantSize, const void *pushConstantData,
+		const BufferHandle vertexBuffer, const BufferHandle indexBuffer, const size_t indexCount) {
 
 		if (m_currentSwapchainImageIndex == std::numeric_limits<uint32_t>::max()) {
 			return;
@@ -174,6 +175,8 @@ namespace vkcv
 		const vk::Pipeline pipeline		= m_PipelineManager->getVkPipeline(pipelineHandle);
         const vk::PipelineLayout pipelineLayout = m_PipelineManager->getVkPipelineLayout(pipelineHandle);
 		const vk::Rect2D renderArea(vk::Offset2D(0, 0), vk::Extent2D(width, height));
+		const vk::Buffer vulkanVertexBuffer	= m_BufferManager->getBuffer(vertexBuffer);
+		const vk::Buffer vulkanIndexBuffer	= m_BufferManager->getBuffer(indexBuffer);
 
 		const vk::Framebuffer framebuffer = createFramebuffer(m_Context.getDevice(), renderpass, width, height, imageView);
 		m_TemporaryFramebuffers.push_back(framebuffer);
@@ -181,7 +184,8 @@ namespace vkcv
 		SubmitInfo submitInfo;
 		submitInfo.queueType = QueueType::Graphics;
 		submitInfo.signalSemaphores = { m_SyncResources.renderFinished };
-		submitCommands(submitInfo, [renderpass, renderArea, imageView, framebuffer, pipeline, pipelineLayout, pushConstantSize, pushConstantData](const vk::CommandBuffer& cmdBuffer) {
+		submitCommands(submitInfo, [renderpass, renderArea, imageView, framebuffer, pipeline, pipelineLayout, 
+			pushConstantSize, pushConstantData, vulkanVertexBuffer, indexCount, vulkanIndexBuffer](const vk::CommandBuffer& cmdBuffer) {
 
 			const std::array<float, 4> clearColor = { 0.f, 0.f, 0.f, 1.f };
 			const vk::ClearValue clearValues(clearColor);
@@ -191,8 +195,11 @@ namespace vkcv
 			cmdBuffer.beginRenderPass(beginInfo, subpassContents, {});
 
 			cmdBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline, {});
+			
+			cmdBuffer.bindVertexBuffers(0, (vulkanVertexBuffer), { 0 });
+			cmdBuffer.bindIndexBuffer(vulkanIndexBuffer, 0, vk::IndexType::eUint16);	//FIXME: choose proper size
             cmdBuffer.pushConstants(pipelineLayout, vk::ShaderStageFlagBits::eAll, 0, pushConstantSize, pushConstantData);
-			cmdBuffer.draw(3, 1, 0, 0, {});
+			cmdBuffer.drawIndexed(indexCount, 1, 0, 0, {});
 			cmdBuffer.endRenderPass();
 		}, nullptr);
 	}
diff --git a/src/vkcv/PipelineManager.cpp b/src/vkcv/PipelineManager.cpp
index c253aafd0438a64b2312fc4737d9b52d2b37f2e8..8b6202eb901f26c84585597e327c297902e54b03 100644
--- a/src/vkcv/PipelineManager.cpp
+++ b/src/vkcv/PipelineManager.cpp
@@ -67,15 +67,30 @@ namespace vkcv
         );
 
         // vertex input state
-        vk::VertexInputBindingDescription vertexInputBindingDescription(0, 12, vk::VertexInputRate::eVertex);
-        vk::VertexInputAttributeDescription vertexInputAttributeDescription(0, 0, vk::Format::eR32G32B32Sfloat, 0);
 
+        // Fill up VertexInputBindingDescription and VertexInputAttributeDescription Containers
+        std::vector<vk::VertexInputBindingDescription> vertexBindingDescriptions;
+        std::vector<vk::VertexInputAttributeDescription> vertexAttributeDescriptions;
+
+        VertexLayout layout = config.m_ShaderProgram.getVertexLayout();
+        std::unordered_map<uint32_t, VertexInputAttachment> attachments = layout.attachmentMap;
+
+        for (auto& attachment: attachments) {
+            uint32_t location = attachment.second.location;
+            uint32_t binding = attachment.second.binding;
+            uint32_t offset = attachment.second.offset;
+            vk::Format vertexFormat = vertexFormatToVulkanFormat(attachment.second.format);
+            vertexBindingDescriptions.push_back({binding, layout.stride, vk::VertexInputRate::eVertex}); // TODO: What's about the input rate?
+            vertexAttributeDescriptions.push_back({location, binding, vk::Format::eR32G32B32Sfloat, offset});
+        }
+
+        // Handover Containers to PipelineVertexInputStateCreateIngo Struct
         vk::PipelineVertexInputStateCreateInfo pipelineVertexInputStateCreateInfo(
-                {},			// no vertex input until vertex buffer is implemented
-                0,			// 1,
-                nullptr,	// &vertexInputBindingDescription,
-                0,			// 1,
-                nullptr		// &vertexInputAttributeDescription
+                {},
+                vertexBindingDescriptions.size(),
+                vertexBindingDescriptions.data(),
+                vertexAttributeDescriptions.size(),
+                vertexAttributeDescriptions.data()
         );
 
         // input assembly state
diff --git a/src/vkcv/VertexLayout.cpp b/src/vkcv/VertexLayout.cpp
index 88c9406bc321a76b48df60dae51486e39a4160de..ef2fedf6fe85a35df40a284554df40659b23470c 100644
--- a/src/vkcv/VertexLayout.cpp
+++ b/src/vkcv/VertexLayout.cpp
@@ -50,4 +50,18 @@ namespace vkcv {
         }
     }
 
+	vk::Format vertexFormatToVulkanFormat(const VertexFormat format) {
+		switch (format) {
+			case VertexFormat::FLOAT	: return vk::Format::eR32Sfloat;
+			case VertexFormat::FLOAT2	: return vk::Format::eR32G32Sfloat;
+			case VertexFormat::FLOAT3	: return vk::Format::eR32G32B32Sfloat;
+			case VertexFormat::FLOAT4	: return vk::Format::eR32G32B32A32Sfloat;
+			case VertexFormat::INT		: return vk::Format::eR32Sint;
+			case VertexFormat::INT2		: return vk::Format::eR32G32Sint;
+			case VertexFormat::INT3		: return vk::Format::eR32G32B32Sint;
+			case VertexFormat::INT4		: return vk::Format::eR32G32B32A32Sint;
+			default: std::cerr << "Warning: Unknown vertex format" << std::endl; return vk::Format::eUndefined;
+		}
+	}
+
 }
\ No newline at end of file