diff --git a/resources/shaders/options_120.fs b/resources/shaders/options_120_flat.fs
similarity index 81%
rename from resources/shaders/options_120.fs
rename to resources/shaders/options_120_flat.fs
index 90d417b6e..656eccd1d 100644
--- a/resources/shaders/options_120.fs
+++ b/resources/shaders/options_120_flat.fs
@@ -5,7 +5,7 @@ uniform vec3 uniform_color;
 uniform float percent_outline_radius;
 uniform float percent_center_radius;
 
-vec4 hard_color(float sq_radius)
+vec4 hardcoded_color(float sq_radius)
 {
     if ((sq_radius < 0.005625) || (sq_radius > 0.180625))
         return vec4(0.5 * uniform_color, 1.0);
@@ -13,7 +13,7 @@ vec4 hard_color(float sq_radius)
         return vec4(uniform_color, 1.0);
 }
 
-vec4 custom_color(float sq_radius)
+vec4 customizable_color(float sq_radius)
 {
     float in_radius = 0.5 * percent_center_radius;
     float out_radius = 0.5 * (1.0 - percent_outline_radius);
@@ -30,5 +30,6 @@ void main()
     if (sq_radius > 0.25)
         discard;
      
-    gl_FragColor = custom_color(sq_radius);
+    gl_FragColor = customizable_color(sq_radius);
+//    gl_FragColor = hardcoded_color(sq_radius);
 }
