Implemented Mipmaps
This commit is contained in:
+94
-17
@@ -412,7 +412,7 @@ namespace vapp{
|
||||
swapChainImageViews.resize(swapChainImages.size());
|
||||
|
||||
for(uint32_t i = 0; i < swapChainImages.size(); i++){
|
||||
swapChainImageViews[i] = createImageView(swapChainImages[i], swapChainImageFormat, VK_IMAGE_ASPECT_COLOR_BIT);
|
||||
swapChainImageViews[i] = createImageView(swapChainImages[i], swapChainImageFormat, VK_IMAGE_ASPECT_COLOR_BIT, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -745,8 +745,8 @@ namespace vapp{
|
||||
|
||||
void Vulkan::createDepthResources(){
|
||||
VkFormat depthFormat = findDepthFormat();
|
||||
createImage(swapChainExtent.width, swapChainExtent.height, depthFormat, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, depthImage, depthImageMemory);
|
||||
depthImageView = createImageView(depthImage, depthFormat, VK_IMAGE_ASPECT_DEPTH_BIT);
|
||||
createImage(swapChainExtent.width, swapChainExtent.height, 1, depthFormat, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, depthImage, depthImageMemory);
|
||||
depthImageView = createImageView(depthImage, depthFormat, VK_IMAGE_ASPECT_DEPTH_BIT, 1);
|
||||
}
|
||||
|
||||
VkCommandBuffer Vulkan::beginSingleTimeCommands(){
|
||||
@@ -791,7 +791,7 @@ namespace vapp{
|
||||
endSingleTimeCommands(commandBuffer);
|
||||
}
|
||||
|
||||
void Vulkan::transitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout){
|
||||
void Vulkan::transitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout, uint32_t mipLevels){
|
||||
VkCommandBuffer commandBuffer = beginSingleTimeCommands();
|
||||
|
||||
VkImageMemoryBarrier barrier{};
|
||||
@@ -805,9 +805,8 @@ namespace vapp{
|
||||
barrier.image = image;
|
||||
|
||||
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
|
||||
barrier.subresourceRange.baseMipLevel = 0;
|
||||
barrier.subresourceRange.levelCount = 1;
|
||||
barrier.subresourceRange.levelCount = mipLevels;
|
||||
barrier.subresourceRange.baseArrayLayer = 0;
|
||||
barrier.subresourceRange.layerCount = 1;
|
||||
|
||||
@@ -856,14 +855,14 @@ namespace vapp{
|
||||
endSingleTimeCommands(commandBuffer);
|
||||
}
|
||||
|
||||
void Vulkan::createImage(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage &image, VkDeviceMemory &imageMemory){
|
||||
void Vulkan::createImage(uint32_t width, uint32_t height, uint32_t mipLevels, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage &image, VkDeviceMemory &imageMemory){
|
||||
VkImageCreateInfo imageInfo{};
|
||||
imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||
imageInfo.imageType = VK_IMAGE_TYPE_2D; // 3D is used to store voxel volumes
|
||||
imageInfo.extent.width = width;
|
||||
imageInfo.extent.height = height;
|
||||
imageInfo.extent.depth = 1;
|
||||
imageInfo.mipLevels = 1;
|
||||
imageInfo.mipLevels = mipLevels;
|
||||
imageInfo.arrayLayers = 1;
|
||||
imageInfo.format = format;
|
||||
imageInfo.tiling = tiling; // or LINEAR for direct memory access of texels, OPTIMAL provides efficient access from shader
|
||||
@@ -892,6 +891,80 @@ namespace vapp{
|
||||
vkBindImageMemory(device, image, imageMemory, 0);
|
||||
}
|
||||
|
||||
void Vulkan::generateMipmaps(VkImage image, VkFormat imageFormat, int32_t texWidth, int32_t texHeight, uint32_t mipLevels){
|
||||
// normally mipmaps are stored alongside base level of image
|
||||
VkFormatProperties formatProperties;
|
||||
vkGetPhysicalDeviceFormatProperties(physicalDevice, imageFormat, &formatProperties);
|
||||
|
||||
if (!(formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT))
|
||||
{
|
||||
throw std::runtime_error("Func: generateMipmaps\nError: Texture Image Format does not support linear blitting!\n");
|
||||
}
|
||||
|
||||
VkCommandBuffer commandBuffer = beginSingleTimeCommands();
|
||||
|
||||
VkImageMemoryBarrier barrier{};
|
||||
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
barrier.image = image;
|
||||
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
barrier.subresourceRange.baseArrayLayer = 0;
|
||||
barrier.subresourceRange.layerCount = 1;
|
||||
barrier.subresourceRange.levelCount = 1;
|
||||
|
||||
int32_t mipWidth = texWidth;
|
||||
int32_t mipHeight = texHeight;
|
||||
|
||||
for (uint32_t i = 1; i < mipLevels; i++)
|
||||
{
|
||||
barrier.subresourceRange.baseMipLevel = i - 1;
|
||||
barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||
barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
||||
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
barrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
|
||||
|
||||
vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier);
|
||||
|
||||
VkImageBlit blit{};
|
||||
blit.srcOffsets[0] = { 0, 0, 0 };
|
||||
blit.srcOffsets[1] = { mipWidth, mipHeight, 1 };
|
||||
blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
blit.srcSubresource.mipLevel = i - 1;
|
||||
blit.srcSubresource.baseArrayLayer = 0;
|
||||
blit.srcSubresource.layerCount = 1;
|
||||
|
||||
blit.dstOffsets[0] = { 0, 0, 0 };
|
||||
blit.dstOffsets[1] = { mipWidth > 1 ? mipWidth / 2 : 1, mipHeight > 1 ? mipHeight / 2 : 1, 1 };
|
||||
blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
blit.dstSubresource.mipLevel = i;
|
||||
blit.dstSubresource.baseArrayLayer = 0;
|
||||
blit.dstSubresource.layerCount = 1;
|
||||
|
||||
vkCmdBlitImage(commandBuffer, image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit, VK_FILTER_LINEAR);
|
||||
|
||||
barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
||||
barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
||||
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
|
||||
vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier);
|
||||
|
||||
if (mipWidth > 1) mipWidth /= 2;
|
||||
if (mipHeight > 1) mipHeight /= 2;
|
||||
}
|
||||
|
||||
barrier.subresourceRange.baseMipLevel = mipLevels - 1;
|
||||
barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||
barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
|
||||
vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier);
|
||||
|
||||
endSingleTimeCommands(commandBuffer);
|
||||
}
|
||||
|
||||
void Vulkan::createTextureImage(){
|
||||
int texWidth, texHeight, texChannels;
|
||||
|
||||
@@ -902,6 +975,7 @@ namespace vapp{
|
||||
stbi_uc *pixels = stbi_load(TEXTURE_PATH.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
|
||||
|
||||
VkDeviceSize imageSize = texWidth * texHeight * 4; // 4 bytes per pixel
|
||||
mipLevels = static_cast<uint32_t>(std::floor(std::log2(std::max(texWidth, texHeight)))) + 1;
|
||||
|
||||
if(!pixels) throw std::runtime_error("Func: createTextureImage\nError: Failed to load Texture Image!\n");
|
||||
|
||||
@@ -917,15 +991,18 @@ namespace vapp{
|
||||
|
||||
stbi_image_free(pixels);
|
||||
|
||||
createImage(texWidth, texHeight, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, textureImage, textureImageMemory);
|
||||
transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
createImage(texWidth, texHeight, mipLevels, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, textureImage, textureImageMemory);
|
||||
transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, mipLevels);
|
||||
copyBufferToImage(stagingBuffer, textureImage, static_cast<uint32_t>(texWidth), static_cast<uint32_t>(texHeight));
|
||||
transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
// removed because of mipmapping
|
||||
// transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_UNDEFINED /*TRANSFER_DST_OPTIMAL*/, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL /*SHADER_READ_ONLY_OPTIMAL*/, mipLevels);
|
||||
vkDestroyBuffer(device, stagingBuffer, nullptr);
|
||||
vkFreeMemory(device, stagingBufferMemory, nullptr);
|
||||
|
||||
generateMipmaps(textureImage, VK_FORMAT_R8G8B8A8_SRGB, texWidth, texHeight, mipLevels);
|
||||
}
|
||||
|
||||
VkImageView Vulkan::createImageView(VkImage image, VkFormat format, VkImageAspectFlags aspectFlags){
|
||||
VkImageView Vulkan::createImageView(VkImage image, VkFormat format, VkImageAspectFlags aspectFlags, uint32_t mipLevels){
|
||||
VkImageViewCreateInfo viewInfo{};
|
||||
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
viewInfo.image = image;
|
||||
@@ -933,7 +1010,7 @@ namespace vapp{
|
||||
viewInfo.format = format;
|
||||
viewInfo.subresourceRange.aspectMask = aspectFlags;
|
||||
viewInfo.subresourceRange.baseMipLevel = 0;
|
||||
viewInfo.subresourceRange.levelCount = 1;
|
||||
viewInfo.subresourceRange.levelCount = mipLevels;
|
||||
viewInfo.subresourceRange.baseArrayLayer = 0;
|
||||
viewInfo.subresourceRange.layerCount = 1;
|
||||
|
||||
@@ -946,7 +1023,7 @@ namespace vapp{
|
||||
}
|
||||
|
||||
void Vulkan::createTextureImageView(){
|
||||
textureImageView = createImageView(textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_ASPECT_COLOR_BIT);
|
||||
textureImageView = createImageView(textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_ASPECT_COLOR_BIT, mipLevels);
|
||||
}
|
||||
|
||||
void Vulkan::createTextureSampler(){
|
||||
@@ -973,9 +1050,9 @@ namespace vapp{
|
||||
samplerInfo.compareEnable = VK_FALSE;
|
||||
samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
|
||||
samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
||||
samplerInfo.minLod = /*static_cast<float>(mipLevels / 2);*/ 0.0f;
|
||||
samplerInfo.maxLod = static_cast<float>(mipLevels);
|
||||
samplerInfo.mipLodBias = 0.0f;
|
||||
samplerInfo.minLod = 0.0f;
|
||||
samplerInfo.maxLod = 0.0f;
|
||||
|
||||
if(vkCreateSampler(device, &samplerInfo, nullptr, &textureSampler) != VK_SUCCESS){
|
||||
throw std::runtime_error("Func: createTextureSampler\nError: Failed to create Texture Sampler!\n");
|
||||
@@ -1317,7 +1394,7 @@ namespace vapp{
|
||||
|
||||
UniformBufferObject ubo{};
|
||||
// INFO: Change here for other angles
|
||||
ubo.model = glm::rotate(glm::mat4(1.0f), time * glm::radians(60.0f), glm::vec3(0.2f, 0.2f, 0.8f));
|
||||
ubo.model = glm::rotate(glm::mat4(1.0f), time * glm::radians(60.0f), glm::vec3(0.0f, 0.0f, 1.0f));
|
||||
ubo.view = glm::lookAt(glm::vec3(2.0f, 2.0f, 2.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f));
|
||||
ubo.proj = glm::perspective(glm::radians(45.0f), swapChainExtent.width / (float)swapChainExtent.height, 0.1f, 10.0f);
|
||||
|
||||
|
||||
+12
-7
@@ -120,7 +120,7 @@ namespace vapp{
|
||||
|
||||
class Vulkan{
|
||||
private:
|
||||
#pragma region Fields
|
||||
#pragma region PrivateFields
|
||||
GLFWwindow *window;
|
||||
uint32_t _width, _height;
|
||||
|
||||
@@ -173,6 +173,7 @@ namespace vapp{
|
||||
VkDescriptorPool descriptorPool;
|
||||
std::vector<VkDescriptorSet> descriptorSets;
|
||||
|
||||
int32_t mipLevels;
|
||||
VkImage textureImage;
|
||||
VkDeviceMemory textureImageMemory;
|
||||
|
||||
@@ -183,7 +184,7 @@ namespace vapp{
|
||||
VkDeviceMemory depthImageMemory;
|
||||
VkImageView depthImageView;
|
||||
#pragma endregion
|
||||
|
||||
#pragma region PrivateFunctions
|
||||
bool checkValidationLayerSupport();
|
||||
std::vector<const char*> getRequiredExtensions();
|
||||
|
||||
@@ -212,11 +213,12 @@ namespace vapp{
|
||||
void createDepthResources();
|
||||
VkCommandBuffer beginSingleTimeCommands();
|
||||
void endSingleTimeCommands(VkCommandBuffer commandBuffer);
|
||||
void transitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout);
|
||||
void transitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout, uint32_t mipLevels);
|
||||
void copyBufferToImage(VkBuffer buffer, VkImage image, uint32_t width, uint32_t height);
|
||||
void createImage(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage& image, VkDeviceMemory &imageMemory);
|
||||
void createImage(uint32_t width, uint32_t height, uint32_t mipLevels, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage& image, VkDeviceMemory &imageMemory);
|
||||
void generateMipmaps(VkImage image, VkFormat imageFormat, int32_t texWidth, int32_t texHeight, uint32_t mipLevels);
|
||||
void createTextureImage();
|
||||
VkImageView createImageView(VkImage image, VkFormat format, VkImageAspectFlags aspectFlags);
|
||||
VkImageView createImageView(VkImage image, VkFormat format, VkImageAspectFlags aspectFlags, uint32_t mipLevels);
|
||||
void createTextureImageView();
|
||||
void createTextureSampler();
|
||||
uint32_t findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties);
|
||||
@@ -240,8 +242,9 @@ namespace vapp{
|
||||
void initVulkan();
|
||||
void mainLoop();
|
||||
void cleanup();
|
||||
|
||||
#pragma endregion
|
||||
public:
|
||||
#pragma region PublicFields
|
||||
#ifdef DEBUG
|
||||
const bool enableValidationLayers = true;
|
||||
#else
|
||||
@@ -251,8 +254,10 @@ namespace vapp{
|
||||
bool framebufferResized = false;
|
||||
std::string MODEL_PATH;
|
||||
std::string TEXTURE_PATH;
|
||||
|
||||
#pragma endregion
|
||||
#pragma region PublicFunctions
|
||||
void run(const char *windowName, const uint32_t width = 800, const uint32_t height = 600);
|
||||
#pragma endregion
|
||||
};
|
||||
} // vapp
|
||||
|
||||
|
||||
Reference in New Issue
Block a user