Eric Chen
Eric Chen

Reputation: 47

In vulkan: I want save a depth image to file, but always got a error depth image

I want to save a depth image that from frame buffer render result.

1, I create a stage buffer used to save image data.

2, use vkCmdCopyImageToBuffer copy depth image to stage buffer.

3, use vkMapMemory map this stage buffer memory to host memory.

4, read host memory and write depth data to a file.

but always got an error depth image. I don't know where have wrong.

application window output.

bug depth image file.

(source file)

save depth image function:

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

hope someone drag me out. thanks!

Upvotes: 3

Views: 2161

Answers (1)

Jherico
Jherico

Reputation: 29240

Assuming you've done all the transfer work correctly, your mapped data is basically an array of floats. This is reflected in your code by this line:

float *row = (float*)data;

However, when you actually write out the file you're treating the data like bytes...

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

So you're writing out 8 bytes of a 32 bit float. What you need is some function to convert from the float to a color value.

Assuming the depth value is normalized (I can't remember off the top of my head whether this is the case, or if it's dependent on the pipeline or framebuffer setup) and if you just want greyscale, you could use

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

and inside your file writing loop you'd so something like

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

Alternatively if you want some sort of color gradient for easier visulization you'd want a more complex mapping function...

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

and in your file output loop...

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;

Upvotes: 3

Related Questions