diff --git a/resources/shaders/options_120.vs b/resources/shaders/options_120_flat.vs
similarity index 100%
rename from resources/shaders/options_120.vs
rename to resources/shaders/options_120_flat.vs
diff --git a/resources/shaders/options_120_solid.fs b/resources/shaders/options_120_solid.fs
new file mode 100644
index 000000000..68d0bd4ee
--- /dev/null
+++ b/resources/shaders/options_120_solid.fs
@@ -0,0 +1,88 @@
+// version 120 is needed for gl_PointCoord
+#version 120
+
+#define INTENSITY_CORRECTION 0.6
+
+// normalized values for (-0.6/1.31, 0.6/1.31, 1./1.31)
+const vec3 LIGHT_TOP_DIR = vec3(-0.4574957, 0.4574957, 0.7624929);
+#define LIGHT_TOP_DIFFUSE    (0.8 * INTENSITY_CORRECTION)
+#define LIGHT_TOP_SPECULAR   (0.125 * INTENSITY_CORRECTION)
+#define LIGHT_TOP_SHININESS  20.0
+
+// normalized values for (1./1.43, 0.2/1.43, 1./1.43)
+const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074);
+#define LIGHT_FRONT_DIFFUSE  (0.3 * INTENSITY_CORRECTION)
+
+#define INTENSITY_AMBIENT    0.3
+
+uniform vec3 uniform_color;
+uniform float percent_outline_radius;
+uniform float percent_center_radius;
+
+// x = width, y = height
+uniform ivec2 viewport_sizes;
+uniform vec2 z_range;
+uniform mat4 inv_proj_matrix;
+
+varying vec3 eye_center;
+
+float radius = 0.5;
+// x = tainted, y = specular;
+vec2 intensity;
+
+vec3 eye_position_from_fragment()
+{
+    // Convert screen coordinates to normalized device coordinates (NDC)
+    vec4 ndc = vec4(
+        (gl_FragCoord.x / viewport_sizes.x - 0.5) * 2.0,
+        (gl_FragCoord.y / viewport_sizes.y - 0.5) * 2.0,
+        (gl_FragCoord.z - 0.5) * 2.0,
+        1.0);
+
+    // Convert NDC throuch inverse clip coordinates to view coordinates
+    vec4 clip = inv_proj_matrix * ndc;
+    return (clip / clip.w).xyz;
+}
+
+vec3 eye_position_on_sphere(vec3 eye_fragment_position)
+{
+    vec3 eye_dir = normalize(eye_fragment_position);
+    float a = dot(eye_dir, eye_dir);
+    float b = 2.0 * dot(-eye_center, eye_dir);
+    float c = dot(eye_center, eye_center) - radius * radius;
+    float discriminant = b * b - 4 * a * c;
+    float t = -(b + sqrt(discriminant)) / (2.0 * a);
+    return t * eye_dir;
+}
+
+vec4 on_sphere_color(vec3 eye_on_sphere_position)
+{
+    vec3 eye_normal = normalize(eye_on_sphere_position - eye_center);
+
+    // Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex.
+    // Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range.
+    float NdotL = max(dot(eye_normal, LIGHT_TOP_DIR), 0.0);
+
+    intensity.x = INTENSITY_AMBIENT + NdotL * LIGHT_TOP_DIFFUSE;
+    intensity.y = LIGHT_TOP_SPECULAR * pow(max(dot(-normalize(eye_on_sphere_position), reflect(-LIGHT_TOP_DIR, eye_normal)), 0.0), LIGHT_TOP_SHININESS);
+
+    // Perform the same lighting calculation for the 2nd light source (no specular applied).
+    NdotL = max(dot(eye_normal, LIGHT_FRONT_DIR), 0.0);
+    intensity.x += NdotL * LIGHT_FRONT_DIFFUSE;
+    
+    return vec4(vec3(intensity.y, intensity.y, intensity.y) + uniform_color.rgb * intensity.x, 1.0);
+}
+
+void main()
+{
+    vec2 pos = gl_PointCoord - vec2(0.5, 0.5);
+    float sq_radius = dot(pos, pos);
+    if (sq_radius > 0.25)
+        discard;
+     
+    vec3 eye_on_sphere_position = eye_position_on_sphere(eye_position_from_fragment());
+
+//    gl_FragDepth = eye_on_sphere_position.z;
+//    gl_FragDepth = (eye_on_sphere_position.z - z_range.x) / (z_range.y - z_range.x);
+    gl_FragColor = on_sphere_color(eye_on_sphere_position);
+}
diff --git a/resources/shaders/options_120_solid.vs b/resources/shaders/options_120_solid.vs
new file mode 100644
index 000000000..0ad75003c
--- /dev/null
+++ b/resources/shaders/options_120_solid.vs
@@ -0,0 +1,14 @@
+#version 120
+
+uniform float zoom;
+// x = min, y = max
+uniform vec2 point_sizes;
+
+varying vec3 eye_center;
+
+void main()
+{
+    gl_PointSize = clamp(zoom, point_sizes.x, point_sizes.y);
+    eye_center = (gl_ModelViewMatrix * gl_Vertex).xyz;
+    gl_Position = ftransform();    
+}
diff --git a/resources/shaders/shells.fs b/resources/shaders/shells.fs
deleted file mode 100644
index 0c3388df7..000000000
--- a/resources/shaders/shells.fs
+++ /dev/null
@@ -1,13 +0,0 @@
-#version 110
-
-const vec3 ZERO = vec3(0.0, 0.0, 0.0);
-
-uniform vec4 uniform_color;
-
-// x = tainted, y = specular;
-varying vec2 intensity;
-
-void main()
-{
-    gl_FragColor = vec4(vec3(intensity.y, intensity.y, intensity.y) + uniform_color.rgb * intensity.x, uniform_color.a);
-}
diff --git a/resources/shaders/shells.vs b/resources/shaders/shells.vs
deleted file mode 100644
index bb9c144e6..000000000
--- a/resources/shaders/shells.vs
+++ /dev/null
@@ -1,42 +0,0 @@
-#version 110
-
-#define INTENSITY_CORRECTION 0.6
-
-// normalized values for (-0.6/1.31, 0.6/1.31, 1./1.31)
-const vec3 LIGHT_TOP_DIR = vec3(-0.4574957, 0.4574957, 0.7624929);
-#define LIGHT_TOP_DIFFUSE    (0.8 * INTENSITY_CORRECTION)
-#define LIGHT_TOP_SPECULAR   (0.125 * INTENSITY_CORRECTION)
-#define LIGHT_TOP_SHININESS  20.0
-
-// normalized values for (1./1.43, 0.2/1.43, 1./1.43)
-const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074);
-#define LIGHT_FRONT_DIFFUSE  (0.3 * INTENSITY_CORRECTION)
-
-#define INTENSITY_AMBIENT    0.3
-
-// x = tainted, y = specular;
-varying vec2 intensity;
-
-void main()
-{
-    // First transform the normal into camera space and normalize the result.
-    vec3 normal = normalize(gl_NormalMatrix * gl_Normal);
-    
-    // Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex.
-    // Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range.
-    float NdotL = max(dot(normal, LIGHT_TOP_DIR), 0.0);
-
-    intensity.x = INTENSITY_AMBIENT + NdotL * LIGHT_TOP_DIFFUSE;
-    intensity.y = 0.0;
-
-    if (NdotL > 0.0)
-    {    
-        vec3 position = (gl_ModelViewMatrix * gl_Vertex).xyz;
-        intensity.y += LIGHT_TOP_SPECULAR * pow(max(dot(-normalize(position), reflect(-LIGHT_TOP_DIR, normal)), 0.0), LIGHT_TOP_SHININESS);
-    }
-
-    // Perform the same lighting calculation for the 2nd light source (no specular applied).
-    intensity.x += max(dot(normal, LIGHT_FRONT_DIR), 0.0) * LIGHT_FRONT_DIFFUSE;
-        
-    gl_Position = ftransform();
-}
diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp
index 5631dadf3..984373ea4 100644
--- a/src/libslic3r/Technologies.hpp
+++ b/src/libslic3r/Technologies.hpp
@@ -15,7 +15,7 @@
 #define ENABLE_RENDER_STATISTICS 0
 // Shows an imgui dialog with camera related data
 #define ENABLE_CAMERA_STATISTICS 0
