diff --git a/resources/shaders/flat_attr.vs b/resources/shaders/flat_attr.vs
new file mode 100644
index 000000000..1b0088675
--- /dev/null
+++ b/resources/shaders/flat_attr.vs
@@ -0,0 +1,10 @@
+#version 110
+
+attribute vec3 v_position;
+
+uniform mat4 projection_view_model_matrix;
+
+void main()
+{
+    gl_Position = projection_view_model_matrix * vec4(v_position, 1.0);
+}
diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp
index 8e7fba126..ac4dace80 100644
--- a/src/libslic3r/Technologies.hpp
+++ b/src/libslic3r/Technologies.hpp
@@ -70,6 +70,8 @@
 #define ENABLE_GLBEGIN_GLEND_REMOVAL (1 && ENABLE_2_5_0_ALPHA1)
 // Enable replace GLIndexedVertexArray with GLModel
 #define ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL (1 && ENABLE_GLBEGIN_GLEND_REMOVAL)
+// Enable using vertex attributes and matrices in shaders
+#define ENABLE_GLBEGIN_GLEND_SHADERS_ATTRIBUTES (1 && ENABLE_GLBEGIN_GLEND_REMOVAL)
 // Enable show non-manifold edges
 #define ENABLE_SHOW_NON_MANIFOLD_EDGES (1 && ENABLE_2_5_0_ALPHA1)
 // Enable rework of Reload from disk command
diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp
index 244a802db..b0b6fcd42 100644
--- a/src/slic3r/GUI/3DBed.cpp
+++ b/src/slic3r/GUI/3DBed.cpp
@@ -11,6 +11,10 @@
 
 #include "GUI_App.hpp"
 #include "GLCanvas3D.hpp"
+#if ENABLE_GLBEGIN_GLEND_SHADERS_ATTRIBUTES
+#include "Plater.hpp"
+#include "Camera.hpp"
+#endif // ENABLE_GLBEGIN_GLEND_SHADERS_ATTRIBUTES
 
 #include <GL/glew.h>
 
@@ -384,7 +388,7 @@ void Bed3D::init_gridlines()
     init_data.reserve_vertices(2 * gridlines.size());
     init_data.reserve_indices(2 * gridlines.size());
 
