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
This commit is contained in:
committed by
Copybara-Service
parent
c41ed42407
commit
57ad7463b1
@@ -36,6 +36,7 @@
|
||||
#include <mujoco/mujoco.h>
|
||||
#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<const RenderRequest> requests,
|
||||
std::span<const ReadPixelsRequest> 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_;
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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<SceneView>(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<std::uint16_t>(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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<SceneView> scene_view_;
|
||||
std::vector<std::unique_ptr<Renderable>> renderables_;
|
||||
std::vector<std::unique_ptr<Mesh>> meshes_;
|
||||
std::unordered_map<uintptr_t, std::unique_ptr<Texture>> textures_;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include "experimental/filament/filament/mjr_filament_renderer.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
@@ -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<SceneView>(GetEngine());
|
||||
scene_bridge_ = std::make_unique<SceneBridge>(GetObjectManager(),
|
||||
scene_view_.get(), model);
|
||||
imgui_bridge_ =
|
||||
std::make_unique<ImguiBridge>(GetObjectManager(), scene_view_.get());
|
||||
scene_bridge_ = std::make_unique<SceneBridge>(GetObjectManager(), model);
|
||||
imgui_bridge_ = std::make_unique<ImguiBridge>(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<RenderTarget>(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<RenderTarget>(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<uint8_t*>(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()); }
|
||||
|
||||
@@ -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<SceneView> scene_view_;
|
||||
FrameBufferMode mode_ = FrameBufferMode::Window;
|
||||
RenderRequest render_requests_[2];
|
||||
std::unique_ptr<SceneBridge> scene_bridge_;
|
||||
std::unique_ptr<ImguiBridge> imgui_bridge_;
|
||||
};
|
||||
|
||||
@@ -87,9 +87,9 @@ static std::unique_ptr<Texture> 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<SceneView>(object_mgr_->GetEngine());
|
||||
model_objects_ =
|
||||
std::make_unique<ModelObjects>(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];
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#include <mujoco/mjvisualize.h>
|
||||
#include <mujoco/mujoco.h>
|
||||
#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<filament::math::float3> ClipFromWorld(
|
||||
const filament::math::float3& pos) const;
|
||||
|
||||
SceneView* scene_view_ = nullptr;
|
||||
std::unique_ptr<SceneView> scene_view_;
|
||||
ObjectManager* object_mgr_ = nullptr;
|
||||
std::unique_ptr<ModelObjects> model_objects_;
|
||||
std::unique_ptr<Light> fallback_ibl_;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
@@ -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<Renderable*> renderables_;
|
||||
filament::Skybox* skybox_ = nullptr;
|
||||
|
||||
// Custom view for UX.
|
||||
filament::View* ux_view_ = nullptr;
|
||||
filament::Camera* ux_camera_ = nullptr;
|
||||
std::unordered_set<Renderable*> 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<Renderable*> reflectives_;
|
||||
std::vector<std::unique_ptr<RenderTarget>> reflect_targets_;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user