diff --git a/CMakeLists.txt b/CMakeLists.txt index 4a75a8f..d8d2ac2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,6 @@ cmake_policy(VERSION 3.5) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake") set(NAME PlumageRender) - project(${NAME}) include_directories(external) @@ -49,6 +48,7 @@ ELSEIF(LINUX) MESSAGE("Using bundled Vulkan library version") ENDIF() ENDIF() + find_package(Threads REQUIRED) IF(USE_D2D_WSI) MESSAGE("Using direct to display extension...") @@ -82,10 +82,11 @@ ELSEIF(LINUX) include_directories(${CMAKE_BINARY_DIR}) ELSEIF(USE_HEADLESS) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DVK_USE_PLATFORM_HEADLESS_EXT") - ELSE(USE_D2D_WSI) - find_package(XCB REQUIRED) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DVK_USE_PLATFORM_XCB_KHR") + #ELSE(USE_D2D_WSI) + # find_package(XCB REQUIRED) + # set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DVK_USE_PLATFORM_XCB_KHR") ENDIF(USE_D2D_WSI) + ELSEIF(APPLE) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DVK_USE_PLATFORM_MACOS_MVK -DVK_EXAMPLE_XCODE_GENERATED") # Todo : android? diff --git a/CMakeSettings.json b/CMakeSettings.json index b736cfc..57eb7de 100644 --- a/CMakeSettings.json +++ b/CMakeSettings.json @@ -42,8 +42,45 @@ "cmakeCommandArgs": "", "buildCommandArgs": "", "ctestCommandArgs": "", - "inheritEnvironments": [ "msvc_x64_x64" ], - "variables": [] + "inheritEnvironments": [ "msvc_x64_x64" ] + }, + { + "name": "Linux-Clang-Debug", + "generator": "Ninja", + "configurationType": "Debug", + "cmakeExecutable": "cmake", + "remoteCopySourcesExclusionList": [ ".vs", ".git", "out" ], + "cmakeCommandArgs": "", + "buildCommandArgs": "", + "ctestCommandArgs": "", + "inheritEnvironments": [ "linux_clang_x64" ], + "remoteMachineName": "${defaultRemoteMachineName}", + "remoteCMakeListsRoot": "$HOME/.vs/${projectDirName}/${workspaceHash}/src", + "remoteBuildRoot": "$HOME/.vs/${projectDirName}/${workspaceHash}/out/build/${name}", + "remoteInstallRoot": "$HOME/.vs/${projectDirName}/${workspaceHash}/out/install/${name}", + "remoteCopySources": true, + "rsyncCommandArgs": "-t --delete", + "remoteCopyBuildOutput": false, + "remoteCopySourcesMethod": "rsync" + }, + { + "name": "Linux-GCC-Debug", + "generator": "Ninja", + "configurationType": "Debug", + "cmakeExecutable": "cmake", + "remoteCopySourcesExclusionList": [ ".vs", ".git", "out" ], + "cmakeCommandArgs": "", + "buildCommandArgs": "", + "ctestCommandArgs": "", + "inheritEnvironments": [ "linux_x64" ], + "remoteMachineName": "${defaultRemoteMachineName}", + "remoteCMakeListsRoot": "$HOME/.vs/${projectDirName}/${workspaceHash}/src", + "remoteBuildRoot": "$HOME/.vs/${projectDirName}/${workspaceHash}/out/build/${name}", + "remoteInstallRoot": "$HOME/.vs/${projectDirName}/${workspaceHash}/out/install/${name}", + "remoteCopySources": true, + "rsyncCommandArgs": "-t --delete", + "remoteCopyBuildOutput": false, + "remoteCopySourcesMethod": "rsync" } ] } \ No newline at end of file diff --git a/base/vulkanexamplebase.h b/base/vulkanexamplebase.h index 1744b7f..7019d63 100644 --- a/base/vulkanexamplebase.h +++ b/base/vulkanexamplebase.h @@ -113,17 +113,21 @@ public: uint32_t lastFPS = 0; struct Settings { - bool validation = false; - bool fullscreen = false; - bool vsync = false; - bool multiSampling = true; - bool rotateModel = true; - bool enableSaveToImageSequeue = false; - bool headless = false; - uint32_t outputFrameCount = 50; - bool takeScreenShot = false; + bool validation = false; // 校验层开关 + bool fullscreen = false; // 全屏开关 + bool vsync = false; // 垂直同步开关 + bool multiSampling = true; // 多重采样 + bool rotateModel = true; // 模型自旋转(暂时失效) + bool headless = false; // 无头开关 - VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_4_BIT; + bool enableSaveToImageSequeue = false; // 图片序列开关(暂时弃用) + uint32_t outputFrameCount = 10; // 图片序列结束帧 + bool takeScreenShot = false; // 截屏(暂时弃用) + uint32_t startFrameCount = 1; // 图片序列开始帧 + + uint32_t videoFrameRate = 25; + + VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_4_BIT; // 多重采样倍率 } settings; struct DepthStencil { diff --git a/data/output/video/device0/result.mp4 b/data/output/video/device0/result.mp4 new file mode 100644 index 0000000..27d645e Binary files /dev/null and b/data/output/video/device0/result.mp4 differ diff --git a/data/script/image2video.bat b/data/script/image2video.bat new file mode 100644 index 0000000..298875e --- /dev/null +++ b/data/script/image2video.bat @@ -0,0 +1,2 @@ + +ffmpeg -y -r %1 -i %2 -b:v 1440k -vcodec libx264 -crf 18 %3 \ No newline at end of file diff --git a/data/script/image2video.sh b/data/script/image2video.sh new file mode 100644 index 0000000..5f73189 --- /dev/null +++ b/data/script/image2video.sh @@ -0,0 +1 @@ +ffmpeg -y -r $1 -i $2 -b:v 1440k -vcodec libx264 -crf 18 $3 \ No newline at end of file diff --git a/src/render/render.cpp b/src/render/render.cpp index 2a15cdf..7bf4695 100644 --- a/src/render/render.cpp +++ b/src/render/render.cpp @@ -1806,10 +1806,17 @@ PlumageRender::PlumageRender() void PlumageRender::outputImageSequence() { - std::string deviceFilePath = filePath.outputPath + "/device" + std::to_string(selectedPhysicalDeviceIndex); + std::string deviceFilePath = filePath.imageOutputPath + "/device" + std::to_string(selectedPhysicalDeviceIndex); - if (savedFrameCounter == settings.outputFrameCount) + if (savedFrameCounter > settings.outputFrameCount) { + if (signal.imageSequenceOutputComplete) // 避免重复改变为true + { + return; + } + signal.imageSequenceOutputComplete = true; + std::string fileName = "/%dresult.ppm"; + filePath.totalImageOutputPath = deviceFilePath + fileName; return; } if (_access(deviceFilePath.c_str(), 0) == -1) @@ -1817,12 +1824,45 @@ PlumageRender::PlumageRender() std::filesystem::create_directories(deviceFilePath.c_str()); } std::string fileName = "/" + std::to_string(savedFrameCounter) + "result.ppm"; - std::string outputPath = deviceFilePath + fileName; + filePath.totalImageOutputPath = deviceFilePath + fileName; //std::cout << outputPath << std::endl; - writeImageToFile(outputPath.c_str()); + writeImageToFile(filePath.totalImageOutputPath.c_str()); savedFrameCounter++; } + void PlumageRender::imageSequenceToVideo() + { + if (!signal.imageSequenceOutputComplete) + { + return; + } + if (signal.imageSequenceToVideoComplete) + { + return; + } + std::string deviceFilePath = filePath.videoOutputPath + "/device" + std::to_string(selectedPhysicalDeviceIndex); + if (_access(deviceFilePath.c_str(), 0) == -1) + { + std::filesystem::create_directories(deviceFilePath.c_str()); + } + + std::string resultVideoPath = deviceFilePath + "/result.mp4"; + + std::string commandLineImageSequencePath = filePath.totalImageOutputPath; + //std::string commandLineCodecAndResultPath = resultVideoPath; + std::string commandLineFrameRate = std::to_string(settings.videoFrameRate); +#if defined(_WIN32) + std::string commandLine = filePath.image2videoBatFilePath + " " + commandLineFrameRate + " " + commandLineImageSequencePath + " " + resultVideoPath; +#else + std::string commandLine = filePath.image2videoShFilePath + " " + commandLineFrameRate + " " + commandLineImageSequencePath + " " + resultVideoPath; +#endif + std::cout << commandLine << std::endl; + std::system(commandLine.c_str()); + + signal.imageSequenceToVideoComplete = true; + std::cout << "vidoe codec complete,saved in:" << resultVideoPath << std::endl; + } + uint32_t PlumageRender::getMemoryTypeIndex(uint32_t typeBits, VkMemoryPropertyFlags properties) { VkPhysicalDeviceMemoryProperties deviceMemoryProperties; @@ -1856,6 +1896,7 @@ PlumageRender::PlumageRender() VK_CHECK_RESULT(vkWaitForFences(device, 1, &waitFences[frameIndex], VK_TRUE, UINT64_MAX)); outputImageSequence(); + imageSequenceToVideo(); VK_CHECK_RESULT(vkResetFences(device, 1, &waitFences[frameIndex])); VkResult acquire = swapChain.acquireNextImage(presentCompleteSemaphores[frameIndex], ¤tBuffer); diff --git a/src/render/render.h b/src/render/render.h index 846e9dd..20dd7f3 100644 --- a/src/render/render.h +++ b/src/render/render.h @@ -1,5 +1,16 @@ #pragma once + +#if defined(_WIN32) +#include +#include +#else +#include +#include +#endif + + + #include #include #include @@ -7,8 +18,7 @@ #include #include #include -#include -#include + #include #include #include "algorithm" @@ -40,6 +50,13 @@ public: { } info ; + + struct Signal + { + bool imageSequenceOutputComplete = false; + bool imageSequenceToVideoComplete = false; + + }signal; struct Models @@ -164,8 +181,13 @@ public: // output file path - std::string outputPath = getAssetPath() + "output/imageSequence"; - + std::string imageOutputPath = getAssetPath() + "output/imageSequence"; + std::string videoOutputPath = getAssetPath() + "output/video"; + std::string totalImageOutputPath; + + // script file path + std::string image2videoBatFilePath = getAssetPath() + "script/image2video.bat"; + std::string image2videoShFilePath = getAssetPath() + "script/image2video.sh"; } filePath; @@ -278,7 +300,7 @@ public: UI* gui; - uint64_t savedFrameCounter = 0; + uint64_t savedFrameCounter = settings.startFrameCount; PlumageRender(); @@ -339,9 +361,11 @@ public: void windowResized(); void prepare(); void submitWork(VkCommandBuffer cmdBuffer, VkQueue queue); + void writeImageToFile(std::string filePath); void outputImageSequence(); - void outputScreenShot(); + void imageSequenceToVideo(); + //void outputScreenShot(); uint32_t getMemoryTypeIndex(uint32_t typeBits, VkMemoryPropertyFlags properties); virtual void render(); virtual void updateUIOverlay();