diff --git a/src/main.cpp b/src/main.cpp
index 89a0f11..ad5d479 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -94,6 +94,10 @@ private:
     vk::Format m_swapChainImageFormat;
     vk::Extent2D m_swapChainExtent;
     std::vector<vk::raii::ImageView> m_swapChainImageViews;
+    vk::SampleCountFlagBits m_msaaSamples = vk::SampleCountFlagBits::e1;
+    vk::raii::DeviceMemory m_colorImageMemory{ nullptr };
+    vk::raii::Image m_colorImage{ nullptr };
+    vk::raii::ImageView m_colorImageView{ nullptr };
     vk::raii::DeviceMemory m_depthImageMemory{ nullptr };
     vk::raii::Image m_depthImage{ nullptr };
     vk::raii::ImageView m_depthImageView{ nullptr };
@@ -137,6 +141,7 @@ private:
         createDescriptorSetLayout();
         createGraphicsPipeline();
         createCommandPool();
+        createColorResources();
         createDepthResources();
         createFramebuffers();
         createTextureImage();
@@ -313,6 +318,7 @@ private:
         for (const auto& it : physicalDevices) {
             if (isDeviceSuitable(it)) {
                 m_physicalDevice = it;
+                m_msaaSamples = getMaxUsableSampleCount();
                 break;
             }
         }
