Add global Preferences dialog and per-viewport render delegate

Preferences (Edit > Preferences, tabbed General/Animation/Viewport):
- Viewport tab: Default Render Delegate and Color Correction settings
- Persisted to %APPDATA%\UsdLayerManager\preferences.ini
- Render delegate: startup default only (not live-applied to running tiles)
- Color correction: global, applied live to all viewports on change

Render delegate per-viewport:
- Each tile toolbar switches its own delegate independently
- Saved per-tile in viewport_settings.ini; restored on next launch
- Tiles with no saved delegate get the pref default on startup

Color correction global:
- Removed from gear popup; lives in Preferences > Viewport only
- Applied to all tiles on init and on live change from Preferences

Fix InitRenderer always applying m_currentRendererPlugin when set,
rather than skipping when UsdImagingGLEngine auto-selects a default.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-28 11:43:32 +08:00
parent b02a736da0
commit cb0d72d980
8 changed files with 376 additions and 216 deletions
+23 -151
View File
@@ -1,6 +1,5 @@
#include "ViewportTile.h"
#include "../utils/Logger.h"
#include "../utils/OcioConfigParser.h"
#include <pxr/usd/usdGeom/camera.h>
#include <pxr/usd/usdGeom/xformCommonAPI.h>
@@ -100,12 +99,7 @@ ViewportTileSettings ViewportTile::GetSettings() const
s.bboxMode = static_cast<int>(m_renderer.GetBBoxMode());
s.ambientLightOnly = m_renderer.GetAmbientLightOnly();
s.domeLightEnabled = m_renderer.GetDomeLightEnabled();
s.shadingMode = static_cast<int>(m_renderer.GetShadingMode());
s.colorCorrectionMode = static_cast<int>(m_renderer.GetColorCorrectionMode());
s.ocioDisplay = m_renderer.GetOcioDisplay();
s.ocioView = m_renderer.GetOcioView();
s.ocioColorSpace = m_renderer.GetOcioColorSpace();
s.ocioLook = m_renderer.GetOcioLook();
s.shadingMode = static_cast<int>(m_renderer.GetShadingMode());
return s;
}
@@ -120,12 +114,6 @@ void ViewportTile::ApplySettings(const ViewportTileSettings& s)
m_renderer.SetAmbientLightOnly(s.ambientLightOnly);
m_renderer.SetDomeLightEnabled(s.domeLightEnabled);
m_renderer.SetShadingMode(static_cast<ShadingMode>(s.shadingMode));
m_renderer.SetColorCorrectionMode(static_cast<ColorCorrectionMode>(s.colorCorrectionMode));
m_renderer.SetOcioDisplay(s.ocioDisplay);
m_renderer.SetOcioView(s.ocioView);
m_renderer.SetOcioColorSpace(s.ocioColorSpace);
m_renderer.SetOcioLook(s.ocioLook);
m_ocioFieldsSynced = false; // re-seed OCIO edit buffers from restored values
}
// ---------------------------------------------------------------------------
@@ -912,29 +900,31 @@ void ViewportTile::RenderCompactToolbar(int tileIndex)
ImGui::TextDisabled("|");
ImGui::SameLine();
// -- Render delegate -----------------------------------------------------
pxr::TfToken currentId = m_renderer.GetCurrentRendererId();
std::string displayName = currentId.IsEmpty()
? "Rdr"
: UsdSceneRenderer::GetRendererDisplayName(currentId);
if (displayName.size() > 8) displayName = displayName.substr(0, 8);
// -- Render delegate (global) --------------------------------------------
{
pxr::TfToken currentId = m_renderer.GetCurrentRendererId();
std::string displayName = currentId.IsEmpty()
? "Rdr"
: UsdSceneRenderer::GetRendererDisplayName(currentId);
if (displayName.size() > 8) displayName = displayName.substr(0, 8);
std::string rdrBtnId = "##Rdr_" + std::to_string(tileIndex);
ImGui::Button(displayName.c_str(), ImVec2(72.0f, 0.0f));
if (ImGui::IsItemHovered())
ImGui::SetTooltip("Render delegate -- click to change");
std::string rdrPopupId = "RdrPopup_" + std::to_string(tileIndex);
ImGui::Button(displayName.c_str(), ImVec2(72.0f, 0.0f));
if (ImGui::IsItemHovered())
ImGui::SetTooltip("Render delegate");
ImGuiPopupFlags popupFlags = ImGuiPopupFlags_MouseButtonLeft;
std::string rdrPopupId = "RdrPopup_" + std::to_string(tileIndex);
if (ImGui::BeginPopupContextItem(rdrPopupId.c_str(), popupFlags)) {
for (const auto& pluginId : UsdSceneRenderer::GetRendererPlugins()) {
std::string name = UsdSceneRenderer::GetRendererDisplayName(pluginId);
if (name.empty()) name = pluginId.GetString();
bool selected = (pluginId == currentId);
if (ImGui::MenuItem(name.c_str(), nullptr, selected))
if (!selected) m_renderer.SetRendererPlugin(pluginId);
if (ImGui::BeginPopupContextItem(rdrPopupId.c_str(),
ImGuiPopupFlags_MouseButtonLeft))
{
for (const auto& pluginId : UsdSceneRenderer::GetRendererPlugins()) {
std::string name = UsdSceneRenderer::GetRendererDisplayName(pluginId);
if (name.empty()) name = pluginId.GetString();
bool selected = (pluginId == currentId);
if (ImGui::MenuItem(name.c_str(), nullptr, selected) && !selected)
m_renderer.SetRendererPlugin(pluginId);
}
ImGui::EndPopup();
}
ImGui::EndPopup();
}
ImGui::SameLine();
@@ -997,124 +987,6 @@ void ViewportTile::RenderCompactToolbar(int tileIndex)
if (ImGui::BeginPopupContextItem(gearPopupId.c_str(),
ImGuiPopupFlags_MouseButtonLeft))
{
// -- Color correction --------------------------------------------
if (ImGui::BeginMenu("Color Correction")) {
ColorCorrectionMode ccm = m_renderer.GetColorCorrectionMode();
auto ccItem = [&](const char* label, ColorCorrectionMode mode) {
if (ImGui::MenuItem(label, nullptr, ccm == mode)) {
m_renderer.SetColorCorrectionMode(mode);
m_ocioFieldsSynced = false;
}
};
ccItem("Disabled", ColorCorrectionMode::Disabled);
ccItem("sRGB", ColorCorrectionMode::sRGB);
ccItem("OpenColorIO", ColorCorrectionMode::OpenColorIO);
if (ccm == ColorCorrectionMode::OpenColorIO) {
ImGui::Separator();
const OcioConfig& ocfg = GetCurrentOcioConfig();
// Seed buffers from renderer, falling back to OCIO config defaults
if (!m_ocioFieldsSynced) {
std::string disp = m_renderer.GetOcioDisplay();
std::string view = m_renderer.GetOcioView();
if (disp.empty()) disp = ocfg.defaultDisplay;
if (view.empty()) view = ocfg.defaultView;
strncpy(m_ocioDisplayBuf, disp.c_str(), 127);
strncpy(m_ocioViewBuf, view.c_str(), 127);
strncpy(m_ocioColorSpaceBuf, m_renderer.GetOcioColorSpace().c_str(), 127);
strncpy(m_ocioLookBuf, m_renderer.GetOcioLook().c_str(), 127);
if (m_renderer.GetOcioDisplay().empty() && !disp.empty())
m_renderer.SetOcioDisplay(disp);
if (m_renderer.GetOcioView().empty() && !view.empty())
m_renderer.SetOcioView(view);
m_ocioFieldsSynced = true;
}
ImGui::PushItemWidth(200.f);
// Display combo
if (ImGui::BeginCombo("Display##ocio", m_ocioDisplayBuf)) {
for (const auto& d : ocfg.displays) {
bool sel = (d == m_ocioDisplayBuf);
if (ImGui::Selectable(d.c_str(), sel)) {
strncpy(m_ocioDisplayBuf, d.c_str(), 127);
m_renderer.SetOcioDisplay(d);
// Auto-select default view for new display
auto vit = ocfg.views.find(d);
if (vit != ocfg.views.end() && !vit->second.empty()) {
strncpy(m_ocioViewBuf, vit->second[0].c_str(), 127);
m_renderer.SetOcioView(vit->second[0]);
}
}
if (sel) ImGui::SetItemDefaultFocus();
}
ImGui::EndCombo();
}
// View combo — filtered by current display
{
static const std::vector<std::string> kEmpty;
auto vit = ocfg.views.find(std::string(m_ocioDisplayBuf));
const auto& views = (vit != ocfg.views.end()) ? vit->second : kEmpty;
if (ImGui::BeginCombo("View##ocio", m_ocioViewBuf)) {
for (const auto& v : views) {
bool sel = (v == m_ocioViewBuf);
if (ImGui::Selectable(v.c_str(), sel)) {
strncpy(m_ocioViewBuf, v.c_str(), 127);
m_renderer.SetOcioView(v);
}
if (sel) ImGui::SetItemDefaultFocus();
}
ImGui::EndCombo();
}
}
// Color Space combo
if (ImGui::BeginCombo("Color Space##ocio",
m_ocioColorSpaceBuf[0] ? m_ocioColorSpaceBuf : "(default)")) {
if (ImGui::Selectable("(default)", m_ocioColorSpaceBuf[0] == '\0')) {
m_ocioColorSpaceBuf[0] = '\0';
m_renderer.SetOcioColorSpace("");
}
if (m_ocioColorSpaceBuf[0] == '\0') ImGui::SetItemDefaultFocus();
for (const auto& cs : ocfg.colorSpaces) {
bool sel = (cs == m_ocioColorSpaceBuf);
if (ImGui::Selectable(cs.c_str(), sel)) {
strncpy(m_ocioColorSpaceBuf, cs.c_str(), 127);
m_renderer.SetOcioColorSpace(cs);
}
if (sel) ImGui::SetItemDefaultFocus();
}
ImGui::EndCombo();
}
// Look combo
if (ImGui::BeginCombo("Look##ocio",
m_ocioLookBuf[0] ? m_ocioLookBuf : "(none)")) {
if (ImGui::Selectable("(none)", m_ocioLookBuf[0] == '\0')) {
m_ocioLookBuf[0] = '\0';
m_renderer.SetOcioLook("");
}
if (m_ocioLookBuf[0] == '\0') ImGui::SetItemDefaultFocus();
for (const auto& look : ocfg.looks) {
bool sel = (look == m_ocioLookBuf);
if (ImGui::Selectable(look.c_str(), sel)) {
strncpy(m_ocioLookBuf, look.c_str(), 127);
m_renderer.SetOcioLook(look);
}
if (sel) ImGui::SetItemDefaultFocus();
}
ImGui::EndCombo();
}
ImGui::PopItemWidth();
}
ImGui::EndMenu();
}
ImGui::Separator();
// -- Shading mode ------------------------------------------------
if (ImGui::BeginMenu("Shading")) {
ShadingMode cur = m_renderer.GetShadingMode();