diff --git a/shaders/frag.glsl b/shaders/frag.glsl
index b8e81af..fdaaa23 100644
--- a/shaders/frag.glsl
+++ b/shaders/frag.glsl
@@ -45,7 +45,12 @@ uniform Material material;
 uniform DirLight directional_light;
 uniform PointLight point_lights[POINT_LIGHT_COUNT];
 uniform SpotLight spot_light;
-uniform vec3 camera_position;
+
+layout (std140) uniform Common {
+  mat4 projection;
+  mat4 view;
+  vec3 camera_position;
+};
 
 vec3 calc_dir_light(DirLight light, vec3 normal, vec3 view_direction);
 vec3 calc_point_light(PointLight light, vec3 normal, vec3 frag_position, vec3 view_direction);
diff --git a/shaders/reflective_frag.glsl b/shaders/reflective_frag.glsl
index 589fc3f..e75439d 100644
--- a/shaders/reflective_frag.glsl
+++ b/shaders/reflective_frag.glsl
@@ -6,9 +6,14 @@ in VS_OUT {
   vec2 uv_coords;
 } fs_in;
 
-uniform vec3 camera_position;
 uniform samplerCube cubemap;
 
+layout (std140) uniform Common {
+  mat4 projection;
+  mat4 view;
+  vec3 camera_position;
+};
+
 out vec4 color;
 
 void main() {
diff --git a/shaders/refractive_frag.glsl b/shaders/refractive_frag.glsl
index 9aaab80..9362ddb 100644
--- a/shaders/refractive_frag.glsl
+++ b/shaders/refractive_frag.glsl
@@ -9,9 +9,14 @@ in VS_OUT {
   vec2 uv_coords;
 } fs_in;
 
-uniform vec3 camera_position;
 uniform samplerCube cubemap;
 
+layout (std140) uniform Common {
+  mat4 projection;
+  mat4 view;
+  vec3 camera_position;
+};
+
 out vec4 color;
 
 void main() {
diff --git a/shaders/sb_vert.glsl b/shaders/sb_vert.glsl
index a59433d..4675721 100644
--- a/shaders/sb_vert.glsl
+++ b/shaders/sb_vert.glsl
@@ -4,13 +4,18 @@ layout(location=0) in vec3 position;
 layout(location=1) in vec3 normal;
 layout(location=2) in vec2 uv;
 
-uniform mat4 view;
-uniform mat4 projection;
+uniform mat4 sb_view;
+
+layout (std140) uniform Common {
+  mat4 projection;
+  mat4 view;
+  vec3 camera_position;
+};
 
 out vec3 uv_coords;
 
 void main() {
-  vec4 pos    = projection * view * vec4(position, 1.0);
+  vec4 pos    = projection * sb_view * vec4(position, 1.0);
   gl_Position = pos.xyww;
   uv_coords   = position;
 }
diff --git a/shaders/vert.glsl b/shaders/vert.glsl
index 48cb808..a4fa499 100644
--- a/shaders/vert.glsl
+++ b/shaders/vert.glsl
@@ -6,8 +6,12 @@ layout(location=2) in vec2 uv;
 
 uniform mat3 normal_mat;
 uniform mat4 model;
-uniform mat4 view;
-uniform mat4 projection;
+
+layout (std140) uniform Common {
+  mat4 projection;
+  mat4 view;
+  vec3 camera_position;
+};
 
 // interface block
 out VS_OUT {
diff --git a/src/main.cc b/src/main.cc
index 8c4e728..01c888c 100644
--- a/src/main.cc
+++ b/src/main.cc
@@ -290,14 +290,6 @@ int main() {
   glm::mat4 projection = glm::perspective(glm::radians(45.0f), (float)WINDOW_WIDTH / (float)WINDOW_HEIGHT, 0.1f, 100.0f);
   glm::mat3 normal_mat = glm::mat3(1.0f);
 
-  main_shader.set_mat4 ("projection", projection);
-  main_shader.set_float("material.shininess", 32.0f);
-
-  light_shader.set_mat4("projection", projection);
-  skybox_shader.set_mat4("projection", projection);
-  reflective_shader.set_mat4("projection", projection);
-  refractive_shader.set_mat4("projection", projection);
-
   std::vector<glm::vec3> point_light_positions = {
     glm::vec3( 0.7f,  0.2f,  2.0f),
     glm::vec3( 2.3f, -3.3f, -4.0f),
@@ -305,6 +297,9 @@ int main() {
     glm::vec3( 1.0f,  0.0f, -18.0f)
   };
 
+  // Setup material
+  main_shader.set_float("material.shininess", 32.0f);
+
   // Setup lights
   main_shader.set_vec3("directional_light.direction", glm::vec3(-0.2f, -1.0f, -0.3f));
   main_shader.set_vec3("directional_light.ambient", light_ambient);
@@ -364,6 +359,32 @@ int main() {
 
   GLuint cubemap = load_cubemap(cube_map_textures);
 
+  // Generate and bind uniform buffer
+  GLuint ubo;
+  GLuint ubo_binding_point = 0;
+  glGenBuffers(1, &ubo);
+  glBindBuffer(GL_UNIFORM_BUFFER, ubo);
+  glBufferData(GL_UNIFORM_BUFFER, 144, NULL, GL_STATIC_DRAW);
+  // Bind the uniform buffer object to a binding point
+  // Can also be done using glBindBufferRange instead of glBindBufferBase
+  glBindBufferBase(GL_UNIFORM_BUFFER, ubo_binding_point, ubo);
+
+  // Set the shaders binding points
+  GLuint main_shader_common_block_index = glGetUniformBlockIndex(main_shader.program, "Common");
+  GLuint light_shader_common_block_index = glGetUniformBlockIndex(light_shader.program, "Common");
+  GLuint skybox_shader_common_block_index = glGetUniformBlockIndex(skybox_shader.program, "Common");
+  GLuint reflective_shader_common_block_index = glGetUniformBlockIndex(reflective_shader.program, "Common");
+  GLuint refractive_shader_common_block_index = glGetUniformBlockIndex(refractive_shader.program, "Common");
+  glUniformBlockBinding(main_shader.program, main_shader_common_block_index, ubo_binding_point);
+  glUniformBlockBinding(light_shader.program, light_shader_common_block_index, ubo_binding_point);
+  glUniformBlockBinding(skybox_shader.program, skybox_shader_common_block_index, ubo_binding_point);
+  glUniformBlockBinding(reflective_shader.program, reflective_shader_common_block_index, ubo_binding_point);
+  glUniformBlockBinding(refractive_shader.program, refractive_shader_common_block_index, ubo_binding_point);
+
+  // Add projection matrix to uniform buffer
+  glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(glm::mat4), glm::value_ptr(projection));
+  glBindBuffer(GL_UNIFORM_BUFFER, 0);
+
   const float sensitivity   = 0.1f;
   int last_mouse_x          = WINDOW_HALF_WIDTH;
   int last_mouse_y          = WINDOW_HALF_HEIGHT;
@@ -442,18 +463,18 @@ int main() {
     camera_forward   = glm::normalize(camera_forward);
 
     view = glm::lookAt(camera_position, camera_position + camera_forward, world_up);
-    main_shader.set_vec3("camera_position", camera_position);
+
+    // Add view matrix and camera_position to uniform buffer
+    glBindBuffer(GL_UNIFORM_BUFFER, ubo);
+    glBufferSubData(GL_UNIFORM_BUFFER, sizeof(glm::mat4), sizeof(glm::mat4), glm::value_ptr(view));
+    glBufferSubData(GL_UNIFORM_BUFFER, 2 * sizeof(glm::mat4), sizeof(glm::vec3), glm::value_ptr(camera_position));
+    glBindBuffer(GL_UNIFORM_BUFFER, 0);
+
     main_shader.set_vec3("spot_light.position", camera_position);
     main_shader.set_vec3("spot_light.direction", camera_forward);
     main_shader.set_float("spot_light.cutoff", glm::cos(glm::radians(12.5)));
     main_shader.set_float("spot_light.outer_cutoff", glm::cos(glm::radians(17.5)));
-    main_shader.set_mat4("view", view);
-    light_shader.set_mat4("view", view);
-    reflective_shader.set_vec3("camera_position", camera_position);
-    reflective_shader.set_mat4("view", view);
-    refractive_shader.set_vec3("camera_position", camera_position);
-    refractive_shader.set_mat4("view", view);
-    skybox_shader.set_mat4("view", glm::mat4(glm::mat3(view)));
+    skybox_shader.set_mat4("sb_view", glm::mat4(glm::mat3(view)));
 
     // Main render pass
     glBindFramebuffer(GL_FRAMEBUFFER, offscreen_buffer.fbo);