e2a4961ebe
Build against OpenUSD 25.11 built from source with Python 3.12, OCIO 2.2.1, OpenVDB, Ptex and Embree, replacing the 25.05/py311 mix. Build system: - CMAKE_PREFIX_PATH -> third_party/OpenUSD-v25.11; HDARNOLD_ROOT -> hdArnold-v25.11. hdEmbree is bundled in the USD build now, so HDEMBREE_USD_ROOT is no longer needed. - FindOpenUSD: drop usd_ndr (ndr was merged into sdr in 25.11). - hdArnold plugin renames: ndrArnold -> nodeRegistryArnold, plus the new usdImagingArnold plugin. - Glob the version-suffixed OpenColorIO_*.dll instead of hardcoding 2_1. - Drop the python311.dll workaround; USD and Cycles now share Python 3.12. - Cycles: deploy OpenColorIO_2_5.dll (needed by its bundled OpenImageIO) and stop the debug-DLL filter from eating IlmThread.dll -- the regex `d[.]dll$` also matched legitimate Release DLLs. Runtime fixes: - cullStyle now defaults to Nothing, matching usdview (viewSettingsDataModel cullBackfaces=False). BackUnlessDoubleSided drops back faces on geometry that isn't authored doubleSided, which hdEmbree applies to occlusion rays too, so interiors shaded as single-sided. - Set HDARNOLD_osl_includepath (and PXR_MTLX_STDLIB_SEARCH_PATHS) in main.cpp before the plugin DLL pre-load. hdArnold compiles MaterialX via generated OSL that begins with #include "mx_funcs.h"; without an include path Arnold fails with "fatal error: 'mx_funcs.h' file not found". It must be set before any plugin loads because TF_DEFINE_ENV_SETTING caches the value when hdArnold.dll registers its settings. - Deploy the MaterialX standard library next to the executable. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
181 lines
12 KiB
Markdown
181 lines
12 KiB
Markdown
# USD Layer Manager
|
|
|
|
A C++17 / Windows desktop application providing a **Maya-style** USD scene and look-dev editor using **OpenUSD v25.11**, **ImGui 1.92.7** (docking branch), and **OpenGL 3.3** (via GLAD). Users can open, edit, and save USD files, manage layered stage overrides, inspect and edit prim properties, author UsdShade material graphs with a live shader-ball preview, animate with a Bezier curve editor, and interact with 3D scenes through a multi-viewport Hydra renderer with OCIO color management.
|
|
|
|

