В vulkan: я хочу сохранить изображение глубины в файл, но всегда получаю изображение глубины ошибки

Я хочу сохранить изображение глубины из результата рендеринга кадрового буфера.

1 я создаю буфер сцены, используемый для сохранения данных изображения.

2, используйте vkCmdCopyImageToBuffer для копирования изображения глубины в буфер рабочей области.

3, используйте vkMapMemory, чтобы сопоставить буферную память этого этапа с памятью хоста.

4, чтение памяти хоста и запись данных о глубине в файл.

но всегда получал ошибку глубины изображения. Я не знаю, где ошибся.

вывод окна приложения.

изображение глубины ошибки файл.

(исходный файл)

функция сохранения изображения глубины:

VkDeviceSize size = WIDTH * HEIGHT * 4;
    VkBuffer dstBuffer;
    VkDeviceMemory dstMemory;

    createBuffer(
        size,
        VK_BUFFER_USAGE_TRANSFER_DST_BIT, 
        VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, 
        dstBuffer,
        dstMemory);

    VkCommandBuffer copyCmd = beginSingleTimeCommands();

    // depth format -> VK_FORMAT_D32_SFLOAT_S8_UINT
    VkBufferImageCopy region = {};
    region.bufferOffset = 0;
    region.bufferImageHeight = 0;
    region.bufferRowLength = 0;
    region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
    region.imageSubresource.mipLevel = 0;
    region.imageSubresource.baseArrayLayer = 0;
    region.imageSubresource.layerCount = 1;
    region.imageOffset = VkOffset3D{ 0, 0, 0 };
    region.imageExtent = VkExtent3D{ swapChainExtent.width, swapChainExtent.height, 1};


    vkCmdCopyImageToBuffer(
        copyCmd,
        depthImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
        dstBuffer,
        1,
        &region
    );

    endSingleTimeCommands(copyCmd);


    // Map image memory so we can start copying from it
    void *data;
    vkMapMemory(device, dstMemory, 0, size, 0, &data);


    std::ofstream file(path, std::ios::out | std::ios::binary);

    // ppm header
    file << "P6\n" << WIDTH << "\n" << HEIGHT << "\n" << 255 << "\n";

    float *row = (float*)data;

    auto size_v = WIDTH * HEIGHT;

    for (uint32_t y = 0; y < size_v; y++) {

        file.write((char*)row + 1, 1);
        file.write((char*)row + 1, 1);
        file.write((char*)row + 1, 1);

        row++;

    }

    file.close();

    // Clean up resources
    vkUnmapMemory(device, dstMemory);
    vkFreeMemory(device, dstMemory, nullptr);
    vkDestroyBuffer(device, dstBuffer, nullptr);

надеюсь, кто-нибудь вытащит меня. Спасибо!


person Eric Chen    schedule 26.07.2018    source источник
comment
Выполняете ли вы правильные переходы макета на исходном изображении?   -  person Ekzuzy    schedule 26.07.2018
comment
мое исходное изображение (изображение глубины) VkAttachmentDescription set initialLayout VK_IMAGE_LAYOUT_UNDEFINED, finalLayout VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, использование изображения VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT. я много раз проверял код, до сих пор не нашел, в чем проблема.!!!!   -  person Eric Chen    schedule 26.07.2018
comment
мой формат глубины использует VK_FORMAT_D32_SFLOAT_S8_UINT.   -  person Eric Chen    schedule 26.07.2018
comment
Не могли бы вы также показать вывод вашего приложения (скриншот сцены, буфер глубины которой вы хотите сохранить)?   -  person Ekzuzy    schedule 26.07.2018
comment
да, я добавил скриншот приложения и мое изображение глубины сохранения и файл исходного кода к этому вопросу в начале.   -  person Eric Chen    schedule 26.07.2018
comment
Как узнать, что вывод глубины неверен? Сфера выглядит примерно такого же размера и положения. Эти несколько градиентов выглядят как значения с плавающей запятой, интерпретируемые как uint. И белое пятно на сфере выглядит либо как конкретное значение с плавающей запятой, интерпретируемое как белая точка, либо как значения глубины, зажатые настройкой теста глубины. Попробуйте преобразовать значения с плавающей запятой в цвета uint (это можно сделать на стороне процессора после того, как вы прочитаете данные из буфера).   -  person Ekzuzy    schedule 26.07.2018


Ответы (1)


Предполагая, что вы правильно выполнили всю работу по передаче, ваши сопоставленные данные в основном представляют собой массив с плавающей запятой. Это отражено в вашем коде этой строкой:

float *row = (float*)data;

Однако, когда вы на самом деле записываете файл, вы обрабатываете данные как байты...

file.write((char*)row + 1, 1);

Итак, вы записываете 8 байтов 32-битного числа с плавающей запятой. Что вам нужно, так это некоторая функция для преобразования из значения с плавающей запятой в значение цвета.

Предполагая, что значение глубины нормализовано (я не могу вспомнить, так ли это, или зависит ли это от настройки конвейера или кадрового буфера), и если вам просто нужны оттенки серого, вы можете использовать

uint8_t map(float f) {
  return (uint8_t)(f * 255.0f);
}

и внутри цикла записи файла вы хотели бы что-то вроде

uint8_t grey = map(*row);
file.write(&grey, 1);
file.write(&grey, 1);
file.write(&grey, 1);
++row;

В качестве альтернативы, если вам нужен какой-то цветовой градиент для упрощения визуализации, вам понадобится более сложная функция отображения...

vec3 colorWheel(float normalizedHue) {
    float v = normalizedHue * 6.f;
    if (v < 0.f) {
        return vec3(1.f, 0.f, 0.f);
    } else if (v < 1.f) {
        return vec3(1.f, v, 0.f);
    } else if (v < 2.f) {
        return vec3(1.f - (v-1.f), 1.f, 0.f);
    } else if (v < 3.f) {
        return vec3(0.f, 1.f, (v-2.f));
    } else if (v < 4.f) {
        return vec3(0.f, 1.f - (v-3.f), 1.f );
    } else if (v < 5.f) {
        return vec3((v-4.f), 0.f, 1.f );
    } else if (v < 6.f) {
        return vec3(1.f, 0.f, 1.f - (v-5.f));
    } else {
        return vec3(1.f, 0.f, 0.f);
    }
}

и в вашем цикле вывода файла...

vec3 color = colorWheel(*row);
uint8_t r = map(color.r);
uint8_t g = map(color.g);
uint8_t b = map(color.b);
file.write(&r, 1);
file.write(&g, 1);
file.write(&b, 1);
++row;
person Jherico    schedule 26.07.2018
comment
Я получил желаемый результат. большое спасибо. :) - person Eric Chen; 27.07.2018