diff --git a/shaders/surface.frag b/shaders/surface.frag
index 451c16c9484f96c43522b4a1ee1c956de528dc87..cd97f4c09f277f7297e852a194f575c0a64c35e9 100644
--- a/shaders/surface.frag
+++ b/shaders/surface.frag
@@ -18,7 +18,7 @@ const float R0 = 0.0204;
 const float ATTENUATION = 0.145f;
 //const float ATTENUATION = 0.5f;
 
-const float MIN_T = 0;
+const float MIN_T = 0.05;
 const float MAX_T = 10.0;
 const float DT = 0.1;
 
@@ -77,7 +77,7 @@ vec3 refraction_ray(vec3 pos, vec3 dir) {
         ly = cur_pos.y;
     }
 
-    return vec3(1, 0, 1);
+    return vec3(0, 0, 0);
 }
 
 vec3 reflection_ray_second_bounce(vec3 pos, vec3 dir) {
@@ -147,10 +147,10 @@ vec3 reflection_ray_first_bounce(vec3 pos, vec3 dir) {
                 float R = fresnel(nnormal, dir);
                 // vec3 water_color = vec3(0, 0.05, 0.1);
 
-                vec3 sky_color = reflection_ray_second_bounce(world_pos, reflected);
+                vec3 sky_color = reflection_ray_second_bounce(cur_pos, reflected);
                 //vec3 sky_color = texture(sky, sphere_uv(reflected)).rgb;
                 vec3 refracted = refract(dir, nnormal, 0.75);
-                vec3 water_color = refraction_ray(world_pos, refracted);
+                vec3 water_color = refraction_ray(cur_pos, refracted);
                 return mix(water_color, sky_color, R);
             }
         }
@@ -163,6 +163,104 @@ vec3 reflection_ray_first_bounce(vec3 pos, vec3 dir) {
     return texture(sky, sphere_uv(dir)).rgb;
 }
 
