diff --git a/data/Animations/RoboATT/SKIN_ROBOT.env b/data/Animations/RoboATT/SKIN_ROBOT.env new file mode 100644 index 000000000..fa546040c Binary files /dev/null and b/data/Animations/RoboATT/SKIN_ROBOT.env differ diff --git a/data/Meshes/Road/Road.max b/data/Meshes/Road/Road.max new file mode 100644 index 000000000..e95cf325d Binary files /dev/null and b/data/Meshes/Road/Road.max differ diff --git a/editor.exe b/editor.exe index 2822a2cda..22719829b 100644 Binary files a/editor.exe and b/editor.exe differ diff --git a/imgui.ini b/imgui.ini index ad572f513..bb95f7f92 100644 --- a/imgui.ini +++ b/imgui.ini @@ -1,6 +1,6 @@ [Window][Game] Pos=0,0 -Size=2560,1369 +Size=2194,1171 Collapsed=0 [Window][Debug##Default] @@ -10,73 +10,73 @@ Collapsed=0 [Window][ Platform] Pos=0,22 -Size=290,149 +Size=290,127 Collapsed=0 DockId=0x00000005,2 [Window][ Shaders] Pos=0,22 -Size=290,149 +Size=290,127 Collapsed=0 DockId=0x00000005,1 [Window][ FPS] Pos=0,22 -Size=290,149 +Size=290,127 Collapsed=0 DockId=0x00000005,0 [Window][ Resources] -Pos=290,1108 -Size=1980,261 +Pos=290,910 +Size=1614,261 Collapsed=0 DockId=0x0000000E,1 [Window][###Scene] -Pos=0,171 -Size=290,936 +Pos=0,149 +Size=290,798 Collapsed=0 DockId=0x00000007,0 [Window][###Prefab] -Pos=0,171 -Size=290,936 +Pos=0,149 +Size=290,798 Collapsed=0 DockId=0x00000007,1 [Window][ Inspector] -Pos=2270,612 -Size=290,500 +Pos=1904,525 +Size=290,427 Collapsed=0 DockId=0x0000000C,0 [Window][ Editor] -Pos=2270,22 -Size=290,590 +Pos=1904,22 +Size=290,503 Collapsed=0 DockId=0x0000000B,3 [Window][ Renderer] -Pos=2270,22 -Size=290,590 +Pos=1904,22 +Size=290,503 Collapsed=0 DockId=0x0000000B,1 [Window][ Physics] -Pos=2270,22 -Size=290,590 +Pos=1904,22 +Size=290,503 Collapsed=0 DockId=0x0000000B,2 [Window][ Engine] -Pos=2270,22 -Size=290,590 +Pos=1904,22 +Size=290,503 Collapsed=0 DockId=0x0000000B,0 [Window][### Game] -Pos=1281,44 -Size=989,1064 +Pos=1277,44 +Size=627,866 Collapsed=0 DockId=0x00000010,0 @@ -87,38 +87,38 @@ Collapsed=0 DockId=0x00000008,1 [Window][ Statistics] -Pos=2270,612 -Size=290,500 +Pos=1904,525 +Size=290,427 Collapsed=0 DockId=0x0000000C,1 [Window][ Time] -Pos=0,1107 -Size=290,262 +Pos=0,947 +Size=290,224 Collapsed=0 DockId=0x00000008,0 [Window][ Undo/Redo] -Pos=2270,1112 -Size=290,257 +Pos=1904,952 +Size=290,219 Collapsed=0 DockId=0x0000000A,0 [Window][Main Toolbar] Pos=290,22 -Size=1980,22 +Size=1614,22 Collapsed=0 DockId=0x00000011,0 [Window][ Console] -Pos=290,1108 -Size=1980,261 +Pos=290,910 +Size=1614,261 Collapsed=0 DockId=0x0000000E,0 [Window][### Editor] Pos=290,44 -Size=991,1064 +Size=987,866 Collapsed=0 DockId=0x0000000F,0 @@ -138,20 +138,20 @@ Size=2560,1369 Collapsed=0 [Window][ Game] -Pos=2270,22 -Size=290,590 +Pos=1904,22 +Size=290,503 Collapsed=0 DockId=0x0000000B,5 [Window][ Input] -Pos=0,1107 -Size=290,262 +Pos=0,947 +Size=290,224 Collapsed=0 DockId=0x00000008,1 [Window][ Audio] -Pos=2270,22 -Size=290,590 +Pos=1904,22 +Size=290,503 Collapsed=0 DockId=0x0000000B,4 @@ -501,8 +501,46 @@ Column 0 Width=96 Column 1 Width=96 Column 2 Weight=1.0000 +[Table][0x47250C01,11] +RefScale=14 +Column 0 Weight=1.0000 Sort=0v +Column 1 Width=0 +Column 2 Width=0 +Column 3 Width=0 +Column 4 Width=0 +Column 5 Width=0 +Column 6 Width=0 +Column 7 Width=0 +Column 8 Width=0 +Column 9 Weight=1.0000 +Column 10 Width=0 + +[Table][0xAC8E4A04,3] +RefScale=14 +Column 0 Width=96 +Column 1 Width=96 +Column 2 Weight=1.0000 + +[Table][0x407F83B7,3] +RefScale=14 +Column 0 Width=96 +Column 1 Width=96 +Column 2 Weight=1.0000 + +[Table][0x76B37378,3] +RefScale=14 +Column 0 Width=96 +Column 1 Width=96 +Column 2 Weight=1.0000 + +[Table][0xA67089BC,3] +RefScale=14 +Column 0 Width=96 +Column 1 Width=96 +Column 2 Weight=1.0000 + [Docking][Data] -DockSpace ID=0x245145B4 Window=0x6D36DD32 Pos=0,22 Size=2560,1347 Split=X +DockSpace ID=0x245145B4 Window=0x6D36DD32 Pos=0,22 Size=2194,1149 Split=X DockNode ID=0x00000003 Parent=0x245145B4 SizeRef=290,1347 Split=Y Selected=0x568B9410 DockNode ID=0x00000005 Parent=0x00000003 SizeRef=290,149 Selected=0x9F98B8AF DockNode ID=0x00000006 Parent=0x00000003 SizeRef=290,1198 Split=Y Selected=0x568B9410 @@ -512,9 +550,9 @@ DockSpace ID=0x245145B4 Window=0x6D36DD32 Pos=0,22 Size=2560,1347 Spli DockNode ID=0x00000001 Parent=0x00000004 SizeRef=2270,1347 Split=Y Selected=0xA601DFD0 DockNode ID=0x0000000D Parent=0x00000001 SizeRef=1980,1086 Split=Y Selected=0xA601DFD0 DockNode ID=0x00000011 Parent=0x0000000D SizeRef=999,22 Selected=0x37EAA1FD - DockNode ID=0x00000012 Parent=0x0000000D SizeRef=999,1064 Split=X Selected=0xA601DFD0 - DockNode ID=0x0000000F Parent=0x00000012 SizeRef=991,1064 CentralNode=1 Selected=0xA601DFD0 - DockNode ID=0x00000010 Parent=0x00000012 SizeRef=989,1064 Selected=0x260566DD + DockNode ID=0x00000012 Parent=0x0000000D SizeRef=999,866 Split=X Selected=0xA601DFD0 + DockNode ID=0x0000000F Parent=0x00000012 SizeRef=713,1064 CentralNode=1 Selected=0xA601DFD0 + DockNode ID=0x00000010 Parent=0x00000012 SizeRef=627,1064 Selected=0x260566DD DockNode ID=0x0000000E Parent=0x00000001 SizeRef=1980,261 Selected=0x04DD4A87 DockNode ID=0x00000002 Parent=0x00000004 SizeRef=290,1347 Split=Y Selected=0xE59A54D7 DockNode ID=0x00000009 Parent=0x00000002 SizeRef=290,1090 Split=Y Selected=0xE59A54D7 diff --git a/src/editor/Editor.cpp b/src/editor/Editor.cpp index 8e45a32e5..4cd037b3a 100644 --- a/src/editor/Editor.cpp +++ b/src/editor/Editor.cpp @@ -5,6 +5,7 @@ #include "core/IResource.h" #include "core/IGameObject.h" #include "core/File/File.h" +#include "core/Time/Time.h" #include "core/Time/Timer.h" #include "core/UndoRedo/UndoRedo.h" #include "renderer/IUIRenderer.h" @@ -314,6 +315,23 @@ namespace vg::editor else if (input->IsKeyJustPressed(Key::Y)) Kernel::getUndoRedoManager()->Redo(); } + + // Update editor cameras *before* the renderer builds and renders the FrameGraph. + // The editor GUI is drawn from ImGuiPass::Render, so updating the views from ImGuiView::DrawGUI + // would change the camera (and its settings) while the render passes are being recorded. + { + VG_PROFILE_CPU("EditorCameras"); + + const float dt = getEngine()->GetTime().m_realDeltaTime; + + for (uint i = 0; i < m_imGuiWindows.size(); ++i) + { + auto * imGuiView = dynamic_cast(m_imGuiWindows[i]); + + if (nullptr != imGuiView && imGuiView->isVisible() && gfx::ViewportTarget::Editor == imGuiView->getViewportTarget()) + imGuiView->updateEditorCamera(dt); + } + } } //-------------------------------------------------------------------------------------- diff --git a/src/editor/ImGui/Window/View/ImGuiView.hpp b/src/editor/ImGui/Window/View/ImGuiView.hpp index 39d08f2f4..2a14dfb1d 100644 --- a/src/editor/ImGui/Window/View/ImGuiView.hpp +++ b/src/editor/ImGui/Window/View/ImGuiView.hpp @@ -290,9 +290,8 @@ namespace vg::editor { float padding = 1; - // TODO : update editor camera *BEFORE* render? - if (m_target == gfx::ViewportTarget::Editor) - updateEditorCamera(getEngine()->GetTime().m_realDeltaTime); + // Editor cameras are updated by Editor::RunOneFrame, before the renderer builds the FrameGraph: + // 'DrawGUI' is called from ImGuiPass::Render, i.e. while the render passes are being recorded. // Update { diff --git a/src/renderer/RenderPass/Compute/ComputeDeferredLighting/ComputeDeferredLightingPass.h b/src/renderer/RenderPass/Compute/ComputeDeferredLighting/ComputeDeferredLightingPass.h index 32d3f1b72..ec21e852d 100644 --- a/src/renderer/RenderPass/Compute/ComputeDeferredLighting/ComputeDeferredLightingPass.h +++ b/src/renderer/RenderPass/Compute/ComputeDeferredLighting/ComputeDeferredLightingPass.h @@ -18,5 +18,6 @@ namespace vg::renderer private: gfx::RootSignatureHandle m_computeDeferredLightingRootSignature; gfx::ComputeShaderKey m_computeDeferredLightingShaderKey; + bool m_useScreenSpaceAmbient = false; // Set during Setup so that Render uses the resources actually declared in the FrameGraph }; } \ No newline at end of file diff --git a/src/renderer/RenderPass/Compute/ComputeDeferredLighting/ComputeDeferredLightingPass.hpp b/src/renderer/RenderPass/Compute/ComputeDeferredLighting/ComputeDeferredLightingPass.hpp index b180bba18..decaf03fe 100644 --- a/src/renderer/RenderPass/Compute/ComputeDeferredLighting/ComputeDeferredLightingPass.hpp +++ b/src/renderer/RenderPass/Compute/ComputeDeferredLighting/ComputeDeferredLightingPass.hpp @@ -53,12 +53,13 @@ namespace vg::renderer const View * view = static_cast(_renderPassContext.getView()); readDepthStencil(view->getShadowMaps()); - if (ScreenSpaceAmbient::None != view->GetScreenSpaceAmbient()) + m_useScreenSpaceAmbient = ScreenSpaceAmbient::None != view->GetScreenSpaceAmbient(); + if (m_useScreenSpaceAmbient) { const auto screenSpaceAmbientID = _renderPassContext.getFrameGraphID("ScreenSpaceAmbient"); readRWTexture(screenSpaceAmbientID); } - + const MSAA msaa = options->GetMSAA(); if (MSAA::None != msaa) { @@ -171,7 +172,7 @@ namespace vg::renderer deferredLighting.setStencil(stencil); deferredLighting.setRWBufferOut(dstTex->getRWTextureHandle()); - if (ScreenSpaceAmbient::None != view->GetScreenSpaceAmbient()) + if (m_useScreenSpaceAmbient) { const auto screenSpaceAmbientID = _renderPassContext.getFrameGraphID("ScreenSpaceAmbient"); auto screenSpaceAmbient= getRWTexture(screenSpaceAmbientID)->getTextureHandle(); diff --git a/src/renderer/Renderer.cpp b/src/renderer/Renderer.cpp index a0002fa78..0c6edc4b2 100644 --- a/src/renderer/Renderer.cpp +++ b/src/renderer/Renderer.cpp @@ -776,6 +776,10 @@ namespace vg::renderer { View * view = (View *)visibleViews[v]; + // Camera settings can be updated by the editor GUI while the FrameGraph is rendered, + // so freeze the values used to build the graph before registering the passes + view->snapshotRenderSettings(); + gfx::RenderPassContext rc; rc.setView(view); rc.setWorld(view->getWorld()); diff --git a/src/renderer/View/View.cpp b/src/renderer/View/View.cpp index da62cf20e..bfb4cac73 100644 --- a/src/renderer/View/View.cpp +++ b/src/renderer/View/View.cpp @@ -38,6 +38,7 @@ namespace vg::renderer { m_viewport = _params.viewport; m_viewID.target = _params.target; + m_screenSpaceAmbient = ScreenSpaceAmbient::None; SetRenderTargetSize(_params.size); @@ -679,14 +680,37 @@ namespace vg::renderer } //-------------------------------------------------------------------------------------- - bool View::IsComputePostProcessNeeded() const + // The editor GUI is drawn *during* the FrameGraph render (cf. ImGuiPass::Render => IEditor::DrawGUI) + // and updates the camera settings from there (cf. ImGuiView::updateEditorCamera). As render passes + // are recorded by parallel RenderJobs, the camera settings can change while the FrameGraph is being + // rendered, i.e. *after* the passes have been registered and setup. + // Snapshot the settings driving the FrameGraph topology once per frame so that RegisterFrameGraph, + // UserPass::Setup and UserPass::Render always agree on which resources exist. + //-------------------------------------------------------------------------------------- + void View::snapshotRenderSettings() + { + const auto * camSettings = GetCameraSettings(); + + m_screenSpaceAmbient = camSettings ? camSettings->GetScreenSpaceAmbient() : ScreenSpaceAmbient::None; + m_outlinePassNeeded = updateOutlinePassNeeded(); + m_computePostProcessNeeded = updateComputePostProcessNeeded(); + } + + //-------------------------------------------------------------------------------------- + bool View::updateComputePostProcessNeeded() const { const auto options = RendererOptions::get(); - return options->isPostProcessEnabled() || IsOutlinePassNeeded() || (isToolmode() && IsUsingRayTracing() && options->anyRayTracingDebugDisplay()); + return options->isPostProcessEnabled() || m_outlinePassNeeded || (isToolmode() && IsUsingRayTracing() && options->anyRayTracingDebugDisplay()); } //-------------------------------------------------------------------------------------- - bool View::IsOutlinePassNeeded() const + bool View::IsComputePostProcessNeeded() const + { + return m_computePostProcessNeeded; + } + + //-------------------------------------------------------------------------------------- + bool View::updateOutlinePassNeeded() const { const auto * camSettings = GetCameraSettings(); if (nullptr != camSettings) @@ -699,13 +723,16 @@ namespace vg::renderer return isToolmode(); } + //-------------------------------------------------------------------------------------- + bool View::IsOutlinePassNeeded() const + { + return m_outlinePassNeeded; + } + //-------------------------------------------------------------------------------------- ScreenSpaceAmbient View::GetScreenSpaceAmbient() const { - const auto * camSettings = GetCameraSettings(); - if (nullptr != camSettings) - return camSettings->GetScreenSpaceAmbient(); - return ScreenSpaceAmbient::None; + return m_screenSpaceAmbient; } //-------------------------------------------------------------------------------------- @@ -745,6 +772,9 @@ namespace vg::renderer //-------------------------------------------------------------------------------------- void View::RegisterFrameGraph(const RenderPassContext & _rc, FrameGraph & _frameGraph) { + // Views registered by another view (e.g. shadow views) do not go through Renderer::RunOneFrame + snapshotRenderSettings(); + _frameGraph.addUserPass(_rc, m_viewConstantsUpdatePass, "View Constants Update"); } diff --git a/src/renderer/View/View.h b/src/renderer/View/View.h index e518c2f4e..4d442a32e 100644 --- a/src/renderer/View/View.h +++ b/src/renderer/View/View.h @@ -124,6 +124,9 @@ namespace vg::renderer VG_INLINE const Frustum & getCameraFrustum () const; + // Cache the settings used to build the FrameGraph. Must be called once per frame, before 'RegisterFrameGraph' + void snapshotRenderSettings (); + virtual void RegisterFrameGraph (const gfx::RenderPassContext & _rc, gfx::FrameGraph & _frameGraph); const ViewCullingJobOutput & getCullingJobResult () const; @@ -176,11 +179,19 @@ namespace vg::renderer private: void computeCameraFrustum (); + bool updateOutlinePassNeeded () const; + bool updateComputePostProcessNeeded () const; + private: IViewport * m_viewport = nullptr; const core::IGameObject * m_cameraGO = nullptr; PickingID m_pickingID = 0; const ICameraSettings * m_cameraSettings = nullptr; + + // Snapshot of the camera settings used by the FrameGraph for the current frame + ScreenSpaceAmbient m_screenSpaceAmbient; + bool m_outlinePassNeeded = false; + bool m_computePostProcessNeeded = false; gfx::ViewID m_viewID; ViewFlags m_flags = (ViewFlags)0; gfx::Texture * m_renderTarget = nullptr; // use 'nullptr' for backbuffer