Add gear icon toolbar button with viewport options dropdown

Adds a ⚙ icon button to the right of the AA toggle in each viewport
tile's compact toolbar.  Clicking it opens a dropdown with:
  - Shading submenu: Smooth Shaded / Flat Shaded / Wireframe on Surface /
    Wireframe / Unlit  (new ShadingMode enum driving UsdImagingGLDrawMode)
  - Lighting submenu: Camera Headlight / Scene Lights + Dome Light toggle
  - Show Grid and Anti-Aliasing toggles (mirrored from icon buttons)
  - Bounding Box submenu: None / Per Object / All Selection
  - Background submenu: Dark Gray / Black / Light Gray / Midnight Blue

ShadingMode is persisted in viewport_settings.ini alongside the existing
per-tile settings (saved on shutdown, restored on startup).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-25 09:56:49 +08:00
parent 9d8840ced6
commit 8316e419ba
8 changed files with 137 additions and 3 deletions
+3
View File
@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
<path fill="white" d="M495.9 166.6c3.2 8.7.5 18.4-6.4 24.6l-43.3 39.4c1.1 8.3 1.7 16.8 1.7 25.4s-.6 17.1-1.7 25.4l43.3 39.4c6.9 6.2 9.6 15.9 6.4 24.6-4.4 11.9-9.7 23.3-15.8 34.3l-4.7 8.1c-6.6 11-14 21.4-22.1 31.2-5.9 7.2-15.7 9.6-24.5 6.8l-55.7-17.7c-13.4 10.3-28.2 18.9-44 25.4l-12.5 57.1c-2 9.1-9 16.3-18.2 17.8C283.7 510.8 269.5 512 255 512s-28.7-1.2-42.5-3.5c-9.2-1.5-16.2-8.7-18.2-17.8l-12.5-57.1c-15.8-6.5-30.6-15.1-44-25.4l-55.7 17.7c-8.8 2.8-18.6.3-24.5-6.8-8.1-9.8-15.5-20.2-22.1-31.2l-4.7-8.1C25.1 368.8 19.8 357.4 15.4 345.5c-3.2-8.7-.5-18.4 6.4-24.6l43.3-39.4C64.0 273.1 63.4 264.6 63.4 256s.6-17.1 1.7-25.4L21.8 191.2c-6.9-6.2-9.6-15.9-6.4-24.6 4.4-11.9 9.7-23.3 15.8-34.3l4.7-8.1c6.6-11 14-21.4 22.1-31.2 5.9-7.2 15.7-9.6 24.5-6.8l55.7 17.7c13.4-10.3 28.2-18.9 44-25.4l12.5-57.1C196.5 12.3 203.5 5.1 212.7 3.6 226.5 1.2 240.7 0 255.2 0s28.7 1.2 42.5 3.5c9.2 1.5 16.2 8.7 18.2 17.8l12.5 57.1c15.8 6.5 30.6 15.1 44 25.4l55.7-17.7c8.8-2.8 18.6-.3 24.5 6.8 8.1 9.8 15.5 20.2 22.1 31.2l4.7 8.1c6.1 11 11.4 22.4 15.8 34.3zM255.2 336a80 80 0 1 0 0-160 80 80 0 1 0 0 160z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