-    for (const Line& l : gridlines) {
+    for (const Slic3r::Line& l : gridlines) {
         init_data.add_vertex(Vec3f(unscale<float>(l.a.x()), unscale<float>(l.a.y()), GROUND_Z));
         init_data.add_vertex(Vec3f(unscale<float>(l.b.x()), unscale<float>(l.b.y()), GROUND_Z));
         const unsigned int vertices_counter = (unsigned int)init_data.vertices_count();
@@ -694,10 +698,19 @@ void Bed3D::render_default(bool bottom, bool picking)
     init_gridlines();
     init_triangles();
 
+#if ENABLE_GLBEGIN_GLEND_SHADERS_ATTRIBUTES
+    GLShaderProgram* shader = wxGetApp().get_shader("flat_attr");
+#else
     GLShaderProgram* shader = wxGetApp().get_shader("flat");
+#endif // ENABLE_GLBEGIN_GLEND_SHADERS_ATTRIBUTES
     if (shader != nullptr) {
         shader->start_using();
 
+#if ENABLE_GLBEGIN_GLEND_SHADERS_ATTRIBUTES
+        const Transform3d matrix = wxGetApp().plater()->get_camera().get_projection_view_matrix();
+        shader->set_uniform("projection_view_model_matrix", matrix);
+#endif // ENABLE_GLBEGIN_GLEND_SHADERS_ATTRIBUTES
+
         glsafe(::glEnable(GL_DEPTH_TEST));
         glsafe(::glEnable(GL_BLEND));
         glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
diff --git a/src/slic3r/GUI/Camera.hpp b/src/slic3r/GUI/Camera.hpp
index a61eb44ec..6a0158e6d 100644
--- a/src/slic3r/GUI/Camera.hpp
+++ b/src/slic3r/GUI/Camera.hpp
@@ -78,6 +78,9 @@ public:
     const std::array<int, 4>& get_viewport() const { return m_viewport; }
     const Transform3d& get_view_matrix() const { return m_view_matrix; }
     const Transform3d& get_projection_matrix() const { return m_projection_matrix; }
+#if ENABLE_GLBEGIN_GLEND_SHADERS_ATTRIBUTES
+    Transform3d get_projection_view_matrix() const { return m_projection_matrix * m_view_matrix; }
+#endif // ENABLE_GLBEGIN_GLEND_SHADERS_ATTRIBUTES
 
     Vec3d get_dir_right() const { return m_view_matrix.matrix().block(0, 0, 3, 3).row(0); }
     Vec3d get_dir_up() const { return m_view_matrix.matrix().block(0, 0, 3, 3).row(1); }
diff --git a/src/slic3r/GUI/GLModel.cpp b/src/slic3r/GUI/GLModel.cpp
index f0eac9a24..6eeeda7d9 100644
--- a/src/slic3r/GUI/GLModel.cpp
+++ b/src/slic3r/GUI/GLModel.cpp
@@ -982,17 +982,64 @@ void GLModel::render(const std::pair<size_t, size_t>& range)
 
     glsafe(::glBindBuffer(GL_ARRAY_BUFFER, m_render_data.vbo_id));
 
+#if ENABLE_GLBEGIN_GLEND_SHADERS_ATTRIBUTES
+    bool use_attributes = boost::algorithm::iends_with(shader->get_name(), "_attr");
+
+    int position_id = -1;
+    int normal_id = -1;
+    int tex_coord_id = -1;
+#endif // ENABLE_GLBEGIN_GLEND_SHADERS_ATTRIBUTES
+
     if (position) {
-        glsafe(::glVertexPointer(Geometry::position_stride_floats(data.format), GL_FLOAT, vertex_stride_bytes, (const void*)Geometry::position_offset_bytes(data.format)));
-        glsafe(::glEnableClientState(GL_VERTEX_ARRAY));
+#if ENABLE_GLBEGIN_GLEND_SHADERS_ATTRIBUTES
+        if (use_attributes) {
+            position_id = shader->get_attrib_location("v_position");
+            if (position_id != -1) {
+                glsafe(::glVertexAttribPointer(position_id, Geometry::position_stride_floats(data.format), GL_FLOAT, GL_FALSE, vertex_stride_bytes, (GLvoid*)Geometry::position_offset_bytes(data.format)));
+                glsafe(::glEnableVertexAttribArray(position_id));
+            }
+        }
+        else {
+#endif // ENABLE_GLBEGIN_GLEND_SHADERS_ATTRIBUTES
+            glsafe(::glVertexPointer(Geometry::position_stride_floats(data.format), GL_FLOAT, vertex_stride_bytes, (const void*)Geometry::position_offset_bytes(data.format)));
+            glsafe(::glEnableClientState(GL_VERTEX_ARRAY));
+#if ENABLE_GLBEGIN_GLEND_SHADERS_ATTRIBUTES
+        }
+#endif // ENABLE_GLBEGIN_GLEND_SHADERS_ATTRIBUTES
     }
     if (normal) {
-        glsafe(::glNormalPointer(GL_FLOAT, vertex_stride_bytes, (const void*)Geometry::normal_offset_bytes(data.format)));
-        glsafe(::glEnableClientState(GL_NORMAL_ARRAY));
+#if ENABLE_GLBEGIN_GLEND_SHADERS_ATTRIBUTES
+        if (use_attributes) {
+            normal_id = shader->get_attrib_location("v_normal");
+            if (normal_id != -1) {
+                glsafe(::glVertexAttribPointer(normal_id, Geometry::normal_stride_floats(data.format), GL_FLOAT, GL_FALSE, vertex_stride_bytes, (GLvoid*)Geometry::normal_offset_bytes(data.format)));
+                glsafe(::glEnableVertexAttribArray(normal_id));
+            }
+        }
+        else {
+#endif // ENABLE_GLBEGIN_GLEND_SHADERS_ATTRIBUTES
+            glsafe(::glNormalPointer(GL_FLOAT, vertex_stride_bytes, (const void*)Geometry::normal_offset_bytes(data.format)));
+            glsafe(::glEnableClientState(GL_NORMAL_ARRAY));
+#if ENABLE_GLBEGIN_GLEND_SHADERS_ATTRIBUTES
+        }
+#endif // ENABLE_GLBEGIN_GLEND_SHADERS_ATTRIBUTES
     }
     if (tex_coord) {
-        glsafe(::glTexCoordPointer(Geometry::tex_coord_stride_floats(data.format), GL_FLOAT, vertex_stride_bytes, (const void*)Geometry::tex_coord_offset_bytes(data.format)));
-        glsafe(::glEnableClientState(GL_TEXTURE_COORD_ARRAY));
+#if ENABLE_GLBEGIN_GLEND_SHADERS_ATTRIBUTES
+        if (use_attributes) {
+            tex_coord_id = shader->get_attrib_location("v_tex_coord");
+            if (tex_coord_id != -1) {
+                glsafe(::glVertexAttribPointer(tex_coord_id, Geometry::tex_coord_stride_floats(data.format), GL_FLOAT, GL_FALSE, vertex_stride_bytes, (GLvoid*)Geometry::tex_coord_offset_bytes(data.format)));
+                glsafe(::glEnableVertexAttribArray(tex_coord_id));
+            }
+        }
+        else {
+#endif // ENABLE_GLBEGIN_GLEND_SHADERS_ATTRIBUTES
+            glsafe(::glTexCoordPointer(Geometry::tex_coord_stride_floats(data.format), GL_FLOAT, vertex_stride_bytes, (const void*)Geometry::tex_coord_offset_bytes(data.format)));
+            glsafe(::glEnableClientState(GL_TEXTURE_COORD_ARRAY));
+#if ENABLE_GLBEGIN_GLEND_SHADERS_ATTRIBUTES
+        }
+#endif // ENABLE_GLBEGIN_GLEND_SHADERS_ATTRIBUTES
     }
 
     shader->set_uniform("uniform_color", data.color);
@@ -1001,12 +1048,26 @@ void GLModel::render(const std::pair<size_t, size_t>& range)
     glsafe(::glDrawElements(mode, range.second - range.first, index_type, (const void*)(range.first * Geometry::index_stride_bytes(data.format))));
     glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
 
-    if (tex_coord)
-        glsafe(::glDisableClientState(GL_TEXTURE_COORD_ARRAY));
-    if (normal)
-        glsafe(::glDisableClientState(GL_NORMAL_ARRAY));
-    if (position)
-        glsafe(::glDisableClientState(GL_VERTEX_ARRAY));
+#if ENABLE_GLBEGIN_GLEND_SHADERS_ATTRIBUTES
+    if (use_attributes) {
+        if (tex_coord_id != -1)
+            glsafe(::glDisableVertexAttribArray(tex_coord_id));
+        if (normal_id != -1)
+            glsafe(::glDisableVertexAttribArray(normal_id));
+        if (position_id != -1)
+            glsafe(::glDisableVertexAttribArray(position_id));
+    }
+    else {
+#endif // ENABLE_GLBEGIN_GLEND_SHADERS_ATTRIBUTES
+        if (tex_coord)
+            glsafe(::glDisableClientState(GL_TEXTURE_COORD_ARRAY));
+        if (normal)
+            glsafe(::glDisableClientState(GL_NORMAL_ARRAY));
+        if (position)
+            glsafe(::glDisableClientState(GL_VERTEX_ARRAY));
+#if ENABLE_GLBEGIN_GLEND_SHADERS_ATTRIBUTES
+    }
+#endif // ENABLE_GLBEGIN_GLEND_SHADERS_ATTRIBUTES
 
     glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
 }
diff --git a/src/slic3r/GUI/GLShadersManager.cpp b/src/slic3r/GUI/GLShadersManager.cpp
index 33ac9b6bc..70b1b6c31 100644
--- a/src/slic3r/GUI/GLShadersManager.cpp
+++ b/src/slic3r/GUI/GLShadersManager.cpp
@@ -36,6 +36,9 @@ std::pair<bool, std::string> GLShadersManager::init()
 #if ENABLE_GLBEGIN_GLEND_REMOVAL
     // basic shader, used to render all what was previously rendered using the immediate mode
     valid &= append_shader("flat", { "flat.vs", "flat.fs" });
+#if ENABLE_GLBEGIN_GLEND_SHADERS_ATTRIBUTES
+    valid &= append_shader("flat_attr", { "flat_attr.vs", "flat.fs" });
+#endif // ENABLE_GLBEGIN_GLEND_SHADERS_ATTRIBUTES
     // basic shader for textures, used to render textures
     valid &= append_shader("flat_texture", { "flat_texture.vs", "flat_texture.fs" });
     // used to render 3D scene background