Add Hypershade-style Material Editor with node graph and shader-ball preview
Browser column lists all scene materials plus a searchable create-node list; Show Graph (or double-click) loads a material into the node-graph work area. The graph shows the entire network including MaterialX (.mtlx) node graphs, resolving connections through NodeGraph boundaries via UsdShadeUtils::GetValueProducingAttributes, with layered auto-layout for nodes lacking authored uiPosition. Canvas navigates viewport-style (Alt+MMB pan / Alt+RMB zoom) and TAB opens a Nuke-style search popup. Selecting a node shows a typed property editor (live-apply, one undo command per edit) and previews that node's output on the shader ball. The preview renders through its own Hydra engine into a scratch stage that composes the material via a reference to the source root layer (so referenced .mtlx materials work), re-renders until progressive delegates (Arnold/Cycles/Embree) converge, and lights with HDR dome presets (External/Room/Interior/Sunset; CC0 Poly Haven EXRs fetched at CMake configure). texture:format is authored latlong explicitly - left automatic, hdArnold falls back to Arnold's angular fisheye default - and hdCycles gets a -90 X pole rotation to match Storm's +Y-pole sampling. Mutations go through new ICommand subclasses (create shader node, connect/disconnect attrs). imgui-node-editor is vendored (gitignored) with a local one-line patch: c_ScrollButtonIndex 1->2 for MMB pan. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -46,6 +46,7 @@ Application::Application()
|
||||
, m_showPropertyPanel(true)
|
||||
, m_showTimeline(true)
|
||||
, m_showCurveEditor(false)
|
||||
, m_showMaterialEditor(false)
|
||||
, m_running(false) {
|
||||
}
|
||||
|
||||
@@ -84,6 +85,12 @@ bool Application::Initialize(const std::string& windowTitle, int width, int heig
|
||||
m_curveEditorPanel = std::make_unique<CurveEditorPanel>();
|
||||
m_curveEditorPanel->SetCommandHistory(&m_commandHistory);
|
||||
|
||||
m_materialManager = std::make_unique<MaterialManager>();
|
||||
|
||||
m_materialEditorPanel = std::make_unique<MaterialEditorPanel>();
|
||||
m_materialEditorPanel->SetMaterialManager(m_materialManager.get());
|
||||
m_materialEditorPanel->SetCommandHistory(&m_commandHistory);
|
||||
|
||||
m_timelinePanel = std::make_unique<TimelinePanel>();
|
||||
m_timelinePanel->OnTimeChanged = [this](pxr::UsdTimeCode displayTime,
|
||||
pxr::UsdTimeCode editTime) {
|
||||
@@ -107,12 +114,14 @@ bool Application::Initialize(const std::string& windowTitle, int width, int heig
|
||||
m_viewportPanel->SetIconManager(m_iconManager.get());
|
||||
m_timelinePanel->SetIconManager(m_iconManager.get());
|
||||
m_stageEditorPanel->SetIconManager(m_iconManager.get());
|
||||
m_materialEditorPanel->SetIconManager(m_iconManager.get());
|
||||
|
||||
m_sceneHierarchyPanel->SetOnPrimSelected(
|
||||
[this](const std::string& path) {
|
||||
m_viewportPanel->SetSelectedPrimPath(path);
|
||||
m_propertyPanel->SetSelectedPrimPath(path);
|
||||
m_curveEditorPanel->SetSelectedPrimPath(path);
|
||||
m_materialEditorPanel->SetTargetPrimPath(path);
|
||||
});
|
||||
|
||||
m_sceneHierarchyPanel->SetOnPrimsSelected(
|
||||
@@ -130,6 +139,7 @@ bool Application::Initialize(const std::string& windowTitle, int width, int heig
|
||||
m_sceneHierarchyPanel->SetSelectedPath(path);
|
||||
m_propertyPanel->SetSelectedPrimPath(path);
|
||||
m_curveEditorPanel->SetSelectedPrimPath(path);
|
||||
m_materialEditorPanel->SetTargetPrimPath(path);
|
||||
};
|
||||
|
||||
// Rect drag in viewport → sync hierarchy + property panel + curve editor (primary)
|
||||
@@ -137,6 +147,14 @@ bool Application::Initialize(const std::string& windowTitle, int width, int heig
|
||||
m_sceneHierarchyPanel->SetSelectedPaths(paths);
|
||||
m_propertyPanel->SetSelectedPrimPath(paths.empty() ? "" : paths.front());
|
||||
m_curveEditorPanel->SetSelectedPrimPath(paths.empty() ? "" : paths.front());
|
||||
m_materialEditorPanel->SetTargetPrimPath(paths.empty() ? "" : paths.front());
|
||||
};
|
||||
|
||||
// "Edit Material" in the Property Panel's Material Binding section →
|
||||
// open the Material Editor on the resolved material.
|
||||
m_propertyPanel->OnEditMaterialRequested = [this](const std::string& materialPath) {
|
||||
m_showMaterialEditor = true;
|
||||
m_materialEditorPanel->OpenOrCreateMaterial(materialPath);
|
||||
};
|
||||
|
||||
|
||||
@@ -173,6 +191,9 @@ bool Application::Initialize(const std::string& windowTitle, int width, int heig
|
||||
m_viewportPanel->ApplyGlobalColorCorrection(
|
||||
m_prefs.colorCorrectionMode, m_prefs.ocioDisplay,
|
||||
m_prefs.ocioView, m_prefs.ocioColorSpace, m_prefs.ocioLook);
|
||||
m_materialEditorPanel->SetColorCorrectionFromPrefs(
|
||||
m_prefs.colorCorrectionMode, m_prefs.ocioDisplay,
|
||||
m_prefs.ocioView, m_prefs.ocioColorSpace, m_prefs.ocioLook);
|
||||
}
|
||||
|
||||
LOG_INFO("Application initialized successfully");
|
||||
@@ -201,6 +222,9 @@ void Application::Shutdown() {
|
||||
m_sceneHierarchyPanel.reset();
|
||||
m_propertyPanel.reset();
|
||||
m_stageEditorPanel.reset();
|
||||
// Owns the shader-ball preview's Hydra engine + GL draw target — must be
|
||||
// destroyed while the GL context still exists, like m_viewportPanel.
|
||||
m_materialEditorPanel.reset();
|
||||
m_propertyManager.reset();
|
||||
m_layerManager.reset();
|
||||
|
||||
@@ -233,6 +257,8 @@ void Application::RefreshManagers() {
|
||||
m_propertyPanel->SetStage(stage);
|
||||
m_timelinePanel->SetStage(stage);
|
||||
m_curveEditorPanel->SetStage(stage);
|
||||
m_materialManager->SetStage(stage);
|
||||
m_materialEditorPanel->SetStage(stage);
|
||||
} else {
|
||||
m_layerManager->SetStage(nullptr);
|
||||
m_propertyManager->SetStage(nullptr);
|
||||
@@ -241,6 +267,8 @@ void Application::RefreshManagers() {
|
||||
m_propertyPanel->SetStage(nullptr);
|
||||
m_timelinePanel->SetStage(nullptr);
|
||||
m_curveEditorPanel->SetStage(nullptr);
|
||||
m_materialManager->SetStage(nullptr);
|
||||
m_materialEditorPanel->SetStage(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -318,6 +346,13 @@ void Application::RenderUI() {
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
if (m_showMaterialEditor) {
|
||||
ImGui::SetNextWindowSize({960, 320}, ImGuiCond_FirstUseEver);
|
||||
ImGui::Begin("Material Editor", &m_showMaterialEditor, ImGuiWindowFlags_NoCollapse);
|
||||
m_materialEditorPanel->Render();
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
if (m_showPreferences)
|
||||
RenderPreferencesDialog();
|
||||
|
||||
@@ -414,6 +449,13 @@ void Application::ApplyPrefsToAllViewports()
|
||||
m_prefs.ocioView,
|
||||
m_prefs.ocioColorSpace,
|
||||
m_prefs.ocioLook);
|
||||
if (m_materialEditorPanel)
|
||||
m_materialEditorPanel->SetColorCorrectionFromPrefs(
|
||||
m_prefs.colorCorrectionMode,
|
||||
m_prefs.ocioDisplay,
|
||||
m_prefs.ocioView,
|
||||
m_prefs.ocioColorSpace,
|
||||
m_prefs.ocioLook);
|
||||
}
|
||||
|
||||
void Application::RenderPreferencesDialog()
|
||||
@@ -689,6 +731,7 @@ void Application::RenderMenuBar() {
|
||||
ImGui::MenuItem("Property Panel", nullptr, &m_showPropertyPanel);
|
||||
ImGui::MenuItem("Timeline", nullptr, &m_showTimeline);
|
||||
ImGui::MenuItem("Curve Editor", nullptr, &m_showCurveEditor);
|
||||
ImGui::MenuItem("Material Editor", nullptr, &m_showMaterialEditor);
|
||||
ImGui::Separator();
|
||||
ImGui::MenuItem("Stage Info", nullptr, &m_showStageInfo);
|
||||
ImGui::MenuItem("Demo Window", nullptr, &m_showDemoWindow);
|
||||
|
||||
Reference in New Issue
Block a user