From be8a3af04eabb64a5081f95929d86b16b714a821 Mon Sep 17 00:00:00 2001 From: Sebastian Pape <Pape@vr.rwth-aachen.de> Date: Thu, 3 Jan 2019 11:21:08 +0100 Subject: [PATCH] Added video dolly feature --- demos/optical_bench/src/optical_bench.cpp | 1 + demos/optical_bench/src/optix_engine.cpp | 14 +- .../optical_bench/src/video_capture_pass.cpp | 146 ++++++++++++++---- .../optical_bench/src/video_capture_pass.hpp | 19 ++- 4 files changed, 143 insertions(+), 37 deletions(-) diff --git a/demos/optical_bench/src/optical_bench.cpp b/demos/optical_bench/src/optical_bench.cpp index 7c5af18b..60f6378d 100644 --- a/demos/optical_bench/src/optical_bench.cpp +++ b/demos/optical_bench/src/optical_bench.cpp @@ -152,6 +152,7 @@ int main(int argc, char** args) { videoPass[1]->Stop(); video = false; } + if (key == 'u') videoPass[1]->ToggleDolly(); if (key == '.') contextManager->EnableUsageCallback(usage); usage = !usage; if (key == 'l') object_manager->PrintLensInfos(); diff --git a/demos/optical_bench/src/optix_engine.cpp b/demos/optical_bench/src/optix_engine.cpp index 24a7c914..b515ce09 100644 --- a/demos/optical_bench/src/optix_engine.cpp +++ b/demos/optical_bench/src/optix_engine.cpp @@ -163,10 +163,10 @@ void OpticalBenchSetup::SetupOptixFrameGraphWindow( frame_graph->AddRenderPass( std::make_unique<RayPass>(render_target, camera_target, engine, manager)); frame_graph->AddRenderPass(std::make_unique<ScreenshotPass>(render_target)); - frame_graph->AddRenderPass( - std::make_unique<phx::VideoCapturePass>(render_target, "normal_camera_")); - frame_graph->AddRenderPass( - std::make_unique<phx::VideoCapturePass>(camera_target, "static_camera_")); + frame_graph->AddRenderPass(std::make_unique<phx::VideoCapturePass>( + render_target, nullptr, "normal_camera_")); + frame_graph->AddRenderPass(std::make_unique<phx::VideoCapturePass>( + camera_target, render_target, "static_camera_")); frame_graph->AddRenderPass(std::make_unique<BlitPass>(render_target)); frame_graph->Initialize(); @@ -214,9 +214,9 @@ void OpticalBenchSetup::SetupOptixFrameGraphOpenVR( frame_graph->AddRenderPass( std::make_unique<ScreenshotPass>(right_render_target)); frame_graph->AddRenderPass(std::make_unique<phx::VideoCapturePass>( - right_render_target, "right_eye_")); - frame_graph->AddRenderPass( - std::make_unique<phx::VideoCapturePass>(camera_target, "static_camera_")); + right_render_target, nullptr, "right_eye_")); + frame_graph->AddRenderPass(std::make_unique<phx::VideoCapturePass>( + camera_target, right_render_target, "static_camera_")); frame_graph->AddRenderPass(std::make_unique<BlitPass>(camera_target)); frame_graph->Initialize(); diff --git a/demos/optical_bench/src/video_capture_pass.cpp b/demos/optical_bench/src/video_capture_pass.cpp index 08a84203..c2f3b503 100644 --- a/demos/optical_bench/src/video_capture_pass.cpp +++ b/demos/optical_bench/src/video_capture_pass.cpp @@ -21,10 +21,12 @@ //------------------------------------------------------------------------------ #include "video_capture_pass.hpp" +#include "phx/core/entity.hpp" #include "phx/core/logger.hpp" +#include "phx/rendering/components/transform.hpp" -#include <fstream> #include <stdio.h> +#include <fstream> namespace phx { @@ -34,14 +36,17 @@ inline bool file_exists(const std::string& name) { return f.good(); } -VideoCapturePass::VideoCapturePass(RenderTarget* render_target, std::string file_name) - : render_target_(render_target) { - file_name_ = file_name; +VideoCapturePass::VideoCapturePass(RenderTarget* render_target, + RenderTarget* dolly_target, + std::string file_name) { + render_target_ = render_target; + dolly_target_ = dolly_target; + file_name_ = file_name; } VideoCapturePass::~VideoCapturePass() { - Stop(); - free(data_storage_); + Stop(); + free(data_storage_); } void VideoCapturePass::Initialize() { @@ -50,42 +55,125 @@ void VideoCapturePass::Initialize() { } void VideoCapturePass::Execute() { + if (video_dolly_running_) { + video_dolly_interpolation_ = + glm::clamp(video_dolly_interpolation_ + 0.01f, 0.0f, 1.0f); + if (video_dolly_target_is_head_) { + render_target_->GetEntity() + ->GetFirstComponent<phx::Transform>() + ->SetGlobalTranslation( + glm::mix(video_dolly_start_position, + glm::vec3(dolly_target_->GetEntity() + ->GetFirstComponent<phx::Transform>() + ->GetGlobalTranslation()), + video_dolly_interpolation_)); + render_target_->GetEntity() + ->GetFirstComponent<phx::Transform>() + ->SetGlobalRotation( + glm::slerp(video_dolly_start_rotation, + dolly_target_->GetEntity() + ->GetFirstComponent<phx::Transform>() + ->GetGlobalRotation(), + video_dolly_interpolation_)); + if (video_dolly_interpolation_ == 1.0f) { + render_target_->GetEntity() + ->GetFirstComponent<phx::Transform>() + ->SetParent(dolly_target_->GetEntity() + ->GetFirstComponent<phx::Transform>()); + } + } else { + render_target_->GetEntity() + ->GetFirstComponent<phx::Transform>() + ->SetGlobalTranslation(glm::mix(video_dolly_start_position, + video_dolly_camera_position, + video_dolly_interpolation_)); + render_target_->GetEntity() + ->GetFirstComponent<phx::Transform>() + ->SetGlobalRotation(glm::slerp(video_dolly_start_rotation, + video_dolly_camera_rotation, + video_dolly_interpolation_)); + } + + if (video_dolly_interpolation_ == 1.0f) { + video_dolly_running_ = false; + phx::info("Panning finished."); + } + } + + // Video capturing stuff + if (!capturing) return; // Get Pixels into Memory render_target_->bind(); - glReadPixels(0, 0, dims_.x, dims_.y, GL_RGBA, GL_UNSIGNED_BYTE, data_storage_); + glReadPixels(0, 0, dims_.x, dims_.y, GL_RGBA, GL_UNSIGNED_BYTE, + data_storage_); render_target_->unbind(); // Stream to ffmpeg - fwrite(data_storage_, 4*dims_.x*dims_.y, 1, ffmpeg); + fwrite(data_storage_, 4 * dims_.x * dims_.y, 1, ffmpeg); } -void VideoCapturePass::Start() { - if (capturing) return; - capturing = true; - auto name = FindNextFileName(file_name_) + ".mp4"; - - // start ffmpeg telling it to expect raw rgba 720p-60hz frames - // -i - tells it to read frames from stdin - std::string cmd = "ffmpeg.exe -r 30 -f rawvideo -pix_fmt rgba -s " + std::to_string(dims_.x) + "x" + std::to_string(dims_.y) + " -i - " - "-threads 0 -preset fast -y -pix_fmt yuv420p -crf 21 -vf vflip -loglevel fatal " + name; - - // open pipe to ffmpeg's stdin in binary write mode - ffmpeg = _popen(cmd.c_str(), "wb"); - - if (!ffmpeg){ - phx::error("Can't open video stream"); - } +void VideoCapturePass::Start() { + if (capturing) return; + capturing = true; + auto name = FindNextFileName(file_name_) + ".mp4"; + + // start ffmpeg telling it to expect raw rgba 720p-60hz frames + // -i - tells it to read frames from stdin + std::string cmd = "ffmpeg.exe -r 30 -f rawvideo -pix_fmt rgba -s " + + std::to_string(dims_.x) + "x" + std::to_string(dims_.y) + + " -i - " + "-threads 0 -preset fast -y -pix_fmt yuv420p -crf 21 -vf " + "vflip -loglevel fatal " + + name; + + // open pipe to ffmpeg's stdin in binary write mode + ffmpeg = _popen(cmd.c_str(), "wb"); + + if (!ffmpeg) { + phx::error("Can't open video stream"); + } - phx::info(("Started video recording on " + name + "...").c_str()); + phx::info(("Started video recording on " + name + "...").c_str()); } void VideoCapturePass::Stop() { - if (!capturing) return; - capturing = false; - _pclose(ffmpeg); - phx::info("Stopped video recording..."); + if (!capturing) return; + capturing = false; + _pclose(ffmpeg); + phx::info("Stopped video recording..."); +} + +void VideoCapturePass::ToggleDolly() { + if (video_dolly_running_ || dolly_target_ == nullptr) return; + video_dolly_running_ = true; + video_dolly_target_is_head_ = !video_dolly_target_is_head_; + video_dolly_interpolation_ = 0.0f; + + if (video_dolly_target_is_head_) { + video_dolly_camera_position = render_target_->GetEntity() + ->GetFirstComponent<phx::Transform>() + ->GetGlobalTranslation(); + + video_dolly_camera_rotation = render_target_->GetEntity() + ->GetFirstComponent<phx::Transform>() + ->GetGlobalRotation(); + video_dolly_start_rotation = video_dolly_camera_rotation; + video_dolly_start_position = video_dolly_camera_position; + phx::info("Panning towards head started."); + } else { + video_dolly_start_position = dolly_target_->GetEntity() + ->GetFirstComponent<phx::Transform>() + ->GetGlobalTranslation(); + + video_dolly_start_rotation = dolly_target_->GetEntity() + ->GetFirstComponent<phx::Transform>() + ->GetGlobalRotation(); + render_target_->GetEntity()->GetFirstComponent<phx::Transform>()->SetParent( + nullptr); + phx::info("Panning towards old camera position started."); + } } std::string VideoCapturePass::FindNextFileName(const std::string name) { diff --git a/demos/optical_bench/src/video_capture_pass.hpp b/demos/optical_bench/src/video_capture_pass.hpp index 802c326c..48fa7aa1 100644 --- a/demos/optical_bench/src/video_capture_pass.hpp +++ b/demos/optical_bench/src/video_capture_pass.hpp @@ -29,11 +29,17 @@ #include "phx/rendering/backend/render_target.hpp" #include "phx/rendering/render_passes/render_pass.hpp" +SUPPRESS_WARNINGS_BEGIN +#include "glm/glm.hpp" +#include "glm/gtc/quaternion.hpp" +SUPPRESS_WARNINGS_END + namespace phx { class VideoCapturePass : public RenderPass { public: - explicit VideoCapturePass(RenderTarget* render_target, std::string file_name); + explicit VideoCapturePass(RenderTarget* render_target, + RenderTarget* dolly_target, std::string file_name); VideoCapturePass(const VideoCapturePass&) = default; VideoCapturePass(VideoCapturePass&&) = default; ~VideoCapturePass(); @@ -47,6 +53,8 @@ class VideoCapturePass : public RenderPass { void Start(); void Stop(); + void ToggleDolly(); + private: RenderTarget* render_target_; bool capturing = false; @@ -56,6 +64,15 @@ class VideoCapturePass : public RenderPass { std::string FindNextFileName(const std::string name); FILE* ffmpeg; + + RenderTarget* dolly_target_; + bool video_dolly_running_ = false; + float video_dolly_interpolation_ = 0.0f; + bool video_dolly_target_is_head_ = false; + glm::vec3 video_dolly_start_position = glm::vec3(0); + glm::quat video_dolly_start_rotation = glm::quat(); + glm::vec3 video_dolly_camera_position = glm::vec3(0); + glm::quat video_dolly_camera_rotation = glm::quat(); }; } // namespace phx -- GitLab