在vulkan中:我想将深度图像保存到文件中,但始终收到错误的深度图像

时间:2018-07-26 07:59:29

标签: vulkan

我想保存来自帧缓冲区渲染结果的深度图像。

1,我创建了一个用于保存图像数据的舞台缓冲区。

2,使用vkCmdCopyImageToBuffer复制深度图像到舞台缓冲区。

3,使用vkMapMemory将此阶段的缓冲区内存映射到主机内存。

4,读取主机内存并将深度数据写入文件。

,但始终得到错误深度图像。我不知道哪里有错。

应用程序窗口output

错误深度图像file

(来源file

保存深度图像功能:

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);

希望有人把我拖出去。谢谢!

1 个答案:

答案 0 :(得分:2)

假设您已正确完成所有传输工作,则映射数据基本上是一个浮点数组。这行代码反映在您的代码中:

float *row = (float*)data;

但是,当您实际写出文件时,您正在像对待字节一样对待数据...

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

因此,您正在写出32位浮点数的8个字节。您需要一些功能将浮点数转换为颜色值。

假设深度值已标准化(我不记得是这种情况了,还是取决于管道或帧缓冲区设置),并且如果您只想要灰度,则可以使用

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;