diff --git a/include/vkcv/Core.hpp b/include/vkcv/Core.hpp
index c7512346c9137b77c365e807b679b3950925f535..493534f77a0f930cbd0d292a504300f51ebc0f76 100644
--- a/include/vkcv/Core.hpp
+++ b/include/vkcv/Core.hpp
@@ -223,6 +223,11 @@ namespace vkcv
 			bool        supportStorage = false,
 			bool        supportColorAttachment = false);
 
+        [[nodiscard]]
+        const uint32_t getImageWidth(ImageHandle imageHandle);
+        [[nodiscard]]
+        const uint32_t getImageHeight(ImageHandle imageHandle);
+
         /** TODO:
          *   @param setDescriptions
          *   @return
diff --git a/modules/CMakeLists.txt b/modules/CMakeLists.txt
index 5edb802b3adf16878c2dec4050d8444278739026..28b2184b2a83515a514f1428733bcf8cf1499633 100644
--- a/modules/CMakeLists.txt
+++ b/modules/CMakeLists.txt
@@ -1,6 +1,7 @@
 
 # Add new modules here:
 add_subdirectory(asset_loader)
+add_subdirectory(material)
 add_subdirectory(camera)
 add_subdirectory(gui)
 add_subdirectory(shader_compiler)
diff --git a/modules/material/CMakeLists.txt b/modules/material/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..d5b654cc6d00ce77d93b4666f48b7a5097e674b3
--- /dev/null
+++ b/modules/material/CMakeLists.txt
@@ -0,0 +1,29 @@
+cmake_minimum_required(VERSION 3.16)
+project(vkcv_material)
+
+# setting c++ standard for the module
+set(CMAKE_CXX_STANDARD 17)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+
+set(vkcv_material_source ${PROJECT_SOURCE_DIR}/src)
+set(vkcv_material_include ${PROJECT_SOURCE_DIR}/include)
+
+# Add source and header files to the module
+set(vkcv_material_sources
+		${vkcv_material_include}/vkcv/material/Material.hpp
+		${vkcv_material_source}/vkcv/material/Material.cpp
+		${vkcv_material_include}/vkcv/material/PBRMaterial.hpp
+		${vkcv_material_source}/vkcv/material/PBRMaterial.cpp
+)
+
+# adding source files to the module
+add_library(vkcv_material STATIC ${vkcv_material_sources})
+
+# link the required libraries to the module
+target_link_libraries(vkcv_material vkcv ${vkcv_libraries})
+
+# including headers of dependencies and the VkCV framework
+target_include_directories(vkcv_material SYSTEM BEFORE PRIVATE ${vkcv_include} ${vkcv_includes})
+
+# add the own include directory for public headers
+target_include_directories(vkcv_material BEFORE PUBLIC ${vkcv_material_include})
diff --git a/modules/material/include/vkcv/material/Material.hpp b/modules/material/include/vkcv/material/Material.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..00b492072fa4ef8b7b41f70202d515ee4ac828fa
--- /dev/null
+++ b/modules/material/include/vkcv/material/Material.hpp
@@ -0,0 +1,14 @@
+#pragma once
+#include <vkcv/Handles.hpp>
+
+namespace vkcv::material {
+
+	class Material {
+	private:
+	public:
+		const DescriptorSetHandle m_DescriptorSetHandle;
+	protected:
+		Material(const DescriptorSetHandle& setHandle); 
+	};
+	
+}
diff --git a/modules/material/include/vkcv/material/PBRMaterial.hpp b/modules/material/include/vkcv/material/PBRMaterial.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..09a5214b0e748a09ef8caefe5bf2b1a69ecbd8e1
--- /dev/null
+++ b/modules/material/include/vkcv/material/PBRMaterial.hpp
@@ -0,0 +1,103 @@
+#pragma once
+
+#include <vector>
+
+#include <vkcv/DescriptorConfig.hpp>
+#include <vkcv/Core.hpp>
+
+
+#include "Material.hpp"
+
+namespace vkcv::material
+{
+    class PBRMaterial : Material
+    {
+    private:
+        struct vec3 {
+            float x, y, z;
+        };
+        struct vec4 {
+            float x, y, z, a;
+        };
+        PBRMaterial(const ImageHandle& colorImg,
+            const SamplerHandle& colorSmp,
+            const ImageHandle& normalImg,
+            const SamplerHandle& normalSmp,
+            const ImageHandle& metRoughImg,
+            const SamplerHandle& metRoughSmp,
+            const ImageHandle& occlusionImg,
+            const SamplerHandle& occlusionSmp,
+            const ImageHandle& emissiveImg,
+            const SamplerHandle& emissiveSmp,
+            const DescriptorSetHandle& setHandle,
+            vec4 baseColorFactor,
+            float metallicFactor,
+            float roughnessFactor,
+            float normalScale,
+            float occlusionStrength,
+            vec3 emissiveFactor) noexcept;
+
+
+    public:
+        PBRMaterial() = delete;
+        
+        const ImageHandle   m_ColorTexture;
+        const SamplerHandle m_ColorSampler;
+
+        const ImageHandle   m_NormalTexture;
+        const SamplerHandle m_NormalSampler;
+
+        const ImageHandle   m_MetRoughTexture;
+        const SamplerHandle m_MetRoughSampler;
+
+        const ImageHandle m_OcclusionTexture;
+        const SamplerHandle m_OcclusionSampler;
+
+        const ImageHandle m_EmissiveTexture;
+        const SamplerHandle m_EmissiveSampler;
+
+        //
+        const vec4 m_BaseColorFactor;
+		const float m_MetallicFactor;
+		const float m_RoughnessFactor;
+		const float m_NormalScale;
+		const float m_OcclusionStrength;
+		const vec3 m_EmissiveFactor;
+
+        /*
+        * Returns the material's necessary descriptor bindings which serves as its descriptor layout
+        * The binding is in the following order:
+        * 0 - diffuse texture
+        * 1 - diffuse sampler
+        * 2 - normal texture
+        * 3 - normal sampler
+        * 4 - metallic roughness texture
+        * 5 - metallic roughness sampler
+        * 6 - occlusion texture
+        * 7 - occlusion sampler
+        * 8 - emissive texture
+        * 9 - emissive sampler
+        */
+        static std::vector<DescriptorBinding> getDescriptorBindings() noexcept;
+
+        static PBRMaterial create(
+            vkcv::Core* core,
+            ImageHandle          &colorImg,
+            SamplerHandle        &colorSmp,
+            ImageHandle          &normalImg,
+            SamplerHandle        &normalSmp,
+            ImageHandle          &metRoughImg,
+            SamplerHandle        &metRoughSmp,
+			ImageHandle			&occlusionImg,
+			SamplerHandle		&occlusionSmp,
+			ImageHandle			&emissiveImg,
+			SamplerHandle		&emissiveSmp,
+            vec4 baseColorFactor,
+            float metallicFactor,
+            float roughnessFactor,
+            float normalScale,
+            float occlusionStrength,
+            vec3 emissiveFactor);
+
+    };
+}
\ No newline at end of file
diff --git a/modules/material/src/vkcv/material/Material.cpp b/modules/material/src/vkcv/material/Material.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9168bcfbf924e9868ceaaff74aef5d3c6b99739c
--- /dev/null
+++ b/modules/material/src/vkcv/material/Material.cpp
@@ -0,0 +1,12 @@
+
+#include "vkcv/material/Material.hpp"
+
+namespace vkcv::material {
+
+	//TODO
+
+	Material::Material(const DescriptorSetHandle& setHandle) : m_DescriptorSetHandle(setHandle)
+	{
+	}
+
+}
diff --git a/modules/material/src/vkcv/material/PBRMaterial.cpp b/modules/material/src/vkcv/material/PBRMaterial.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d27e755c06a39e369d22efc997a0b411d067c132
--- /dev/null
+++ b/modules/material/src/vkcv/material/PBRMaterial.cpp
@@ -0,0 +1,194 @@
+#include "vkcv/material/PBRMaterial.hpp"
+
+
+namespace vkcv::material
+{
+    PBRMaterial::PBRMaterial(
+        const ImageHandle& colorImg,
+        const SamplerHandle& colorSmp,
+        const ImageHandle& normalImg,
+        const SamplerHandle& normalSmp,
+        const ImageHandle& metRoughImg,
+        const SamplerHandle& metRoughSmp,
+        const ImageHandle& occlusionImg,
+        const SamplerHandle& occlusionSmp,
+        const ImageHandle& emissiveImg,
+        const SamplerHandle& emissiveSmp,
+        const DescriptorSetHandle& setHandle,
+        vec4 baseColorFactor,
+        float metallicFactor,
+        float roughnessFactor,
+        float normalScale,
+        float occlusionStrength,
+        vec3 emissiveFactor) noexcept :
+        m_ColorTexture(colorImg),
+        m_ColorSampler(colorSmp),
+        m_NormalTexture(normalImg),
+        m_NormalSampler(normalSmp),
+        m_MetRoughTexture(metRoughImg),
+        m_MetRoughSampler(metRoughSmp),
+        m_OcclusionTexture(occlusionImg),
+        m_OcclusionSampler(occlusionSmp),
+        m_EmissiveTexture(emissiveImg),
+        m_EmissiveSampler(emissiveSmp),
+        Material(setHandle),
+        m_BaseColorFactor(baseColorFactor),
+        m_MetallicFactor(metallicFactor),
+        m_RoughnessFactor(roughnessFactor),
+        m_NormalScale(normalScale),
+        m_OcclusionStrength(occlusionStrength),
+        m_EmissiveFactor(emissiveFactor)
+    {
+    }
+
+    std::vector<DescriptorBinding> PBRMaterial::getDescriptorBindings() noexcept
+    {
+		static std::vector<DescriptorBinding> bindings;
+		
+		if (bindings.empty()) {
+			bindings.emplace_back(0, DescriptorType::IMAGE_SAMPLED, 1, ShaderStage::FRAGMENT);
+			bindings.emplace_back(1, DescriptorType::SAMPLER, 1, ShaderStage::FRAGMENT);
+			bindings.emplace_back(2, DescriptorType::IMAGE_SAMPLED, 1, ShaderStage::FRAGMENT);
+			bindings.emplace_back(3, DescriptorType::SAMPLER, 1, ShaderStage::FRAGMENT);
+			bindings.emplace_back(4, DescriptorType::IMAGE_SAMPLED, 1, ShaderStage::FRAGMENT);
+			bindings.emplace_back(5, DescriptorType::SAMPLER, 1, ShaderStage::FRAGMENT);
+			bindings.emplace_back(6, DescriptorType::IMAGE_SAMPLED, 1, ShaderStage::FRAGMENT);
+			bindings.emplace_back(7, DescriptorType::SAMPLER, 1, ShaderStage::FRAGMENT);
+			bindings.emplace_back(8, DescriptorType::IMAGE_SAMPLED, 1, ShaderStage::FRAGMENT);
+			bindings.emplace_back(9, DescriptorType::SAMPLER, 1, ShaderStage::FRAGMENT);
+		}
+    	
+        return bindings;
+    }
+
+    PBRMaterial PBRMaterial::create(
+        vkcv::Core* core,
+        ImageHandle& colorImg,
+        SamplerHandle& colorSmp,
+        ImageHandle& normalImg,
+        SamplerHandle& normalSmp,
+        ImageHandle& metRoughImg,
+        SamplerHandle& metRoughSmp,
+        ImageHandle& occlusionImg,
+        SamplerHandle& occlusionSmp,
+        ImageHandle& emissiveImg,
+        SamplerHandle& emissiveSmp,
+        vec4 baseColorFactor,
+        float metallicFactor,
+        float roughnessFactor,
+        float normalScale,
+        float occlusionStrength,
+        vec3 emissiveFactor)
+    {
+        //Test if Images and samplers valid, if not use default
+         if (!colorImg) {
+            vkcv::Image defaultColor = core->createImage(vk::Format::eR8G8B8A8Srgb, 1, 1);
+            vec4 colorData{ 228, 51, 255,1 };
+            defaultColor.fill(&colorData);
+            colorImg = defaultColor.getHandle();
+        }
+        if (!normalImg) {
+            vkcv::Image defaultNormal = core->createImage(vk::Format::eR8G8B8A8Srgb, 1, 1);
+            vec4 normalData{ 0, 0, 1,0 };
+            defaultNormal.fill(&normalData);
+            normalImg = defaultNormal.getHandle();
+        }
+        if (!metRoughImg) {
+            vkcv::Image defaultRough = core->createImage(vk::Format::eR8G8B8A8Srgb, 1, 1);
+            vec4 roughData{ 228, 51, 255,1 };
+            defaultRough.fill(&roughData);
+            metRoughImg = defaultRough.getHandle();
+        }
+        if (!occlusionImg) {
+            vkcv::Image defaultOcclusion = core->createImage(vk::Format::eR8G8B8A8Srgb, 1, 1);
+            vec4 occlusionData{ 228, 51, 255,1 };
+            defaultOcclusion.fill(&occlusionData);
+            occlusionImg = defaultOcclusion.getHandle();
+        }
+        if (!emissiveImg) {
+            vkcv::Image defaultEmissive = core->createImage(vk::Format::eR8G8B8A8Srgb, 1, 1);
+            vec4 emissiveData{ 0, 0, 0,1 };
+            defaultEmissive.fill(&emissiveData);
+            emissiveImg = defaultEmissive.getHandle();
+        }
+        if (!colorSmp) {            
+            colorSmp = core->createSampler(
+                vkcv::SamplerFilterType::LINEAR,
+                vkcv::SamplerFilterType::LINEAR,
+                vkcv::SamplerMipmapMode::LINEAR,
+                vkcv::SamplerAddressMode::REPEAT
+            );            
+        }
+        if (!normalSmp) {            
+            normalSmp = core->createSampler(
+                vkcv::SamplerFilterType::LINEAR,
+                vkcv::SamplerFilterType::LINEAR,
+                vkcv::SamplerMipmapMode::LINEAR,
+                vkcv::SamplerAddressMode::REPEAT
+            );            
+        }
+        if (!metRoughSmp) {
+            metRoughSmp = core->createSampler(
+                vkcv::SamplerFilterType::LINEAR,
+                vkcv::SamplerFilterType::LINEAR,
+                vkcv::SamplerMipmapMode::LINEAR,
+                vkcv::SamplerAddressMode::REPEAT
+            );            
+        }
+        if (!occlusionSmp) {
+            occlusionSmp = core->createSampler(
+                vkcv::SamplerFilterType::LINEAR,
+                vkcv::SamplerFilterType::LINEAR,
+                vkcv::SamplerMipmapMode::LINEAR,
+                vkcv::SamplerAddressMode::REPEAT
+            );
+        }
+        if (!emissiveSmp) {
+            emissiveSmp = core->createSampler(
+                vkcv::SamplerFilterType::LINEAR,
+                vkcv::SamplerFilterType::LINEAR,
+                vkcv::SamplerMipmapMode::LINEAR,
+                vkcv::SamplerAddressMode::REPEAT
+            );
+        }
+        
+
+
+        //create descriptorset
+        vkcv::DescriptorSetHandle descriptorSetHandle = core->createDescriptorSet(getDescriptorBindings());
+        //writes
+        vkcv::DescriptorWrites setWrites;
+        setWrites.sampledImageWrites = {
+            vkcv::SampledImageDescriptorWrite(0, colorImg),
+            vkcv::SampledImageDescriptorWrite(2, normalImg),
+            vkcv::SampledImageDescriptorWrite(4, metRoughImg),
+            vkcv::SampledImageDescriptorWrite(6, occlusionImg),
+            vkcv::SampledImageDescriptorWrite(8, emissiveImg) };
+        setWrites.samplerWrites = {
+            vkcv::SamplerDescriptorWrite(1, colorSmp),
+            vkcv::SamplerDescriptorWrite(3, normalSmp),
+            vkcv::SamplerDescriptorWrite(5, metRoughSmp),
+            vkcv::SamplerDescriptorWrite(7, occlusionSmp),
+            vkcv::SamplerDescriptorWrite(9, emissiveSmp) };
+        core->writeDescriptorSet(descriptorSetHandle, setWrites);
+
+        return PBRMaterial(
+            colorImg,
+            colorSmp,
+            normalImg,
+            normalSmp,
+            metRoughImg,
+            metRoughSmp,
+            occlusionImg,
+            occlusionSmp,
+            emissiveImg,
+            emissiveSmp,
+            descriptorSetHandle,
+            baseColorFactor,
+            metallicFactor,
+            roughnessFactor,
+            normalScale,
+            occlusionStrength,
+            emissiveFactor);
+    }
+}
\ No newline at end of file
diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp
index 1492b1afa563543e6a9eef380295bcb71fef58b8..59f2cf3b652a88854b9ea4a4077f18749b9e6d51 100644
--- a/src/vkcv/Core.cpp
+++ b/src/vkcv/Core.cpp
@@ -462,6 +462,16 @@ namespace vkcv
 			supportColorAttachment);
 	}
 
+	const uint32_t Core::getImageWidth(ImageHandle imageHandle)
+	{
+		return m_ImageManager->getImageWidth(imageHandle);
+	}
+
+	const uint32_t Core::getImageHeight(ImageHandle imageHandle)
+	{
+		return m_ImageManager->getImageHeight(imageHandle);
+	}
+
     DescriptorSetHandle Core::createDescriptorSet(const std::vector<DescriptorBinding>& bindings)
     {
         return m_DescriptorManager->createDescriptorSet(bindings);