-//  Render the picking pass instead of the main scene (use [T] key to toggle between regular rendering and picking pass only rendering)
+// Render the picking pass instead of the main scene (use [T] key to toggle between regular rendering and picking pass only rendering)
 #define ENABLE_RENDER_PICKING_PASS 0
 // Enable extracting thumbnails from selected gcode and save them as png files
 #define ENABLE_THUMBNAIL_GENERATOR_DEBUG 0
diff --git a/src/slic3r/GUI/Camera.hpp b/src/slic3r/GUI/Camera.hpp
index ece999c07..6e4256235 100644
--- a/src/slic3r/GUI/Camera.hpp
+++ b/src/slic3r/GUI/Camera.hpp
@@ -84,6 +84,7 @@ public:
 
     double get_near_z() const { return m_frustrum_zs.first; }
     double get_far_z() const { return m_frustrum_zs.second; }
+    const std::pair<double, double>& get_z_range() const { return m_frustrum_zs; }
 
     double get_fov() const;
 
diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp
index 6d4197694..978b4b95a 100644
--- a/src/slic3r/GUI/GCodeViewer.cpp
+++ b/src/slic3r/GUI/GCodeViewer.cpp
@@ -415,12 +415,12 @@ void GCodeViewer::init_shaders()
     {
         switch (buffer_type(i))
         {
-        case GCodeProcessor::EMoveType::Tool_change:  { m_buffers[i].shader = wxGetApp().is_glsl_version_greater_or_equal_to(1, 20) ? "options_120" : "options_110"; break; }
-        case GCodeProcessor::EMoveType::Color_change: { m_buffers[i].shader = wxGetApp().is_glsl_version_greater_or_equal_to(1, 20) ? "options_120" : "options_110"; break; }
-        case GCodeProcessor::EMoveType::Pause_Print:  { m_buffers[i].shader = wxGetApp().is_glsl_version_greater_or_equal_to(1, 20) ? "options_120" : "options_110"; break; }
-        case GCodeProcessor::EMoveType::Custom_GCode: { m_buffers[i].shader = wxGetApp().is_glsl_version_greater_or_equal_to(1, 20) ? "options_120" : "options_110"; break; }
-        case GCodeProcessor::EMoveType::Retract:      { m_buffers[i].shader = wxGetApp().is_glsl_version_greater_or_equal_to(1, 20) ? "options_120" : "options_110"; break; }
-        case GCodeProcessor::EMoveType::Unretract:    { m_buffers[i].shader = wxGetApp().is_glsl_version_greater_or_equal_to(1, 20) ? "options_120" : "options_110"; break; }
+        case GCodeProcessor::EMoveType::Tool_change:  { m_buffers[i].shader = wxGetApp().is_glsl_version_greater_or_equal_to(1, 20) ? "options_120_solid" : "options_110"; break; }
+        case GCodeProcessor::EMoveType::Color_change: { m_buffers[i].shader = wxGetApp().is_glsl_version_greater_or_equal_to(1, 20) ? "options_120_solid" : "options_110"; break; }
+        case GCodeProcessor::EMoveType::Pause_Print:  { m_buffers[i].shader = wxGetApp().is_glsl_version_greater_or_equal_to(1, 20) ? "options_120_solid" : "options_110"; break; }
+        case GCodeProcessor::EMoveType::Custom_GCode: { m_buffers[i].shader = wxGetApp().is_glsl_version_greater_or_equal_to(1, 20) ? "options_120_solid" : "options_110"; break; }
+        case GCodeProcessor::EMoveType::Retract:      { m_buffers[i].shader = wxGetApp().is_glsl_version_greater_or_equal_to(1, 20) ? "options_120_solid" : "options_110"; break; }
+        case GCodeProcessor::EMoveType::Unretract:    { m_buffers[i].shader = wxGetApp().is_glsl_version_greater_or_equal_to(1, 20) ? "options_120_solid" : "options_110"; break; }
         case GCodeProcessor::EMoveType::Extrude:      { m_buffers[i].shader = "extrusions"; break; }
         case GCodeProcessor::EMoveType::Travel:       { m_buffers[i].shader = "travels"; break; }
         default: { break; }
@@ -754,21 +754,26 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
 void GCodeViewer::render_toolpaths() const
 {
 #if ENABLE_GCODE_VIEWER_SHADERS_EDITOR
-    bool is_glsl_120 = m_shaders_editor.glsl_version == 1 && wxGetApp().is_glsl_version_greater_or_equal_to(1, 20);
+    bool is_glsl_120 = m_shaders_editor.shader_version >= 1 && wxGetApp().is_glsl_version_greater_or_equal_to(1, 20);
     std::array<float, 2> point_sizes;
     if (m_shaders_editor.size_dependent_on_zoom)
-    {
         point_sizes = { std::min(static_cast<float>(m_shaders_editor.sizes[0]), m_detected_point_sizes[1]), std::min(static_cast<float>(m_shaders_editor.sizes[1]), m_detected_point_sizes[1]) };
-    }
     else
         point_sizes = { static_cast<float>(m_shaders_editor.fixed_size), static_cast<float>(m_shaders_editor.fixed_size) };
 #else
     bool is_glsl_120 = wxGetApp().is_glsl_version_greater_or_equal_to(1, 20);
     std::array<float, 2> point_sizes = { std::min(8.0f, m_detected_point_sizes[1]), std::min(48.0f, m_detected_point_sizes[1]) };
 #endif // ENABLE_GCODE_VIEWER_SHADERS_EDITOR
-    double zoom = wxGetApp().plater()->get_camera().get_zoom();
+    const Camera& camera = wxGetApp().plater()->get_camera();
+    double zoom = camera.get_zoom();
+    const std::array<int, 4>& viewport = camera.get_viewport();
+    std::array<int, 2> viewport_sizes = { viewport[2], viewport[3] };
+    const std::pair<double, double>& camera_z_range = camera.get_z_range();
+    std::array<float, 2> z_range = { static_cast<float>(camera_z_range.first), static_cast<float>(camera_z_range.second) };
 
-    auto render_options = [this, is_glsl_120, zoom, point_sizes](const IBuffer& buffer, EOptionsColors colors_id, GLShaderProgram& shader) {
+    Transform3d inv_proj = camera.get_projection_matrix().inverse();
+
+    auto render_options = [this, is_glsl_120, zoom, viewport, inv_proj, viewport_sizes, z_range, point_sizes](const IBuffer& buffer, EOptionsColors colors_id, GLShaderProgram& shader) {
         shader.set_uniform("uniform_color", Options_Colors[static_cast<unsigned int>(colors_id)]);
 #if ENABLE_GCODE_VIEWER_SHADERS_EDITOR
         shader.set_uniform("zoom", m_shaders_editor.size_dependent_on_zoom ? zoom : 1.0f);
@@ -779,6 +784,9 @@ void GCodeViewer::render_toolpaths() const
         shader.set_uniform("percent_outline_radius", 0.15f);
         shader.set_uniform("percent_center_radius", 0.15f);
 #endif // ENABLE_GCODE_VIEWER_SHADERS_EDITOR
+        shader.set_uniform("viewport_sizes", viewport_sizes);
+        shader.set_uniform("inv_proj_matrix", inv_proj);
+        shader.set_uniform("z_range", z_range);
         shader.set_uniform("point_sizes", point_sizes);
         glsafe(::glEnable(GL_VERTEX_PROGRAM_POINT_SIZE));
         if (is_glsl_120)
@@ -896,7 +904,7 @@ void GCodeViewer::render_shells() const
     if (!m_shells.visible || m_shells.volumes.empty())
         return;
 
-    GLShaderProgram* shader = wxGetApp().get_shader("shells");
+    GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light");
     if (shader == nullptr)
         return;
 
@@ -954,25 +962,25 @@ void GCodeViewer::render_legend() const
         {
 #if ENABLE_GCODE_VIEWER_SHADERS_EDITOR
             draw_list->AddCircle({ 0.5f * (pos.x + pos.x + icon_size), 0.5f * (pos.y + pos.y + icon_size) }, 0.5f * icon_size, ICON_BORDER_COLOR, 16);
-            draw_list->AddCircleFilled({ 0.5f * (pos.x + pos.x + icon_size), 0.5f * (pos.y + pos.y + icon_size) }, (0.5f * icon_size) - 2.0f,
-                ImGui::GetColorU32({ 0.5f * color[0], 0.5f * color[1], 0.5f * color[2], 1.0f }), 16);
-            float radius = ((0.5f * icon_size) - 2.0f) * (1.0f - 0.01f * static_cast<float>(m_shaders_editor.percent_outline));
-            draw_list->AddCircleFilled({ 0.5f * (pos.x + pos.x + icon_size), 0.5f * (pos.y + pos.y + icon_size) }, radius,
-                ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }), 16);
-            if (m_shaders_editor.percent_center > 0)
-            {
-                radius = ((0.5f * icon_size) - 2.0f) * 0.01f * static_cast<float>(m_shaders_editor.percent_center);
-                draw_list->AddCircleFilled({ 0.5f * (pos.x + pos.x + icon_size), 0.5f * (pos.y + pos.y + icon_size) }, radius,
+            if (m_shaders_editor.shader_version == 1) {
+                draw_list->AddCircleFilled({ 0.5f * (pos.x + pos.x + icon_size), 0.5f * (pos.y + pos.y + icon_size) }, (0.5f * icon_size) - 2.0f,
                     ImGui::GetColorU32({ 0.5f * color[0], 0.5f * color[1], 0.5f * color[2], 1.0f }), 16);
+                float radius = ((0.5f * icon_size) - 2.0f) * (1.0f - 0.01f * static_cast<float>(m_shaders_editor.percent_outline));
+                draw_list->AddCircleFilled({ 0.5f * (pos.x + pos.x + icon_size), 0.5f * (pos.y + pos.y + icon_size) }, radius,
+                    ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }), 16);
+                if (m_shaders_editor.percent_center > 0) {
+                    radius = ((0.5f * icon_size) - 2.0f) * 0.01f * static_cast<float>(m_shaders_editor.percent_center);
+                    draw_list->AddCircleFilled({ 0.5f * (pos.x + pos.x + icon_size), 0.5f * (pos.y + pos.y + icon_size) }, radius,
+                        ImGui::GetColorU32({ 0.5f * color[0], 0.5f * color[1], 0.5f * color[2], 1.0f }), 16);
+                }
+            } else {
+                draw_list->AddCircleFilled({ 0.5f * (pos.x + pos.x + icon_size), 0.5f * (pos.y + pos.y + icon_size) }, (0.5f * icon_size) - 2.0f,
+                    ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }), 16);
             }
 #else
             draw_list->AddCircle({ 0.5f * (pos.x + pos.x + icon_size), 0.5f * (pos.y + pos.y + icon_size) }, 0.5f * icon_size, ICON_BORDER_COLOR, 16);
             draw_list->AddCircleFilled({ 0.5f * (pos.x + pos.x + icon_size), 0.5f * (pos.y + pos.y + icon_size) }, (0.5f * icon_size) - 2.0f,
-                ImGui::GetColorU32({ 0.5f * color[0], 0.5f * color[1], 0.5f * color[2], 1.0f }), 16);
-            draw_list->AddCircleFilled({ 0.5f * (pos.x + pos.x + icon_size), 0.5f * (pos.y + pos.y + icon_size) }, (0.5f * icon_size) - 3.0f,
                 ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }), 16);