+19 -2
View File
@@ -131,6 +131,7 @@ UsdSceneRenderer::UsdSceneRenderer()
: m_showGrid(true) : m_showGrid(true)
, m_aaEnabled(false) , m_aaEnabled(false)
, m_backgroundColor(0.15f, 0.15f, 0.15f) , m_backgroundColor(0.15f, 0.15f, 0.15f)
, m_shadingMode(ShadingMode::SmoothShaded)
, m_ambientLightOnly(true) , m_ambientLightOnly(true)
, m_domeLightEnabled(false) , m_domeLightEnabled(false)
, m_stageIsZup(false) , m_stageIsZup(false)
@@ -616,11 +617,27 @@ void UsdSceneRenderer::Render(int width, int height)
m_renderParams = pxr::UsdImagingGLRenderParams(); m_renderParams = pxr::UsdImagingGLRenderParams();
m_renderParams.frame = m_currentTime; m_renderParams.frame = m_currentTime;
m_renderParams.complexity = 1.0f; m_renderParams.complexity = 1.0f;
m_renderParams.drawMode = pxr::UsdImagingGLDrawMode::DRAW_SHADED_SMOOTH; // Apply shading mode → drawMode + enableLighting
switch (m_shadingMode) {
case ShadingMode::FlatShaded:
m_renderParams.drawMode = pxr::UsdImagingGLDrawMode::DRAW_SHADED_FLAT;
m_renderParams.enableLighting = true; break;
case ShadingMode::WireframeOnSurface:
m_renderParams.drawMode = pxr::UsdImagingGLDrawMode::DRAW_WIREFRAME_ON_SURFACE;
m_renderParams.enableLighting = true; break;
case ShadingMode::Wireframe:
m_renderParams.drawMode = pxr::UsdImagingGLDrawMode::DRAW_WIREFRAME;
m_renderParams.enableLighting = false; break;
case ShadingMode::Unlit:
m_renderParams.drawMode = pxr::UsdImagingGLDrawMode::DRAW_SHADED_SMOOTH;
m_renderParams.enableLighting = false; break;
default: // SmoothShaded
m_renderParams.drawMode = pxr::UsdImagingGLDrawMode::DRAW_SHADED_SMOOTH;
m_renderParams.enableLighting = true; break;
}
m_renderParams.showGuides = true; m_renderParams.showGuides = true;
m_renderParams.showProxy = true; m_renderParams.showProxy = true;
m_renderParams.showRender = false; m_renderParams.showRender = false;
m_renderParams.enableLighting = true;
m_renderParams.enableSampleAlphaToCoverage = true; m_renderParams.enableSampleAlphaToCoverage = true;
m_renderParams.gammaCorrectColors = false; m_renderParams.gammaCorrectColors = false;
m_renderParams.cullStyle = pxr::UsdImagingGLCullStyle::CULL_STYLE_BACK_UNLESS_DOUBLE_SIDED; m_renderParams.cullStyle = pxr::UsdImagingGLCullStyle::CULL_STYLE_BACK_UNLESS_DOUBLE_SIDED;
+13
View File
@@ -31,6 +31,15 @@ enum class BBoxMode {
AllSelection ///< One combined box for the entire selection AllSelection ///< One combined box for the entire selection
}; };
/// Surface shading mode — maps to UsdImagingGLDrawMode + enableLighting.
enum class ShadingMode {
SmoothShaded, ///< Smooth shading with materials (default)
FlatShaded, ///< Flat shading with materials
WireframeOnSurface, ///< Wireframe overlay on solid surface
Wireframe, ///< Wireframe only, no fill
Unlit, ///< Smooth geometry, lighting disabled
};
class UsdSceneRenderer { class UsdSceneRenderer {
public: public:
UsdSceneRenderer(); UsdSceneRenderer();
@@ -199,6 +208,9 @@ public:
bool GetDomeLightEnabled() const { return m_domeLightEnabled; } bool GetDomeLightEnabled() const { return m_domeLightEnabled; }
void SetDomeLightEnabled(bool val) { m_domeLightEnabled = val; } void SetDomeLightEnabled(bool val) { m_domeLightEnabled = val; }
ShadingMode GetShadingMode() const { return m_shadingMode; }
void SetShadingMode(ShadingMode m) { m_shadingMode = m; m_forceRefresh = true; }
/// Default material ambient (kA, default 0.2 — matches viewSettingsDataModel.py). /// Default material ambient (kA, default 0.2 — matches viewSettingsDataModel.py).
float GetDefaultMaterialAmbient() const { return m_defaultMaterialAmbient; } float GetDefaultMaterialAmbient() const { return m_defaultMaterialAmbient; }
void SetDefaultMaterialAmbient(float v) { m_defaultMaterialAmbient = v; } void SetDefaultMaterialAmbient(float v) { m_defaultMaterialAmbient = v; }
@@ -298,6 +310,7 @@ private:
pxr::GfVec3f m_backgroundColor; pxr::GfVec3f m_backgroundColor;
// Lighting settings (mirrors stageView.py viewSettings) // Lighting settings (mirrors stageView.py viewSettings)
ShadingMode m_shadingMode; // draw mode + lighting flags
bool m_ambientLightOnly; // camera headlight bool m_ambientLightOnly; // camera headlight
bool m_domeLightEnabled; // dome/IBL light bool m_domeLightEnabled; // dome/IBL light
bool m_stageIsZup; // used for dome light rotation bool m_stageIsZup; // used for dome light rotation
+2 -1
View File
@@ -60,6 +60,7 @@ static const char* IconFilename(Icon icon) {
case Icon::Refresh: return "arrows-rotate.svg"; case Icon::Refresh: return "arrows-rotate.svg";
case Icon::FilePlus: return "file-plus.svg"; case Icon::FilePlus: return "file-plus.svg";
case Icon::Pen: return "pen.svg"; case Icon::Pen: return "pen.svg";
case Icon::Settings: return "gear.svg";
default: return nullptr; default: return nullptr;
} }
} }
@@ -75,7 +76,7 @@ static constexpr Icon kAllIcons[] = {
Icon::LayoutSingle, Icon::LayoutHSplit, Icon::LayoutVSplit, Icon::LayoutQuad, Icon::LayoutSingle, Icon::LayoutHSplit, Icon::LayoutVSplit, Icon::LayoutQuad,
Icon::SkipBack, Icon::StepBack, Icon::PlayBack, Icon::Play, Icon::Pause, Icon::SkipBack, Icon::StepBack, Icon::PlayBack, Icon::Play, Icon::Pause,
Icon::StepForward, Icon::SkipEnd, Icon::Loop, Icon::Bounce, Icon::StepForward, Icon::SkipEnd, Icon::Loop, Icon::Bounce,
Icon::Refresh, Icon::FilePlus, Icon::Pen, Icon::Refresh, Icon::FilePlus, Icon::Pen, Icon::Settings,
}; };
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
+1
View File
@@ -54,6 +54,7 @@ enum class Icon {
Refresh, // reload / refresh Refresh, // reload / refresh
FilePlus, // create new file FilePlus, // create new file
Pen, // edit / edit target Pen, // edit / edit target
Settings, // gear / viewport options
}; };
/// Loads SVG files from disk, rasterizes them with NanoSVG, uploads them as /// Loads SVG files from disk, rasterizes them with NanoSVG, uploads them as
+2
View File
@@ -635,6 +635,7 @@ void ViewportPanel::SaveSettings(const std::string& path) const
f << "BBoxMode=" << s.bboxMode << "\n"; f << "BBoxMode=" << s.bboxMode << "\n";
f << "AmbientLightOnly=" << (s.ambientLightOnly ? 1 : 0) << "\n"; f << "AmbientLightOnly=" << (s.ambientLightOnly ? 1 : 0) << "\n";
f << "DomeLightEnabled=" << (s.domeLightEnabled ? 1 : 0) << "\n"; f << "DomeLightEnabled=" << (s.domeLightEnabled ? 1 : 0) << "\n";
f << "ShadingMode=" << s.shadingMode << "\n";
} }
} }
@@ -700,6 +701,7 @@ void ViewportPanel::LoadSettings(const std::string& path)
else if (key == "BBoxMode") ts.bboxMode = toInt(val, ts.bboxMode); else if (key == "BBoxMode") ts.bboxMode = toInt(val, ts.bboxMode);
else if (key == "AmbientLightOnly") ts.ambientLightOnly = (val == "1"); else if (key == "AmbientLightOnly") ts.ambientLightOnly = (val == "1");
else if (key == "DomeLightEnabled") ts.domeLightEnabled = (val == "1"); else if (key == "DomeLightEnabled") ts.domeLightEnabled = (val == "1");
else if (key == "ShadingMode") ts.shadingMode = toInt(val, ts.shadingMode);
} }
} }
+96
View File
@@ -99,6 +99,7 @@ ViewportTileSettings ViewportTile::GetSettings() const
s.bboxMode = static_cast<int>(m_renderer.GetBBoxMode()); s.bboxMode = static_cast<int>(m_renderer.GetBBoxMode());
s.ambientLightOnly = m_renderer.GetAmbientLightOnly(); s.ambientLightOnly = m_renderer.GetAmbientLightOnly();
s.domeLightEnabled = m_renderer.GetDomeLightEnabled(); s.domeLightEnabled = m_renderer.GetDomeLightEnabled();
s.shadingMode = static_cast<int>(m_renderer.GetShadingMode());
return s; return s;
} }
@@ -112,6 +113,7 @@ void ViewportTile::ApplySettings(const ViewportTileSettings& s)
m_renderer.SetBBoxMode(static_cast<BBoxMode>(s.bboxMode)); m_renderer.SetBBoxMode(static_cast<BBoxMode>(s.bboxMode));
m_renderer.SetAmbientLightOnly(s.ambientLightOnly); m_renderer.SetAmbientLightOnly(s.ambientLightOnly);
m_renderer.SetDomeLightEnabled(s.domeLightEnabled); m_renderer.SetDomeLightEnabled(s.domeLightEnabled);
m_renderer.SetShadingMode(static_cast<ShadingMode>(s.shadingMode));
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@@ -963,6 +965,100 @@ void ViewportTile::RenderCompactToolbar(int tileIndex)
if (iconToggle(aaId.c_str(), "AA", Icon::Antialias, aa, "Toggle anti-aliasing")) if (iconToggle(aaId.c_str(), "AA", Icon::Antialias, aa, "Toggle anti-aliasing"))
m_renderer.SetAAEnabled(!aa); m_renderer.SetAAEnabled(!aa);
ImGui::SameLine();
ImGui::TextDisabled("|");
ImGui::SameLine();
// -- Gear / viewport options popup ---------------------------------------
{
std::string gearId = "##gear_" + std::to_string(tileIndex);
std::string gearPopupId = "GearPopup_" + std::to_string(tileIndex);
if (m_iconManager) {
ImTextureID tex = m_iconManager->Get(Icon::Settings);
ImGui::ImageButton(gearId.c_str(), ImTextureRef(tex), ImVec2(16.f, 16.f));
} else {
ImGui::Button("*");
}
if (ImGui::IsItemHovered()) ImGui::SetTooltip("Viewport options");
if (ImGui::BeginPopupContextItem(gearPopupId.c_str(),
ImGuiPopupFlags_MouseButtonLeft))
{
// -- Shading mode ------------------------------------------------
if (ImGui::BeginMenu("Shading")) {
ShadingMode cur = m_renderer.GetShadingMode();
auto shadingItem = [&](const char* label, ShadingMode mode) {
if (ImGui::MenuItem(label, nullptr, cur == mode))
m_renderer.SetShadingMode(mode);
};
shadingItem("Smooth Shaded", ShadingMode::SmoothShaded);
shadingItem("Flat Shaded", ShadingMode::FlatShaded);
shadingItem("Wireframe on Surface", ShadingMode::WireframeOnSurface);
shadingItem("Wireframe", ShadingMode::Wireframe);
shadingItem("Unlit", ShadingMode::Unlit);
ImGui::EndMenu();
}
// -- Lighting ----------------------------------------------------
if (ImGui::BeginMenu("Lighting")) {
bool ambient = m_renderer.GetAmbientLightOnly();
if (ImGui::MenuItem("Camera Headlight", nullptr, ambient))
m_renderer.SetAmbientLightOnly(true);
if (ImGui::MenuItem("Scene Lights", nullptr, !ambient))
m_renderer.SetAmbientLightOnly(false);
ImGui::Separator();
bool dome = m_renderer.GetDomeLightEnabled();
if (ImGui::MenuItem("Dome Light", nullptr, dome))
m_renderer.SetDomeLightEnabled(!dome);
ImGui::EndMenu();
}
ImGui::Separator();
// -- Display toggles ---------------------------------------------
{
bool grid = m_renderer.ShowGrid();
if (ImGui::MenuItem("Show Grid", nullptr, grid))
m_renderer.SetShowGrid(!grid);
bool aaItem = m_renderer.GetAAEnabled();
if (ImGui::MenuItem("Anti-Aliasing", nullptr, aaItem))
m_renderer.SetAAEnabled(!aaItem);
}
ImGui::Separator();
// -- BBox --------------------------------------------------------
if (ImGui::BeginMenu("Bounding Box")) {
BBoxMode bbox = m_renderer.GetBBoxMode();
if (ImGui::MenuItem("None", nullptr, bbox == BBoxMode::None))
m_renderer.SetBBoxMode(BBoxMode::None);
if (ImGui::MenuItem("Per Object", nullptr, bbox == BBoxMode::PerObject))
m_renderer.SetBBoxMode(BBoxMode::PerObject);
if (ImGui::MenuItem("All Selection", nullptr, bbox == BBoxMode::AllSelection))
m_renderer.SetBBoxMode(BBoxMode::AllSelection);
ImGui::EndMenu();
}
// -- Background --------------------------------------------------
if (ImGui::BeginMenu("Background")) {
auto& bg = m_renderer.GetBackgroundColor();
if (ImGui::MenuItem("Dark Gray", nullptr, bg == pxr::GfVec3f(0.15f, 0.15f, 0.15f)))
m_renderer.SetBackgroundColor(pxr::GfVec3f(0.15f, 0.15f, 0.15f));
if (ImGui::MenuItem("Black", nullptr, bg == pxr::GfVec3f(0.0f, 0.0f, 0.0f)))
m_renderer.SetBackgroundColor(pxr::GfVec3f(0.0f, 0.0f, 0.0f));
if (ImGui::MenuItem("Light Gray", nullptr, bg == pxr::GfVec3f(0.45f, 0.45f, 0.45f)))
m_renderer.SetBackgroundColor(pxr::GfVec3f(0.45f, 0.45f, 0.45f));
if (ImGui::MenuItem("Midnight Blue", nullptr, bg == pxr::GfVec3f(0.1f, 0.1f, 0.2f)))
m_renderer.SetBackgroundColor(pxr::GfVec3f(0.1f, 0.1f, 0.2f));
ImGui::EndMenu();
}
ImGui::EndPopup();
}
}
ImGui::PopStyleVar(); // ItemSpacing ImGui::PopStyleVar(); // ItemSpacing
} }
+1
View File
@@ -28,6 +28,7 @@ struct ViewportTileSettings {
int bboxMode = 0; ///< BBoxMode cast to int int bboxMode = 0; ///< BBoxMode cast to int
bool ambientLightOnly = false; bool ambientLightOnly = false;
bool domeLightEnabled = false; bool domeLightEnabled = false;
int shadingMode = 0; ///< ShadingMode cast to int (0 = SmoothShaded)
}; };
/// Named orthographic view directions. /// Named orthographic view directions.