hydra-rs 0.0.4

Rust bindings to OpenUSD's Hydra rendering layer: scene-index ingestion, render-delegate enumeration, headless render to RGBA via Storm.
docs.rs failed to build hydra-rs-0.0.4
Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.

hydra-rs

Rust bindings to OpenUSD's Hydra rendering layer. Sibling crate of rust-usd; the two are designed to be used together but currently interop via path strings rather than shared cxx types.

What's here:

  • SceneIndex::from_path(path) opens a stage and ingests it into a UsdImagingStageSceneIndex. prim_paths() and prim_count() walk the index so callers can verify Hydra sees the prims they expect, including filtering of shaders inside materials.
  • list_render_delegates() enumerates the HdRendererPlugin plugins USD's plug system found at startup. On a typical macOS dev box that returns ["HdStormRendererPlugin"].
  • Renderer is a stateful renderer that holds a UsdStageRefPtr, the Hgi, and a UsdImagingGLEngine across calls so a viewport can re-render at interactive rates without rebuilding any of the scaffolding. Camera matrices, output size, lights, time code, and clear color are all mutable between renders.
  • render_to_rgba(usd_path, delegate, w, h) is a stateless convenience wrapper around Renderer for one shot renders.

The build environment matches rust-usd. Set USD_INCLUDE_DIR, USD_LIB_DIR, USD_LIB_PREFIX, and the Python framework variables documented in the rust-usd README before running cargo.

Renderer

use hydra_rs::Renderer;

let mut renderer = Renderer::new("scene.usda")?;
renderer.set_size(1920, 1080);

// Switch out the default headlight for a key plus fill.
renderer.clear_lights();
renderer.add_distant_light([1.0, 1.0, 0.5],  [1.0, 1.0, 0.95], 1.5);
renderer.add_distant_light([-1.0, -0.3, 1.0], [0.4, 0.5, 0.8], 0.8);

// Camera matrices are row major 16-float arrays in GfMatrix4d's row vector
// convention (`vec_world * view = vec_camera`).
renderer.set_camera_matrices(&view, &projection);

// Render returns RGBA8 of size `width * height * 4` in top-down order
// (origin = top-left), the same convention `image`, egui, wgpu sampled
// textures, and the PNG file format use.
let pixels = renderer.render()?;

The hydra_render example renders a single frame and writes raw RGBA next to the input asset. The hydra_orbit example reuses one Renderer to render four frames around the test sphere with key plus fill lights, demonstrating the stateful viewport pattern.

cd hydra-rs
USD_INCLUDE_DIR=... USD_LIB_DIR=... USD_LIB_PREFIX=pxr_ \
USD_PYTHON_INCLUDE_DIR=... USD_LINK_PYTHON=framework USD_PYTHON_FRAMEWORK_DIR=... \
cargo run --example hydra_orbit
ffmpeg -y -f rawvideo -pixel_format rgba -video_size 256x256 \
  -i examples/hydra_orbit_00.rgba examples/hydra_orbit_00.png
open examples/hydra_orbit_00.png

Implementation notes

Storm renders into a Metal texture on macOS. Without an active Metal layer, the engine's default HdxPresentTask calls HgiInteropMetal which calls glGetString and segfaults headlessly, so Renderer constructs the engine with SetEnablePresentation(false). Since presentation also drives some of the Hydra 2 scene index lighting setup, the renderer hands the engine a GlfSimpleLightVector via the legacy SetLightingState API and sets enableSceneLights = false. Authored scene lights are not yet routed through to Storm in this configuration; explicit add_distant_light and add_positional_light calls are the supported path for now.

The color AOV comes back as HdFormatFloat16Vec4 on Apple Silicon and HdFormatFloat32Vec4 on most others; both paths convert to RGBA8 inside render_color. Storm writes the AOV in OpenGL convention (origin = bottom-left); render_color reverses rows before returning so every consumer sees the more common top-down layout.

What's not here yet

Scene authored lights routed through to the render delegate, additional AOVs (depth, normals, primId for picking), camera matrices read from a UsdGeomCamera prim, and Embree as a CPU fallback are the obvious next pulls. Each lands when a consumer pushes on it.