diff --git a/projects/voxelization/src/ShadowMapping.cpp b/projects/voxelization/src/ShadowMapping.cpp
index 5e4901e56a2633c4ec49448186832e87bcb90b7f..938aae1f94cb9c9b0351128510727b118c8c130a 100644
--- a/projects/voxelization/src/ShadowMapping.cpp
+++ b/projects/voxelization/src/ShadowMapping.cpp
@@ -15,8 +15,96 @@ vkcv::ShaderProgram loadShadowShader() {
 	return shader;
 }
 
+glm::mat4 computeShadowViewProjectionMatrix(
+	const glm::vec3&            lightDirection, 
+	const vkcv::camera::Camera& camera, 
+	float                       maxShadowDistance,
+	const glm::vec3&            voxelVolumeOffset,
+	float                       voxelVolumeExtent) {
+
+	const glm::vec3 cameraPos   = camera.getPosition();
+	const glm::vec3 forward     = glm::normalize(camera.getFront());
+	glm::vec3 up                = glm::normalize(camera.getUp());
+	const glm::vec3 right       = glm::normalize(glm::cross(forward, up));
+	up = glm::cross(right, forward);
+
+	const float fov         = camera.getFov();
+	const float aspectRatio = camera.getRatio();
+
+	float near;
+	float far;
+	camera.getNearFar(near, far);
+	far = std::min(maxShadowDistance, far);
+
+	const glm::vec3 nearCenter  = cameraPos + forward * near;
+	const float nearUp          = near * tan(fov * 0.5);
+	const float nearRight       = nearUp * aspectRatio;
+	
+	const glm::vec3 farCenter   = cameraPos + forward * far;
+	const float farUp           = far * tan(fov * 0.5);
+	const float farRight        = farUp * aspectRatio;
+
+	std::array<glm::vec3, 8> viewFrustumCorners = {
+		nearCenter + right * nearRight + nearUp * up,
+		nearCenter + right * nearRight - nearUp * up,
+		nearCenter - right * nearRight + nearUp * up,
+		nearCenter - right * nearRight - nearUp * up,
+
+		farCenter + right * farRight + farUp * up,
+		farCenter + right * farRight - farUp * up,
+		farCenter - right * farRight + farUp * up,
+		farCenter - right * farRight - farUp * up
+	};
+
+	std::array<glm::vec3, 8> voxelVolumeCorners = {
+		voxelVolumeOffset + voxelVolumeExtent * glm::vec3(1, 1, 1),
+		voxelVolumeOffset + voxelVolumeExtent * glm::vec3(1, 1, -1),
+		voxelVolumeOffset + voxelVolumeExtent * glm::vec3(1, -1, 1),
+		voxelVolumeOffset + voxelVolumeExtent * glm::vec3(1, -1, -1),
+
+		voxelVolumeOffset + voxelVolumeExtent * glm::vec3(-1, 1, 1),
+		voxelVolumeOffset + voxelVolumeExtent * glm::vec3(-1, 1, -1),
+		voxelVolumeOffset + voxelVolumeExtent * glm::vec3(-1, -1, 1),
+		voxelVolumeOffset + voxelVolumeExtent * glm::vec3(-1, -1, -1),
+	};
+
+	glm::vec3 minView(std::numeric_limits<float>::max());
+	glm::vec3 maxView(std::numeric_limits<float>::lowest());
+
+	const glm::mat4 view = glm::lookAt(glm::vec3(0), -lightDirection, glm::vec3(0, -1, 0));
+
+	auto getMinMaxView = [&](std::array<glm::vec3, 8> points) {
+		for (const glm::vec3& p : points) {
+			const auto& pView = glm::vec3(view * glm::vec4(p, 1));
+			minView = glm::min(minView, pView);
+			maxView = glm::max(maxView, pView);
+		}
+	};
+
+	getMinMaxView(viewFrustumCorners);
+	getMinMaxView(voxelVolumeCorners);
+
+	glm::vec3 scale  = glm::vec3(2) / (maxView - minView);
+	glm::vec3 offset = -0.5f * (maxView + minView) * scale;
+
+	glm::mat4 crop(1);
+	crop[0][0] = scale.x;
+	crop[1][1] = scale.y;
+	crop[2][2] = scale.z;
+
+	crop[3][0] = offset.x;
+	crop[3][1] = offset.y;
+	crop[3][2] = offset.z;
+
+	glm::mat4 vulkanCorrectionMatrix(1.f);
+	vulkanCorrectionMatrix[2][2] = 0.5;
+	vulkanCorrectionMatrix[3][2] = 0.5;
+
+	return vulkanCorrectionMatrix * crop * view;
+}
+
 const vk::Format    shadowMapFormat     = vk::Format::eD16Unorm;