-            draw_list->AddCircleFilled({ 0.5f * (pos.x + pos.x + icon_size), 0.5f * (pos.y + pos.y + icon_size) }, 1.5f,
-                ImGui::GetColorU32({ 0.5f * color[0], 0.5f * color[1], 0.5f * color[2], 1.0f }), 16);
 #endif // ENABLE_GCODE_VIEWER_SHADERS_EDITOR
             break;
         }
@@ -1195,7 +1203,11 @@ void GCodeViewer::render_legend() const
     auto add_option = [this, add_item](GCodeProcessor::EMoveType move_type, EOptionsColors color, const std::string& text) {
         const IBuffer& buffer = m_buffers[buffer_id(move_type)];
         if (buffer.visible && buffer.indices_count > 0)
-            add_item(EItemType::Circle, Options_Colors[static_cast<unsigned int>(color)], text);
+#if ENABLE_GCODE_VIEWER_SHADERS_EDITOR
+            add_item((m_shaders_editor.shader_version == 0) ? EItemType::Rect : EItemType::Circle, Options_Colors[static_cast<unsigned int>(color)], text);
+#else
+            add_item((buffer.shader == "options_110") ? EItemType::Rect : EItemType::Circle, Options_Colors[static_cast<unsigned int>(color)], text);
+#endif // ENABLE_GCODE_VIEWER_SHADERS_EDITOR
     };
 
     // options
