diff --git a/lib/Slic3r/GUI.pm b/lib/Slic3r/GUI.pm
index 087f13cc2..e655bb1b3 100644
--- a/lib/Slic3r/GUI.pm
+++ b/lib/Slic3r/GUI.pm
@@ -14,6 +14,7 @@ use Slic3r::GUI::ConfigWizard;
 use Slic3r::GUI::Controller;
 use Slic3r::GUI::Controller::ManualControlDialog;
 use Slic3r::GUI::Controller::PrinterPanel;
+use Slic3r::GUI::GLShader;
 use Slic3r::GUI::MainFrame;
 use Slic3r::GUI::Notifier;
 use Slic3r::GUI::Plater;
diff --git a/lib/Slic3r/GUI/3DScene.pm b/lib/Slic3r/GUI/3DScene.pm
index 374469a0e..ed4b82fbd 100644
--- a/lib/Slic3r/GUI/3DScene.pm
+++ b/lib/Slic3r/GUI/3DScene.pm
@@ -720,6 +720,13 @@ sub InitGL {
     return if $self->init;
     return unless $self->GetContext;
     $self->init(1);
+
+    my $shader;
+#    $shader = $self->{shader} = new Slic3r::GUI::GLShader;
+    if ($self->{shader}) {
+        my $info = $shader->Load($self->_fragment_shader, $self->_vertex_shader);
+        print $info if $info;
+    }
     
     glClearColor(0, 0, 0, 1);
     glColor3f(1, 0, 0);
@@ -957,6 +964,8 @@ sub draw_volumes {
     # $fakecolor is a boolean indicating, that the objects shall be rendered in a color coding the object index for picking.
     my ($self, $fakecolor) = @_;
     
+    $self->{shader}->Enable if (! $fakecolor && $self->{shader});
+
     glEnable(GL_BLEND);
     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
     
@@ -1017,15 +1026,33 @@ sub draw_volumes {
         if ($qverts_begin < $qverts_end) {
             glVertexPointer_c(3, GL_FLOAT, 0, $volume->qverts->verts_ptr);
             glNormalPointer_c(GL_FLOAT, 0, $volume->qverts->norms_ptr);
-            glDrawArrays(GL_QUADS, $qverts_begin / 3, ($qverts_end-$qverts_begin) / 3);
+            $qverts_begin /= 3;
+            $qverts_end /= 3;
+            my $nvertices = $qverts_end-$qverts_begin;
+            while ($nvertices > 0) {
+                my $nvertices_this = ($nvertices > 4096) ? 4096 : $nvertices;
+                glDrawArrays(GL_QUADS, $qverts_begin, $nvertices_this);
+                $qverts_begin += $nvertices_this;
+                $nvertices -= $nvertices_this;
+            }
         }
         
         if ($tverts_begin < $tverts_end) {
             glVertexPointer_c(3, GL_FLOAT, 0, $volume->tverts->verts_ptr);
             glNormalPointer_c(GL_FLOAT, 0, $volume->tverts->norms_ptr);
-            glDrawArrays(GL_TRIANGLES, $tverts_begin / 3, ($tverts_end-$tverts_begin) / 3);
+            $tverts_begin /= 3;
+            $tverts_end /= 3;
+            my $nvertices = $tverts_end-$tverts_begin;
+            while ($nvertices > 0) {
+                my $nvertices_this = ($nvertices > 4095) ? 4095 : $nvertices;
+                glDrawArrays(GL_TRIANGLES, $tverts_begin, $nvertices_this);
+                $tverts_begin += $nvertices_this;
+                $nvertices -= $nvertices_this;
+            }
         }
-        
+
+        glVertexPointer_c(3, GL_FLOAT, 0, 0);
+        glNormalPointer_c(GL_FLOAT, 0, 0);        
         glPopMatrix();
     }
     glDisableClientState(GL_NORMAL_ARRAY);
@@ -1036,8 +1063,11 @@ sub draw_volumes {
         glColor3f(0, 0, 0);
         glVertexPointer_p(3, $self->cut_lines_vertices);
         glDrawArrays(GL_LINES, 0, $self->cut_lines_vertices->elements / 3);
+        glVertexPointer_c(3, GL_FLOAT, 0, 0);
     }
     glDisableClientState(GL_VERTEX_ARRAY);
+
+    $self->{shader}->Disable if (! $fakecolor && $self->{shader});
 }
 
 sub _report_opengl_state
@@ -1069,6 +1099,86 @@ sub _report_opengl_state
     }
 }
 
