添加framebuffer to ppm
parent
5e4acd3f08
commit
81c289ea9c
10
ReadMe.md
10
ReadMe.md
|
@ -10,6 +10,16 @@
|
|||
3. 支持模型的PBR材质渲染
|
||||
4. 使用基于IBL的环境光照
|
||||
|
||||
#### 分支:add image output ToDo list
|
||||
|
||||
1. 添加ppm格式图片序列输出
|
||||
2. 单帧输出,预览效果
|
||||
3. 接入ffmpeg将图片序列转图片
|
||||
|
||||
#### todo list
|
||||
|
||||
1. 参数化模板选择:维护一个模板数组,前端发送一个数组索引
|
||||
|
||||
#### 展示
|
||||
|
||||
展示使用录制的GIF并转换为animated webp,存在**画质损失**,仅供参考
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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, ©Cmd));
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue