Index: graphics-pipeline_vulkan.hpp
===================================================================
--- graphics-pipeline_vulkan.hpp	(revision e1308e874d193cdc00723f7df1f19245df234d38)
+++ graphics-pipeline_vulkan.hpp	(revision 055750aa780089e54a6a30e8455284e2e1f4883c)
@@ -376,4 +376,5 @@
          switch (descriptorWrites[j].descriptorType) {
             case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
+            case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
                descriptorWrites[j].pBufferInfo = &(*this->descriptorInfoList[j].bufferDataList)[i];
                break;
Index: shaders/scene.frag
===================================================================
--- shaders/scene.frag	(revision e1308e874d193cdc00723f7df1f19245df234d38)
+++ shaders/scene.frag	(revision 055750aa780089e54a6a30e8455284e2e1f4883c)
@@ -2,5 +2,5 @@
 #extension GL_ARB_separate_shader_objects : enable
 
-layout(binding = 1) uniform sampler2D texSampler;
+layout(binding = 2) uniform sampler2D texSampler;
 
 layout(location = 0) in vec3 fragColor;
Index: shaders/scene.vert
===================================================================
--- shaders/scene.vert	(revision e1308e874d193cdc00723f7df1f19245df234d38)
+++ shaders/scene.vert	(revision 055750aa780089e54a6a30e8455284e2e1f4883c)
@@ -2,9 +2,16 @@
 #extension GL_ARB_separate_shader_objects : enable
 
+struct Object {
+   mat4 model;
+};
+
 layout (binding = 0) uniform UniformBufferObject {
-   mat4 model;
    mat4 view;
    mat4 proj;
 } ubo;
+
+layout(binding = 1) readonly buffer StorageBufferObject {
+    Object objects[];
+} sbo;
 
 layout(location = 0) in vec3 inPosition;
@@ -19,4 +26,4 @@
    fragTexCoord = inTexCoord;
 
-   gl_Position = ubo.proj * ubo.view * ubo.model * vec4(inPosition, 1.0);
+   gl_Position = ubo.proj * ubo.view * sbo.objects[0].model * vec4(inPosition, 1.0);
 }
Index: shaders/ship.vert
===================================================================
--- shaders/ship.vert	(revision e1308e874d193cdc00723f7df1f19245df234d38)
+++ shaders/ship.vert	(revision 055750aa780089e54a6a30e8455284e2e1f4883c)
@@ -2,9 +2,16 @@
 #extension GL_ARB_separate_shader_objects : enable
 
+struct Object {
+   mat4 model;
+};
+
 layout (binding = 0) uniform UniformBufferObject {
-   mat4 model;
    mat4 view;
    mat4 proj;
 } ubo;
+
+layout(binding = 1) readonly buffer StorageBufferObject {
+    Object objects[];
+} sbo;
 
 layout(location = 0) in vec3 vertex_position;
@@ -26,9 +33,9 @@
 // Check Anton's book to see how to fix this
 void main() {
-   position_eye = vec3(ubo.view * ubo.model * vec4(vertex_position, 1.0));
+   position_eye = vec3(ubo.view * sbo.objects[0].model * vec4(vertex_position, 1.0));
    //position_eye = vec3(view * model_mats[ubo_index] * vec4(vertex_position, 1.0));
 
    // Using 0.0 instead of 1.0 means translations won't effect the normal
-   normal_eye = normalize(vec3(ubo.view * ubo.model * vec4(vertex_normal, 0.0)));
+   normal_eye = normalize(vec3(ubo.view * sbo.objects[0].model * vec4(vertex_normal, 0.0)));
    //normal_eye = normalize(vec3(view * model_mats[ubo_index] * vec4(vertex_normal, 0.0)));
    color = vertex_color;
Index: vulkan-game.cpp
===================================================================
--- vulkan-game.cpp	(revision e1308e874d193cdc00723f7df1f19245df234d38)
+++ vulkan-game.cpp	(revision 055750aa780089e54a6a30e8455284e2e1f4883c)
@@ -26,6 +26,6 @@
    framebufferResized = false;
 
-   modelMvpMats = {};
-   shipMvpMats = {};
+   object_VP_mats = {};
+   ship_VP_mats = {};
 }
 
@@ -196,8 +196,14 @@
    modelPipeline.addAttribute(VK_FORMAT_R32G32_SFLOAT, offset_of(&ModelVertex::texCoord));
 
