diff --git a/resources/icons/gear.svg b/resources/icons/gear.svg
new file mode 100644
index 0000000..112381c
--- /dev/null
+++ b/resources/icons/gear.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/core/UsdSceneRenderer.cpp b/src/core/UsdSceneRenderer.cpp
index e6c80e7..056b941 100644
--- a/src/core/UsdSceneRenderer.cpp
+++ b/src/core/UsdSceneRenderer.cpp
@@ -131,6 +131,7 @@ UsdSceneRenderer::UsdSceneRenderer()
: m_showGrid(true)
, m_aaEnabled(false)
, m_backgroundColor(0.15f, 0.15f, 0.15f)
+ , m_shadingMode(ShadingMode::SmoothShaded)
, m_ambientLightOnly(true)
, m_domeLightEnabled(false)
, m_stageIsZup(false)
@@ -616,11 +617,27 @@ void UsdSceneRenderer::Render(int width, int height)
m_renderParams = pxr::UsdImagingGLRenderParams();
m_renderParams.frame = m_currentTime;
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.showProxy = true;
m_renderParams.showRender = false;
- m_renderParams.enableLighting = true;
m_renderParams.enableSampleAlphaToCoverage = true;
m_renderParams.gammaCorrectColors = false;
m_renderParams.cullStyle = pxr::UsdImagingGLCullStyle::CULL_STYLE_BACK_UNLESS_DOUBLE_SIDED;
diff --git a/src/core/UsdSceneRenderer.h b/src/core/UsdSceneRenderer.h
index 9ad6179..6f9ea2f 100644
--- a/src/core/UsdSceneRenderer.h
+++ b/src/core/UsdSceneRenderer.h
@@ -31,6 +31,15 @@ enum class BBoxMode {
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 {
public:
UsdSceneRenderer();
@@ -199,6 +208,9 @@ public:
bool GetDomeLightEnabled() const { return m_domeLightEnabled; }
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).
float GetDefaultMaterialAmbient() const { return m_defaultMaterialAmbient; }
void SetDefaultMaterialAmbient(float v) { m_defaultMaterialAmbient = v; }
@@ -298,6 +310,7 @@ private:
pxr::GfVec3f m_backgroundColor;
// Lighting settings (mirrors stageView.py viewSettings)
+ ShadingMode m_shadingMode; // draw mode + lighting flags
bool m_ambientLightOnly; // camera headlight
bool m_domeLightEnabled; // dome/IBL light
bool m_stageIsZup; // used for dome light rotation
diff --git a/src/ui/IconManager.cpp b/src/ui/IconManager.cpp
index 6c26576..7a8b899 100644
--- a/src/ui/IconManager.cpp
+++ b/src/ui/IconManager.cpp
@@ -60,6 +60,7 @@ static const char* IconFilename(Icon icon) {
case Icon::Refresh: return "arrows-rotate.svg";
case Icon::FilePlus: return "file-plus.svg";
case Icon::Pen: return "pen.svg";
+ case Icon::Settings: return "gear.svg";
default: return nullptr;
}
}
@@ -75,7 +76,7 @@ static constexpr Icon kAllIcons[] = {
Icon::LayoutSingle, Icon::LayoutHSplit, Icon::LayoutVSplit, Icon::LayoutQuad,
Icon::SkipBack, Icon::StepBack, Icon::PlayBack, Icon::Play, Icon::Pause,
Icon::StepForward, Icon::SkipEnd, Icon::Loop, Icon::Bounce,
- Icon::Refresh, Icon::FilePlus, Icon::Pen,
+ Icon::Refresh, Icon::FilePlus, Icon::Pen, Icon::Settings,
};
// ---------------------------------------------------------------------------
diff --git a/src/ui/IconManager.h b/src/ui/IconManager.h
index f13a899..47ed9e4 100644
--- a/src/ui/IconManager.h
+++ b/src/ui/IconManager.h
@@ -54,6 +54,7 @@ enum class Icon {
Refresh, // reload / refresh
FilePlus, // create new file
Pen, // edit / edit target
+ Settings, // gear / viewport options
};
/// Loads SVG files from disk, rasterizes them with NanoSVG, uploads them as
diff --git a/src/ui/ViewportPanel.cpp b/src/ui/ViewportPanel.cpp
index d4c6b16..aca4c84 100644
--- a/src/ui/ViewportPanel.cpp
+++ b/src/ui/ViewportPanel.cpp
@@ -635,6 +635,7 @@ void ViewportPanel::SaveSettings(const std::string& path) const
f << "BBoxMode=" << s.bboxMode << "\n";
f << "AmbientLightOnly=" << (s.ambientLightOnly ? 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 == "AmbientLightOnly") ts.ambientLightOnly = (val == "1");
else if (key == "DomeLightEnabled") ts.domeLightEnabled = (val == "1");
+ else if (key == "ShadingMode") ts.shadingMode = toInt(val, ts.shadingMode);
}
}
diff --git a/src/ui/ViewportTile.cpp b/src/ui/ViewportTile.cpp
index ffc8687..4362e6b 100644
--- a/src/ui/ViewportTile.cpp
+++ b/src/ui/ViewportTile.cpp
@@ -99,6 +99,7 @@ ViewportTileSettings ViewportTile::GetSettings() const
s.bboxMode = static_cast(m_renderer.GetBBoxMode());
s.ambientLightOnly = m_renderer.GetAmbientLightOnly();
s.domeLightEnabled = m_renderer.GetDomeLightEnabled();
+ s.shadingMode = static_cast(m_renderer.GetShadingMode());
return s;
}
@@ -112,6 +113,7 @@ void ViewportTile::ApplySettings(const ViewportTileSettings& s)
m_renderer.SetBBoxMode(static_cast(s.bboxMode));
m_renderer.SetAmbientLightOnly(s.ambientLightOnly);
m_renderer.SetDomeLightEnabled(s.domeLightEnabled);
+ m_renderer.SetShadingMode(static_cast(s.shadingMode));
}
// ---------------------------------------------------------------------------
@@ -963,6 +965,100 @@ void ViewportTile::RenderCompactToolbar(int tileIndex)
if (iconToggle(aaId.c_str(), "AA", Icon::Antialias, aa, "Toggle anti-aliasing"))
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
}
diff --git a/src/ui/ViewportTile.h b/src/ui/ViewportTile.h
index b3ce184..1403930 100644
--- a/src/ui/ViewportTile.h
+++ b/src/ui/ViewportTile.h
@@ -28,6 +28,7 @@ struct ViewportTileSettings {
int bboxMode = 0; ///< BBoxMode cast to int
bool ambientLightOnly = false;
bool domeLightEnabled = false;
+ int shadingMode = 0; ///< ShadingMode cast to int (0 = SmoothShaded)
};
/// Named orthographic view directions.