Add custom viewport color correction (sRGB/OCIO), bypassing HdxColorCorrectionTask
Hydra's HdxColorCorrectionTask rendered prims black in OCIO mode and could corrupt the GlfDrawTarget bind stack on failure (skipping Unbind), blacking out every later frame including sRGB. Replace it with our own GL post-process: the scene renders linear (RGBA16F) and is corrected by a fullscreen shader -- linear->sRGB encode, or OCIO via the OCIO 2.1 GPU API (GpuShaderDesc plus uploaded 1D/3D LUT textures). OCIO build failures fall back to sRGB (never black) and USD diagnostics are routed to the app log. - core: ViewportColorCorrector + ApplyViewportColorCorrection in UsdSceneRenderer - utils: OcioConfigParser enumerates displays/views/colorspaces/looks from $OCIO - ui: gear-menu OCIO controls (ViewportTile) + per-viewport persistence (ViewportPanel) - Application: point $OCIO at the bundled ACES 1.2 config - CMake: link/copy OpenColorIO, download ACES 1.2 config; plus hdCycles build config (disable OpenVDB/Embree, fix TBB/OpenSubdiv/Imath dirs, exclude CRT DLLs) - main: pre-flight plugin DLL load check to skip plugins with missing deps Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+131
-1
@@ -1,5 +1,6 @@
|
||||
#include "ViewportTile.h"
|
||||
#include "../utils/Logger.h"
|
||||
#include "../utils/OcioConfigParser.h"
|
||||
|
||||
#include <pxr/usd/usdGeom/camera.h>
|
||||
#include <pxr/usd/usdGeom/xformCommonAPI.h>
|
||||
@@ -99,7 +100,12 @@ 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.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();
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -114,6 +120,12 @@ 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
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -985,6 +997,124 @@ 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();
|
||||
|
||||
Reference in New Issue
Block a user