-   createUniformBuffers<UBO_MvpMat>(uniformBuffers, uniformBuffersMemory, uniformBufferInfoList);
+   createBufferSet(sizeof(UBO_VP_mats), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
+      uniformBuffers_scenePipeline, uniformBuffersMemory_scenePipeline, uniformBufferInfoList_scenePipeline);
+   createBufferSet(10 * sizeof(SBO_SceneObject), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
+      storageBuffers_scenePipeline, storageBuffersMemory_scenePipeline, storageBufferInfoList_scenePipeline);
 
    modelPipeline.addDescriptorInfo(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
-      VK_SHADER_STAGE_VERTEX_BIT, &uniformBufferInfoList);
+      VK_SHADER_STAGE_VERTEX_BIT, &uniformBufferInfoList_scenePipeline);
+   modelPipeline.addDescriptorInfo(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
+      VK_SHADER_STAGE_VERTEX_BIT, &storageBufferInfoList_scenePipeline);
+
    modelPipeline.addDescriptorInfo(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
       VK_SHADER_STAGE_FRAGMENT_BIT, &floorTextureImageDescriptor);
@@ -250,8 +256,13 @@
    shipPipeline.addAttribute(VK_FORMAT_R32G32B32_SFLOAT, offset_of(&ShipVertex::normal));
 
-   createUniformBuffers<UBO_MvpMat>(uniformBuffers_shipPipeline, uniformBuffersMemory_shipPipeline, uniformBufferInfoList_shipPipeline);
+   createBufferSet(sizeof(UBO_VP_mats), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
+      uniformBuffers_shipPipeline, uniformBuffersMemory_shipPipeline, uniformBufferInfoList_shipPipeline);
+   createBufferSet(10 * sizeof(SBO_SceneObject), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
+      storageBuffers_shipPipeline, storageBuffersMemory_shipPipeline, storageBufferInfoList_shipPipeline);
 
    shipPipeline.addDescriptorInfo(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
       VK_SHADER_STAGE_VERTEX_BIT, &uniformBufferInfoList_shipPipeline);
+   shipPipeline.addDescriptorInfo(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
+      VK_SHADER_STAGE_VERTEX_BIT, &storageBufferInfoList_shipPipeline);
 
    // TODO: With the normals, indexing basically becomes pointless since no vertices will have exactly
@@ -525,14 +536,9 @@
    proj[1][1] *= -1; // flip the y-axis so that +y is up
 
-   modelMvpMats.model = mat4(1.0f);
-   modelMvpMats.view = view;
-   modelMvpMats.proj = proj;
-
-   mat4 T_model = translate(mat4(1.0f), vec3(0.0f, -1.2f, 1.65f));
-   mat4 R_model(1.0f);
-
-   shipMvpMats.model = T_model * R_model * scale(mat4(1.0f), vec3(0.1f, 0.1f, 0.1f));
-   shipMvpMats.view = view;
-   shipMvpMats.proj = proj;
+   object_VP_mats.view = view;
+   object_VP_mats.proj = proj;
+
+   ship_VP_mats.view = view;
+   ship_VP_mats.proj = proj;
 }
 
@@ -607,4 +613,6 @@
 }
 
+// TODO: The view and projection mats only need to be updated once.
+// Create a separate function that can do this once per Vulkan image at the beginning
 void VulkanGame::updateScene(uint32_t currentImage) {
    static auto startTime = chrono::high_resolution_clock::now();
@@ -613,11 +621,19 @@
    float time = chrono::duration<float, chrono::seconds::period>(currentTime - startTime).count();
 
-   modelMvpMats.model =
+   so_Object.model =
       translate(mat4(1.0f), vec3(0.0f, -2.0f, -0.0f)) *
       rotate(mat4(1.0f), time * radians(90.0f), vec3(0.0f, 0.0f, 1.0f));
 
-   VulkanUtils::copyDataToMemory(device, uniformBuffersMemory[currentImage], modelMvpMats);
-
-   VulkanUtils::copyDataToMemory(device, uniformBuffersMemory_shipPipeline[currentImage], shipMvpMats);
+   so_Ship.model =
+      translate(mat4(1.0f), vec3(0.0f, -1.2f, 1.65f)) *
+      scale(mat4(1.0f), vec3(0.1f, 0.1f, 0.1f));
+
+   VulkanUtils::copyDataToMemory(device, uniformBuffersMemory_scenePipeline[currentImage], object_VP_mats);
+
+   VulkanUtils::copyDataToMemory(device, storageBuffersMemory_scenePipeline[currentImage], so_Object);
+
+   VulkanUtils::copyDataToMemory(device, uniformBuffersMemory_shipPipeline[currentImage], ship_VP_mats);
+
+   VulkanUtils::copyDataToMemory(device, storageBuffersMemory_shipPipeline[currentImage], so_Ship);
 }
 
@@ -901,6 +917,5 @@
 
 void VulkanGame::createLogicalDevice(
-      const vector<const char*> validationLayers,
-      const vector<const char*>& deviceExtensions) {
+      const vector<const char*> validationLayers, const vector<const char*>& deviceExtensions) {
    QueueFamilyIndices indices = VulkanUtils::findQueueFamilies(physicalDevice, surface);
 
@@ -1237,4 +1252,21 @@
 }
 
+void VulkanGame::createBufferSet(VkDeviceSize bufferSize, VkBufferUsageFlags flags,
+      vector<VkBuffer>& buffers, vector<VkDeviceMemory>& buffersMemory, vector<VkDescriptorBufferInfo>& bufferInfoList) {
+   buffers.resize(swapChainImages.size());
+   buffersMemory.resize(swapChainImages.size());
+   bufferInfoList.resize(swapChainImages.size());
+
+   for (size_t i = 0; i < swapChainImages.size(); i++) {
+      VulkanUtils::createBuffer(device, physicalDevice, bufferSize, flags,
+         VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
+         buffers[i], buffersMemory[i]);
+
+      bufferInfoList[i].buffer = buffers[i];
+      bufferInfoList[i].offset = 0; // This is the offset from the start of the buffer, so always 0 for now
+      bufferInfoList[i].range = bufferSize; // Size of the update starting from offset, or VK_WHOLE_SIZE
+   }
+}
+
 // TODO: Fix the crash that happens when alt-tabbing
 void VulkanGame::recreateSwapChain() {
@@ -1260,5 +1292,8 @@
    createFramebuffers();
 
-   createUniformBuffers<UBO_MvpMat>(uniformBuffers, uniformBuffersMemory, uniformBufferInfoList);
+   createBufferSet(sizeof(UBO_VP_mats), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
+      uniformBuffers_scenePipeline, uniformBuffersMemory_scenePipeline, uniformBufferInfoList_scenePipeline);
+   createBufferSet(10 * sizeof(SBO_SceneObject), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
+      storageBuffers_scenePipeline, storageBuffersMemory_scenePipeline, storageBufferInfoList_scenePipeline);
 
    modelPipeline.updateRenderPass(renderPass);
@@ -1272,5 +1307,8 @@
    overlayPipeline.createDescriptorSets(swapChainImages);
 
-   createUniformBuffers<UBO_MvpMat>(uniformBuffers_shipPipeline, uniformBuffersMemory_shipPipeline, uniformBufferInfoList_shipPipeline);
+   createBufferSet(sizeof(UBO_VP_mats), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
+      uniformBuffers_shipPipeline, uniformBuffersMemory_shipPipeline, uniformBufferInfoList_shipPipeline);
+   createBufferSet(10 * sizeof(SBO_SceneObject), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
+      storageBuffers_shipPipeline, storageBuffersMemory_shipPipeline, storageBufferInfoList_shipPipeline);
 
    shipPipeline.updateRenderPass(renderPass);
@@ -1303,7 +1341,12 @@
    vkDestroySwapchainKHR(device, swapChain, nullptr);
 
-   for (size_t i = 0; i < uniformBuffers.size(); i++) {
-      vkDestroyBuffer(device, uniformBuffers[i], nullptr);
-      vkFreeMemory(device, uniformBuffersMemory[i], nullptr);
+   for (size_t i = 0; i < uniformBuffers_scenePipeline.size(); i++) {
+      vkDestroyBuffer(device, uniformBuffers_scenePipeline[i], nullptr);
+      vkFreeMemory(device, uniformBuffersMemory_scenePipeline[i], nullptr);
+   }
+
+   for (size_t i = 0; i < storageBuffers_scenePipeline.size(); i++) {
+      vkDestroyBuffer(device, storageBuffers_scenePipeline[i], nullptr);
+      vkFreeMemory(device, storageBuffersMemory_scenePipeline[i], nullptr);
    }
 
@@ -1312,3 +1355,8 @@
       vkFreeMemory(device, uniformBuffersMemory_shipPipeline[i], nullptr);
    }
-}
+
+   for (size_t i = 0; i < storageBuffers_shipPipeline.size(); i++) {
+      vkDestroyBuffer(device, storageBuffers_shipPipeline[i], nullptr);
+      vkFreeMemory(device, storageBuffersMemory_shipPipeline[i], nullptr);
+   }
+}
Index: vulkan-game.hpp
===================================================================
--- vulkan-game.hpp	(revision e1308e874d193cdc00723f7df1f19245df234d38)
+++ vulkan-game.hpp	(revision 055750aa780089e54a6a30e8455284e2e1f4883c)
@@ -35,8 +35,11 @@
 };
 
