diff --git a/CMakeLists.txt b/CMakeLists.txt
index 284e47dc75833783a3e08c288a67eba5c0243bef..fb879f27af33a85f6078b1984e1f7a7b00120f80 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -5,7 +5,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED NO)
 set(CMAKE_CXX_EXTENSIONS        OFF)
 
 # major, minor, patch, and _STAGE_ (0 = alpha, 1 = beta, 2 = gamma/release)
-project(radiance_cascades VERSION 0.5.1.1)
+project(radiance_cascades VERSION 0.5.2.1)
 
 configure_file(src/config.h.in config.h)
 
diff --git a/res/shaders/gi.frag b/res/shaders/gi.frag
index 5085da32d5341ba01745731e81bb270d348cc8d8..99a15bb933d21be84a4837f018aeb20b4c46b8ee 100644
--- a/res/shaders/gi.frag
+++ b/res/shaders/gi.frag
@@ -3,7 +3,7 @@
 #define PI 3.141596
 #define TWO_PI 6.2831853071795864769252867665590
 #define TAU 0.0008
-#define DECAY_RATE 1.3
+#define DECAY_RATE 1.1
 
 out vec4 fragColor;
 
@@ -58,24 +58,24 @@ float noise(vec2 p){
 
 void main() {
  /*
-  * To calculate the light value of a pixel we cast `uRaysPerPx` amount of rays in all directions
+  * To calculate the radiance value of a pixel we cast `uRaysPerPx` amount of rays in all directions
   * and add all of the resulting samples up, then divide by uRaysPerPx
   */
   vec2 fragCoord = gl_FragCoord.xy/uResolution;
 
   float dist = texture(uDistanceField, fragCoord).r;
   float noise = noise(fragCoord.xy * 2000);
-  vec3 light = texture(uLastFrame, fragCoord).rgb;
+  vec3 radiance = texture(uLastFrame, fragCoord).rgb;
 
   if (dist >= TAU) { // if we're not already in a wall
     // cast rays angularly with equal angles between them
     for (float i = 0.0; i < TWO_PI; i += TWO_PI / uRaysPerPx) {
       float angle = i + noise;
       vec3 hitcol = raymarch(fragCoord, vec2(cos(angle) * uResolution.y/uResolution.x, sin(angle)));
-      light += hitcol;
+      radiance += hitcol;
     }
-    light /= uRaysPerPx;
+    radiance /= uRaysPerPx;
   }
 
-  fragColor = vec4(light, 1.0);
+  fragColor = vec4(radiance, 1.0);
 }
diff --git a/res/shaders/rc.frag b/res/shaders/rc.frag
new file mode 100644
index 0000000000000000000000000000000000000000..ffa69b0f6003086b8096263afe2db3c2391076c9
--- /dev/null
+++ b/res/shaders/rc.frag
@@ -0,0 +1,63 @@
+#version 330 core
+
+#define PI 3.141596
+#define TWO_PI 6.2831853071795864769252867665590
+#define TAU 0.0008
+#define DECAY_RATE 1.3
+
+out vec4 fragColor;
+
+uniform vec2  uResolution;
+uniform int   uRaysPerPx;
+uniform int   uMaxSteps;
+uniform float uPointA;
+uniform float uPointB;
+uniform float uLinearResolution;
+
+uniform sampler2D uDistanceField;
+uniform sampler2D uSceneMap;
+uniform sampler2D uLastPass;
+
+// altered raymarching function; only returns coordinates with a distance between a and b
+vec2 radiance_interval(vec2 uv, vec2 dir, float a, float b) {
+  uv += a * dir;
+  float travelledDist = a;
+  for (int i = 0; i < uMaxSteps; i++) {
+    float dist = texture(uDistanceField, uv).r;         // sample distance field
+    uv += (dir * dist); // march our ray (divided by our aspect ratio so no skewed directions)
+
+    // skip UVs outside of the window
+    if (uv.x != clamp(uv.x,  0.0, 1.0) || uv.y != clamp(uv.y, 0.0, 1.0))
+      break;
+
+    // surface hit
+    if (dist < TAU)
+      return uv;
+
+    travelledDist += dist;
+    if (travelledDist >= b)
+      break;
+  }
+  return vec2(0.0);
+}
+
+void main() {
+  vec2 fragCoord = gl_FragCoord.xy/uResolution;
+
+  float dist = texture(uDistanceField, fragCoord).r;
+  vec3 radiance = texture(uSceneMap, fragCoord).rgb;
+
+  vec2 uv = floor(gl_FragCoord.xy / uLinearResolution) * uLinearResolution / uResolution;
+
+  if (dist >= TAU) { // if we're not already in a wall
+    // cast rays angularly with equal angles between them
+    for (float i = 0.0; i < TWO_PI; i += TWO_PI / uRaysPerPx) {
+      float angle = i + 0.5;
+      vec2 hitpos = radiance_interval(uv, vec2(cos(angle) * uResolution.y/uResolution.x, sin(angle)), uPointA, uPointB);
+      radiance += texture(uSceneMap, hitpos).rgb;
+    }
+    radiance /= uRaysPerPx;
+  }
+
+  fragColor = vec4((radiance + texture(uLastPass, fragCoord).rgb) / 2, 1.0);
+}
diff --git a/src/demo.cpp b/src/demo.cpp
index b9ac30d2cf2047a5f22980824f0195ee3c02a512..a0ceb4194d30308bf4b06b0486eeac296d6958e1 100644
--- a/src/demo.cpp
+++ b/src/demo.cpp
@@ -14,6 +14,7 @@ Demo::Demo() {
   pointA = 0.0;
   pointB = 1.0;
   orbs = 0.0;
+  gi = false;
 
   user.mode= DRAWING;
   userSetRandomColor();
@@ -104,6 +105,7 @@ void Demo::render() {
   ClearBackground(PINK);
 
   // const Shader& rcShader  = shaders["rc.frag"];
+  const Shader& rcShader        = shaders["rc.frag"];
   const Shader& giShader        = shaders["gi.frag"];
   const Shader& jfaShader       = shaders["jfa.frag"];
   const Shader& prepJfaShader   = shaders["prepjfa.frag"];
@@ -183,18 +185,49 @@ void Demo::render() {
     EndShaderMode();
   EndTextureMode();
 
-  BeginTextureMode(radianceBufferA);
-    BeginShaderMode(giShader);
-      ClearBackground(BLANK);
-      SetShaderValueTexture(giShader, GetShaderLocation(giShader, "uDistanceField"), distFieldBuf.texture);
-      SetShaderValueTexture(giShader, GetShaderLocation(giShader, "uSceneMap"),      sceneBuf.texture);
-      SetShaderValueTexture(giShader, GetShaderLocation(giShader, "uLastFrame"),     radianceBufferB.texture);
-      SetShaderValue(giShader, GetShaderLocation(giShader, "uResolution"), &resolution, SHADER_UNIFORM_VEC2);
-      SetShaderValue(giShader, GetShaderLocation(giShader, "uRaysPerPx"),  &raysPerPx,  SHADER_UNIFORM_INT);
-      SetShaderValue(giShader, GetShaderLocation(giShader, "uMaxSteps"),   &maxSteps,   SHADER_UNIFORM_INT);
-      DrawRectangle(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, WHITE);
-    EndShaderMode();
-  EndTextureMode();
+  if (gi) {
+    BeginTextureMode(radianceBufferA);
+      BeginShaderMode(giShader);
+        ClearBackground(BLANK);
+        SetShaderValueTexture(giShader, GetShaderLocation(giShader, "uDistanceField"), distFieldBuf.texture);
+        SetShaderValueTexture(giShader, GetShaderLocation(giShader, "uSceneMap"),      sceneBuf.texture);
+        SetShaderValueTexture(giShader, GetShaderLocation(giShader, "uLastFrame"),     radianceBufferB.texture);
+        SetShaderValue(giShader, GetShaderLocation(giShader, "uResolution"), &resolution, SHADER_UNIFORM_VEC2);
+        SetShaderValue(giShader, GetShaderLocation(giShader, "uRaysPerPx"),  &raysPerPx,  SHADER_UNIFORM_INT);
+        SetShaderValue(giShader, GetShaderLocation(giShader, "uMaxSteps"),   &maxSteps,   SHADER_UNIFORM_INT);
+        DrawRectangle(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, WHITE);
+      EndShaderMode();
+    EndTextureMode();
+  } else {
+    for (int i = 0; i < 2; i++) {
+      radianceBufferC = radianceBufferA;
+      radianceBufferA = radianceBufferB;
+      radianceBufferB = radianceBufferC;
+
+
+      #define BASE_RAY_COUNT 16
+      float intervalStart = i == 0 ? 0.0   : 0.125;
+      float intervalEnd   = i == 0 ? 0.125 : 1.0;
+      int rayCount = pow(BASE_RAY_COUNT, i+1); // angular resolution
+      float linearResolution = i == 0 ? 1.0 : 4.0;
+
+      BeginTextureMode(radianceBufferA);
+        BeginShaderMode(rcShader);
+          ClearBackground(BLANK);
+          SetShaderValueTexture(rcShader, GetShaderLocation(rcShader, "uDistanceField"), distFieldBuf.texture);
+          SetShaderValueTexture(rcShader, GetShaderLocation(rcShader, "uSceneMap"),      sceneBuf.texture);
+          SetShaderValueTexture(rcShader, GetShaderLocation(rcShader, "uLastPass"),      radianceBufferC.texture);
+          SetShaderValue(rcShader, GetShaderLocation(rcShader, "uResolution"), &resolution,   SHADER_UNIFORM_VEC2);
+          SetShaderValue(rcShader, GetShaderLocation(rcShader, "uRaysPerPx"),  &rayCount, SHADER_UNIFORM_INT);
+          SetShaderValue(rcShader, GetShaderLocation(rcShader, "uLinearResolution"),  &linearResolution, SHADER_UNIFORM_FLOAT);
+          SetShaderValue(rcShader, GetShaderLocation(rcShader, "uMaxSteps"),   &maxSteps,     SHADER_UNIFORM_INT);
+          SetShaderValue(rcShader, GetShaderLocation(rcShader, "uPointA"),   &intervalStart,  SHADER_UNIFORM_FLOAT);
+          SetShaderValue(rcShader, GetShaderLocation(rcShader, "uPointB"),   &intervalEnd,    SHADER_UNIFORM_FLOAT);
+          DrawRectangle(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, WHITE);
+        EndShaderMode();
+      EndTextureMode();
+    }
+  }
 
   BeginTextureMode(lastFrameBuf);
     DrawTextureRec(radianceBufferA.texture, {0, 0.0, SCREEN_WIDTH, SCREEN_HEIGHT}, {0.0, 0.0}, WHITE);
@@ -263,14 +296,15 @@ void Demo::renderUI() {
       bool orbsBool = (orbs == 1);
       ImGui::Checkbox("light orb circle", &orbsBool);
       orbs = (int)orbsBool;
+      ImGui::Checkbox("gi", &gi);
       if (ImGui::SmallButton("show buffers")) debugShowBuffers = !debugShowBuffers;
       if (debugShowBuffers) {
         if (ImGui::BeginTable("buffer_table", 2)) {
-          ImGui::TableNextRow();
-            ImGui::TableSetColumnIndex(0);
-            rlImGuiImageSizeV(&emissionMap.tex,      {80, 60});
-            ImGui::TableSetColumnIndex(1);
-            rlImGuiImageSizeV(&occlusionMap.tex,     {80, 60});
+          // ImGui::TableNextRow();
+          //   ImGui::TableSetColumnIndex(0);
+          //   rlImGuiImageSizeV(&emissionMap.tex,      {80, 60});
+          //   ImGui::TableSetColumnIndex(1);
+          //   rlImGuiImageSizeV(&occlusionMap.tex,     {80, 60});
           ImGui::TableNextRow();
             ImGui::TableSetColumnIndex(0);
             rlImGuiImageSizeV(&sceneBuf.texture,     {80, 60});
@@ -283,7 +317,10 @@ void Demo::renderUI() {
             ImGui::TableSetColumnIndex(0);
             rlImGuiImageSizeV(&radianceBufferA.texture,      {80, 60});
             ImGui::TableSetColumnIndex(1);
-            rlImGuiImageSizeV(&lastFrameBuf.texture,      {80, 60});
+            rlImGuiImageSizeV(&radianceBufferB.texture,      {80, 60});
+          ImGui::TableNextRow();
+            ImGui::TableSetColumnIndex(0);
+            rlImGuiImageSizeV(&radianceBufferC.texture,      {80, 60});
           ImGui::EndTable();
         }
       }
diff --git a/src/demo.h b/src/demo.h
index 8f6d4335d15714f002792103fddb1aa80eba634c..20f75ed6af609d07169d9c655dcdf26c546b2cbe 100644
--- a/src/demo.h
+++ b/src/demo.h
@@ -53,6 +53,7 @@ class Demo {
     int raysPerPx;
     bool debug;
     bool sceneHasChanged;
+    bool gi;
     float pointA;
     float pointB;
     int orbs; // bool uniform