diff --git a/include/vkcv/PipelineConfig.hpp b/include/vkcv/PipelineConfig.hpp
index c17f04ee6b6bcf9ae011e2fc88d22c90f9e50809..0d29625aec6b7f607372e5f0c147ff32f229ad03 100644
--- a/include/vkcv/PipelineConfig.hpp
+++ b/include/vkcv/PipelineConfig.hpp
@@ -16,6 +16,7 @@ namespace vkcv {
 
     enum class PrimitiveTopology{PointList, LineList, TriangleList };
 	enum class CullMode{ None, Front, Back };
+    enum class DepthTest { None, Less, LessEqual, Greater, GreatherEqual, Equal };
 
     struct PipelineConfig {
         ShaderProgram                           m_ShaderProgram;
@@ -25,11 +26,13 @@ namespace vkcv {
         VertexLayout                            m_VertexLayout;
         std::vector<vk::DescriptorSetLayout>    m_DescriptorLayouts;
         bool                                    m_UseDynamicViewport;
-        bool                                    m_UseConservativeRasterization = false;
-        PrimitiveTopology                       m_PrimitiveTopology = PrimitiveTopology::TriangleList;
-        bool                                    m_EnableDepthClamping = false;
-        Multisampling                           m_multisampling = Multisampling::None;
-        CullMode                                m_culling = CullMode::None;
+        bool                                    m_UseConservativeRasterization  = false;
+        PrimitiveTopology                       m_PrimitiveTopology             = PrimitiveTopology::TriangleList;
+        bool                                    m_EnableDepthClamping           = false;
+        Multisampling                           m_multisampling                 = Multisampling::None;
+        CullMode                                m_culling                       = CullMode::None;
+        DepthTest                               m_depthTest                     = DepthTest::LessEqual;
+        bool                                    m_depthWrite              = true;
     };
 
 }
\ No newline at end of file
diff --git a/projects/voxelization/resources/shaders/depthPrepass.frag b/projects/voxelization/resources/shaders/depthPrepass.frag
new file mode 100644
index 0000000000000000000000000000000000000000..65592d2cfe161b8522de1a0c3e68fa1d6afa80be
--- /dev/null
+++ b/projects/voxelization/resources/shaders/depthPrepass.frag
@@ -0,0 +1,7 @@
+#version 450
+#extension GL_ARB_separate_shader_objects : enable
+#extension GL_GOOGLE_include_directive : enable
+
+void main()	{
+
+}
\ No newline at end of file
diff --git a/projects/voxelization/resources/shaders/depthPrepass.vert b/projects/voxelization/resources/shaders/depthPrepass.vert
new file mode 100644
index 0000000000000000000000000000000000000000..d800c547368c4f2126c880534276a3be3cf336f5
--- /dev/null
+++ b/projects/voxelization/resources/shaders/depthPrepass.vert
@@ -0,0 +1,14 @@
+#version 450
+#extension GL_ARB_separate_shader_objects : enable
+
+#extension GL_GOOGLE_include_directive : enable
+
+layout(location = 0) in vec3 inPosition;
+
+layout( push_constant ) uniform constants{
+    mat4 mvp;
+};
+
+void main()	{
+	gl_Position = mvp * vec4(inPosition, 1.0);
+}
\ No newline at end of file
diff --git a/projects/voxelization/src/main.cpp b/projects/voxelization/src/main.cpp
index 59b2d9fb3460ab6f1e9a8b59b9ce422b83c4a87c..fa2b921d9eb88a6f526617e95ec5e5f66bbe808b 100644
--- a/projects/voxelization/src/main.cpp
+++ b/projects/voxelization/src/main.cpp
@@ -118,11 +118,12 @@ int main(int argc, const char** argv) {
 	
 	const vk::Format depthBufferFormat = vk::Format::eD32Sfloat;
 	const vkcv::AttachmentDescription depth_attachment(
-		vkcv::AttachmentOperation::STORE,
-		vkcv::AttachmentOperation::CLEAR,
+		vkcv::AttachmentOperation::DONT_CARE,
+		vkcv::AttachmentOperation::LOAD,
 		depthBufferFormat
 	);
-
+	
+	// forward shading config
 	vkcv::PassConfig forwardPassDefinition({ color_attachment, depth_attachment }, msaa);
 	vkcv::PassHandle forwardPass = core.createPass(forwardPassDefinition);
 
@@ -149,6 +150,48 @@ int main(int argc, const char** argv) {
 	vkcv::DescriptorSetHandle forwardShadingDescriptorSet = 
 		core.createDescriptorSet({ forwardProgram.getReflectedDescriptors()[0] });
 
+	// depth prepass config
+	vkcv::ShaderProgram depthPrepassShader;
+	compiler.compile(vkcv::ShaderStage::VERTEX, std::filesystem::path("resources/shaders/depthPrepass.vert"),
+		[&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
+		depthPrepassShader.addShader(shaderStage, path);
+	});
+	compiler.compile(vkcv::ShaderStage::FRAGMENT, std::filesystem::path("resources/shaders/depthPrepass.frag"),
+		[&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
+		depthPrepassShader.addShader(shaderStage, path);
+	});
+
+	const std::vector<vkcv::VertexAttachment> prepassVertexAttachments = depthPrepassShader.getVertexAttachments();
+
+	std::vector<vkcv::VertexBinding> prepassVertexBindings;
+	for (size_t i = 0; i < prepassVertexAttachments.size(); i++) {
+		prepassVertexBindings.push_back(vkcv::VertexBinding(i, { prepassVertexAttachments[i] }));
+	}
+	const vkcv::VertexLayout prepassVertexLayout(prepassVertexBindings);
+
+	const vkcv::AttachmentDescription prepassAttachment(
+		vkcv::AttachmentOperation::STORE,
+		vkcv::AttachmentOperation::CLEAR,
+		depthBufferFormat);
+
+	vkcv::PassConfig prepassPassDefinition({ prepassAttachment }, msaa);
+	vkcv::PassHandle prepassPass = core.createPass(prepassPassDefinition);
+
+	vkcv::PipelineConfig prepassPipelineConfig{
+		depthPrepassShader,
+		windowWidth,
+		windowHeight,
+		prepassPass,
+		vertexLayout,
+		{},
+		true};
+	prepassPipelineConfig.m_culling         = vkcv::CullMode::Back;
+	prepassPipelineConfig.m_multisampling   = msaa;
+	prepassPipelineConfig.m_depthTest       = vkcv::DepthTest::LessEqual;
+
+	vkcv::PipelineHandle prepassPipeline = core.createGraphicsPipeline(prepassPipelineConfig);
+
+	// create descriptor sets
 	vkcv::SamplerHandle colorSampler = core.createSampler(
 		vkcv::SamplerFilterType::LINEAR,
 		vkcv::SamplerFilterType::LINEAR,
@@ -156,7 +199,6 @@ int main(int argc, const char** argv) {
 		vkcv::SamplerAddressMode::REPEAT
 	);
 
-	// create descriptor sets
 	std::vector<vkcv::DescriptorSetHandle> materialDescriptorSets;
 	std::vector<vkcv::Image> sceneImages;
 
@@ -234,6 +276,8 @@ int main(int argc, const char** argv) {
 	};
     forwardPipelineConfig.m_culling         = vkcv::CullMode::Back;
 	forwardPipelineConfig.m_multisampling   = msaa;
+	forwardPipelineConfig.m_depthTest       = vkcv::DepthTest::Equal;
+	forwardPipelineConfig.m_depthWrite      = false;
 	
 	vkcv::PipelineHandle forwardPipeline = core.createGraphicsPipeline(forwardPipelineConfig);
 	
@@ -312,11 +356,13 @@ int main(int argc, const char** argv) {
 	}
 
 	std::vector<vkcv::DrawcallInfo> drawcalls;
+	std::vector<vkcv::DrawcallInfo> prepassDrawcalls;
 	for (int i = 0; i < meshes.size(); i++) {
 
 		drawcalls.push_back(vkcv::DrawcallInfo(meshes[i], { 
 			vkcv::DescriptorSetUsage(0, core.getDescriptorSet(forwardShadingDescriptorSet).vulkanHandle),
 			vkcv::DescriptorSetUsage(1, core.getDescriptorSet(perMeshDescriptorSets[i]).vulkanHandle) }));
+		prepassDrawcalls.push_back(vkcv::DrawcallInfo(meshes[i], {}));
 	}
 
 	vkcv::SamplerHandle voxelSampler = core.createSampler(
@@ -440,9 +486,26 @@ int main(int argc, const char** argv) {
 			modelMatrices,
 			perMeshDescriptorSets);
 
-		// main pass
+		// depth prepass
 		const glm::mat4 viewProjectionCamera = cameraManager.getActiveCamera().getMVP();
 
+		std::vector<glm::mat4> prepassMatrices;
+		for (const auto& m : modelMatrices) {
+			prepassMatrices.push_back(viewProjectionCamera * m);
+		}
+
+		const vkcv::PushConstantData            prepassPushConstantData((void*)prepassMatrices.data(), sizeof(glm::mat4));
+		const std::vector<vkcv::ImageHandle>    prepassRenderTargets = { depthBuffer };
+
+		core.recordDrawcallsToCmdStream(
+			cmdStream,
+			prepassPass,
+			prepassPipeline,
+			prepassPushConstantData,
+			prepassDrawcalls,
+			prepassRenderTargets);
+
+		// main pass
 		std::vector<std::array<glm::mat4, 2>> mainPassMatrices;
 		for (const auto& m : modelMatrices) {
 			mainPassMatrices.push_back({ viewProjectionCamera * m, m });
diff --git a/src/vkcv/PipelineManager.cpp b/src/vkcv/PipelineManager.cpp
index 621abb0a5659d572b22ce11eb38adeb5e2297a4c..1b05269a34f90d2df0f218dd6155c2ba85164db7 100644
--- a/src/vkcv/PipelineManager.cpp
+++ b/src/vkcv/PipelineManager.cpp
@@ -51,6 +51,18 @@ namespace vkcv
         }
     }
 
+    vk::CompareOp depthTestToVkCompareOp(DepthTest depthTest) {
+        switch (depthTest) {
+        case(DepthTest::None):          return vk::CompareOp::eAlways;
+        case(DepthTest::Less):          return vk::CompareOp::eLess;
+        case(DepthTest::LessEqual):     return vk::CompareOp::eLessOrEqual;
+        case(DepthTest::Greater):       return vk::CompareOp::eGreater;
+        case(DepthTest::GreatherEqual): return vk::CompareOp::eGreaterOrEqual;
+        case(DepthTest::Equal):         return vk::CompareOp::eEqual;
+        default: vkcv_log(vkcv::LogLevel::ERROR, "Unknown depth test enum"); return vk::CompareOp::eAlways;
+        }
+    }
+
     PipelineHandle PipelineManager::createPipeline(const PipelineConfig &config, PassManager& passManager)
     {
 		const vk::RenderPass &pass = passManager.getVkPass(config.m_PassHandle);
@@ -228,9 +240,9 @@ namespace vkcv
 	
 		const vk::PipelineDepthStencilStateCreateInfo depthStencilCreateInfo(
 				vk::PipelineDepthStencilStateCreateFlags(),
-				true,
-				true,
-				vk::CompareOp::eLessOrEqual,
+				config.m_depthTest != DepthTest::None,
+				config.m_depthWrite,
+				depthTestToVkCompareOp(config.m_depthTest),
 				false,
 				false,
 				{},