添加framebuffer to ppm

pull/1/head
ink-soul 2024-03-22 18:05:18 +08:00
parent 5e4acd3f08
commit 81c289ea9c
5 changed files with 193 additions and 9 deletions

View File

@ -10,6 +10,16 @@
3. 支持模型的PBR材质渲染
4. 使用基于IBL的环境光照
#### 分支add image output ToDo list
1. 添加ppm格式图片序列输出
2. 单帧输出,预览效果
3. 接入ffmpeg将图片序列转图片
#### todo list
1. 参数化模板选择:维护一个模板数组,前端发送一个数组索引
#### 展示
展示使用录制的GIF并转换为animated webp存在**画质损失**,仅供参考

View File

@ -625,13 +625,13 @@ void VulkanExampleBase::initVulkan()
for (size_t i = 0; i < args.size(); i++) {
if ((args[i] == std::string("-g")) || (args[i] == std::string("--gpu"))) {
char* endptr;
uint32_t index = strtol(args[i + 1], &endptr, 10);
selectedPhysicalDeviceIndex = strtol(args[i + 1], &endptr, 10);
if (endptr != args[i + 1]) {
if (index > gpuCount - 1) {
std::cerr << "Selected device index " << index << " is out of range, reverting to device 0 (use -listgpus to show available Vulkan devices)" << std::endl;
if (selectedPhysicalDeviceIndex > gpuCount - 1) {
std::cerr << "Selected device index " << selectedPhysicalDeviceIndex << " is out of range, reverting to device 0 (use -listgpus to show available Vulkan devices)" << std::endl;
} else {
std::cout << "Selected Vulkan device " << index << std::endl;
selectedDevice = index;
std::cout << "Selected Vulkan device " << selectedPhysicalDeviceIndex << std::endl;
selectedDevice = selectedPhysicalDeviceIndex;
}
};
break;

View File

@ -102,6 +102,7 @@ protected:
void windowResize();
public:
static std::vector<const char*> args;
uint32_t selectedPhysicalDeviceIndex = 0;
bool prepared = false;
uint32_t width = 1280;
uint32_t height = 720;

View File

@ -1572,6 +1572,153 @@ PlumageRender::PlumageRender()
prepared = true;
}
void PlumageRender::submitWork(VkCommandBuffer cmdBuffer, VkQueue queue)
{
VkSubmitInfo submitInfo = vks::initializers::submitInfo();
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &cmdBuffer;
VkFenceCreateInfo fenceInfo = vks::initializers::fenceCreateInfo();
VkFence fence;
VK_CHECK_RESULT(vkCreateFence(device, &fenceInfo, nullptr, &fence));
VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, fence));
VK_CHECK_RESULT(vkWaitForFences(device, 1, &fence, VK_TRUE, UINT64_MAX));
vkDestroyFence(device, fence, nullptr);
}
// todo :根据physicalDeviceIndex确定子文件夹路径frameIndex确定fileName
void PlumageRender::writeImageToFile(std::string filePath,std::string fileName)
{
char* imageData;
// create dst image to copy
VkImageCreateInfo imageCreateInfo(vks::initializers::imageCreateInfo());
imageCreateInfo.imageType = VK_IMAGE_TYPE_2D;
imageCreateInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
imageCreateInfo.extent.width = width;
imageCreateInfo.extent.height = height;
imageCreateInfo.extent.depth = 1;
imageCreateInfo.arrayLayers = 1;
imageCreateInfo.mipLevels = 1;
imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT;
imageCreateInfo.tiling = VK_IMAGE_TILING_LINEAR;
imageCreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT;
VkImage dstImage;
VK_CHECK_RESULT(vkCreateImage(device, &imageCreateInfo, nullptr, &dstImage));
// get memory ready to store the image
VkMemoryRequirements memRequirements;
VkMemoryAllocateInfo memAllocInfo(vks::initializers::memoryAllocateInfo());
VkDeviceMemory dstImageMemory;
vkGetImageMemoryRequirements(device, dstImage, &memRequirements);
memAllocInfo.allocationSize = memRequirements.size;
memAllocInfo.memoryTypeIndex = getMemoryTypeIndex(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
// allocate and bind memory
VK_CHECK_RESULT(vkAllocateMemory(device, &memAllocInfo, nullptr, &dstImageMemory));
VK_CHECK_RESULT(vkBindImageMemory(device, dstImage, dstImageMemory, 0));
// blit image and copy to host visualable memory
VkCommandBufferAllocateInfo cmdBufferAllocInfo;
VkCommandBuffer copyCmd;
VK_CHECK_RESULT(vkAllocateCommandBuffers(device, &cmdBufferAllocInfo, &copyCmd));
VkCommandBufferBeginInfo cmdBufferBeginInfo(vks::initializers::commandBufferBeginInfo());
VK_CHECK_RESULT(vkBeginCommandBuffer(copyCmd, &cmdBufferBeginInfo));
vks::tools::insertImageMemoryBarrier(copyCmd, dstImage, 0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VkImageSubresourceRange{ VK_IMAGE_ASPECT_COLOR_BIT,0,1,0,1 });
VkImageCopy imageCopyRegion{};
imageCopyRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
imageCopyRegion.srcSubresource.layerCount = 1;
imageCopyRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
imageCopyRegion.dstSubresource.layerCount = 1;
imageCopyRegion.extent.width = width;
imageCopyRegion.extent.height = height;
imageCopyRegion.extent.depth = 1;
vkCmdCopyImage(copyCmd, offscreen.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dstImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &imageCopyRegion);
// transition dst image to general layout for map memory
vks::tools::insertImageMemoryBarrier(copyCmd, dstImage, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_MEMORY_READ_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,VkImageSubresourceRange{VK_IMAGE_ASPECT_COLOR_BIT,0,1,0,1});
VK_CHECK_RESULT(vkEndCommandBuffer(copyCmd));
submitWork(copyCmd, queue);
// Get layout of the image
VkImageSubresource subResource{};
subResource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
VkSubresourceLayout subResourceLayout;
vkGetImageSubresourceLayout(device, dstImage, &subResource, &subResourceLayout);
// Map image memory
vkMapMemory(device, dstImageMemory, 0, VK_WHOLE_SIZE, 0, (void**)&imageData);
imageData += subResourceLayout.offset;
std::ofstream file(fileName, std::ios::out | std::ios::binary);
// ppm header
file << "P6\n" << width << "\n" << height << "\n" << 255 << "\n";
std::vector<VkFormat> formatsBGR = { VK_FORMAT_B8G8R8A8_SRGB, VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_B8G8R8A8_SNORM };
const bool colorSwizzle = (std::find(formatsBGR.begin(), formatsBGR.end(), VK_FORMAT_R8G8B8A8_UNORM) != formatsBGR.end());
// ppm binary pixel data
for (int32_t y = 0; y < height; y++) {
unsigned int* row = (unsigned int*)imageData;
for (int32_t x = 0; x < width; x++) {
if (colorSwizzle) {
file.write((char*)row + 2, 1);
file.write((char*)row + 1, 1);
file.write((char*)row, 1);
}
else {
file.write((char*)row, 3);
}
row++;
}
imageData += subResourceLayout.rowPitch;
}
file.close();
std::cout << "Framebuffer image saved to " << filePath << fileName << std::endl;
// Clean up resources
vkUnmapMemory(device, dstImageMemory);
vkFreeMemory(device, dstImageMemory, nullptr);
vkDestroyImage(device, dstImage, nullptr);
}
void PlumageRender::outputImageSequence(VkImage image, std::string filePath)
{
for (uint32_t i = 0; i < settings.outputFrameCount; i++)
{
std::string fileName = std::to_string(i) + "result.pmm";
std::string filePath = std::to_string(selectedPhysicalDeviceIndex);
}
}
uint32_t PlumageRender::getMemoryTypeIndex(uint32_t typeBits, VkMemoryPropertyFlags properties)
{
VkPhysicalDeviceMemoryProperties deviceMemoryProperties;
vkGetPhysicalDeviceMemoryProperties(physicalDevice, &deviceMemoryProperties);
for (uint32_t i = 0; i < deviceMemoryProperties.memoryTypeCount; i++)
{
if ((typeBits & 1) == 1)
{
if ((deviceMemoryProperties.memoryTypes[i].propertyFlags & properties) == properties)
{
return i;
}
}
typeBits >>= 1;
}
return 0;
}
void PlumageRender::render()
{
if (!prepared) {
@ -1579,7 +1726,9 @@ PlumageRender::PlumageRender()
}
updateUIOverlay();
//加入写到文件的函数
//swapChainImage = swapChain.images[frameIndex];
//outputImageSequeue(swapChainImage,filePath.imageSequenceFilePath);
VK_CHECK_RESULT(vkWaitForFences(device, 1, &waitFences[frameIndex], VK_TRUE, UINT64_MAX));
VK_CHECK_RESULT(vkResetFences(device, 1, &waitFences[frameIndex]));
@ -1589,6 +1738,8 @@ PlumageRender::PlumageRender()
}
else {
VK_CHECK_RESULT(acquire);
}
// Update UBOs
@ -1610,6 +1761,7 @@ PlumageRender::PlumageRender()
submitInfo.commandBufferCount = 1;
VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, waitFences[frameIndex]));
//显示队列
VkResult present = swapChain.queuePresent(queue, currentBuffer, renderCompleteSemaphores[frameIndex]);
if (!((present == VK_SUCCESS) || (present == VK_SUBOPTIMAL_KHR))) {
if (present == VK_ERROR_OUT_OF_DATE_KHR) {
@ -1625,7 +1777,7 @@ PlumageRender::PlumageRender()
frameIndex %= renderAhead;
if (!paused) {
if (rotateModel) {
if (settings.rotateModel) {
modelrot.y += frameTimer * 35.0f;
if (modelrot.y > 360.0f) {
modelrot.y -= 360.0f;
@ -1639,13 +1791,15 @@ PlumageRender::PlumageRender()
models.scene.updateAnimation(animationIndex, animationTimer);
}
updateShaderData();
if (rotateModel) {
if (settings.rotateModel) {
updateUniformBuffers();
}
}
if (camera.updated) {
updateUniformBuffers();
}
}

View File

@ -159,11 +159,18 @@ public:
//ttf file path
std::string ttfFilePath = getAssetPath() + "/data/Roboto-Medium.ttf";
// output file path
// imageSequence
std::string imageSequenceFilePath = getAssetPath() + "/output/imageSequence";
// screen shot image
std::string screenShotFilePath = getAssetPath() + "/output/screenShot";
} filePath;
bool rotateModel = false;
glm::vec3 modelrot = glm::vec3(0.0f);
glm::vec3 modelPos = glm::vec3(0.0f);
enum PBRWorkflows { PBR_WORKFLOW_METALLIC_ROUGHNESS = 0, PBR_WORKFLOW_SPECULAR_GLOSINESS = 1 };
@ -214,6 +221,11 @@ public:
bool fullscreen = false;
bool vsync = false;
bool multiSampling = true;
bool rotateModel = true;
bool enableSaveToImageSequeue = false;
uint32_t outputFrameCount = 50;
bool takeScreenShot = false;
VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_4_BIT;
} settings;
@ -235,6 +247,8 @@ public:
const uint32_t renderAhead = 2;
uint32_t frameIndex = 0;
//VkImage swapChainImage;
int32_t animationIndex = 0;
float animationTimer = 0.0f;
bool animate = true;
@ -331,6 +345,11 @@ public:
void updateShaderData();
void windowResized();
void prepare();
void submitWork(VkCommandBuffer cmdBuffer, VkQueue queue);
void writeImageToFile(std::string filePath, std::string fileName);
void outputImageSequence(VkImage image,std::string filePath);
void outputScreenShot(VkImage image, std::string filePath);
uint32_t getMemoryTypeIndex(uint32_t typeBits, VkMemoryPropertyFlags properties);
virtual void render();
virtual void updateUIOverlay();
virtual void fileDropped(std::string filename);