From 57ad7463b11da49bc33cb48884b47c8a1f8c3d76 Mon Sep 17 00:00:00 2001 From: Haroon Qureshi Date: Thu, 23 Apr 2026 02:22:53 -0700 Subject: [PATCH] Use separate SceneView for main scene and UX. Refactor FilamentContext to allow multiple render requests to be submitted onto a single RenderTarget. The main scene and the ux scene are then submitted as two separate requests that share the same target, resulting in a single, composited render. PiperOrigin-RevId: 904324801 Change-Id: I7c47ec4f8d159320612fa33384c01e8db3414daa --- .../filament/filament/filament_context.cc | 129 ++++++++++-------- .../filament/filament/filament_context.h | 4 - .../filament/filament/imgui_bridge.cc | 13 +- .../filament/filament/imgui_bridge.h | 9 +- .../filament/mjr_filament_renderer.cc | 127 ++++++++++------- .../filament/filament/mjr_filament_renderer.h | 15 +- .../filament/filament/scene_bridge.cc | 18 ++- .../filament/filament/scene_bridge.h | 9 +- .../filament/filament/scene_geom_util.cc | 4 +- .../filament/filament/scene_view.cc | 83 +++++------ .../filament/filament/scene_view.h | 28 ++-- 11 files changed, 244 insertions(+), 195 deletions(-) diff --git a/src/experimental/filament/filament/filament_context.cc b/src/experimental/filament/filament/filament_context.cc index 39e3dc0a..8c159ce2 100644 --- a/src/experimental/filament/filament/filament_context.cc +++ b/src/experimental/filament/filament/filament_context.cc @@ -36,6 +36,7 @@ #include #include "experimental/filament/filament/filament_platform_factory.h" #include "experimental/filament/filament/object_manager.h" +#include "experimental/filament/filament/render_target.h" #include "experimental/filament/filament/scene_view.h" #include "experimental/filament/render_context_filament.h" @@ -81,77 +82,91 @@ FilamentContext::~FilamentContext() { FilamentContext::FrameHandle FilamentContext::Render( std::span requests, std::span read_requests) { - if (requests.size() != 1) { - mju_error("Only one render request is supported for now."); - } if (read_requests.size() > 1) { mju_error("Only one read request is supported for now."); } - const RenderRequest& request = requests[0]; - - if (request.target == nullptr) { - if (!read_requests.empty()) { - mju_error("Cannot read pixels from the window."); - } - - if constexpr (UTILS_HAS_THREADING) { - // Wait until previous frame is completed before requesting a new frame. - engine_->flushAndWait(); - } - - // If the window size has changed, we need to reacquire the swap chain. - if (request.width != window_width_ || request.height != window_height_) { - if (window_width_ != 0 && window_height_ != 0) { - engine_->destroy(window_swap_chain_); - window_swap_chain_ = engine_->createSwapChain(config_.native_window); - } - window_width_ = request.width; - window_height_ = request.height; - } - - SceneView::RenderRequest scene_view_request; - scene_view_request.draw_mode = request.draw_mode; - scene_view_request.viewport = {0, 0, request.width, request.height}; - scene_view_request.camera = request.camera; - scene_view_request.enable_ux = request.draw_ux; - if (renderer_->beginFrame(window_swap_chain_)) { - request.scene->Render(renderer_, scene_view_request); + bool render_began = false; + RenderTarget* current_target = nullptr; + for (const RenderRequest& request : requests) { + if (request.target != current_target && render_began) { renderer_->endFrame(); + render_began = false; } + current_target = request.target; + if (current_target == nullptr) { + if (!read_requests.empty()) { + mju_error("Cannot read pixels from the window."); + } + + if constexpr (UTILS_HAS_THREADING) { + // Wait until previous frame is completed before requesting a new frame. + engine_->flushAndWait(); + } + + // If the window size has changed, we need to reacquire the swap chain. + if (request.width != window_width_ || request.height != window_height_) { + if (window_width_ != 0 && window_height_ != 0) { + engine_->destroy(window_swap_chain_); + window_swap_chain_ = engine_->createSwapChain(config_.native_window); + } + window_width_ = request.width; + window_height_ = request.height; + } + + if (!render_began) { + render_began = renderer_->beginFrame(window_swap_chain_); + } + if (render_began) { + SceneView::RenderRequest scene_view_request; + scene_view_request.draw_mode = request.draw_mode; + scene_view_request.viewport = {0, 0, request.width, request.height}; + scene_view_request.camera = request.camera; + request.scene->Render(renderer_, scene_view_request); + } + } else { + if (read_requests.empty()) { + mju_error( + "Rendering to a render target without a read request is pointless."); + } + + const ReadPixelsRequest& read_request = read_requests[0]; + if (read_request.num_bytes == 0) { + mju_error("Output buffer size is zero."); + } + + if (!render_began) { + render_began = renderer_->beginFrame(offscreen_swap_chain_); + } + if (render_began) { + SceneView::RenderRequest scene_view_request; + scene_view_request.draw_mode = request.draw_mode; + scene_view_request.viewport = {0, 0, request.width, request.height}; + scene_view_request.camera = request.camera; + scene_view_request.target = request.target; + request.scene->Render(renderer_, scene_view_request); + request.target->ReadColorPixels(renderer_, read_request.output, + read_request.num_bytes); + } + } + } + + if (render_began) { + renderer_->endFrame(); + render_began = false; if constexpr (!UTILS_HAS_THREADING) { engine_->execute(); } - } else { - if (read_requests.empty()) { - mju_error( - "Rendering to a render target without a read request is pointless."); - } + } - const ReadPixelsRequest& read_request = read_requests[0]; - if (read_request.num_bytes == 0) { - mju_error("Output buffer size is zero."); - - } - - if (renderer_->beginFrame(offscreen_swap_chain_)) { - SceneView::RenderRequest scene_view_request; - scene_view_request.draw_mode = request.draw_mode; - scene_view_request.viewport = {0, 0, request.width, request.height}; - scene_view_request.camera = request.camera; - scene_view_request.enable_ux = request.draw_ux; - scene_view_request.target = request.target; - request.scene->Render(renderer_, scene_view_request); - request.target->ReadColorPixels(renderer_, read_request.output, - read_request.num_bytes); - renderer_->endFrame(); - } + if (!read_requests.empty()) { engine_->flushAndWait(); - if (read_request.read_completed_callback) { - read_request.read_completed_callback(read_request.user_data); + if (read_requests[0].read_completed_callback) { + read_requests[0].read_completed_callback(read_requests[0].user_data); } } + return ++frame_counter_; } diff --git a/src/experimental/filament/filament/filament_context.h b/src/experimental/filament/filament/filament_context.h index 7bb0dd62..391e9818 100644 --- a/src/experimental/filament/filament/filament_context.h +++ b/src/experimental/filament/filament/filament_context.h @@ -59,10 +59,6 @@ class FilamentContext { // will be rendered to the window (as previously configured in // mjrFilamentConfig::native_window). RenderTarget* target = nullptr; - - // Whether or not to include the UX scene in the render. (The SceneView - // stores both a main simulation scene and the UX scene.) - bool draw_ux = true; }; // Information needed to read pixels from a render target. diff --git a/src/experimental/filament/filament/imgui_bridge.cc b/src/experimental/filament/filament/imgui_bridge.cc index 97dd852a..85da0d00 100644 --- a/src/experimental/filament/filament/imgui_bridge.cc +++ b/src/experimental/filament/filament/imgui_bridge.cc @@ -37,8 +37,13 @@ namespace mujoco { using filament::math::float3; using filament::math::mat3f; -ImguiBridge::ImguiBridge(ObjectManager* object_mgr, SceneView* scene_view) - : object_mgr_(object_mgr), scene_view_(scene_view) {} +ImguiBridge::ImguiBridge(ObjectManager* object_mgr) + : object_mgr_(object_mgr) { + scene_view_ = std::make_unique(object_mgr_->GetEngine()); + scene_view_->DisableShadows(); + scene_view_->DisableReflections(); + scene_view_->DisablePostProcessing(); +} ImguiBridge::~ImguiBridge() { PrepareRenderables(0); } @@ -279,10 +284,10 @@ void ImguiBridge::PrepareRenderables(int count) { r->SetCastShadows(false); r->SetReceiveShadows(false); r->SetBlendOrder(static_cast(renderables_.size())); - scene_view_->AddToUxScene(r.get()); + scene_view_->AddToScene(r.get()); } while (renderables_.size() > count) { - scene_view_->RemoveFromUxScene(renderables_.back().get()); + scene_view_->RemoveFromScene(renderables_.back().get()); renderables_.pop_back(); } } diff --git a/src/experimental/filament/filament/imgui_bridge.h b/src/experimental/filament/filament/imgui_bridge.h index 54b5f494..d205db5c 100644 --- a/src/experimental/filament/filament/imgui_bridge.h +++ b/src/experimental/filament/filament/imgui_bridge.h @@ -29,10 +29,10 @@ namespace mujoco { -// Manages Renderables that will be added a SceneView's UX scene. +// Creates and manages a SceneView using data read from ImGui. class ImguiBridge { public: - ImguiBridge(ObjectManager* object_mgr, SceneView* scene_view); + explicit ImguiBridge(ObjectManager* object_mgr); ~ImguiBridge(); // Prepares the Renderables using data from the current ImGui state. This @@ -40,6 +40,9 @@ class ImguiBridge { // synced. void Update(); + // Returns the managed UX scene. + SceneView* GetSceneView() const { return scene_view_.get(); } + // Uploads texture to be used with ImGui's Image and ImageButton functions. uintptr_t UploadImage(uintptr_t tex_id, const uint8_t* pixels, int width, int height, int bpp); @@ -57,7 +60,7 @@ class ImguiBridge { void DestroyTexture(ImTextureData* data); ObjectManager* object_mgr_ = nullptr; - SceneView* scene_view_ = nullptr; + std::unique_ptr scene_view_; std::vector> renderables_; std::vector> meshes_; std::unordered_map> textures_; diff --git a/src/experimental/filament/filament/mjr_filament_renderer.cc b/src/experimental/filament/filament/mjr_filament_renderer.cc index 36908518..5e1112c8 100644 --- a/src/experimental/filament/filament/mjr_filament_renderer.cc +++ b/src/experimental/filament/filament/mjr_filament_renderer.cc @@ -14,6 +14,7 @@ #include "experimental/filament/filament/mjr_filament_renderer.h" +#include #include #include @@ -28,7 +29,6 @@ #include "experimental/filament/filament/model_util.h" #include "experimental/filament/filament/render_target.h" #include "experimental/filament/filament/scene_bridge.h" -#include "experimental/filament/filament/scene_view.h" #include "experimental/filament/filament/texture.h" #include "experimental/filament/render_context_filament.h" @@ -39,11 +39,31 @@ MjrFilamentRenderer::MjrFilamentRenderer(const mjrFilamentConfig* config) } void MjrFilamentRenderer::Init(const mjModel* model) { - scene_view_ = std::make_unique(GetEngine()); - scene_bridge_ = std::make_unique(GetObjectManager(), - scene_view_.get(), model); - imgui_bridge_ = - std::make_unique(GetObjectManager(), scene_view_.get()); + scene_bridge_ = std::make_unique(GetObjectManager(), model); + imgui_bridge_ = std::make_unique(GetObjectManager()); + + render_requests_[0].scene = scene_bridge_->GetSceneView(); + render_requests_[0].draw_mode = DrawMode::Color; + + render_requests_[1].scene = imgui_bridge_->GetSceneView(); + render_requests_[1].draw_mode = DrawMode::Color; + + // The UX camera is a fixed orthographic camera. We only need to change the + // width/height based on the viewport per frame. + render_requests_[1].camera.orthographic = true; + render_requests_[1].camera.pos[0] = 0.0f; + render_requests_[1].camera.pos[1] = 0.0f; + render_requests_[1].camera.pos[2] = 1.0f; + render_requests_[1].camera.forward[0] = 0.0f; + render_requests_[1].camera.forward[1] = 0.0f; + render_requests_[1].camera.forward[2] = -1.0f; + render_requests_[1].camera.up[0] = 0.0f; + render_requests_[1].camera.up[1] = 1.0f; + render_requests_[1].camera.up[2] = 0.0f; + render_requests_[1].camera.frustum_top = 0.0f; + render_requests_[1].camera.frustum_near = 0.0f; + render_requests_[1].camera.frustum_far = 1.0f; + SetClearColor(ReadElement(model, "filament.clearColor", filament::math::float4(0, 0, 0, 1))); @@ -53,46 +73,45 @@ void MjrFilamentRenderer::Render(const mjrRect& viewport, const mjvScene* scene) scene_bridge_->Update(viewport, scene); // Update the UX renderable entity after processing the scene in case there // are any elements in the scene which generate UX draw calls (e.g. labels). - if (imgui_bridge_ && gui_swap_chain_target_ == scene_swap_chain_target_) { - // Prepare the filament Renderable that contains the GUI draw commands. We - // must call this function even if we do not plan on rendering the GUI to - // ensure the ImGui state is updated. + if (mode_ != FrameBufferMode::OffScreen) { imgui_bridge_->Update(); } - last_render_mode_ = DrawMode::Color; if (scene->flags[mjRND_SEGMENT]) { - last_render_mode_ = DrawMode::Segmentation; + render_requests_[0].draw_mode = DrawMode::Segmentation; } else if (scene->flags[mjRND_DEPTH]) { - last_render_mode_ = DrawMode::Depth; + render_requests_[0].draw_mode = DrawMode::Depth; + } else { + render_requests_[0].draw_mode = DrawMode::Color; } - last_camera_ = mjv_averageCamera(scene->camera, scene->camera + 1); - if (scene_swap_chain_target_ == kWindowSwapChain) { - RenderRequest request; - request.scene = scene_view_.get(); - request.draw_mode = last_render_mode_; - request.camera = last_camera_; - request.draw_ux = (gui_swap_chain_target_ == kWindowSwapChain); - request.width = viewport.width; - request.height = viewport.height; - FilamentContext::Render({&request, 1}); + render_requests_[0].width = viewport.width; + render_requests_[0].height = viewport.height; + render_requests_[1].width = viewport.width; + render_requests_[1].height = viewport.height; + + render_requests_[0].camera = mjv_averageCamera(scene->camera, scene->camera + 1); + render_requests_[1].camera.frustum_center = viewport.width / 2.0f; + render_requests_[1].camera.frustum_width = viewport.width / 2.0f; + render_requests_[1].camera.frustum_bottom = viewport.height; + + if (mode_ == FrameBufferMode::Window) { + render_requests_[0].target = nullptr; + render_requests_[1].target = nullptr; + FilamentContext::Render(render_requests_); } } void MjrFilamentRenderer::SetFrameBuffer(int framebuffer) { switch (framebuffer) { case mjFB_WINDOW: - scene_swap_chain_target_ = kWindowSwapChain; - gui_swap_chain_target_ = kWindowSwapChain; + mode_ = FrameBufferMode::Window; break; case mjFB_OFFSCREEN: - scene_swap_chain_target_ = kOffscreenSwapChain; - gui_swap_chain_target_ = kWindowSwapChain; + mode_ = FrameBufferMode::OffScreen; break; case 2: // No official constant fo this. - scene_swap_chain_target_ = kOffscreenSwapChain; - gui_swap_chain_target_ = kOffscreenSwapChain; + mode_ = FrameBufferMode::OffScreenWithGui; break; default: mju_error("Invalid framebuffer mode: %d", framebuffer); @@ -101,53 +120,62 @@ void MjrFilamentRenderer::SetFrameBuffer(int framebuffer) { void MjrFilamentRenderer::ReadPixels(mjrRect viewport, unsigned char* rgb, float* depth) { - if (scene_swap_chain_target_ != kOffscreenSwapChain) { + if (mode_ == FrameBufferMode::Window) { mju_error("ReadPixels is only supported for offscreen rendering."); } - RenderRequest request; - request.scene = scene_view_.get(); - request.camera = last_camera_; - request.draw_ux = (gui_swap_chain_target_ == kOffscreenSwapChain); - request.width = viewport.width; - request.height = viewport.height; + render_requests_[0].width = viewport.width; + render_requests_[0].height = viewport.height; + render_requests_[1].width = viewport.width; + render_requests_[1].height = viewport.height; if (rgb) { - request.draw_mode = last_render_mode_; - RenderTargetConfig config; DefaultRenderTargetConfig(&config); config.color_format = mjPIXEL_FORMAT_RGB8; config.depth_format = mjPIXEL_FORMAT_DEPTH32F; auto target = std::make_unique(GetEngine(), config); - target->Prepare(request.width, request.height); - request.target = target.get(); + target->Prepare(viewport.width, viewport.height); + render_requests_[0].target = target.get(); + render_requests_[1].target = target.get(); + + const size_t num_requests = + (mode_ == FrameBufferMode::OffScreenWithGui) ? 2 : 1; ReadPixelsRequest read_request; read_request.output = rgb; read_request.num_bytes = viewport.width * viewport.height * 3; - const FrameHandle frame = - FilamentContext::Render({&request, 1}, {&read_request, 1}); + const FrameHandle frame = FilamentContext::Render( + {&render_requests_[0], num_requests}, {&read_request, 1}); FilamentContext::WaitForFrame(frame); + + render_requests_[0].target = nullptr; + render_requests_[1].target = nullptr; } if (depth) { - request.draw_mode = DrawMode::Depth; - RenderTargetConfig config; DefaultRenderTargetConfig(&config); config.color_format = mjPIXEL_FORMAT_R32F; config.depth_format = mjPIXEL_FORMAT_DEPTH32F; auto target = std::make_unique(GetEngine(), config); - target->Prepare(request.width, request.height); - request.target = target.get(); + target->Prepare(viewport.width, viewport.height); + render_requests_[0].target = target.get(); + render_requests_[1].target = target.get(); + + DrawMode last_draw_mode = render_requests_[0].draw_mode; + render_requests_[0].draw_mode = DrawMode::Depth; ReadPixelsRequest read_request; read_request.output = reinterpret_cast(depth); read_request.num_bytes = viewport.width * viewport.height * sizeof(float); const FrameHandle frame = - FilamentContext::Render({&request, 1}, {&read_request, 1}); + FilamentContext::Render({&render_requests_[0], 1}, {&read_request, 1}); FilamentContext::WaitForFrame(frame); + + render_requests_[0].target = nullptr; + render_requests_[1].target = nullptr; + render_requests_[0].draw_mode = last_draw_mode; } } @@ -175,10 +203,7 @@ void MjrFilamentRenderer::UploadHeightField(const mjModel* model, int id) { uintptr_t MjrFilamentRenderer::UploadGuiImage(uintptr_t tex_id, const uint8_t* pixels, int width, int height, int bpp) { - if (imgui_bridge_) { - return imgui_bridge_->UploadImage(tex_id, pixels, width, height, bpp); - } - return 0; + return imgui_bridge_->UploadImage(tex_id, pixels, width, height, bpp); } void MjrFilamentRenderer::UpdateGui() { DrawGui(scene_bridge_.get()); } diff --git a/src/experimental/filament/filament/mjr_filament_renderer.h b/src/experimental/filament/filament/mjr_filament_renderer.h index 929e3378..205b8beb 100644 --- a/src/experimental/filament/filament/mjr_filament_renderer.h +++ b/src/experimental/filament/filament/mjr_filament_renderer.h @@ -25,7 +25,6 @@ #include "experimental/filament/filament/filament_context.h" #include "experimental/filament/filament/imgui_bridge.h" #include "experimental/filament/filament/scene_bridge.h" -#include "experimental/filament/filament/scene_view.h" #include "experimental/filament/render_context_filament.h" namespace mujoco { @@ -71,16 +70,14 @@ class MjrFilamentRenderer : public FilamentContext { MjrFilamentRenderer& operator=(const MjrFilamentRenderer&) = delete; private: - enum SwapChainType { - kWindowSwapChain, - kOffscreenSwapChain, + enum class FrameBufferMode { + Window, + OffScreen, + OffScreenWithGui, }; - DrawMode last_render_mode_ = DrawMode::Color; - mjvGLCamera last_camera_; - SwapChainType scene_swap_chain_target_ = kWindowSwapChain; - SwapChainType gui_swap_chain_target_ = kWindowSwapChain; - std::unique_ptr scene_view_; + FrameBufferMode mode_ = FrameBufferMode::Window; + RenderRequest render_requests_[2]; std::unique_ptr scene_bridge_; std::unique_ptr imgui_bridge_; }; diff --git a/src/experimental/filament/filament/scene_bridge.cc b/src/experimental/filament/filament/scene_bridge.cc index 3438b8c9..4cd23fa9 100644 --- a/src/experimental/filament/filament/scene_bridge.cc +++ b/src/experimental/filament/filament/scene_bridge.cc @@ -87,9 +87,9 @@ static std::unique_ptr CreateFallbackIndirectLightTexture( return texture; } -SceneBridge::SceneBridge(ObjectManager* object_mgr, SceneView* scene_view, - const mjModel* model) - : scene_view_(scene_view), object_mgr_(object_mgr) { +SceneBridge::SceneBridge(ObjectManager* object_mgr, const mjModel* model) + : object_mgr_(object_mgr) { + scene_view_ = std::make_unique(object_mgr_->GetEngine()); model_objects_ = std::make_unique(model, object_mgr_->GetEngine()); @@ -354,8 +354,16 @@ filament::math::mat4 CalculateClipFromWorld(const mjrRect& viewport, } void SceneBridge::Update(const mjrRect& viewport, const mjvScene* scene) { - filament::View* view = scene_view_->GetDefaultRenderView(); - view->setShadowingEnabled(scene->flags[mjRND_SHADOW] ? true : false); + if (scene->flags[mjRND_SHADOW]) { + scene_view_->EnableShadows(); + } else { + scene_view_->DisableShadows(); + } + if (scene->flags[mjRND_REFLECTION]) { + scene_view_->EnableReflections(); + } else { + scene_view_->DisableReflections(); + } mjtNum hpos[3], hfwd[3]; float headpos[3], gazedir[3]; diff --git a/src/experimental/filament/filament/scene_bridge.h b/src/experimental/filament/filament/scene_bridge.h index e707d6ed..8c31de05 100644 --- a/src/experimental/filament/filament/scene_bridge.h +++ b/src/experimental/filament/filament/scene_bridge.h @@ -25,7 +25,6 @@ #include #include #include "experimental/filament/filament/light.h" -#include "experimental/filament/filament/material.h" #include "experimental/filament/filament/model_objects.h" #include "experimental/filament/filament/object_manager.h" #include "experimental/filament/filament/renderable.h" @@ -37,8 +36,7 @@ namespace mujoco { // Manages all mjModel data and updates a SceneView using an mjvScene. class SceneBridge { public: - SceneBridge(ObjectManager* object_mgr, SceneView* scene_view, - const mjModel* model); + SceneBridge(ObjectManager* object_mgr, const mjModel* model); ~SceneBridge(); // Updates the environment light using the KTX image at the given path. @@ -56,7 +54,8 @@ class SceneBridge { void UploadTexture(const mjModel* model, int id); void UploadHeightField(const mjModel* model, int id); - SceneView* GetSceneView() const { return scene_view_; } + // Returns the managed scene. + SceneView* GetSceneView() const { return scene_view_.get(); } SceneBridge(const SceneBridge&) = delete; SceneBridge& operator=(const SceneBridge&) = delete; @@ -69,7 +68,7 @@ class SceneBridge { std::optional ClipFromWorld( const filament::math::float3& pos) const; - SceneView* scene_view_ = nullptr; + std::unique_ptr scene_view_; ObjectManager* object_mgr_ = nullptr; std::unique_ptr model_objects_; std::unique_ptr fallback_ibl_; diff --git a/src/experimental/filament/filament/scene_geom_util.cc b/src/experimental/filament/filament/scene_geom_util.cc index 80c653a7..8db3d76e 100644 --- a/src/experimental/filament/filament/scene_geom_util.cc +++ b/src/experimental/filament/filament/scene_geom_util.cc @@ -351,7 +351,6 @@ static void UpdateGeomMaterial(Renderable& renderable, const mjvGeom& geom, const mjModel* model = model_objs->GetModel(); const bool use_segid_color = scene->flags[mjRND_IDCOLOR]; - const bool enable_reflection = scene->flags[mjRND_REFLECTION]; MaterialParams params; params.color = ReadFloat4(geom.rgba); if (geom.type == mjGEOM_PLANE) { @@ -361,8 +360,7 @@ static void UpdateGeomMaterial(Renderable& renderable, const mjvGeom& geom, params.reflective = false; } else { renderable.SetReceiveShadows(true); - params.reflective = - enable_reflection && geom.reflectance > 0 && params.color.a == 1.0f; + params.reflective = geom.reflectance > 0 && params.color.a == 1.0f; } } renderable.SetLayerMask(geom.category); diff --git a/src/experimental/filament/filament/scene_view.cc b/src/experimental/filament/filament/scene_view.cc index efcbd76f..eb2bb47c 100644 --- a/src/experimental/filament/filament/scene_view.cc +++ b/src/experimental/filament/filament/scene_view.cc @@ -127,9 +127,7 @@ static void SetupReflectionCamera(const mat4& surface_xform, SceneView::SceneView(filament::Engine* engine) : engine_(engine) { scene_ = engine->createScene(); - ux_scene_ = engine->createScene(); camera_ = engine->createCamera(utils::EntityManager::get().create()); - ux_camera_ = engine->createCamera(utils::EntityManager::get().create()); reflect_camera_ = engine->createCamera(utils::EntityManager::get().create()); for (auto& view : views_) { @@ -139,12 +137,6 @@ SceneView::SceneView(filament::Engine* engine) : engine_(engine) { view->setVisibleLayers(0xff, mjCAT_ALL); } - ux_view_ = engine->createView(); - ux_view_->setScene(ux_scene_); - ux_view_->setCamera(ux_camera_); - ux_view_->setPostProcessingEnabled(false); - ux_view_->setShadowingEnabled(false); - reflect_view_ = engine->createView(); reflect_view_->setScene(scene_); reflect_view_->setCamera(reflect_camera_); @@ -172,22 +164,16 @@ SceneView::~SceneView() { for (auto& renderable : renderables_) { renderable->RemoveFromScene(scene_); } - for (auto& renderable : ux_renderables_) { - renderable->RemoveFromScene(ux_scene_); - } lights_.clear(); renderables_.clear(); reflect_targets_.clear(); engine_->destroyCameraComponent(reflect_camera_->getEntity()); engine_->destroy(reflect_view_); - engine_->destroyCameraComponent(ux_camera_->getEntity()); - engine_->destroy(ux_view_); engine_->destroyCameraComponent(camera_->getEntity()); if (color_grading_) { engine_->destroy(color_grading_); } engine_->destroy(scene_); - engine_->destroy(ux_scene_); for (auto& view : views_) { engine_->destroy(view); } @@ -224,18 +210,6 @@ void SceneView::RemoveFromScene(Renderable* renderable) { } } -void SceneView::AddToUxScene(Renderable* renderable) { - if (ux_renderables_.insert(renderable).second) { - renderable->AddToScene(ux_scene_); - } -} - -void SceneView::RemoveFromUxScene(Renderable* renderable) { - if (ux_renderables_.erase(renderable)) { - renderable->RemoveFromScene(ux_scene_); - } -} - void SceneView::AddToScene(filament::Skybox* skybox) { skybox_ = skybox; scene_->setSkybox(skybox); @@ -255,7 +229,6 @@ void SceneView::Render(filament::Renderer* renderer, for (auto& view : views_) { view->setViewport(viewport); } - ux_view_->setViewport(viewport); reflect_view_->setViewport(viewport); SetupCamera(request.camera, viewport, camera_); @@ -276,7 +249,7 @@ void SceneView::Render(filament::Renderer* renderer, } // Render reflection passes. - if (request.draw_mode == DrawMode::Color) { + if (request.draw_mode == DrawMode::Color && reflections_enabled_) { for (size_t i = 0; i < reflectives_.size(); ++i) { Renderable* renderable = reflectives_[i]; @@ -301,15 +274,6 @@ void SceneView::Render(filament::Renderer* renderer, renderer->render(view); view->setRenderTarget(nullptr); - if (request.enable_ux) { - ux_camera_->setProjection(filament::Camera::Projection::ORTHO, 0.0f, - viewport.width, viewport.height, 0.0f, 0.0f, - 1.0f); - ux_view_->setRenderTarget(render_target); - renderer->render(ux_view_); - ux_view_->setRenderTarget(nullptr); - } - if (request.target) { view->setMultiSampleAntiAliasingOptions(options); } @@ -335,9 +299,11 @@ void SceneView::AddReflectiveRenderable(Renderable* renderable) { auto& target = reflect_targets_[index]; target->Prepare(viewport.width, viewport.height); - MaterialTextures textures = renderable->GetMaterialTextures(); - textures.reflection = target->GetColorTexture(); - renderable->UpdateMaterial(renderable->GetMaterialParams(), textures); + if (reflections_enabled_) { + MaterialTextures textures = renderable->GetMaterialTextures(); + textures.reflection = target->GetColorTexture(); + renderable->UpdateMaterial(renderable->GetMaterialParams(), textures); + } } void SceneView::SetColorGradingOptions(const ColorGradingOptions& opts) { @@ -353,6 +319,43 @@ void SceneView::SetColorGradingOptions(const ColorGradingOptions& opts) { color_grading_options_ = opts; } +void SceneView::EnableShadows() { + views_[kNormalIndex]->setShadowingEnabled(true); +} + +void SceneView::DisableShadows() { + views_[kNormalIndex]->setShadowingEnabled(false); +} + +void SceneView::EnableReflections() { + reflections_enabled_ = true; + + for (int i = 0; i < reflectives_.size(); ++i) { + Renderable* renderable = reflectives_[i]; + MaterialTextures textures = renderable->GetMaterialTextures(); + textures.reflection = reflect_targets_[i]->GetColorTexture(); + renderable->UpdateMaterial(renderable->GetMaterialParams(), textures); + } +} + +void SceneView::DisableReflections() { + reflections_enabled_ = false; + for (Renderable* renderable : reflectives_) { + MaterialTextures textures = renderable->GetMaterialTextures(); + textures.reflection = nullptr; + renderable->UpdateMaterial(renderable->GetMaterialParams(), textures); + } + +} + +void SceneView::EnablePostProcessing() { + views_[kNormalIndex]->setPostProcessingEnabled(true); +} + +void SceneView::DisablePostProcessing() { + views_[kNormalIndex]->setPostProcessingEnabled(false); +} + filament::View* SceneView::GetDefaultRenderView() { return views_[kNormalIndex]; } diff --git a/src/experimental/filament/filament/scene_view.h b/src/experimental/filament/filament/scene_view.h index a9a2874b..b6d5dfa6 100644 --- a/src/experimental/filament/filament/scene_view.h +++ b/src/experimental/filament/filament/scene_view.h @@ -38,8 +38,7 @@ namespace mujoco { // // The filament Scene is populated with the objects (e.g. lights, renderables, // skybox, etc.). It manages multiple views to support a variety of draw modes -// (e.g. normal, depth, segmentation, etc.) as well as reflective surfaces. It -// also manages a separate scene and view for UX rendering. +// (e.g. normal, depth, segmentation, etc.) as well as reflective surfaces. class SceneView { public: SceneView(filament::Engine* engine); @@ -53,10 +52,6 @@ class SceneView { void AddToScene(filament::Skybox* skybox); void RemoveFromScene(filament::Skybox* skybox); - // Adds/removes entities from the UX scene, which is rendered separately. - void AddToUxScene(Renderable* renderable); - void RemoveFromUxScene(Renderable* renderable); - // Parameters for rendering the scene. struct RenderRequest { // The draw mode (e.g. normal, depth, segmentation) to render. @@ -67,8 +62,6 @@ class SceneView { mjvGLCamera camera; // An optional render target into which the scene will be rendered. RenderTarget* target = nullptr; - // Whether or not to render the UX as a separate pass. - bool enable_ux = false; }; // Renders the scene. @@ -77,6 +70,18 @@ class SceneView { // Returns the filament Engine managing the scene. filament::Engine* GetEngine() const { return engine_; } + // Enables/disables shadows for the default render view. + void EnableShadows(); + void DisableShadows(); + + // Enables/disables reflections for the default render view. + void EnableReflections(); + void DisableReflections(); + + // Enables/disables post processing for the default render view. + void EnablePostProcessing(); + void DisablePostProcessing(); + // Returns the underlying filament View that is used for normal rendering. // Callers can update rendering settings (e.g. post processing) directly. filament::View* GetDefaultRenderView(); @@ -95,7 +100,6 @@ class SceneView { filament::Engine* engine_ = nullptr; filament::Scene* scene_ = nullptr; - filament::Scene* ux_scene_ = nullptr; filament::Camera* camera_ = nullptr; filament::ColorGrading* color_grading_ = nullptr; ColorGradingOptions color_grading_options_; @@ -106,16 +110,12 @@ class SceneView { std::unordered_set renderables_; filament::Skybox* skybox_ = nullptr; - // Custom view for UX. - filament::View* ux_view_ = nullptr; - filament::Camera* ux_camera_ = nullptr; - std::unordered_set ux_renderables_; - // Custom view and camera for reflective surfaces. filament::View* reflect_view_ = nullptr; filament::Camera* reflect_camera_ = nullptr; // The list of reflective renderables and their corresponding render targets. + bool reflections_enabled_ = true; std::vector reflectives_; std::vector> reflect_targets_; };