+sub _vertex_shader {
+    return <<'VERTEX';
+#version 110
+
+varying float object_z;
+
+void main()
+{
+    vec3 normal, lightDir, viewVector, halfVector;
+    vec4 diffuse, ambient, globalAmbient, specular = vec4(0.0);
+    float NdotL,NdotHV;
+    
+    // First transform the normal into eye space and normalize the result.
+    normal = normalize(gl_NormalMatrix * gl_Normal);
+    
+    // Now normalize the light's direction. Note that according to the OpenGL specification, the light is stored in eye space. 
+    // Also since we're talking about a directional light, the position field is actually direction.
+    lightDir = normalize(vec3(gl_LightSource[0].position));
+    
+    // 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.
+    NdotL = max(dot(normal, lightDir), 0.0);
+    
+    // Compute the diffuse, ambient and globalAmbient terms.
+//    diffuse = NdotL * (gl_FrontMaterial.diffuse * gl_LightSource[0].diffuse);
+//    ambient = gl_FrontMaterial.ambient * gl_LightSource[0].ambient;
+    diffuse = NdotL * (gl_Color * gl_LightSource[0].diffuse);
+    ambient = gl_Color * gl_LightSource[0].ambient;
+    globalAmbient = gl_LightModel.ambient * gl_FrontMaterial.ambient;
+    
+    // compute the specular term if NdotL is  larger than zero
+    if (NdotL > 0.0) {
+        NdotHV = max(dot(normal, normalize(gl_LightSource[0].halfVector.xyz)),0.0);
+        specular = gl_FrontMaterial.specular * gl_LightSource[0].specular * pow(NdotHV,gl_FrontMaterial.shininess);
+    }
+
+    // Perform the same lighting calculation for the 2nd light source.
+    lightDir = normalize(vec3(gl_LightSource[1].position));
+    NdotL = max(dot(normal, lightDir), 0.0);
+//    diffuse += NdotL * (gl_FrontMaterial.diffuse * gl_LightSource[1].diffuse);
+//    ambient += gl_FrontMaterial.ambient * gl_LightSource[1].ambient;
+    diffuse += NdotL * (gl_Color * gl_LightSource[1].diffuse);
+    ambient += gl_Color * gl_LightSource[1].ambient;
+    
+    // compute the specular term if NdotL is  larger than zero
+    if (NdotL > 0.0) {
+        NdotHV = max(dot(normal, normalize(gl_LightSource[1].halfVector.xyz)),0.0);
+        specular += gl_FrontMaterial.specular * gl_LightSource[1].specular * pow(NdotHV,gl_FrontMaterial.shininess);
+    }
+    
+    gl_FrontColor = globalAmbient + diffuse + ambient + specular;
+    gl_FrontColor.a = 1.;
+    
+    gl_Position = ftransform();  
+    object_z = gl_Vertex.z / gl_Vertex.w;
+} 
+
+VERTEX
+}
+
+sub _fragment_shader {
+    return <<'FRAGMENT';
+#version 110
+#define M_PI 3.1415926535897932384626433832795
+
+varying float object_z;
+
+void main()
+{
+    float layer_height = 0.25;
+    float layer_height2 = 0.5 * layer_height;
+    float layer_center = floor(object_z / layer_height) * layer_height + layer_height2;
+    float intensity = cos(M_PI * 0.7 * (layer_center - object_z) / layer_height);
+    gl_FragColor = gl_Color * intensity;
+    gl_FragColor.a = 1.;
+}
+
+FRAGMENT
+}
+
 # Container for object geometry and selection status.
 package Slic3r::GUI::3DScene::Volume;
 use Moo;