+vec3 inside_reflection_ray_second_bounce(vec3 pos, vec3 dir) {
+    float lh = 0.0f;
+    float lh2 = 0.0f;
+    float ly = 0.0f;
+
+    for (float t = MIN_T; t < MAX_T; t += DT) {
+        vec3 cur_pos = pos + t * dir;
+
+        if (abs(cur_pos.x) > 5.0 || abs(cur_pos.z) > 5.0) {
+            break;
+        }
+
+        float ground_y_at = depth_at(cur_pos);
+        float wave_y_at = wave_depth_at(cur_pos);
+        float y_at = max(ground_y_at, wave_y_at);
+
+        if (cur_pos.y < ground_y_at) {
+            float res_t = t - DT + DT * (lh - ly) / (cur_pos.y - ly - y_at + lh);
+            vec3 hit_pos = pos + res_t * dir;
+
+            return texture(ground, tex_at(hit_pos)).rgb;
+        } else if (cur_pos.y > wave_y_at) {
+            float res_t = t - DT + DT * (lh2 - ly) / (cur_pos.y - ly - y_at + lh2);
+            vec3 hit_pos = pos + res_t * dir;
+
+            vec3 nnormal = normalize(wave_normal_at(hit_pos));
+            vec3 reflected = reflect(dir, nnormal);
+            vec3 refracted = refract(dir, -nnormal, 1.333);
+            float R = fresnel(nnormal, -refracted);
+            if (dot(refracted, refracted) < 0.1) {
+                R = 1.0;
+            }
+            // vec3 water_color = vec3(0, 0.05, 0.1);
+
+            //vec3 sky_color = reflection_ray_second_bounce(cur_pos, refracted);
+            vec3 sky_color = texture(sky, sphere_uv(reflected)).rgb;
+            vec3 water_color = refraction_ray(cur_pos, reflected);
+            return mix(sky_color, water_color, R);
+        }
+
+
+        lh = ground_y_at;
+        lh2 = wave_y_at;
+        ly = cur_pos.y;
+    }
+
+    return texture(sky, sphere_uv(dir)).rgb;
+}
+
+vec3 inside_reflection_ray_first_bounce(vec3 pos, vec3 dir) {
+    float lh = 0.0f;
+    float lh2 = 0.0f;
+    float ly = 0.0f;
+
+    for (float t = MIN_T; t < MAX_T; t += DT) {
+        vec3 cur_pos = pos + t * dir;
+
+        if (abs(cur_pos.x) > 5.0 || abs(cur_pos.z) > 5.0) {
+            break;
+        }
+
+        float ground_y_at = depth_at(cur_pos);
+        float wave_y_at = wave_depth_at(cur_pos);
+        float y_at = max(ground_y_at, wave_y_at);
+
+        if (cur_pos.y < ground_y_at) {
+            float res_t = t - DT + DT * (lh - ly) / (cur_pos.y - ly - y_at + lh);
+            vec3 hit_pos = pos + res_t * dir;
+
+            return texture(ground, tex_at(hit_pos)).rgb;
+        } else if (cur_pos.y > wave_y_at) {
+            float res_t = t - DT + DT * (lh2 - ly) / (cur_pos.y - ly - y_at + lh2);
+            vec3 hit_pos = pos + res_t * dir;
+
+            vec3 nnormal = normalize(wave_normal_at(hit_pos));
+            vec3 reflected = reflect(dir, nnormal);
+            vec3 refracted = refract(dir, -nnormal, 1.333);
+            float R = fresnel(nnormal, -refracted);
+            if (dot(refracted, refracted) < 0.1) {
+                R = 1.0;
+            }
+            // vec3 water_color = vec3(0, 0.05, 0.1);
+
+            vec3 sky_color = reflection_ray_second_bounce(cur_pos, refracted);
+            //vec3 sky_color = texture(sky, sphere_uv(reflected)).rgb;
+            vec3 water_color = inside_reflection_ray_second_bounce(cur_pos, reflected);
+            return mix(sky_color, water_color, R);
+        }
+
+
+        lh = ground_y_at;
+        lh2 = wave_y_at;
+        ly = cur_pos.y;
+    }
+
+    return texture(sky, sphere_uv(dir)).rgb;
+}
+
 vec3 map(float v)
 {
     if (v > 1.0 || v < 0.0) {
@@ -176,15 +274,29 @@ void main(void)
 {
     vec3 view = normalize(world_pos - camera_pos);
     vec3 nnormal = normalize(normal);
-    vec3 reflected = reflect(view, nnormal);
-    float R = fresnel(nnormal, view);
-    // vec3 water_color = vec3(0, 0.05, 0.1);
+    vec3 color;
+    if (gl_FrontFacing) {
+        vec3 reflected = reflect(view, nnormal);
+        vec3 refracted = refract(view, nnormal, 0.75);
+        float R = fresnel(nnormal, view);
+
+        vec3 sky_color = reflection_ray_first_bounce(world_pos + vec3(0, 0.001, 0), reflected);
+        vec3 water_color = refraction_ray(world_pos, refracted);
 
-    vec3 sky_color = reflection_ray_first_bounce(world_pos + vec3(0, 0.001, 0), reflected);
-    vec3 refracted = refract(view, nnormal, 0.75);
-    vec3 water_color = refraction_ray(world_pos, refracted);
+        color = mix(water_color, sky_color, R);
+    } else {
+        vec3 reflected = reflect(view, nnormal);
+        vec3 refracted = refract(view, -nnormal, 1.333);
+        float R = fresnel(nnormal, -refracted);
+        if (dot(refracted, refracted) < 0.1) {
+            R = 1.0;
+        }
 
-    vec3 hdr = mix(water_color, sky_color, R);
-    out_Color = vec4(hdr, 1.0);
+        vec3 sky_color = reflection_ray_second_bounce(world_pos + vec3(0, 0.001, 0), refracted);
+        vec3 water_color = inside_reflection_ray_first_bounce(world_pos - vec3(0, 0.001, 0), reflected);
+
+        color = mix(sky_color, water_color, R);
+    }
+    out_Color = vec4(color, 1.0);
 }
 
diff --git a/src/main.cpp b/src/main.cpp
index 2b8ee8f6512cdca07ef5f34e32e0c55b6f019350..e3487458e52c0d5310ef73962f9c12dc82198e31 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -372,7 +372,9 @@ struct Scene {
     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
     draw_skybox();
+    glDisable(GL_CULL_FACE);
     draw_surface();
+    glEnable(GL_CULL_FACE);
     draw_ground();
     draw_waterfall();
     draw_bubble();