-const uint32_t      shadowMapResolution = 1024;
+const uint32_t      shadowMapResolution = 2048;
 
 ShadowMapping::ShadowMapping(vkcv::Core* corePtr, const vkcv::VertexLayout& vertexLayout) : 
 	m_corePtr(corePtr),
@@ -55,10 +143,13 @@ void ShadowMapping::recordShadowMapRendering(
 	const vkcv::CommandStreamHandle&    cmdStream, 
 	const glm::vec2&                    lightAngleRadian,
 	const glm::vec3&                    lightColor,
-	const float                         lightStrength,
+	float                               lightStrength,
+	float                               maxShadowDistance,
 	const std::vector<vkcv::Mesh>&      meshes,
 	const std::vector<glm::mat4>&       modelMatrices,
-	const vkcv::camera::Camera&         camera) {
+	const vkcv::camera::Camera&         camera,
+	const glm::vec3&                    voxelVolumeOffset,
+	float                               voxelVolumeExtent) {
 
 	LightInfo lightInfo;
 	lightInfo.sunColor      = lightColor;
@@ -68,23 +159,12 @@ void ShadowMapping::recordShadowMapRendering(
 		std::sin(lightAngleRadian.x),
 		std::cos(lightAngleRadian.x) * std::sin(lightAngleRadian.y)));
 
-	const float shadowProjectionSize = 20.f;
-	glm::mat4 projectionLight = glm::ortho(
-		-shadowProjectionSize,
-		shadowProjectionSize,
-		-shadowProjectionSize,
-		shadowProjectionSize,
-		-shadowProjectionSize,
-		shadowProjectionSize);
-
-	glm::mat4 vulkanCorrectionMatrix(1.f);
-	vulkanCorrectionMatrix[2][2] = 0.5;
-	vulkanCorrectionMatrix[3][2] = 0.5;
-	projectionLight = vulkanCorrectionMatrix * projectionLight;
-
-	const glm::mat4 viewLight = glm::lookAt(glm::vec3(0), lightInfo.direction, glm::vec3(0, -1, 0));
-
-	lightInfo.lightMatrix = projectionLight * viewLight;
+	lightInfo.lightMatrix = computeShadowViewProjectionMatrix(
+		lightInfo.direction,
+		camera,
+		maxShadowDistance,
+		voxelVolumeOffset,
+		voxelVolumeExtent);
 	m_lightInfoBuffer.fill({ lightInfo });
 
 	std::vector<glm::mat4> mvpLight;
diff --git a/projects/voxelization/src/ShadowMapping.hpp b/projects/voxelization/src/ShadowMapping.hpp
index 295dbae319beb222c96538c359debef7583f4045..6bbceff9320ef9605d02168aaad31c73faa63702 100644
--- a/projects/voxelization/src/ShadowMapping.hpp
+++ b/projects/voxelization/src/ShadowMapping.hpp
@@ -24,9 +24,12 @@ public:
 		const glm::vec2&                    lightAngleRadian,
 		const glm::vec3&                    lightColor,
 		const float                         lightStrength,
+		float                               maxShadowDistance,
 		const std::vector<vkcv::Mesh>&      meshes,
 		const std::vector<glm::mat4>&       modelMatrices,
-		const vkcv::camera::Camera&         camera);
+		const vkcv::camera::Camera&         camera,
+		const glm::vec3&                    voxelVolumeOffset,
+		float                               voxelVolumeExtent);
 
 	vkcv::ImageHandle   getShadowMap();
 	vkcv::SamplerHandle getShadowSampler();
diff --git a/projects/voxelization/src/Voxelization.cpp b/projects/voxelization/src/Voxelization.cpp
index a14a880c208de2eb20fb9f77b2d8ff8948c98316..b62bb42ae1557eafca67475d760a8af502db3c62 100644
--- a/projects/voxelization/src/Voxelization.cpp
+++ b/projects/voxelization/src/Voxelization.cpp
@@ -69,9 +69,10 @@ vkcv::ShaderProgram loadSecondaryBounceShader() {
 	return shader;
 }
 
