KTX 图像文件可以是立方体贴图数组吗?

Can a KTX image file be a cubemap arrays?

KTX 图像作为立方体贴图数组是否有效,或者这不是一回事?

我目前正在使用一些代码将数据从 KTX 文件上传到 GPU。目前,该代码适用于常规二维图像、立方体贴图和纹理数组。但是,它不支持作为立方体贴图数组的 KTX 图像,如果是这样的话。

如果可能的话,下面缺少的代码是什么?

uint32_t offset = 0;
for (uint32_t layer = 0; layer < layers; layer++) {
    for (uint32_t face = 0; face < faces; face++) {
        for (uint32_t level = 0; level < mipLevels; level++) {
            offset = tex->GetImageOffset(layer, face, level);
            vk::BufferImageCopy bufferCopyRegion = {};
            bufferCopyRegion.imageSubresource.aspectMask = vk::ImageAspectFlagBits::eColor;
            bufferCopyRegion.imageSubresource.mipLevel = level;
            bufferCopyRegion.imageSubresource.baseArrayLayer = (faces == 6 ? face : layer); // TexArray or Cubemap, not both.
            bufferCopyRegion.imageSubresource.layerCount = 1;
            bufferCopyRegion.imageExtent.width = width >> level;;
            bufferCopyRegion.imageExtent.height = height >> level;
            bufferCopyRegion.imageExtent.depth = 1;
            bufferCopyRegion.bufferOffset = offset;

            bufferCopyRegions.push_back(bufferCopyRegion);
        }
    }
}

用于传输图像的 Vulkan 命令。

// std::vector<vk::BufferImageCopy> regions;
cmdBuf->copyBufferToImage(srcBufferHandle, destImageHandle,
        vk::ImageLayout::eTransferDstOptimal, uint32_t(regions.size()), regions.data());

是的,KTX 还支持立方体贴图数组(参见KTX specification)。这些是使用图层存储的。

Vulkan 规范说明了立方体贴图如何存储在立方体贴图数组中:

For cube arrays, each set of six sequential layers is a single cube, so the number of cube maps in a cube map array view is layerCount / 6, and image array layer (baseArrayLayer + i) is face index (i mod 6) of cube i / 6.

因此您需要相应地更改缓冲区复制区域的baseArrayLayer

示例代码:

    // Setup buffer copy regions to get the data from the ktx file to your own image
    for (uint32_t layer = 0; layer < ktxTexture->numLayers; layer++) {
        for (uint32_t face = 0; face < 6; face++) {
            for (uint32_t level = 0; level < ktxTexture->numLevels; level++) {
                ktx_size_t offset;
                KTX_error_code ret = ktxTexture_GetImageOffset(ktxTexture, level, layer, face, &offset);
                VkBufferImageCopy bufferCopyRegion = {};
                bufferCopyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
                bufferCopyRegion.imageSubresource.mipLevel = level;
                bufferCopyRegion.imageSubresource.baseArrayLayer = layer * 6 + face;
                bufferCopyRegion.imageSubresource.layerCount = 1;
                bufferCopyRegion.imageExtent.width = ktxTexture->baseWidth >> level;
                bufferCopyRegion.imageExtent.height = ktxTexture->baseHeight >> level;
                bufferCopyRegion.imageExtent.depth = 1;
                bufferCopyRegion.bufferOffset = offset;
                bufferCopyRegions.push_back(bufferCopyRegion);
            }
        }
    }

    // Create the image view for a cube map array
    VkImageViewCreateInfo view = vks::initializers::imageViewCreateInfo();
    view.viewType = VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
    view.format = format;
    view.components = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A };
    view.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
    view.subresourceRange.layerCount = 6 * cubeMap.layerCount;
    view.subresourceRange.levelCount = cubeMap.mipLevels;
    view.image = cubeMap.image;
    vkCreateImageView(device, &view, nullptr, &cubeMap.view);