|
|
|
|
## Features
|
|
|
|
- **Layer Stack Management** — `StageEditorPanel`: create, reorder, mute/unmute sublayers, set the edit target, add existing files as sublayers, with full undo support
|
|
- **Scene Hierarchy** — Browse prim tree with per-type SVG icons; create, delete, rename, reparent, and group prims; add/replace references
|
|
- **Property Editor** — Maya Channel Box-style attribute editing with type-aware drag inputs, color pickers, and undoable transforms
|
|
- **Material Editor** — Hypershade-style node-graph editor for UsdShade/MaterialX networks (`MaterialEditorPanel`): material browser, drag-to-connect node canvas, per-node/per-pin display modes, Sdr-driven node creation menu and enum dropdowns, colorSpace authoring on texture inputs, and a live shader-ball preview (`MaterialPreviewRenderer`) with its own renderer/HDRI/preview-shape controls. In-canvas node thumbnails (`NodeThumbnailCache`) show texture previews and per-node shader-ball renders, amortized across frames and re-rendered until progressive delegates (Arnold/Cycles/Embree) fully converge
|
|
- **Timeline & Curve Editor** — Transport controls with loop/bounce and Auto-Key (`TimelinePanel`); a Maya-style F-curve editor (`CurveEditorPanel`) with Bezier round-trip to USD time samples; Playblast export to MP4 via `MovieEncoder` (libavcodec)
|
|
- **3D Viewport** — Hydra rendering via `UsdImagingGLEngine` into an offscreen FBO; switchable render delegates (Storm, Embree, Arnold, Cycles); OCIO-based color management (sRGB or full display/view/look pipeline) applied as a post-Hydra GL pass; grid overlay; selection bounding boxes; camera/light wireframes
|
|
- **Multi-Viewport** — Single, horizontal split, vertical split, and quad layouts; per-tile camera, render delegate, and AOV; Space to maximize/restore
|
|
- **Camera Control** — Free orbital camera (tumble/truck/dolly) or drive from USD camera prims; auto near/far clipping; frame selection; correct camera prim orientation for Y-up and Z-up stages
|
|
- **Transform Gizmo** — Pure ImDrawList-based manipulator (translate/rotate/scale) in object or world space
|
|
- **Undo/Redo** — Full command history (`ICommand` subclasses under `src/core/commands/`) covering prim creation/deletion/reparenting/grouping, attribute edits, transform changes, shader-node creation/connection, and layer operations; Ctrl+Z / Ctrl+Y hotkeys; Edit menu integration
|
|
- **Multi-select** — Rectangular selection in viewport with cross-panel syncing
|
|
|
|
| Material Editor (Arnold) | Curve Editor | Quad Viewport (4 delegates) | MaterialX import |
|
|
|---|---|---|---|
|
|
|  |  |  |  |
|
|
|
|
## Dependencies
|
|
|
|
| Dependency | Version | Notes |
|
|
|---|---|---|
|
|
| [OpenUSD](https://github.com/PixarAnimationStudios/OpenUSD) | v25.11 | Prebuilt; found via `FindOpenUSD.cmake` |
|
|
| [Dear ImGui](https://github.com/ocornut/imgui) | v1.92.7 | Docking branch; Win32 + OpenGL3 backends |
|
|
| [GLAD](https://glad.dav1d.de/) | — | OpenGL 3.3 core loader |
|
|
| Python | 3.12 | Required by OpenUSD runtime (`python312.dll`) |
|
|
|
|
### Optional Render Delegates
|
|
|
|
| Delegate | Renderer Version | Variable | Notes |
|
|
|---|---|---|---|
|
|
| **hdEmbree** | Embree 4.3.3 | `HDEMBREE_USD_ROOT` (optional) | Bundled directly in `third_party/OpenUSD-v25.11` (built with `--embree`); set `HDEMBREE_USD_ROOT` only if using a separate USD build, and `EMBREE_LOCATION` if Embree DLLs aren't in its `bin/` |
|
|
| **hdArnold** | Arnold 7.4.0 (MtoA 5.5.0) | `HDARNOLD_ROOT`, `ARNOLD_LOCATION` | [arnold-usd](https://github.com/Autodesk/arnold-usd) (tag `Arnold-7.4.5.1`, for USD 25.11's `ndr`→`sdr` API change) install dir + MtoA root for `ai.dll` |
|
|
| **hdCycles** | Cycles 5.2.0 | `WITH_CYCLES=ON` | Built from source under `third_party/cycles` via ExternalProject; requires MSVC |
|
|
|
|
All delegate paths are pre-configured in `CMakePresets.json`.
|
|
|
|
## Build
|
|
|
|
### Prerequisites
|
|
|
|
- Visual Studio 17 2022 (MSVC v143) with C++17 support
|
|
- CMake 3.20+
|
|
- Python 3.12 installed at `%LOCALAPPDATA%\Programs\Python\Python312\`
|
|
|
|
### Steps
|
|
|
|
```powershell
|
|
cmake --preset default
|
|
cmake --build build --config Release
|
|
cmake --install build --config Release
|
|
```
|
|
|
|
The installed executable lives in `install/bin/`.
|
|
|
|
**Presets** — `default` (`Release`, `WITH_CYCLES=ON`, all render delegates), `debug` (`Debug`), `release` (`RelWithDebInfo`, installs), `no-tests` (`Release`). All presets currently build with `BUILD_TESTS=OFF`.
|
|
|
|
### Building with Cycles
|
|
|
|
`WITH_CYCLES=ON` is set in the default preset. The first build compiles Blender Cycles from `third_party/cycles` via ExternalProject — expect a significantly longer initial build. Subsequent builds are incremental.
|
|
|
|
Cycles runtime dependencies (`embree4.dll`, `openvdb.dll`, `OpenImageDenoise.dll`, `tbb12.dll`, etc.) are automatically deployed to the output directory by a post-build step. CRT DLLs bundled inside the Cycles install are excluded to avoid version conflicts with the app's own MSVC runtime.
|
|
|
|
### Tests
|
|
|
|
There is currently no working test runner: `BUILD_TESTS` is `OFF` in every preset. The two test executables (`ViewportDisplayTest`, `RendererDiagnosticTest`) have stale USD include paths and don't build — fix those before turning `BUILD_TESTS` on.
|
|
|
|
## Architecture
|
|
|
|
```
|
|
src/
|
|
├── main.cpp — Entry point (plugin path init, app lifecycle)
|
|
├── core/ — USD business logic (no UI dependency)
|
|
│ ├── UsdStageManager — Stage open/create/save/close lifecycle
|
|
│ ├── LayerManager — Layer stack introspection and mutation
|
|
│ ├── PropertyManager — Property read/write via edit target with undo
|
|
│ ├── MaterialManager — UsdShade graph introspection + Sdr node-type/enum discovery
|
|
│ ├── CommandHistory — Undo/redo stack for ICommand instances
|
|
│ ├── UsdSceneRenderer — Hydra rendering + picking + overlays + OCIO color correction
|
|
│ ├── ViewportCamera — Free / USD-camera-driven orbital camera
|
|
│ └── commands/ — ICommand subclasses for all mutable operations
|
|
│ ├── TransformCommand — Undoable translate/rotate/scale
|
|
│ ├── CreatePrimCommand — Undoable prim creation (with camera orientation)
|
|
│ ├── DeletePrimCommand — Undoable prim deletion (SdfCopySpec snapshot)
|
|
│ ├── RenamePrimCommand — Undoable prim rename
|
|
│ ├── ReparentPrimCommand — Undoable reparent via UsdNamespaceEditor
|
|
│ ├── GroupPrimsCommand — Group selected prims under a new Xform
|
|
│ ├── AttributeSetCommand — Type-agnostic undoable attribute writes
|
|
│ ├── AddReferenceCommand — Undoable reference addition
|
|
│ ├── ReplaceReferenceCommand — Undoable reference replacement
|
|
│ ├── CreateShaderNodeCommand — Undoable UsdShadeShader creation (Material Editor)
|
|
│ ├── ConnectShaderAttrsCommand — Undoable shader input↔output connection
|
|
│ ├── DisconnectShaderAttrCommand — Undoable shader connection removal
|
|
│ └── LayerCommands — Create, remove, reorder sublayers
|
|
├── ui/ — ImGui panels and application shell
|
|
│ ├── Application — App shell (owns managers/panels, docking, menus)
|
|
│ ├── ImGuiContext — Win32+OpenGL+ImGui initialization and loop
|
|
│ ├── ViewportPanel — Viewport container (layout, divider drag, maximize)
|
|
│ ├── ViewportTile — Single viewport tile (camera, rendering, overlays, picking)
|
|
│ ├── SceneHierarchyPanel — Prim tree browser with context menus
|
|
│ ├── PropertyPanel — Attribute/transform editor (channel box-style)
|
|
│ ├── StageEditorPanel — Layer stack editor (edit target, dirty state, drag-drop ordering)
|
|
│ ├── TimelinePanel — Transport controls, loop/bounce, frame scrub, Playblast
|
|
│ ├── CurveEditorPanel — Maya-style F-curve editor (Bezier ↔ USD time samples)
|
|
│ ├── MaterialEditorPanel — Hypershade-style UsdShade node-graph editor
|
|
│ ├── MaterialPreviewRenderer — Shader-ball preview: independent Hydra instance + scratch stage
|
|
│ ├── NodeThumbnailCache — Async texture decode + amortized shader-ball thumbnails for the node canvas
|
|
│ ├── TransformManipulator — ImDrawList gizmo (move/rotate/scale)
|
|
│ ├── IconManager — SVG icon rasterization via NanoSVG
|
|
│ └── NodeEditor/ — Vendored/patched imgui-node-editor
|
|
└── utils/ — Cross-cutting utilities
|
|
├── Logger — Thread-safe logging (file + console); also sinks USD TF_WARN/TF_ERROR
|
|
├── FileDialog — Win32 file open/save dialogs
|
|
├── PathUtils — Exe-relative path resolution
|
|
├── OcioConfigParser — Enumerates displays/views/colorspaces/looks from the active OCIO config
|
|
├── MovieEncoder — Streams RGBA frames to H.264/MP4 via libavcodec (Playblast)
|
|
└── GLExt — GLAD extension initialization
|
|
```
|
|
|
|
## Key Design Patterns
|
|
|
|
- **Command Pattern** — All mutable USD operations go through `ICommand` → `CommandHistory` for undo/redo
|
|
- **Panel-Manager Separation** — UI panels hold pointers to core managers but contain no USD layer/prim logic
|
|
- **Callback Wiring** — Cross-panel communication via `std::function` callbacks (e.g. viewport pick → hierarchy select → property panel update)
|
|
- **Render-Delegate Plugability** — `UsdSceneRenderer` can switch Hydra render plugins at runtime
|
|
- **Own Color Correction Pass** — Hydra's `HdxColorCorrectionTask` is bypassed; a file-local `ViewportColorCorrector` (inside `UsdSceneRenderer.cpp`) applies sRGB/OCIO as a fullscreen GL pass after Hydra renders linear (see `docs/adr/0001-viewport-color-correction.md`)
|
|
- **Gizmo as 2D Overlay** — `TransformManipulator` uses pure `ImDrawList` calls (no GL resources), same approach as ImGuizmo
|
|
|
|
## Project Configuration
|
|
|
|
| Config | Purpose |
|
|
|---|---|
|
|
| `cmake/modules/FindOpenUSD.cmake` | OpenUSD SDK discovery |
|
|
| `cmake/modules/FindImgui.cmake` | ImGui source integration |
|
|
| `cmake/modules/FindGlad.cmake` | GLAD loader setup |
|
|
| `CMakePresets.json` | Build presets (VS 17 2022, x64) |
|
|
| `docs/adr/` | Architecture decision records |
|
|
| `AGENTS.md` | AI agent build/architecture guide |
|
|
| `.kilo/` | Kilo AI configuration (commands, agents, skills) |
|
|
| `openspec/changes/` | Feature proposals and implementation tracking |
|
|
|
|
## Development Workflow
|
|
|
|
This project uses **OpenSpec** for feature development:
|
|
|
|
1. **Propose** — Create a new change under `openspec/changes/<name>/` with `proposal.md`, `design.md`, `specs/`, and `tasks.md`
|
|
2. **Implement** — Work through checkbox-tracked tasks in `tasks.md`
|
|
3. **Archive** — Move completed changes to `openspec/archive/` when done
|
|
|
|
Use Kilo's `openspec-*` skills to streamline this workflow.
|
|
|
|
## Runtime Requirements
|
|
|
|
- **Python 3.12** — OpenUSD requires `python312.dll` at runtime. CMake copies it to the output directory via `POST_BUILD` commands.
|
|
- **USD Plugin Path** — The app scans `<exe_dir>/usd/` for `plugInfo.json` and registers plugins via `pxr::PlugRegistry`.
|
|
- **Render delegate DLLs** — hdEmbree, hdArnold, and hdCycles each bring their own runtime dependencies (Embree, Arnold SDK, Cycles libs). CMake `POST_BUILD` steps deploy all required DLLs next to the executable automatically.
|
|
|
|
## Contributing
|
|
|
|
Before writing any OpenUSD API call, verify the API exists in the actual SDK:
|
|
|
|
```powershell
|
|
findstr /r /s "FunctionName" third_party\OpenUSD-v25.11\include\
|
|
```
|
|
|
|
Always build and install before manually verifying a change:
|
|
|
|
```powershell
|
|
cmake --build build --config Release
|
|
cmake --install build --config Release
|
|
```
|
|
|
|
## License
|
|
|
|
See [LICENSE](LICENSE) file for details. |