-const uint32_t voxelResolution = 128;
-uint32_t voxelCount = voxelResolution * voxelResolution * voxelResolution;
-const vk::Format voxelizationDummyFormat = vk::Format::eR8Unorm;
+const uint32_t      voxelResolution = 128;
+uint32_t            voxelCount = voxelResolution * voxelResolution * voxelResolution;
+const vk::Format    voxelizationDummyFormat = vk::Format::eR8Unorm;
+const int           maxStableMip = 4;	// must be the same as in voxelConeTrace shader function
 
 Voxelization::Voxelization(
 	vkcv::Core* corePtr,
@@ -211,27 +212,13 @@ Voxelization::Voxelization(
 
 void Voxelization::voxelizeMeshes(
 	vkcv::CommandStreamHandle                       cmdStream,
-	const glm::vec3&                                cameraPosition,
-	const glm::vec3&                                cameraLookDirection,
 	const std::vector<vkcv::Mesh>&                  meshes,
 	const std::vector<glm::mat4>&                   modelMatrices,
 	const std::vector<vkcv::DescriptorSetHandle>&   perMeshDescriptorSets) {
 
-	VoxelizationInfo voxelizationInfo;
-	voxelizationInfo.extent = m_voxelExtent;
+	m_voxelInfoBuffer.fill({ m_voxelInfo });
 
-	// move voxel offset with camera in voxel sized steps
-	const float voxelSize       = m_voxelExtent / voxelResolution;
-	const int   maxStableMip    = 4;	// must be the same as in voxelConeTrace shader function
-	const float snapSize        = voxelSize * exp2(maxStableMip);
-
-	glm::vec3 voxelVolumeCenter = cameraPosition + (1.f / 3.f) * m_voxelExtent * cameraLookDirection;
-	voxelVolumeCenter.y         = cameraPosition.y;
-	voxelizationInfo.offset     = glm::floor(voxelVolumeCenter / snapSize) * snapSize;
-
-	m_voxelInfoBuffer.fill({ voxelizationInfo });
-
-	const float voxelizationHalfExtent = 0.5f * m_voxelExtent;
+	const float voxelizationHalfExtent = 0.5f * m_voxelInfo.extent;
 	const glm::mat4 voxelizationProjection = glm::ortho(
 		-voxelizationHalfExtent,
 		voxelizationHalfExtent,
@@ -240,7 +227,7 @@ void Voxelization::voxelizeMeshes(
 		-voxelizationHalfExtent,
 		voxelizationHalfExtent);
 
-	const glm::mat4 voxelizationView = glm::translate(glm::mat4(1.f), -voxelizationInfo.offset);
+	const glm::mat4 voxelizationView = glm::translate(glm::mat4(1.f), -m_voxelInfo.offset);
 	const glm::mat4 voxelizationViewProjection = voxelizationProjection * voxelizationView;
 
 	std::vector<std::array<glm::mat4, 2>> voxelizationMatrices;
@@ -357,8 +344,19 @@ void Voxelization::renderVoxelVisualisation(
 		renderTargets);
 }
 
+void Voxelization::updateVoxelOffset(const vkcv::camera::Camera& camera) {
+
+	// move voxel offset with camera in voxel sized steps
+	const float voxelSize   = m_voxelInfo.extent / voxelResolution;
+	const float snapSize    = voxelSize * exp2(maxStableMip);
+
+	glm::vec3 voxelVolumeCenter = camera.getPosition() + (1.f / 3.f) * m_voxelInfo.extent * glm::normalize(camera.getFront());
+	voxelVolumeCenter.y         = camera.getPosition().y;
+	m_voxelInfo.offset          = glm::floor(voxelVolumeCenter / snapSize) * snapSize;
+}
+
 void Voxelization::setVoxelExtent(float extent) {
-	m_voxelExtent = extent;
+	m_voxelInfo.extent = extent;
 }
 
 vkcv::ImageHandle Voxelization::getVoxelImageHandle() const {
@@ -367,4 +365,12 @@ vkcv::ImageHandle Voxelization::getVoxelImageHandle() const {
 
 vkcv::BufferHandle Voxelization::getVoxelInfoBufferHandle() const {
 	return m_voxelInfoBuffer.getHandle();
-}
\ No newline at end of file
+}
+
+glm::vec3 Voxelization::getVoxelOffset() const{
+	return m_voxelInfo.offset;
+}
+
+float Voxelization::getVoxelExtent() const {
+	return m_voxelInfo.extent;
+}
diff --git a/projects/voxelization/src/Voxelization.hpp b/projects/voxelization/src/Voxelization.hpp
index 6f8d155dbf05ddf8caad2d94e8b25cee5b70e3f6..e200f660d005e2a26eb8cbf7dd1020b072cd50d2 100644
--- a/projects/voxelization/src/Voxelization.hpp
+++ b/projects/voxelization/src/Voxelization.hpp
@@ -1,6 +1,7 @@
 #pragma once
 #include <vkcv/Core.hpp>
 #include <glm/glm.hpp>
+#include <vkcv/camera/Camera.hpp>
 
 class Voxelization{
 public:
@@ -19,8 +20,6 @@ public:
 
 	void voxelizeMeshes(
 		vkcv::CommandStreamHandle                       cmdStream,
-		const glm::vec3&                                cameraPosition,
-		const glm::vec3&                                cameraLookDirection,
 		const std::vector<vkcv::Mesh>&                  meshes,
 		const std::vector<glm::mat4>&                   modelMatrices,
 		const std::vector<vkcv::DescriptorSetHandle>&   perMeshDescriptorSets);
@@ -31,10 +30,14 @@ public:
 		const std::vector<vkcv::ImageHandle>&   renderTargets,
 		uint32_t                                mipLevel);
 
+	void updateVoxelOffset(const vkcv::camera::Camera& camera);
 	void setVoxelExtent(float extent);
 
-	vkcv::ImageHandle getVoxelImageHandle() const;
-	vkcv::BufferHandle getVoxelInfoBufferHandle() const;
+	vkcv::ImageHandle   getVoxelImageHandle() const;
+	vkcv::BufferHandle  getVoxelInfoBufferHandle() const;
+
+	glm::vec3   getVoxelOffset() const;
+	float       getVoxelExtent() const;
 
 private:
 	vkcv::Core* m_corePtr;
@@ -74,5 +77,5 @@ private:
 	};
 	vkcv::Buffer<VoxelizationInfo> m_voxelInfoBuffer;
 
-	float m_voxelExtent = 30.f;
+	VoxelizationInfo m_voxelInfo;
 };
\ No newline at end of file
diff --git a/projects/voxelization/src/main.cpp b/projects/voxelization/src/main.cpp
index d86b8297c8206ce02030bbfcd9f4c53abfe92844..36b6f9d11d868ab7884c903d6122caa6a9feaeef 100644
--- a/projects/voxelization/src/main.cpp
+++ b/projects/voxelization/src/main.cpp
@@ -328,6 +328,7 @@ int main(int argc, const char** argv) {
 	glm::vec2   lightAnglesDegree   = glm::vec2(90.f, 0.f);
 	glm::vec3   lightColor          = glm::vec3(1);
 	float       lightStrength       = 25.f;
+    float       maxShadowDistance   = 30.f;
 
 	int     voxelVisualisationMip   = 0;
 	float   voxelizationExtent      = 30.f;
@@ -366,6 +367,8 @@ int main(int argc, const char** argv) {
 
 		auto cmdStream = core.createCommandStream(vkcv::QueueType::Graphics);
 
+		voxelization.updateVoxelOffset(cameraManager.getActiveCamera());
+
 		// shadow map
 		glm::vec2 lightAngleRadian = glm::radians(lightAnglesDegree);
 		shadowMapping.recordShadowMapRendering(
@@ -373,16 +376,17 @@ int main(int argc, const char** argv) {
 			lightAngleRadian,
 			lightColor,
 			lightStrength,
+			maxShadowDistance,
 			meshes,
 			modelMatrices,
-			cameraManager.getActiveCamera());
+			cameraManager.getActiveCamera(),
+			voxelization.getVoxelOffset(),
+			voxelization.getVoxelExtent());
 
 		// voxelization
 		voxelization.setVoxelExtent(voxelizationExtent);
 		voxelization.voxelizeMeshes(
-			cmdStream, 
-			cameraManager.getActiveCamera().getPosition(), 
-			cameraManager.getActiveCamera().getFront(),
+			cmdStream,
 			meshes, 
 			modelMatrices,
 			perMeshDescriptorSets);
@@ -438,6 +442,9 @@ int main(int argc, const char** argv) {
 		ImGui::DragFloat2("Light angles",           &lightAnglesDegree.x);
 		ImGui::ColorEdit3("Sun color",              &lightColor.x);
 		ImGui::DragFloat("Sun strength",            &lightStrength);
+		ImGui::DragFloat("Max shadow distance",     &maxShadowDistance);
+		maxShadowDistance = std::max(maxShadowDistance, 1.f);
+
 		ImGui::Checkbox("Draw voxel visualisation", &renderVoxelVis);
 		ImGui::SliderInt("Visualisation mip",       &voxelVisualisationMip, 0, 7);
 		ImGui::DragFloat("Voxelization extent",     &voxelizationExtent, 1.f, 0.f);