Population (USD → ovstage)#
The population API (ovstage_population.h) is the bridge that ingests composed
USD content into the runtime stage. It is a self-contained C API with its own
asynchronous model — ovstage_population_enqueue_result_t and
ovstage_population_wait_op — that runs parallel to the data-plane
submit/observe model.
Note
These entry points are pre-release and provisional (“Draft — API in flux”).
Loading a Scene#
ovstage_population_open_usd_from_file (and _from_string) loads a USD
scene into the runtime table in one op at a chosen ordinal. As with any write,
seal the ordinal with advance_write_floor before reading the populated prims
back:
# Load a USD file and populate the runtime table in one op, at the
# caller-owned ordinal 1, then seal that ordinal so reads can see it.
# The application owns the ordinal lifecycle; population never opens
# its own.
population.open_usd(
stage, str(SCENE), ordinal=1, time_code=0.0, domains=PopulationDomain.RENDERING
)
stage.advance_write_floor(ordinal=1).wait()
// One population op loads the USD file into the runtime table at ordinal 1;
// sealing that ordinal makes it readable. An explicit time code keeps later
// USD-change synchronization on the same supported timeline sample;
// RENDERING selects meshes/lights/cameras.
ovstage_population_enqueue_result_t popEnq =
ovstage_population_open_usd_from_file(stage, ovx_string_t{ scenePath.c_str(), scenePath.size() },
/*ordinal*/ 1, /*time*/ 0.0, OVSTAGE_POPULATION_DOMAIN_RENDERING);
waitPop(stage, popEnq, "open_usd");
ovstage_write_floor_desc_t floor1{};
floor1.ordinal = 1;
floor1.scope = OVSTAGE_SCOPE_ALL;
ovstage_enqueue_result_t enq = ovstage_advance_write_floor(stage, &floor1);
waitOp(stage, enq, "advance_write_floor");
Population Domains#
Loads take a population domain bitmask (PopulationDomain /
ovstage_population_domain_t: NONE, RENDERING, PHYSICS, ALL)
selecting which consumer’s attribute set to populate.
Editing the USD Source#
After a scene is live you can edit the USD source and propagate the change into the runtime table at a fresh ordinal:
ovstage_population_add_usd_reference_from_file/_from_string— add a reference onto an existing prim.ovstage_population_remove_usd_reference/ovstage_population_reset_usd— remove a reference or reset.ovstage_population_apply_usd_changes— propagate pending USD edits into the table (at a new ordinal).ovstage_population_apply_usd_time— apply a USD time sample.
# Reference a cube onto a new /World/EditCube in the USD source, then
# propagate the change into the runtime table with apply_usd_changes
# at a fresh ordinal (above the animation's floor). The runtime stage
# now sees a prim that existed only in USD.
usd_ordinal = 2 + FRAMES
population.add_usd_reference_from_string(stage, EDIT_CUBE_USDA, "/World/EditCube")
population.apply_usd_changes(stage, ordinal=usd_ordinal)
stage.advance_write_floor(ordinal=usd_ordinal).wait()
expanded_paths = paths.create_path_list_from_strings(
["/World", "/World/Plane", "/World/Torus", "/World/EditCube"])
expanded_query = stage.query_from_path_list(expanded_paths)
print("after USD edit, prim types:",
", ".join(_prim_types(stage, paths, expanded_query, prim_type, usd_ordinal)))
// Reference a cube onto a new /World/EditCube in the USD source, then
// propagate the edit into the runtime table with apply_usd_changes at a
// fresh ordinal above the animation's floor. add-reference carries no
// ordinal; apply_usd_changes does.
const ovstage_ordinal_t usdOrdinal = static_cast<ovstage_ordinal_t>(2 + kFrames);
const ovx_string_t editLayer = kEditCubeUsda;
// The optional out-handle is only needed for a later remove_usd_reference;
// this reference lives for the stage's lifetime, so pass NULL (as the
// Python sibling does by discarding the returned handle).
popEnq = ovstage_population_add_usd_reference_from_string(stage, editLayer,
literal_to_ovx_string("/World/EditCube"), nullptr);
waitPop(stage, popEnq, "add_usd_reference");
popEnq = ovstage_population_apply_usd_changes(stage, usdOrdinal);
waitPop(stage, popEnq, "apply_usd_changes");
ovstage_write_floor_desc_t usdFloor{};
usdFloor.ordinal = usdOrdinal;
usdFloor.scope = OVSTAGE_SCOPE_ALL;
enq = ovstage_advance_write_floor(stage, &usdFloor);
waitOp(stage, enq, "advance_write_floor");
const ovx_string_t expanded[] = { literal_to_ovx_string("/World"), literal_to_ovx_string("/World/Plane"),
literal_to_ovx_string("/World/Torus"),
literal_to_ovx_string("/World/EditCube") };
ovx_primpath_list_t expandedPaths = OVX_INVALID_PRIMPATH_LIST;
ovxResult = path_dictionary_create_path_list_from_strings(dict, expanded, 4, &expandedPaths);
checkOvx(dict, ovxResult, "create-path-list");
ovstage_query_handle_t expandedQuery = OVSTAGE_INVALID_QUERY_HANDLE;
status = ovstage_query_from_path_list(stage, expandedPaths, &expandedQuery);
check(stage, status, "query_from_path_list");
const std::vector<std::string> editedTypes = readPrimTypes(stage, dict, expandedQuery, primType, usdOrdinal);
// Example plumbing: print the type names on one line; the Cube is the propagated edit.
std::printf("after USD edit, prim types:");
for (const std::string& name : editedTypes)
std::printf(" %s", name.c_str());
std::printf("\n");
Python ↔ C Name Mapping#
Several Python wrappers use shorter names than their C entry points:
Python ( |
C entry point |
|---|---|
|
|
|
|
|
|
|
|
The time_code parameter on open_usd* / update_from_usd_time is in
seconds — it maps to the C time parameter, converted internally via the
stage’s timeCodesPerSecond. math.nan (the open_usd* default)
evaluates at USD’s Default time code.
Ordinal Ownership#
Population never opens or seals an ordinal for you — the application owns the
ordinal lifecycle. Pass the current ordinal to each call and seal each tick with
advance_write_floor. Keep ordinals monotonic (populate at 1, then writes and
USD edits at higher ordinals); an operation at or below the floor is a write-floor
violation.
Where to Go Next#
Runtime Loop — the full populate → read → update → read loop.
Reading Attributes — reading
usd-prim-typeand other populated metadata back.Instancing Queries — discovering instance and prototype roots in populated content.