diff --git a/lib/Slic3r/GUI/GLShader.pm b/lib/Slic3r/GUI/GLShader.pm
new file mode 100644
index 000000000..e5f9c4a62
--- /dev/null
+++ b/lib/Slic3r/GUI/GLShader.pm
@@ -0,0 +1,174 @@
+############################################################
+#
+# OpenGL::Shader::Objects - Copyright 2007 Graphcomp - ALL RIGHTS RESERVED
+# Author: Bob "grafman" Free - grafman@graphcomp.com
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the same terms as Perl itself.
+#
+############################################################
+
+package Slic3r::GUI::GLShader;
+use OpenGL(':all');
+
+# Shader constructor
+sub new
+{
+  # Check for required OpenGL extensions
+  return undef if (OpenGL::glpCheckExtension('GL_ARB_shader_objects'));
+  return undef if (OpenGL::glpCheckExtension('GL_ARB_fragment_shader'));
+  return undef if (OpenGL::glpCheckExtension('GL_ARB_vertex_shader'));
+  return undef if (OpenGL::glpCheckExtension('GL_ARB_shading_language_100'));
+#  my $glsl_version = glGetString(GL_SHADING_LANGUAGE_VERSION);
+#  my $glsl_version_ARB = glGetString(GL_SHADING_LANGUAGE_VERSION_ARB );
+#  print "GLSL version: $glsl_version, ARB: $glsl_version_ARB\n";
+
+  my $this = shift;
+  my $class = ref($this) || $this;
+  my($type) = @_;
+  my $self = {type => uc($type)};
+  bless($self,$class);
+
+  # Get GL_SHADING_LANGUAGE_VERSION_ARB
+  my $shader_ver = glGetString(0x8B8C);
+  $shader_ver =~ m|([\d\.]+)|;
+  $self->{version} = $1 || '0';
+  print 
+  return $self;
+}
+
+# Shader destructor
+# Must be disabled first
+sub DESTROY
+{
+  my($self) = @_;
+
+  if ($self->{program})
+  {
+    glDetachObjectARB($self->{program},$self->{fragment_id}) if ($self->{fragment_id});
+    glDetachObjectARB($self->{program},$self->{vertex_id}) if ($self->{vertex_id});
+    glDeleteProgramsARB_p($self->{program});
+  }
+
+  glDeleteProgramsARB_p($self->{fragment_id}) if ($self->{fragment_id});
+  glDeleteProgramsARB_p($self->{vertex_id}) if ($self->{vertex_id});
+}
+
+
+# Load shader strings
+sub Load
+{
+  my($self,$fragment,$vertex) = @_;
+
+  # Load fragment code
+  if ($fragment)
+  {
+    $self->{fragment_id} = glCreateShaderObjectARB(GL_FRAGMENT_SHADER);
+    return undef if (!$self->{fragment_id});
+
+    glShaderSourceARB_p($self->{fragment_id}, $fragment);
+    #my $frag = glGetShaderSourceARB_p($self->{fragment_id});
+    #print STDERR "Loaded fragment:\n$frag\n";
+
+    glCompileShaderARB($self->{fragment_id});
+    my $stat = glGetInfoLogARB_p($self->{fragment_id});
+    return "Fragment shader: $stat" if ($stat);
+  }
+
+  # Load vertex code
+  if ($vertex)
+  {
+    $self->{vertex_id} = glCreateShaderObjectARB(GL_VERTEX_SHADER);
+    return undef if (!$self->{vertex_id});
+
+    glShaderSourceARB_p($self->{vertex_id}, $vertex);
+    #my $vert = glGetShaderSourceARB_p($self->{vertex_id});
+    #print STDERR "Loaded vertex:\n$vert\n";
+
+    glCompileShaderARB($self->{vertex_id});
+    $stat = glGetInfoLogARB_p($self->{vertex_id});
+    return "Vertex shader: $stat" if ($stat);
+  }
+
+
+  # Link shaders
+  my $sp = glCreateProgramObjectARB();
+  glAttachObjectARB($sp, $self->{fragment_id}) if ($fragment);
+  glAttachObjectARB($sp, $self->{vertex_id}) if ($vertex);
+  glLinkProgramARB($sp);
+  my $linked = glGetObjectParameterivARB_p($sp, GL_OBJECT_LINK_STATUS_ARB);
+  if (!$linked)
+  {
+    $stat = glGetInfoLogARB_p($sp);
+    #print STDERR "Load shader: $stat\n";
+    return "Link shader: $stat" if ($stat);
+    return 'Unable to link shader';
+  }
+
+  $self->{program} = $sp;
+
+  return '';
+}
+
+# Enable shader
+sub Enable
+{
+  my($self) = @_;
+  glUseProgramObjectARB($self->{program}) if ($self->{program});
+}
+
+# Disable shader
+sub Disable
+{
+  my($self) = @_;
+  glUseProgramObjectARB(0) if ($self->{program});
+}
+
+# Return shader vertex attribute ID
+sub MapAttr
+{
+  my($self,$attr) = @_;
+  return undef if (!$self->{program});
+  my $id = glGetAttribLocationARB_p($self->{program},$attr);
+  return undef if ($id < 0);
+  return $id;
+}
+
+# Return shader uniform variable ID
+sub Map
+{
+  my($self,$var) = @_;
+  return undef if (!$self->{program});
+  my $id = glGetUniformLocationARB_p($self->{program},$var);
+  return undef if ($id < 0);
+  return $id;
+}
+
+# Set shader vector
+sub SetVector
+{
+  my($self,$var,@values) = @_;
+
+  my $id = $self->Map($var);
+  return 'Unable to map $var' if (!defined($id));
+
+  my $count = scalar(@values);
+  eval('glUniform'.$count.'fARB($id,@values)');
+
+  return '';
+}
+
+# Set shader 4x4 matrix
+sub SetMatrix
+{
+  my($self,$var,$oga) = @_;
+
+  my $id = $self->Map($var);
+  return 'Unable to map $var' if (!defined($id));
+
+  glUniformMatrix4fvARB_c($id,1,0,$oga->ptr());
+  return '';
+}
+
+1;
+__END__