-struct UBO_MvpMat {
-   alignas(16) mat4 model;
+struct UBO_VP_mats {
    alignas(16) mat4 view;
    alignas(16) mat4 proj;
+};
+
+struct SBO_SceneObject {
+   alignas(16) mat4 model;
 };
 
@@ -57,6 +60,9 @@
       vec3 cam_pos;
 
-      UBO_MvpMat modelMvpMats;
-      UBO_MvpMat shipMvpMats;
+      UBO_VP_mats object_VP_mats;
+      SBO_SceneObject so_Object;
+
+      UBO_VP_mats ship_VP_mats;
+      SBO_SceneObject so_Ship;
 
       GameGui* gui;
@@ -96,11 +102,16 @@
       VkSampler textureSampler;
 
-      // These are currently to store the MVP matrix
-      // I should figure out if it makes sense to use them for other uniforms in the future
-      // If not, I should rename them to better indicate their purpose.
-      vector<VkBuffer> uniformBuffers;
-      vector<VkDeviceMemory> uniformBuffersMemory;
-
-      vector<VkDescriptorBufferInfo> uniformBufferInfoList;
+      // TODO: I should probably rename the uniformBuffer* and storageBuffer*
+      // variables to better reflect the data they hold
+
+      vector<VkBuffer> uniformBuffers_scenePipeline;
+      vector<VkDeviceMemory> uniformBuffersMemory_scenePipeline;
+
+      vector<VkDescriptorBufferInfo> uniformBufferInfoList_scenePipeline;
+
+      vector<VkBuffer> storageBuffers_scenePipeline;
+      vector<VkDeviceMemory> storageBuffersMemory_scenePipeline;
+
+      vector<VkDescriptorBufferInfo> storageBufferInfoList_scenePipeline;
 
       vector<VkBuffer> uniformBuffers_shipPipeline;
@@ -108,4 +119,9 @@
 
       vector<VkDescriptorBufferInfo> uniformBufferInfoList_shipPipeline;
+
+      vector<VkBuffer> storageBuffers_shipPipeline;
+      vector<VkDeviceMemory> storageBuffersMemory_shipPipeline;
+
+      vector<VkDescriptorBufferInfo> storageBufferInfoList_shipPipeline;
 
       VulkanImage floorTextureImage;
@@ -162,7 +178,6 @@
       vector<VertexType> addVertexNormals(vector<VertexType> vertices);
 
-      template<class UniformType>
-      void createUniformBuffers(vector<VkBuffer>& buffers, vector<VkDeviceMemory>& buffersMemory,
-         vector<VkDescriptorBufferInfo>& bufferInfoList);
+      void createBufferSet(VkDeviceSize bufferSize, VkBufferUsageFlags flags,
+         vector<VkBuffer>& buffers, vector<VkDeviceMemory>& buffersMemory, vector<VkDescriptorBufferInfo>& bufferInfoList);
 
       void recreateSwapChain();
@@ -176,22 +191,4 @@
             void* pUserData);
 };
-
-template<class UniformType>
-void VulkanGame::createUniformBuffers(vector<VkBuffer>& buffers, vector<VkDeviceMemory>& buffersMemory,
-      vector<VkDescriptorBufferInfo>& bufferInfoList) {
-   buffers.resize(swapChainImages.size());
-   buffersMemory.resize(swapChainImages.size());
-   bufferInfoList.resize(swapChainImages.size());
-
-   for (size_t i = 0; i < swapChainImages.size(); i++) {
-      VulkanUtils::createBuffer(device, physicalDevice, sizeof(UniformType), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
-         VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
-         buffers[i], buffersMemory[i]);
-
-      bufferInfoList[i].buffer = buffers[i];
-      bufferInfoList[i].offset = 0;
-      bufferInfoList[i].range = sizeof(UniformType);
-   }
-}
 
 template<class VertexType>
Index: vulkan-utils.hpp
===================================================================
--- vulkan-utils.hpp	(revision e1308e874d193cdc00723f7df1f19245df234d38)
+++ vulkan-utils.hpp	(revision 055750aa780089e54a6a30e8455284e2e1f4883c)
@@ -125,4 +125,5 @@
 }
 
+// TODO: Change copyDataToMemory so it can accept offsets for the data source and destination
 template<class DataType>
 void VulkanUtils::copyDataToMemory(VkDevice device, VkDeviceMemory bufferMemory, const DataType& srcData) {
