Files
UsdLayerManager/src/ui/ViewportTile.h
T
indigo fb1ae9d3a6 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>
2026-06-27 17:10:44 +08:00

199 lines
10 KiB
C++

#pragma once
#include "../core/UsdSceneRenderer.h"
#include "../core/ViewportCamera.h"
#include "../core/CommandHistory.h"
#include "TransformManipulator.h"
#include "IconManager.h"
#include <pxr/usd/usd/stage.h>
#include <pxr/usd/sdf/path.h>
#include <imgui.h>
#include <functional>
#include <memory>
#include <vector>
#include <string>
namespace UsdLayerManager {
/// Serialisable snapshot of all per-tile render settings.
struct ViewportTileSettings {
std::string renderDelegate; ///< TfToken string, empty = default (Storm)
bool showGrid = true;
bool aaEnabled = false;
float bgColorR = 0.15f;
float bgColorG = 0.15f;
float bgColorB = 0.15f;
int bboxMode = 0; ///< BBoxMode cast to int
bool ambientLightOnly = true;
bool domeLightEnabled = false;
int shadingMode = 0; ///< ShadingMode cast to int (0 = SmoothShaded)
int colorCorrectionMode = 1; ///< ColorCorrectionMode cast to int (1 = sRGB)
std::string ocioDisplay;
std::string ocioView;
std::string ocioColorSpace;
std::string ocioLook;
};
/// Named orthographic view directions.
/// When m_orthoView != None the tile renders an orthographic camera locked to
/// that world-space direction; the free-camera orbital state (center + dist)
/// is reused for pan and zoom so each tile keeps an independent view.
enum class OrthoView {
None, ///< Not an ortho view — free camera or USD camera prim
Top,
Bottom,
Front,
Back,
Left,
Right,
};
/// A single viewport tile.
///
/// Owns its own ViewportCamera, UsdSceneRenderer, and all per-tile settings
/// (grid, AA, background colour, bbox mode, render delegate). Selection state
/// and the TransformManipulator are owned by the ViewportPanel container and
/// passed in per frame so they can be shared across tiles.
class ViewportTile {
public:
ViewportTile();
~ViewportTile();
// ── Setup (called once by container) ────────────────────────────────────
void SetStage(pxr::UsdStageRefPtr stage);
void SetIconManager(IconManager* icons) { m_iconManager = icons; }
void SetCommandHistory(CommandHistory* h);
/// displayTime — frame used for all evaluation (render, cameras, bboxes).
/// editTime — frame writes are authored at (Default unless Auto-Key).
void SetTimeCodes(pxr::UsdTimeCode displayTime, pxr::UsdTimeCode editTime);
// ── Selection sync ───────────────────────────────────────────────────────
/// Called by the container to broadcast the authoritative selection.
/// Updates the local shadow copy and pushes it into the renderer highlight.
void SetSelectedPaths(const pxr::SdfPathVector& paths,
const std::string& primaryPath);
// ── Per-frame render ─────────────────────────────────────────────────────
/// Render this tile inside an ImGui child window.
///
/// @param tileIndex Unique index used to disambiguate ImGui IDs.
/// @param pos Screen-space top-left of this tile's area.
/// @param size Pixel dimensions of this tile's area.
/// @param isFocused If true the transform gizmo renders here.
/// @param manipulator Shared manipulator owned by the container.
/// @param dividerActive When true a split-handle drag is active (or the
/// mouse is over one), so rect-selection is suppressed.
void Render(int tileIndex, ImVec2 pos, ImVec2 size,
bool isFocused, TransformManipulator& manipulator,
bool dividerActive = false);
// ── Pick callbacks (assigned by container after construction) ────────────
std::function<void(const std::string&)> OnPrimPicked;
std::function<void(const std::vector<std::string>&)> OnPrimsPickedRect;
// ── Per-frame state queries ──────────────────────────────────────────────
/// True when the user clicked LMB inside this tile during the last Render.
bool WasClickedThisFrame() const { return m_wasClickedThisFrame; }
/// True when the mouse was hovering this tile during the last Render.
bool IsHoveredThisFrame() const { return m_wasHoveredThisFrame; }
// ── Forwarding accessors ─────────────────────────────────────────────────
ViewportCamera& GetCamera() { return m_camera; }
UsdSceneRenderer& GetRenderer() { return m_renderer; }
void FrameScene();
/// Snapshot all current render settings into a portable struct.
ViewportTileSettings GetSettings() const;
/// Apply a previously-saved settings snapshot (safe to call before first Render).
void ApplySettings(const ViewportTileSettings& s);
private:
// ── Render sub-functions ─────────────────────────────────────────────────
pxr::GfCamera ResolveCamera();
/// Build an orthographic GfCamera from the current center/dist state.
pxr::GfCamera BuildOrthoCamera() const;
void HandleInput(bool isFocused, TransformManipulator& manipulator,
bool dividerActive);
void DrawSelectionRect();
void RenderContextMenu(int tileIndex);
void RenderCompactToolbar(int tileIndex);
void RenderManipulatorOverlay(TransformManipulator& manipulator);
// ── Camera helpers ───────────────────────────────────────────────────────
void RefreshCameraList();
void TrySwitchToFreeCamera();
void InitCameraNavigation();
pxr::GfVec3d ComputeGizmoPivot() const;
// ── Core components ──────────────────────────────────────────────────────
ViewportCamera m_camera;
UsdSceneRenderer m_renderer;
IconManager* m_iconManager = nullptr;
CommandHistory* m_commandHistory = nullptr;
// ── Timeline time codes (synced by container) ────────────────────────────
pxr::UsdTimeCode m_displayTime = pxr::UsdTimeCode::Default();
pxr::UsdTimeCode m_editTime = pxr::UsdTimeCode::Default();
// ── Stage + camera list ──────────────────────────────────────────────────
pxr::UsdStageRefPtr m_stage;
std::vector<pxr::SdfPath> m_cameraPaths;
int m_selectedCameraIndex = 0;
bool m_cameraListDirty = true;
// ── Camera navigation mouse state ────────────────────────────────────────
float m_lastMouseX = 0.f;
float m_lastMouseY = 0.f;
bool m_isOrbiting = false;
bool m_isPanning = false;
bool m_isDollying = false;
// ── Rect selection state ─────────────────────────────────────────────────
bool m_isRectSelecting = false;
bool m_rectDragStarted = false;
ImVec2 m_rectAnchor = {0.f, 0.f};
ImVec2 m_rectCurrent = {0.f, 0.f};
static constexpr float kRectDragThreshold = 5.0f;
// ── Viewport dimensions (updated each Render) ────────────────────────────
int m_viewWidth = 0;
int m_viewHeight = 0;
ImVec2 m_imageScreenPos = {0.f, 0.f};
// ── Selection shadow (synced by container) ───────────────────────────────
pxr::SdfPathVector m_selectedSdfPaths;
std::string m_selectedPrimPath;
// ── GfCamera cache ───────────────────────────────────────────────────────
pxr::GfCamera m_lastComputedGfCamera;
bool m_hasLastGfCamera = false;
// ── Free-camera saved state (before switching to a USD cam prim) ─────────
pxr::GfCamera m_savedFreeCameraState;
bool m_hasSavedFreeCameraState = false;
// ── USD camera prim navigation state ────────────────────────────────────
bool m_isDrivingUsdCamPrim = false;
pxr::SdfPath m_drivenUsdCamPath;
// ── Orthographic view ────────────────────────────────────────────────────
OrthoView m_orthoView = OrthoView::None;
// ── OCIO InputText edit buffers (per-tile, seeded on mode activation) ────
char m_ocioDisplayBuf[128] = {};
char m_ocioViewBuf[128] = {};
char m_ocioColorSpaceBuf[128] = {};
char m_ocioLookBuf[128] = {};
bool m_ocioFieldsSynced = false;
// ── Per-frame interaction flags ──────────────────────────────────────────
bool m_wasClickedThisFrame = false;
bool m_wasHoveredThisFrame = false;
};
} // namespace UsdLayerManager