Refactor how render requests are generated.

Get the camera and drawmode from the bridges rather than recalculating
it unecessarily.

PiperOrigin-RevId: 911406470
Change-Id: Ia295846bb80105a2b0ad5da21912ca82b25e04bd
This commit is contained in:
Haroon Qureshi
2026-05-06 10:13:04 -07:00
committed by Copybara-Service
parent 2b67fe3c3a
commit 2aa2131057
9 changed files with 95 additions and 82 deletions
@@ -302,6 +302,29 @@ void ImguiBridge::PrepareRenderables(int count) {
}
}
mjrScene* ImguiBridge::GetScene() const { return scene_.get(); }
mjrCamera ImguiBridge::GetCamera(int width, int height) const {
mjrCamera camera;
camera.orthographic = true;
camera.pos[0] = 0.0f;
camera.pos[1] = 0.0f;
camera.pos[2] = 1.0f;
camera.forward[0] = 0.0f;
camera.forward[1] = 0.0f;
camera.forward[2] = -1.0f;
camera.up[0] = 0.0f;
camera.up[1] = 1.0f;
camera.up[2] = 0.0f;
camera.frustum_top = 0.0f;
camera.frustum_near = 0.0f;
camera.frustum_far = 1.0f;
camera.frustum_center = width / 2.0f;
camera.frustum_width = width / 2.0f;
camera.frustum_bottom = height;
return camera;
}
static ImVec2 ClipSpaceToWindowCoordinates(float x, float y) {
const ImVec2& display_size = ImGui::GetIO().DisplaySize;
const float pos_x = display_size.x * ((x + 1) * 0.5f);
@@ -37,7 +37,8 @@ class ImguiBridge {
void Update();
// Returns the managed UX scene.
mjrScene* GetScene() const { return scene_.get(); }
mjrScene* GetScene() const;
mjrCamera GetCamera(int width, int height) const;
// 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,
@@ -17,7 +17,6 @@
#include <cstddef>
#include <cstdint>
#include <memory>
#include <string_view>
#include <math/mathfwd.h>
#include <math/vec4.h>
@@ -42,31 +41,6 @@ void MjrFilamentRenderer::Init(const mjModel* model) {
scene_bridge_ = std::make_unique<SceneBridge>(filament_context_.get(), model);
imgui_bridge_ = std::make_unique<ImguiBridge>(filament_context_.get());
scene_bridge_->SetDrawTextFunction(DrawTextAt);
mjr_defaultRenderRequest(&render_requests_[0]);
mjr_defaultRenderRequest(&render_requests_[1]);
render_requests_[0].scene = scene_bridge_->GetScene();
render_requests_[0].draw_mode = mjDRAW_MODE_COLOR;
render_requests_[1].scene = imgui_bridge_->GetScene();
render_requests_[1].draw_mode = mjDRAW_MODE_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;
}
void MjrFilamentRenderer::Render(const mjrRect& viewport,
@@ -78,29 +52,22 @@ void MjrFilamentRenderer::Render(const mjrRect& viewport,
imgui_bridge_->Update();
}
if (scene->flags[mjRND_SEGMENT]) {
render_requests_[0].draw_mode = mjDRAW_MODE_SEGMENTATION;
} else if (scene->flags[mjRND_DEPTH]) {
render_requests_[0].draw_mode = mjDRAW_MODE_DEPTH;
} else {
render_requests_[0].draw_mode = mjDRAW_MODE_COLOR;
}
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;
filament_context_->Render(render_requests_);
mjrRenderRequest reqs[2];
mjr_defaultRenderRequest(&reqs[0]);
reqs[0].scene = scene_bridge_->GetScene();
reqs[0].draw_mode = scene_bridge_->GetDrawMode();
reqs[0].camera = scene_bridge_->GetCamera();
reqs[0].width = viewport.width;
reqs[0].height = viewport.height;
mjr_defaultRenderRequest(&reqs[1]);
reqs[1].scene = imgui_bridge_->GetScene();
reqs[1].draw_mode = mjDRAW_MODE_COLOR;
reqs[1].camera = imgui_bridge_->GetCamera(viewport.width, viewport.height);
reqs[1].width = viewport.width;
reqs[1].height = viewport.height;
filament_context_->Render(reqs);
}
}
@@ -126,10 +93,21 @@ void MjrFilamentRenderer::ReadPixels(mjrRect viewport, unsigned char* rgb,
mju_error("ReadPixels is only supported for offscreen rendering.");
}
render_requests_[0].width = viewport.width;
render_requests_[0].height = viewport.height;
render_requests_[1].width = viewport.width;
render_requests_[1].height = viewport.height;
mjrRenderRequest reqs[2];
mjr_defaultRenderRequest(&reqs[0]);
reqs[0].scene = scene_bridge_->GetScene();
reqs[0].draw_mode = scene_bridge_->GetDrawMode();
reqs[0].camera = scene_bridge_->GetCamera();
reqs[0].width = viewport.width;
reqs[0].height = viewport.height;
mjr_defaultRenderRequest(&reqs[1]);
reqs[1].scene = imgui_bridge_->GetScene();
reqs[1].draw_mode = mjDRAW_MODE_COLOR;
reqs[1].camera = imgui_bridge_->GetCamera(viewport.width, viewport.height);
reqs[1].width = viewport.width;
reqs[1].height = viewport.height;
if (rgb) {
mjrRenderTargetConfig config;
@@ -139,22 +117,21 @@ void MjrFilamentRenderer::ReadPixels(mjrRect viewport, unsigned char* rgb,
config.color_format = mjPIXEL_FORMAT_RGB8;
config.depth_format = mjPIXEL_FORMAT_DEPTH32F;
auto target = CreateRenderTarget(filament_context_.get(), config);
render_requests_[0].target = target.get();
render_requests_[1].target = target.get();
const size_t num_requests =
(mode_ == FrameBufferMode::OffScreenWithGui) ? 2 : 1;
reqs[0].target = target.get();
reqs[1].target = target.get();
mjrReadPixelsRequest read_request;
mjr_defaultReadPixelsRequest(&read_request);
read_request.target = target.get();
read_request.output = rgb;
read_request.num_bytes = viewport.width * viewport.height * 3;
const mjrFrameHandle frame = filament_context_->Render(
{&render_requests_[0], num_requests}, {&read_request, 1});
filament_context_->WaitForFrame(frame);
render_requests_[0].target = nullptr;
render_requests_[1].target = nullptr;
const size_t num_requests =
(mode_ == FrameBufferMode::OffScreenWithGui) ? 2 : 1;
const mjrFrameHandle frame = filament_context_->Render(
{&reqs[0], num_requests}, {&read_request, 1});
filament_context_->WaitForFrame(frame);
}
if (depth) {
@@ -165,23 +142,19 @@ void MjrFilamentRenderer::ReadPixels(mjrRect viewport, unsigned char* rgb,
config.color_format = mjPIXEL_FORMAT_R32F;
config.depth_format = mjPIXEL_FORMAT_DEPTH32F;
auto target = CreateRenderTarget(filament_context_.get(), config);
render_requests_[0].target = target.get();
render_requests_[1].target = target.get();
mjrDrawMode last_draw_mode = render_requests_[0].draw_mode;
render_requests_[0].draw_mode = mjDRAW_MODE_DEPTH;
reqs[0].draw_mode = mjDRAW_MODE_DEPTH;
reqs[0].target = target.get();
mjrReadPixelsRequest read_request;
mjr_defaultReadPixelsRequest(&read_request);
read_request.target = target.get();
read_request.output = reinterpret_cast<uint8_t*>(depth);
read_request.num_bytes = viewport.width * viewport.height * sizeof(float);
const mjrFrameHandle frame = filament_context_->Render(
{&render_requests_[0], 1}, {&read_request, 1});
filament_context_->WaitForFrame(frame);
render_requests_[0].target = nullptr;
render_requests_[1].target = nullptr;
render_requests_[0].draw_mode = last_draw_mode;
const mjrFrameHandle frame = filament_context_->Render(
{&reqs[0], 1}, {&read_request, 1});
filament_context_->WaitForFrame(frame);
}
}
@@ -80,10 +80,9 @@ class MjrFilamentRenderer {
};
std::unique_ptr<FilamentContext> filament_context_;
FrameBufferMode mode_ = FrameBufferMode::Window;
mjrRenderRequest render_requests_[2];
std::unique_ptr<SceneBridge> scene_bridge_;
std::unique_ptr<ImguiBridge> imgui_bridge_;
FrameBufferMode mode_ = FrameBufferMode::Window;
};
} // namespace mujoco
@@ -252,7 +252,7 @@ void SceneBridge::PrepareLights() {
mjrf_setSceneSkybox(scene_.get(), model_objects_->GetSkyboxTexture());
}
mat4 CalculateClipFromWorld(const mjrRect& viewport, const mjvGLCamera& cam) {
mat4 CalculateClipFromWorld(const mjrRect& viewport, const mjrCamera& cam) {
const float3 cam_pos(cam.pos[0], cam.pos[1], cam.pos[2]);
const float3 cam_fwd(cam.forward[0], cam.forward[1], cam.forward[2]);
const float3 cam_up(cam.up[0], cam.up[1], cam.up[2]);
@@ -282,6 +282,13 @@ mat4 CalculateClipFromWorld(const mjrRect& viewport, const mjvGLCamera& cam) {
void SceneBridge::Update(const mjrRect& viewport, const mjvScene* scene) {
mjrf_setSceneShadowsEnabled(scene_.get(), scene->flags[mjRND_SHADOW]);
mjrf_setSceneReflectionsEnabled(scene_.get(), scene->flags[mjRND_REFLECTION]);
if (scene->flags[mjRND_SEGMENT]) {
draw_mode_ = mjDRAW_MODE_SEGMENTATION;
} else if (scene->flags[mjRND_DEPTH]) {
draw_mode_ = mjDRAW_MODE_DEPTH;
} else {
draw_mode_ = mjDRAW_MODE_COLOR;
}
mjtNum hpos[3], hfwd[3];
float headpos[3], gazedir[3];
@@ -289,9 +296,8 @@ void SceneBridge::Update(const mjrRect& viewport, const mjvScene* scene) {
mju_n2f(headpos, hpos, 3);
mju_n2f(gazedir, hfwd, 3);
const mjvGLCamera gl_camera =
mjv_averageCamera(scene->camera, scene->camera + 1);
clip_from_world_ = CalculateClipFromWorld(viewport, gl_camera);
camera_ = mjv_averageCamera(scene->camera, scene->camera + 1);
clip_from_world_ = CalculateClipFromWorld(viewport, camera_);
// Remove all drawables from previous render and prepare new ones.
for (auto& iter : renderables_) {
@@ -365,4 +371,10 @@ void SceneBridge::SetDrawTextFunction(DrawTextAtFn fn) {
draw_text_callback_ = std::move(fn);
}
mjrScene* SceneBridge::GetScene() const { return scene_.get(); }
mjrCamera SceneBridge::GetCamera() const { return camera_; }
mjrDrawMode SceneBridge::GetDrawMode() const { return draw_mode_; }
} // namespace mujoco
@@ -56,7 +56,9 @@ class SceneBridge {
void SetDrawTextFunction(DrawTextAtFn fn);
// Returns the managed scene.
mjrScene* GetScene() const { return scene_.get(); }
mjrScene* GetScene() const;
mjrCamera GetCamera() const;
mjrDrawMode GetDrawMode() const;
SceneBridge(const SceneBridge&) = delete;
SceneBridge& operator=(const SceneBridge&) = delete;
@@ -71,6 +73,8 @@ class SceneBridge {
mjrfContext* ctx_ = nullptr;
std::unique_ptr<ModelObjects> model_objects_;
mjrCamera camera_;
mjrDrawMode draw_mode_ = mjDRAW_MODE_COLOR;
DrawTextAtFn draw_text_callback_;
UniquePtr<mjrScene> scene_{nullptr, nullptr};
UniquePtr<mjrLight> fallback_ibl_{nullptr, nullptr};
@@ -76,7 +76,7 @@ static filament::ColorGrading::Builder ToBuilder(
.curves(opts.shadow_gamma, opts.mid_point, opts.highlight_scale);
}
static void SetupCamera(const mjvGLCamera& cam,
static void SetupCamera(const mjrCamera& cam,
const filament::Viewport& viewport,
filament::Camera* camera) {
const filament::Camera::Projection type =
@@ -63,7 +63,7 @@ class SceneView : public mjrScene {
// The target viewport for the rendered image.
mjrRect viewport;
// The camera from which to render the scene.
mjvGLCamera camera;
mjrCamera camera;
// An optional render target into which the scene will be rendered.
RenderTarget* target = nullptr;
};
@@ -122,6 +122,7 @@ typedef std::uint64_t mjrFrameHandle;
typedef mjtTexture mjrTextureTarget;
typedef mjtColorSpace mjrColorSpace;
typedef mjtLightType mjrLightType;
typedef mjvGLCamera mjrCamera;
// The textures that can be assigned to the drawable's material.
struct mjrMaterialTextures {
@@ -367,7 +368,7 @@ struct mjrRenderRequest {
mjrDrawMode draw_mode;
// The camera from which to render the scene.
mjvGLCamera camera;
mjrCamera camera;
// The dimensions of the output image.
int width;