@@ -509,13 +515,13 @@ private:
     void createRenderPass() {
         vk::AttachmentDescription colorAttachment;
         colorAttachment.format = m_swapChainImageFormat;
-        colorAttachment.samples = vk::SampleCountFlagBits::e1;
+        colorAttachment.samples = m_msaaSamples;
         colorAttachment.loadOp = vk::AttachmentLoadOp::eClear;
         colorAttachment.storeOp = vk::AttachmentStoreOp::eStore;
         colorAttachment.stencilLoadOp = vk::AttachmentLoadOp::eDontCare;
         colorAttachment.stencilStoreOp = vk::AttachmentStoreOp::eDontCare;
         colorAttachment.initialLayout = vk::ImageLayout::eUndefined;
-        colorAttachment.finalLayout = vk::ImageLayout::ePresentSrcKHR;
+        colorAttachment.finalLayout = vk::ImageLayout::eColorAttachmentOptimal;
 
         vk::AttachmentReference colorAttachmentRef;
         colorAttachmentRef.attachment = 0;
@@ -523,7 +529,7 @@ private:
 
         vk::AttachmentDescription depthAttachment;
         depthAttachment.format = findDepthFormat();
-        depthAttachment.samples = vk::SampleCountFlagBits::e1;
+        depthAttachment.samples = m_msaaSamples;
         depthAttachment.loadOp = vk::AttachmentLoadOp::eClear;
         depthAttachment.storeOp = vk::AttachmentStoreOp::eDontCare;
         depthAttachment.stencilLoadOp = vk::AttachmentLoadOp::eDontCare;
@@ -534,13 +540,30 @@ private:
         vk::AttachmentReference depthAttachmentRef;
         depthAttachmentRef.attachment = 1;
         depthAttachmentRef.layout = vk::ImageLayout::eDepthStencilAttachmentOptimal;
+        
+        vk::AttachmentDescription colorAttachmentResolve;
+        colorAttachmentResolve.format = m_swapChainImageFormat;
+        colorAttachmentResolve.samples = vk::SampleCountFlagBits::e1;
+        colorAttachmentResolve.loadOp = vk::AttachmentLoadOp::eDontCare;
+        colorAttachmentResolve.storeOp = vk::AttachmentStoreOp::eStore;
+        colorAttachmentResolve.stencilLoadOp = vk::AttachmentLoadOp::eDontCare;
+        colorAttachmentResolve.stencilStoreOp = vk::AttachmentStoreOp::eDontCare;
+        colorAttachmentResolve.initialLayout = vk::ImageLayout::eUndefined;
+        colorAttachmentResolve.finalLayout = vk::ImageLayout::ePresentSrcKHR;
+
+        vk::AttachmentReference colorAttachmentResolveRef;
+        colorAttachmentResolveRef.attachment = 2;
+        colorAttachmentResolveRef.layout = vk::ImageLayout::eColorAttachmentOptimal;
+
 
         vk::SubpassDescription subpass;
         subpass.pipelineBindPoint = vk::PipelineBindPoint::eGraphics;
-        subpass.setColorAttachments( colorAttachmentRef );
+        subpass.colorAttachmentCount = 1;
+        subpass.pColorAttachments = &colorAttachmentRef;
         subpass.pDepthStencilAttachment = &depthAttachmentRef;
+        subpass.pResolveAttachments = &colorAttachmentResolveRef;
 
-        auto attachments = { colorAttachment, depthAttachment };
+        auto attachments = { colorAttachment, depthAttachment, colorAttachmentResolve };
         vk::RenderPassCreateInfo renderPassInfo;
         renderPassInfo.setAttachments( attachments );
         renderPassInfo.setSubpasses( subpass );
@@ -635,7 +658,7 @@ private:
         rasterizer.depthBiasEnable = false;
 
         vk::PipelineMultisampleStateCreateInfo multisampling;
-        multisampling.rasterizationSamples =  vk::SampleCountFlagBits::e1;
+        multisampling.rasterizationSamples =  m_msaaSamples;
         multisampling.sampleShadingEnable = false;  // default
 
         vk::PipelineColorBlendAttachmentState colorBlendAttachment;
@@ -694,7 +717,11 @@ private:
         for (size_t i = 0; i < m_swapChainImageViews.size(); i++) {
             vk::FramebufferCreateInfo framebufferInfo;
             framebufferInfo.renderPass = m_renderPass;
-            std::array<vk::ImageView, 2> attachments { m_swapChainImageViews[i], m_depthImageView };
+            std::array<vk::ImageView, 3> attachments { 
+                m_colorImageView, 
+                m_depthImageView,
+                m_swapChainImageViews[i]
+            };
             framebufferInfo.setAttachments( attachments );
             framebufferInfo.width = m_swapChainExtent.width;
             framebufferInfo.height = m_swapChainExtent.height;
@@ -872,6 +899,10 @@ private:
         m_depthImage = nullptr;
         m_depthImageMemory = nullptr;
 
+        m_colorImageView = nullptr;
+        m_colorImage = nullptr;
+        m_colorImageMemory = nullptr;
+
         m_swapChainImageViews.clear();
         m_swapChainImages.clear(); // optional
         m_swapChain = nullptr;
@@ -879,6 +910,7 @@ private:
 
         createSwapChain();
         createImageViews();
+        createColorResources();
         createDepthResources();
         createFramebuffers();
 
@@ -1192,6 +1224,7 @@ private:
         uint32_t width,
         uint32_t height,
         uint32_t mipLevels,
+        vk::SampleCountFlagBits numSamples,
         vk::Format format,
         vk::ImageTiling tilling,
         vk::ImageUsageFlags usage,
@@ -1210,7 +1243,7 @@ private:
         imageInfo.tiling = tilling;
         imageInfo.initialLayout = vk::ImageLayout::eUndefined;
         imageInfo.usage = usage;
-        imageInfo.samples = vk::SampleCountFlagBits::e1;
+        imageInfo.samples = numSamples;
         imageInfo.sharingMode = vk::SharingMode::eExclusive;
 
         image = m_device.createImage(imageInfo);
@@ -1356,6 +1389,7 @@ private:
             texWidth, 
             texHeight,
             m_mipLevels,
+            vk::SampleCountFlagBits::e1,
             vk::Format::eR8G8B8A8Srgb,
             vk::ImageTiling::eOptimal,
             vk::ImageUsageFlagBits::eTransferSrc |
@@ -1500,6 +1534,7 @@ private:
             m_swapChainExtent.width,
             m_swapChainExtent.height,
             1,
+            m_msaaSamples,
             depthFormat,
             vk::ImageTiling::eOptimal,
             vk::ImageUsageFlagBits::eDepthStencilAttachment,
@@ -1686,6 +1721,50 @@ private:
         endSingleTimeCommands( std::move(commandBuffer) );
     }
     /////////////////////////////////////////////////////////////////
+
+    /////////////////////////////////////////////////////////////////
+    /// multi sample
+    vk::SampleCountFlagBits getMaxUsableSampleCount() {
+        // vk::PhysicalDeviceProperties
+        auto properties = m_physicalDevice.getProperties();
+
+        vk::SampleCountFlags counts = (
+            properties.limits.framebufferColorSampleCounts & 
+            properties.limits.framebufferDepthSampleCounts
+        );
+
+        if(counts & vk::SampleCountFlagBits::e64) return vk::SampleCountFlagBits::e64;
+        if(counts & vk::SampleCountFlagBits::e32) return vk::SampleCountFlagBits::e32;
+        if(counts & vk::SampleCountFlagBits::e16) return vk::SampleCountFlagBits::e16;
+        if(counts & vk::SampleCountFlagBits::e8) return vk::SampleCountFlagBits::e8;
+        if(counts & vk::SampleCountFlagBits::e8) return vk::SampleCountFlagBits::e4;
+        if(counts & vk::SampleCountFlagBits::e8) return vk::SampleCountFlagBits::e2;
+        return vk::SampleCountFlagBits::e1;
+    }
+    void createColorResources() {
+        vk::Format colorFormat = m_swapChainImageFormat;
+
+        createImage(
+            m_swapChainExtent.width,
+            m_swapChainExtent.height,
+            1,
+            m_msaaSamples,
+            colorFormat,
+            vk::ImageTiling::eOptimal,
+            vk::ImageUsageFlagBits::eTransientAttachment |
+            vk::ImageUsageFlagBits::eColorAttachment,
+            vk::MemoryPropertyFlagBits::eDeviceLocal,
+            m_colorImage,
+            m_colorImageMemory
+        );
+        m_colorImageView = createImageView(
+            m_colorImage,
+            colorFormat,
+            vk::ImageAspectFlagBits::eColor,
+            1
+        );
+    }
+    /////////////////////////////////////////////////////////////////
 };
 
 
