diff --git a/build/engine/shaders/gi/gi_cubes.gs b/build/engine/shaders/gi/gi_cubes.gs
index c93ebcc98b6d62330013f975e125e6ec82c0d164..3645f109176fb54723d26f35e5ff49a701391471 100644
--- a/build/engine/shaders/gi/gi_cubes.gs
+++ b/build/engine/shaders/gi/gi_cubes.gs
@@ -23,7 +23,7 @@ void main(point VSO_GICubes input[1], inout TriangleStream<GSO_GICubes> OutputSt
 // void main(point VSO_GICubes input[1], inout LineStream<VSO_GICubes> OutputStream)
 // void main(point VSO_GICubes input[1], inout PointStream<VSO_GICubes> OutputStream)
 {
-	const float fSize = 0.05;
+	const float fSize = 0.03;
 	const float fNormal = 0.57735027;
 	
 	float3 vCenter = input[0].vPosition.xyz;
diff --git a/build/engine/shaders/gi/gi_cubes.ps b/build/engine/shaders/gi/gi_cubes.ps
index 36bcd694d2ce66103e7fdb293db9253ffb37bf13..ed5cd567a485c6a75ead68c49682bbe239d1510b 100644
--- a/build/engine/shaders/gi/gi_cubes.ps
+++ b/build/engine/shaders/gi/gi_cubes.ps
@@ -27,7 +27,7 @@ float4 main(GSO_GICubes IN):COLOR0
 {
 	// return(float4(1,1,1,1));
 	
-	float3 vTexCoord = (IN.vCenterPos.xyz - floor(g_vPosCam).xyz) / 32.0 + 0.5 + 1.0 / 64.0;
+	float3 vTexCoord = GetGridTexCoord(IN.vCenterPos.xyz, 0);
 	
 	float4 vColorR = g_txIllumRed.Sample(g_sSampler, vTexCoord);
 	float4 vColorG = g_txIllumGreen.Sample(g_sSampler, vTexCoord);
diff --git a/build/engine/shaders/gi/gi_cubes.vs b/build/engine/shaders/gi/gi_cubes.vs
index fbf745edfa3be4b1bc9335b9672ca6b12713a484..51ef4da0bc8fff26a50ca9c409a3b5592cf51306 100644
--- a/build/engine/shaders/gi/gi_cubes.vs
+++ b/build/engine/shaders/gi/gi_cubes.vs
@@ -5,6 +5,7 @@ terrax_colored.vs
 */
 
 #include <struct.h>
+#include <lpv.h>
 
 //##########################################################################
 
@@ -16,19 +17,12 @@ cbuffer perFrame: register(b1)
 	float3 g_vParamProj;
 };
 
-cbuffer b8: register(b8)
-{
-	// float4x4 mV;
-	float4x4 g_mVP1;
-	float4 g_vPosCam;
-};
-
 //##########################################################################
 
 VSO_GICubes main(VSI_GICubes IN)
 {
 	VSO_GICubes OUT = (VSO_GICubes)0;
-	OUT.vPosition = float4(IN.vPosition.xyz + floor(g_vPosCam).xyz,1);
+	OUT.vPosition = float4(IN.vPosition.xyz * GetGridWorldSize(0) + GetGridCenter(0), 1.0);
 	// OUT.vPosition = mul(half4(IN.vPosition.xyz,1), g_mVP);
 	return(OUT);
 }
diff --git a/build/engine/shaders/gi/gi_inject.vs b/build/engine/shaders/gi/gi_inject.vs
index d370489a986e988c2473006b8708e7879b1c7397..0c890065d6c3a24b839e99e91687ac9da3e4be17 100644
--- a/build/engine/shaders/gi/gi_inject.vs
+++ b/build/engine/shaders/gi/gi_inject.vs
@@ -23,11 +23,6 @@ cbuffer b8: register(b8)
 	float4 g_vPosCam;
 };
 
-int3 getGridPos(float3 worldPos)
-{
-	return(((worldPos - floor(g_vPosCam.xyz)) / LPV_CELL_SIZE) + int3(LPV_DIMH, LPV_DIMH, LPV_DIMH));
-}
-
 struct VS_IN
 {
 	uint posIndex :SV_VertexID;
@@ -121,7 +116,7 @@ GS_IN main(VS_IN input)
 				float texLum = Luminance(rsmTexel);
 				if(texLum > maxLuminance)
 				{
-					brightestCellIndex = getGridPos(rsmTexel.positionWS);
+					brightestCellIndex = getGridPos(rsmTexel.positionWS, 0);
 					maxLuminance = texLum;
 				}
 			}
@@ -137,7 +132,7 @@ GS_IN main(VS_IN input)
 			int2 texIdx = rsmCoords.xy + int2(x, y);
 			RsmTexel rsmTexel = GetRsmTexel(texIdx, RSMsize);
 			
-			int3 texelIndex = getGridPos(rsmTexel.positionWS);
+			int3 texelIndex = getGridPos(rsmTexel.positionWS, 0);
 			float3 deltaGrid = texelIndex - brightestCellIndex;
 			if(dot(deltaGrid, deltaGrid) < 10) // If cell proximity is good enough
 			{
@@ -160,7 +155,7 @@ GS_IN main(VS_IN input)
 	//RsmTexel result = GetRsmTexel(rsmCoords.xy);
 
 	GS_IN output;
-	output.cellIndex = float4(getGridPos(result.positionWS), 1.0);
+	output.cellIndex = float4(getGridPos(result.positionWS, 0), 1.0);
 	// output.cellIndex = float4(result.positionWS, 1.0);
 	output.normal = result.normalWS;
 	output.flux = result.flux.rgb;
diff --git a/build/engine/shaders/gi/gi_inject_cube.vs b/build/engine/shaders/gi/gi_inject_cube.vs
index 921fad3324376361f669f7442a55a77af4f4125e..0569951673baf65b5f640413a9422029074b813f 100644
--- a/build/engine/shaders/gi/gi_inject_cube.vs
+++ b/build/engine/shaders/gi/gi_inject_cube.vs
@@ -23,11 +23,6 @@ cbuffer b8: register(b8)
 	float4 g_vPosCam;
 };
 
-int3 getGridPos(float3 worldPos)
-{
-	return(((worldPos - floor(g_vPosCam.xyz)) / LPV_CELL_SIZE) + int3(LPV_DIMH, LPV_DIMH, LPV_DIMH));
-}
-
 struct VS_IN
 {
 	uint posIndex :SV_VertexID;
@@ -161,7 +156,7 @@ GS_IN main(VS_IN input)
 				float texLum = Luminance(rsmTexel);
 				if (texLum > maxLuminance)
 				{
-					brightestCellIndex = getGridPos(rsmTexel.positionWS);
+					brightestCellIndex = getGridPos(rsmTexel.positionWS, 0);
 					maxLuminance = texLum;
 				}
 			}
@@ -177,7 +172,7 @@ GS_IN main(VS_IN input)
 			int3 texIdx = rsmCoords.xyz + int3(x, y, 0);
 			RsmTexel rsmTexel = GetRsmTexel(texIdx, RSMsize);
 			
-			int3 texelIndex = getGridPos(rsmTexel.positionWS);
+			int3 texelIndex = getGridPos(rsmTexel.positionWS, 0);
 			float3 deltaGrid = texelIndex - brightestCellIndex;
 			if(dot(deltaGrid, deltaGrid) < 10) // If cell proximity is good enough
 			{
@@ -200,7 +195,7 @@ GS_IN main(VS_IN input)
 	//RsmTexel result = GetRsmTexel(rsmCoords.xy);
 
 	GS_IN output;
-	output.cellIndex = float4(getGridPos(result.positionWS), 1.0);
+	output.cellIndex = float4(getGridPos(result.positionWS, 0), 1.0);
 	// output.cellIndex = float4(result.positionWS, 1.0);
 	output.normal = result.normalWS;
 	output.flux = result.flux.rgb;
diff --git a/build/engine/shaders/gi/gi_propagation.cs b/build/engine/shaders/gi/gi_propagation.cs
index 54c5ce07d5d1b6cde4b72310f91931cc94ed5f2c..8c6b328e5c3e7cfc8ead720f6818080877247487 100644
--- a/build/engine/shaders/gi/gi_propagation.cs
+++ b/build/engine/shaders/gi/gi_propagation.cs
@@ -1,12 +1,5 @@
 
-#include "../lpv.h"
-
-int3 getGridPos(float3 worldPos)
-{
-	return((worldPos / LPV_CELL_SIZE) + int3(LPV_DIMH, LPV_DIMH, LPV_DIMH));
-}
-
-// End of lpv.h
+#include <lpv.h>
 
 Texture3D<float4> lpvR :register(t0);
 Texture3D<float4> lpvG :register(t1);
diff --git a/build/engine/shaders/lighting/lighting_gi.ps b/build/engine/shaders/lighting/lighting_gi.ps
index a7ea353248494d4a29f9aff99b7a9b59026c0af0..c2ea1e1ade3aa9a0d76b020d1224604cef4f7252 100644
--- a/build/engine/shaders/lighting/lighting_gi.ps
+++ b/build/engine/shaders/lighting/lighting_gi.ps
@@ -15,13 +15,6 @@ cbuffer perFrame: register(b1)
 	float3 g_vViewPos;
 };
 
-cbuffer b8: register(b8)
-{
-	// float4x4 mV;
-	float4x4 g_mVP;
-	float4 g_vPosCam;
-};
-
 //##########################################################################
 
 SamplerState g_sPointClamp: register(s0);
@@ -42,44 +35,12 @@ PSO_Lbuffer main(VSO_ResPos IN)
 	float4 vNormals = g_txNormals.Sample(g_sPointClamp, IN.vTexUV);
 	float fDepth = g_txDepth.Sample(g_sPointClamp,IN.vTexUV).r;
 	
-	// xy_ - размеры пикселя текстуры, __z - размер сетки в мировых
-	float3 vTexSize = float3(1.0 / 32.0, 1.0 / 32.0, 16); 
 	float3 vOrigin = float3(0, 0, 0); // Центр сетки
 	float4 vPosition = float4(g_vViewPos.xyz + IN.vWorldRay * fDepth, 1.0); // Мировая позиция пиксела
 	
-	vPosition -= floor(g_vPosCam);
-	
 	float3 vNormalPixel = normalize(NormalDecode(vNormals.xyz).xyz);
 	
-	/* half3 vLocalPos = (vPosition - vOrigin);
-		
-	clip(16.0 - abs(vLocalPos.x));
-	clip(16.0 - abs(vLocalPos.y));
-	clip(16.0 - abs(vLocalPos.z));
-		
-	vLocalPos /= vTexSize.z * 2.0;
-	vLocalPos += 0.5;
-	
-	vLocalPos /= 32.0;
-	
-	half4 vColorR = g_txLightVolumeRed.Sample(g_sLinearClamp, vLocalPos);
-	half4 vColorG = g_txLightVolumeGreen.Sample(g_sLinearClamp, vLocalPos);
-	half4 vColorB = g_txLightVolumeBlue.Sample(g_sLinearClamp, vLocalPos);
-		
-	
-	float4 SHintensity = dirToSH(-vNormalPixel);
-	
-	OUT.vAmdient.xyz = max(0, float3(
-		dot(SHintensity, vColorR), 
-		dot(SHintensity, vColorG), 
-		dot(SHintensity, vColorB)
-	)) / PI * 10.0;
-	
-	OUT.vAmdient.w = 1;
-	
-	OUT.vSpecular = 0; */
-	
-	float3 vTexCoord = vPosition.xyz / 32.0 + 0.5 + 1.0 / 64.0;
+	float3 vTexCoord = GetGridTexCoord(vPosition.xyz, 0);
 	
 	float4 vColorR = g_txLightVolumeRed.Sample(g_sLinearClamp, vTexCoord);
 	float4 vColorG = g_txLightVolumeGreen.Sample(g_sLinearClamp, vTexCoord);
diff --git a/build/engine/shaders/lpv.h b/build/engine/shaders/lpv.h
index 476d352a13333558b0378c6c6cdb299f55d51141..fd68c5ad539ac6fc95093891fe302826e09ca2ef 100644
--- a/build/engine/shaders/lpv.h
+++ b/build/engine/shaders/lpv.h
@@ -1,6 +1,6 @@
 #define LPV_DIM 32
 #define LPV_DIMH 16
-#define LPV_CELL_SIZE 1.0
+// #define LPV_CELL_SIZE 1.0
 // #define LPV_POINT_COUNT 256
 // #define LPV_POINT_COUNT 32
 // #define LPV_MAP_SIZE 1024
@@ -10,6 +10,12 @@
 #define STEP_SIZE 1
 
 
+
+cbuffer b9: register(b9)
+{
+	float4 g_vCenterSize[3];
+};
+
 // https://github.com/mafian89/Light-Propagation-Volumes/blob/master/shaders/lightInject.frag and
 // https://github.com/djbozkosz/Light-Propagation-Volumes/blob/master/data/shaders/lpvInjection.cs seem
 // to use the same coefficients, which differ from the RSM paper. Due to completeness of their code, I will stick to their solutions.
@@ -26,7 +32,8 @@
 #define POSWS_BIAS_NORMAL 0.2
 #define POSWS_BIAS_LIGHT 1.0
 
-float4 dirToSH(float3 dir) {
+float4 dirToSH(float3 dir)
+{
 	return float4(SH_C0, -SH_C1 * dir.y, SH_C1 * dir.z, -SH_C1 * dir.x);
 }
 
@@ -35,3 +42,24 @@ float4 dirToCosineLobe(float3 dir)
 	//dir = normalize(dir);
 	return float4(SH_cosLobe_C0, -SH_cosLobe_C1 * dir.y, SH_cosLobe_C1 * dir.z, -SH_cosLobe_C1 * dir.x);
 }
+
+float3 GetGridCenter(uint uCascade)
+{
+	// return(floor(g_vCenterSize[uCascade].xyz) * g_vCenterSize[uCascade].w);
+	return(g_vCenterSize[uCascade].xyz - g_vCenterSize[uCascade].xyz % g_vCenterSize[uCascade].w);
+}
+
+float GetGridWorldSize(uint uCascade)
+{
+	return(g_vCenterSize[uCascade].w);
+}
+
+int3 getGridPos(float3 worldPos, uint uCascade)
+{
+	return((worldPos - GetGridCenter(uCascade)) / GetGridWorldSize(uCascade) + int3(LPV_DIMH, LPV_DIMH, LPV_DIMH));
+}
+
+float3 GetGridTexCoord(float3 worldPos, uint uCascade)
+{
+	return((worldPos - GetGridCenter(0)) / (GetGridWorldSize(uCascade) * LPV_DIM) + 0.5f + 1.0f / (LPV_DIM * 2.0f));
+}