@@ -1337,12 +1349,15 @@ void GCodeViewer::render_shaders_editor() const
     imgui.set_next_window_pos(static_cast<float>(cnv_size.get_width()), 0.5f * static_cast<float>(cnv_size.get_height()), ImGuiCond_Once, 1.0f, 0.5f);
     imgui.begin(std::string("Shaders editor (DEV only)"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize);
 
-    ImGui::RadioButton("glsl version 1.10 (low end PCs)", &m_shaders_editor.glsl_version, 0);
-    ImGui::RadioButton("glsl version 1.20 (default)", &m_shaders_editor.glsl_version, 1);
-    switch (m_shaders_editor.glsl_version)
+    ImGui::RadioButton("glsl version 1.10 (low end PCs)", &m_shaders_editor.shader_version, 0);
+    ImGui::RadioButton("glsl version 1.20 flat (billboards)", &m_shaders_editor.shader_version, 1);
+    ImGui::RadioButton("glsl version 1.20 solid (spheres default)", &m_shaders_editor.shader_version, 2);
+
+    switch (m_shaders_editor.shader_version)
     {
     case 0: { set_shader("options_110"); break; }
-    case 1: { set_shader("options_120"); break; }
+    case 1: { set_shader("options_120_flat"); break; }
+    case 2: { set_shader("options_120_solid"); break; }
     }
 
     if (ImGui::CollapsingHeader("Options", ImGuiTreeNodeFlags_DefaultOpen))
@@ -1364,7 +1379,7 @@ void GCodeViewer::render_shaders_editor() const
         else
             ImGui::SliderInt("fixed size", &m_shaders_editor.fixed_size, 1, 100);
 
-        if (m_shaders_editor.glsl_version == 1)
+        if (m_shaders_editor.shader_version == 1)
         {
             ImGui::SliderInt("percent outline", &m_shaders_editor.percent_outline, 0, 50);
             ImGui::SliderInt("percent center", &m_shaders_editor.percent_center, 0, 50);
diff --git a/src/slic3r/GUI/GCodeViewer.hpp b/src/slic3r/GUI/GCodeViewer.hpp
index 1d940b66a..a2f9c14af 100644
--- a/src/slic3r/GUI/GCodeViewer.hpp
+++ b/src/slic3r/GUI/GCodeViewer.hpp
@@ -205,12 +205,12 @@ class GCodeViewer
 #if ENABLE_GCODE_VIEWER_SHADERS_EDITOR
     struct ShadersEditor
     {
-        int glsl_version{ 1 };
+        int shader_version{ 2 };
         bool size_dependent_on_zoom{ true };
         int fixed_size{ 16 };
-        std::array<int, 2> sizes{ 8, 64 };
-        int percent_outline{ 15 };
-        int percent_center{ 15 };
+        std::array<int, 2> sizes{ 3, 21 };
+        int percent_outline{ 0 };
+        int percent_center{ 33 };
     };
 #endif // ENABLE_GCODE_VIEWER_SHADERS_EDITOR
 
diff --git a/src/slic3r/GUI/GLShader.cpp b/src/slic3r/GUI/GLShader.cpp
index a6d641f89..3c2612b45 100644
--- a/src/slic3r/GUI/GLShader.cpp
+++ b/src/slic3r/GUI/GLShader.cpp
@@ -215,6 +215,26 @@ bool GLShaderProgram::set_uniform(const char* name, double value) const
     return set_uniform(name, static_cast<float>(value));
 }
 
+bool GLShaderProgram::set_uniform(const char* name, const std::array<int, 2>& value) const
+{
+    int id = get_uniform_location(name);
+    if (id >= 0) {
+        glsafe(::glUniform2iv(id, 1, static_cast<const GLint*>(value.data())));
+        return true;
+    }
+    return false;
+}
+
+bool GLShaderProgram::set_uniform(const char* name, const std::array<int, 3>& value) const
+{
+    int id = get_uniform_location(name);
+    if (id >= 0) {
+        glsafe(::glUniform3iv(id, 1, static_cast<const GLint*>(value.data())));
+        return true;
+    }
+    return false;
+}
+
 bool GLShaderProgram::set_uniform(const char* name, const std::array<int, 4>& value) const
 {
     int id = get_uniform_location(name);
diff --git a/src/slic3r/GUI/GLShader.hpp b/src/slic3r/GUI/GLShader.hpp
index 521f6796f..a1160f8e9 100644
--- a/src/slic3r/GUI/GLShader.hpp
+++ b/src/slic3r/GUI/GLShader.hpp
@@ -43,6 +43,8 @@ public:
     bool set_uniform(const char* name, bool value) const;
     bool set_uniform(const char* name, float value) const;
     bool set_uniform(const char* name, double value) const;
+    bool set_uniform(const char* name, const std::array<int, 2>& value) const;
+    bool set_uniform(const char* name, const std::array<int, 3>& value) const;
     bool set_uniform(const char* name, const std::array<int, 4>& value) const;
     bool set_uniform(const char* name, const std::array<float, 2>& value) const;
     bool set_uniform(const char* name, const std::array<float, 3>& value) const;
diff --git a/src/slic3r/GUI/GLShadersManager.cpp b/src/slic3r/GUI/GLShadersManager.cpp
index dd77351bd..4bebf7b98 100644
--- a/src/slic3r/GUI/GLShadersManager.cpp
+++ b/src/slic3r/GUI/GLShadersManager.cpp
@@ -1,6 +1,7 @@
 #include "libslic3r/libslic3r.h"
 #include "GLShadersManager.hpp"
 #include "3DScene.hpp"
+#include "GUI_App.hpp"
 
 #include <cassert>
 #include <algorithm>
@@ -28,19 +29,21 @@ std::pair<bool, std::string> GLShadersManager::init()
 
     bool valid = true;
 
-    // used to render bed axes and model, selection hints, gcode sequential view marker model
+    // used to render bed axes and model, selection hints, gcode sequential view marker model, preview shells
     valid &= append_shader("gouraud_light", { "gouraud_light.vs", "gouraud_light.fs" });
     // used to render printbed
     valid &= append_shader("printbed", { "printbed.vs", "printbed.fs" });
     // used to render options in gcode preview
     valid &= append_shader("options_110", { "options_110.vs", "options_110.fs" });
-    valid &= append_shader("options_120", { "options_120.vs", "options_120.fs" });
+    if (GUI::wxGetApp().is_glsl_version_greater_or_equal_to(1, 20))
+    {
+        valid &= append_shader("options_120_flat", { "options_120_flat.vs", "options_120_flat.fs" });
+        valid &= append_shader("options_120_solid", { "options_120_solid.vs", "options_120_solid.fs" });
+    }
     // used to render extrusion paths in gcode preview
     valid &= append_shader("extrusions", { "extrusions.vs", "extrusions.fs" });
     // used to render travel paths in gcode preview
     valid &= append_shader("travels", { "travels.vs", "travels.fs" });
-    // used to render shells in gcode preview
-    valid &= append_shader("shells", { "shells.vs", "shells.fs" });
     // used to render objects in 3d editor
     valid &= append_shader("gouraud", { "gouraud.vs", "gouraud.fs" });
     // used to render variable layers heights in 3d editor