Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,11 @@ if(FREEUSD_BUILD_TESTS)
target_compile_definitions(
freeusd_usd_vol_volume_test PRIVATE "FREEUSD_TEST_FIXTURES_DIR=\"${CMAKE_SOURCE_DIR}/tests/fixtures\"")

add_executable(freeusd_usd_semantics_labels_test tests/usd_semantics_labels_test.cpp)
target_link_libraries(freeusd_usd_semantics_labels_test PRIVATE freeusd::usd freeusd::usdSemantics)
target_compile_definitions(
freeusd_usd_semantics_labels_test PRIVATE "FREEUSD_TEST_FIXTURES_DIR=\"${CMAKE_SOURCE_DIR}/tests/fixtures\"")

add_executable(freeusd_ar_path_security_test tests/ar_path_security_test.cpp)
target_link_libraries(freeusd_ar_path_security_test PRIVATE freeusd::ar)

Expand All @@ -201,6 +206,11 @@ if(FREEUSD_BUILD_TESTS)
target_compile_definitions(
freeusd_engine_integration_test PRIVATE "FREEUSD_TEST_FIXTURES_DIR=\"${CMAKE_SOURCE_DIR}/tests/fixtures\"")

add_executable(freeusd_usdutils_spatial_grounding_test tests/usdutils_spatial_grounding_test.cpp)
target_link_libraries(freeusd_usdutils_spatial_grounding_test PRIVATE freeusd::usd freeusd::usdUtils)
target_compile_definitions(
freeusd_usdutils_spatial_grounding_test PRIVATE "FREEUSD_TEST_FIXTURES_DIR=\"${CMAKE_SOURCE_DIR}/tests/fixtures\"")

add_executable(freeusd_schema_tokens_bundle_test tests/schema_tokens_bundle_test.cpp)
target_link_libraries(freeusd_schema_tokens_bundle_test PRIVATE freeusd::usd_schemas)

Expand Down Expand Up @@ -273,8 +283,10 @@ if(FREEUSD_BUILD_TESTS)
add_test(NAME freeusd_usd_physics_fixed_joint_test COMMAND freeusd_usd_physics_fixed_joint_test)
add_test(NAME freeusd_usd_vol_openvdb_test COMMAND freeusd_usd_vol_openvdb_test)
add_test(NAME freeusd_usd_vol_volume_test COMMAND freeusd_usd_vol_volume_test)
add_test(NAME freeusd_usd_semantics_labels_test COMMAND freeusd_usd_semantics_labels_test)
add_test(NAME freeusd_ar_path_security_test COMMAND freeusd_ar_path_security_test)
add_test(NAME freeusd_engine_integration_test COMMAND freeusd_engine_integration_test)
add_test(NAME freeusd_usdutils_spatial_grounding_test COMMAND freeusd_usdutils_spatial_grounding_test)
add_test(NAME freeusd_schema_tokens_bundle_test COMMAND freeusd_schema_tokens_bundle_test)
add_test(NAME freeusd_time_code_test COMMAND freeusd_time_code_test)
add_test(NAME freeusd_edit_target_test COMMAND freeusd_edit_target_test)
Expand Down Expand Up @@ -371,6 +383,22 @@ if(FREEUSD_BUILD_TESTS)
set_target_properties(freeusd_c_engine_integration PROPERTIES C_STANDARD 11 C_STANDARD_REQUIRED ON LINKER_LANGUAGE CXX)
add_test(NAME freeusd_c_engine_integration COMMAND freeusd_c_engine_integration)

add_executable(freeusd_c_usdutils_spatial_grounding tests/c_usdutils_spatial_grounding.c)
target_include_directories(freeusd_c_usdutils_spatial_grounding PRIVATE "${PROJECT_SOURCE_DIR}/include")
target_link_libraries(freeusd_c_usdutils_spatial_grounding PRIVATE freeusd::c)
target_compile_definitions(
freeusd_c_usdutils_spatial_grounding PRIVATE "FREEUSD_TEST_FIXTURES_DIR=\"${CMAKE_SOURCE_DIR}/tests/fixtures\"")
set_target_properties(freeusd_c_usdutils_spatial_grounding PROPERTIES C_STANDARD 11 C_STANDARD_REQUIRED ON LINKER_LANGUAGE CXX)
add_test(NAME freeusd_c_usdutils_spatial_grounding COMMAND freeusd_c_usdutils_spatial_grounding)

add_executable(freeusd_c_usd_semantics_labels tests/c_usd_semantics_labels.c)
target_include_directories(freeusd_c_usd_semantics_labels PRIVATE "${PROJECT_SOURCE_DIR}/include")
target_link_libraries(freeusd_c_usd_semantics_labels PRIVATE freeusd::c)
target_compile_definitions(
freeusd_c_usd_semantics_labels PRIVATE "FREEUSD_TEST_FIXTURES_DIR=\"${CMAKE_SOURCE_DIR}/tests/fixtures\"")
set_target_properties(freeusd_c_usd_semantics_labels PROPERTIES C_STANDARD 11 C_STANDARD_REQUIRED ON LINKER_LANGUAGE CXX)
add_test(NAME freeusd_c_usd_semantics_labels COMMAND freeusd_c_usd_semantics_labels)

add_executable(freeusd_c_usd_skel tests/c_usd_skel.c)
target_include_directories(freeusd_c_usd_skel PRIVATE "${PROJECT_SOURCE_DIR}/include")
target_link_libraries(freeusd_c_usd_skel PRIVATE freeusd::c)
Expand Down Expand Up @@ -470,13 +498,15 @@ if(FREEUSD_BUILD_TESTS)
freeusd_usd_physics_fixed_joint_test
freeusd_usd_vol_openvdb_test
freeusd_usd_vol_volume_test
freeusd_usd_semantics_labels_test
freeusd_usd_skel_smoke_test
freeusd_usd_skel_skinning_matrices_test
freeusd_usd_shade_smoke_test
freeusd_stage_kind_active_test
freeusd_usd_lux_distant_light_test
freeusd_ar_path_security_test
freeusd_engine_integration_test
freeusd_usdutils_spatial_grounding_test
freeusd_schema_tokens_bundle_test
freeusd_time_code_test
freeusd_edit_target_test
Expand Down Expand Up @@ -504,6 +534,8 @@ if(FREEUSD_BUILD_TESTS)
freeusd_c_stage_prim_specifier
freeusd_c_stage_layer_hints
freeusd_c_engine_integration
freeusd_c_usdutils_spatial_grounding
freeusd_c_usd_semantics_labels
freeusd_c_usd_skel
freeusd_c_usd_shade
freeusd_c_usd_lux
Expand Down
6 changes: 6 additions & 0 deletions bindings/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ Shared fixture: **`tests/fixtures/usd_cross_language.usda`**. Tests: **`tests/c_

Skel fixture: **`tests/fixtures/parity_skel_skinning.usda`**. Tests: **`tests/c_usd_skel.c`**, **`tests/usd_skel_smoke_test.cpp`**, **`bindings/go/freeusd_test.go`** (`TestSkelCrossLanguageContract`), **`bindings/rust`** (`skel_cross_language_contract`).

Spatial grounding fixture: **`tests/fixtures/parity_spatial_grounding.usda`**. Tests: **`tests/c_usdutils_spatial_grounding.c`**, **`tests/usdutils_spatial_grounding_test.cpp`**, **`tests/python/test_engine_integration.py`**, **`bindings/go/freeusd_test.go`**, and **`bindings/rust`**.

Semantic labels fixture: **`tests/fixtures/parity_semantics_labels.usda`**. Tests: **`tests/c_usd_semantics_labels.c`**, **`tests/usd_semantics_labels_test.cpp`**, **`tests/python/test_engine_integration.py`**, **`bindings/go/freeusd_test.go`**, and **`bindings/rust`**.

| Capability | C ABI | C++ / Python | Go | Rust | D |
|------------|:-----:|:------------:|:--:|:----:|:--:|
| Typed field reads (double/float/bool/int/string/vec/matrix/quat/token) | yes | yes | yes | yes | double/string |
Expand All @@ -86,6 +90,8 @@ Skel fixture: **`tests/fixtures/parity_skel_skinning.usda`**. Tests: **`tests/c_
| `usdPhysics` FixedJoint bodies / enabled (C ABI) | yes | yes | yes | yes | yes |
| `usdSkel` joint names / skinning palette / CPU deform | yes | yes | yes | yes | no |
| `usdUtils` engine runtime assess (skel flags) | yes | yes | yes | yes | no |
| `usdUtils` spatial grounding context records | yes | yes | yes | yes | no |
| `usdSemantics` semantic label reads | yes | yes | yes | yes | no |
| `usdUtils` flatten | C++ only | yes | n/a | n/a | n/a |

## Adding more bindings
Expand Down
2 changes: 2 additions & 0 deletions bindings/d/dub.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"-lfreeusd_usdLux",
"-lfreeusd_usdPhysics",
"-lfreeusd_usdVol",
"-lfreeusd_usdSemantics",
"-lfreeusd_usdGeom",
"-lfreeusd_usd",
"-lfreeusd_ar",
Expand All @@ -39,6 +40,7 @@
"-lfreeusd_usdLux",
"-lfreeusd_usdPhysics",
"-lfreeusd_usdVol",
"-lfreeusd_usdSemantics",
"-lfreeusd_usdGeom",
"-lfreeusd_usd",
"-lfreeusd_ar",
Expand Down
149 changes: 147 additions & 2 deletions bindings/go/freeusd.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ package freeusd

/*
#cgo CFLAGS: -I${SRCDIR}/../../include
#cgo linux LDFLAGS: -L${SRCDIR}/../../build/src -lfreeusd_c -lfreeusd_base -lfreeusd_usdUtils -lfreeusd_usdSkel -lfreeusd_usdShade -lfreeusd_usdLux -lfreeusd_usdPhysics -lfreeusd_usdVol -lfreeusd_usdGeom -lfreeusd_usd -lfreeusd_ar -lfreeusd_io -lfreeusd_pcp -lfreeusd_sdf -lfreeusd_vt -lfreeusd_tf -lfreeusd_gf -lfreeusd_plug -lstdc++ -lm -lz -llz4
#cgo darwin LDFLAGS: -L${SRCDIR}/../../build/src -lfreeusd_c -lfreeusd_base -lfreeusd_usdUtils -lfreeusd_usdSkel -lfreeusd_usdShade -lfreeusd_usdLux -lfreeusd_usdPhysics -lfreeusd_usdVol -lfreeusd_usdGeom -lfreeusd_usd -lfreeusd_ar -lfreeusd_io -lfreeusd_pcp -lfreeusd_sdf -lfreeusd_vt -lfreeusd_tf -lfreeusd_gf -lfreeusd_plug -lc++ -lm -lz -llz4
#cgo linux LDFLAGS: -L${SRCDIR}/../../build/src -lfreeusd_c -lfreeusd_base -lfreeusd_usdUtils -lfreeusd_usdSkel -lfreeusd_usdShade -lfreeusd_usdLux -lfreeusd_usdPhysics -lfreeusd_usdVol -lfreeusd_usdSemantics -lfreeusd_usdGeom -lfreeusd_usd -lfreeusd_ar -lfreeusd_io -lfreeusd_pcp -lfreeusd_sdf -lfreeusd_vt -lfreeusd_tf -lfreeusd_gf -lfreeusd_plug -lstdc++ -lm -lz -llz4
#cgo darwin LDFLAGS: -L${SRCDIR}/../../build/src -lfreeusd_c -lfreeusd_base -lfreeusd_usdUtils -lfreeusd_usdSkel -lfreeusd_usdShade -lfreeusd_usdLux -lfreeusd_usdPhysics -lfreeusd_usdVol -lfreeusd_usdSemantics -lfreeusd_usdGeom -lfreeusd_usd -lfreeusd_ar -lfreeusd_io -lfreeusd_pcp -lfreeusd_sdf -lfreeusd_vt -lfreeusd_tf -lfreeusd_gf -lfreeusd_plug -lc++ -lm -lz -llz4
#include <stdlib.h>
#include <freeusd/c/freeusd.h>
*/
Expand Down Expand Up @@ -1834,6 +1834,7 @@ type EngineRuntimeSupport struct {
UsesPhysicsFixedJoints bool
UsesOpenVdbAssets bool
UsesVolumes bool
UsesSemanticLabels bool
}

// AssessEngineRuntimeSupport reports which engine integration mode fits the composed stage.
Expand Down Expand Up @@ -1877,9 +1878,153 @@ func (s *Stage) AssessEngineRuntimeSupport() (report EngineRuntimeSupport, rc in
report.UsesPhysicsFixedJoints = raw.uses_physics_fixed_joints != 0
report.UsesOpenVdbAssets = raw.uses_open_vdb_assets != 0
report.UsesVolumes = raw.uses_volumes != 0
report.UsesSemanticLabels = raw.uses_semantic_labels != 0
return report, 0
}

// SemanticLabelSet contains one authored semantics:labels:<set> value.
type SemanticLabelSet struct {
Name string
Labels []string
}

// SpatialGroundingRecord contains clean-room USD-derived cues for text/spatial diagnostics.
type SpatialGroundingRecord struct {
Path string
Name string
ParentPath string
SiblingNames []string
SemanticLabelSets []SemanticLabelSet
WorldPosition [3]float64
HasWorldBound bool
WorldBoundDimensions [3]float64
HasMassKg bool
MassKg float64
}

// BuildSpatialGroundingContext extracts spatial/text cue records for every traversed prim.
func (s *Stage) BuildSpatialGroundingContext(time float64) (records []SpatialGroundingRecord, rc int) {
if s == nil || s.ptr == nil {
return nil, 1
}
var raw *C.FreeusdSpatialGroundingRecord
var count C.size_t
rc = int(C.freeusd_usdutils_build_spatial_grounding_context(s.ptr, C.double(time), &raw, &count))
if rc != 0 {
return nil, rc
}
defer C.freeusd_usdutils_spatial_grounding_records_free(raw, count)
if raw == nil || count == 0 {
return []SpatialGroundingRecord{}, 0
}
cRecords := unsafe.Slice(raw, int(count))
records = make([]SpatialGroundingRecord, 0, int(count))
for _, item := range cRecords {
rec := SpatialGroundingRecord{
Path: C.GoString(item.path_utf8),
Name: C.GoString(item.name_utf8),
ParentPath: C.GoString(item.parent_path_utf8),
WorldPosition: [3]float64{
float64(item.world_position[0]),
float64(item.world_position[1]),
float64(item.world_position[2]),
},
HasWorldBound: item.has_world_bound != 0,
WorldBoundDimensions: [3]float64{
float64(item.world_bound_dimensions[0]),
float64(item.world_bound_dimensions[1]),
float64(item.world_bound_dimensions[2]),
},
HasMassKg: item.has_mass_kg != 0,
MassKg: float64(item.mass_kg),
}
if item.sibling_names_utf8 != nil && item.sibling_name_count > 0 {
cSiblings := unsafe.Slice(item.sibling_names_utf8, int(item.sibling_name_count))
rec.SiblingNames = make([]string, 0, int(item.sibling_name_count))
for _, sibling := range cSiblings {
if sibling != nil {
rec.SiblingNames = append(rec.SiblingNames, C.GoString(sibling))
}
}
}
if item.semantic_label_sets != nil && item.semantic_label_set_count > 0 {
cSets := unsafe.Slice(item.semantic_label_sets, int(item.semantic_label_set_count))
rec.SemanticLabelSets = make([]SemanticLabelSet, 0, int(item.semantic_label_set_count))
for _, cSet := range cSets {
set := SemanticLabelSet{Name: C.GoString(cSet.name_utf8)}
if cSet.labels_utf8 != nil && cSet.label_count > 0 {
cLabels := unsafe.Slice(cSet.labels_utf8, int(cSet.label_count))
set.Labels = make([]string, 0, int(cSet.label_count))
for _, label := range cLabels {
if label != nil {
set.Labels = append(set.Labels, C.GoString(label))
}
}
}
rec.SemanticLabelSets = append(rec.SemanticLabelSets, set)
}
}
records = append(records, rec)
}
return records, 0
}

// ListSemanticLabelSets returns authored semantics:labels:<set> instance names for a prim.
func (s *Stage) ListSemanticLabelSets(primPath string) (sets []string, rc int) {
if s == nil || s.ptr == nil {
return nil, 1
}
pp := C.CString(primPath)
defer C.free(unsafe.Pointer(pp))
var arr **C.char
var count C.size_t
rc = int(C.freeusd_stage_list_semantic_label_sets(s.ptr, pp, &arr, &count))
if rc != 0 {
return nil, rc
}
if arr == nil || count == 0 {
return []string{}, 0
}
defer C.freeusd_path_list_free(arr, count)
items := unsafe.Slice(arr, int(count))
sets = make([]string, 0, int(count))
for _, item := range items {
if item != nil {
sets = append(sets, C.GoString(item))
}
}
return sets, 0
}

// ReadSemanticLabels returns authored labels for one semantics:labels:<set> instance.
func (s *Stage) ReadSemanticLabels(primPath, instanceName string) (labels []string, rc int) {
if s == nil || s.ptr == nil {
return nil, 1
}
pp := C.CString(primPath)
defer C.free(unsafe.Pointer(pp))
in := C.CString(instanceName)
defer C.free(unsafe.Pointer(in))
var arr **C.char
var count C.size_t
rc = int(C.freeusd_stage_read_semantic_labels(s.ptr, pp, in, &arr, &count))
if rc != 0 {
return nil, rc
}
if arr == nil || count == 0 {
return []string{}, 0
}
defer C.freeusd_path_list_free(arr, count)
items := unsafe.Slice(arr, int(count))
labels = make([]string, 0, int(count))
for _, item := range items {
if item != nil {
labels = append(labels, C.GoString(item))
}
}
return labels, 0
}

// ReadSkelJointNames returns skeleton joint names (rc 0 ok).
func (s *Stage) ReadSkelJointNames(skeletonPath string) (names []string, rc int) {
if s == nil || s.ptr == nil {
Expand Down
93 changes: 90 additions & 3 deletions bindings/go/freeusd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package freeusd

import (
"encoding/binary"
"math"
"os"
"path/filepath"
"strings"
Expand Down Expand Up @@ -1260,9 +1261,95 @@ func TestUsdGeomEngineSubsetParityImageable(t *testing.T) {
t.Fatalf("world bounds (%g,%g,%g)-(%g,%g,%g)", minX, minY, minZ, maxX, maxY, maxZ)
}

_, _, _, _, _, _, rc = st.ComputeBoundableWorldBounds("/World", 1.0)
if rc == 0 {
t.Fatal("expected NOT_FOUND for non-boundable /World")
// Xform prims without local bounds aggregate descendant world bounds.
wMinX, wMinY, wMinZ, wMaxX, wMaxY, wMaxZ, rc := st.ComputeBoundableWorldBounds("/World", 1.0)
if rc != 0 || wMinX != 0 || wMinY != 1 || wMinZ != 2 || wMaxX != 2 || wMaxY != 3 || wMaxZ != 4 {
t.Fatalf("aggregated /World bounds (%g,%g,%g)-(%g,%g,%g) rc=%d", wMinX, wMinY, wMinZ, wMaxX, wMaxY, wMaxZ, rc)
}
}

func hasString(items []string, want string) bool {
for _, item := range items {
if item == want {
return true
}
}
return false
}

func TestUsdUtilsSpatialGroundingContext(t *testing.T) {
fixture := filepath.Join("..", "..", "tests", "fixtures", "parity_spatial_grounding.usda")
st := OpenStageFromRootFile(fixture, RootSubDepthFirst)
if st == nil {
t.Fatalf("OpenStageFromRootFile: %s", LastErrorMessage())
}
defer st.Free()

records, rc := st.BuildSpatialGroundingContext(1.0)
if rc != 0 {
t.Fatalf("BuildSpatialGroundingContext rc=%d %s", rc, LastErrorMessage())
}
if len(records) != 5 {
t.Fatalf("record count=%d", len(records))
}
var cup *SpatialGroundingRecord
var kitchen *SpatialGroundingRecord
for i := range records {
switch records[i].Path {
case "/World/Kitchen/CupBlue":
cup = &records[i]
case "/World/Kitchen":
kitchen = &records[i]
}
}
if cup == nil || cup.Name != "CupBlue" || cup.ParentPath != "/World/Kitchen" {
t.Fatalf("cup record=%+v", cup)
}
if len(cup.SiblingNames) != 2 || !hasString(cup.SiblingNames, "PlateGreen") || !hasString(cup.SiblingNames, "Stove") {
t.Fatalf("cup siblings=%v", cup.SiblingNames)
}
if len(cup.SemanticLabelSets) != 2 || cup.SemanticLabelSets[0].Name != "engine" || !hasString(cup.SemanticLabelSets[0].Labels, "pickup") || cup.SemanticLabelSets[1].Name != "somaHome" || !hasString(cup.SemanticLabelSets[1].Labels, "Crockery") {
t.Fatalf("cup semantic label sets=%v", cup.SemanticLabelSets)
}
if cup.WorldPosition != [3]float64{6, 2, 3} || !cup.HasWorldBound || cup.WorldBoundDimensions != [3]float64{0.5, 1.5, 0.25} || !cup.HasMassKg || math.Abs(cup.MassKg-0.35) > 1e-6 {
t.Fatalf("cup spatial values=%+v", cup)
}
// Xform prims without local bounds aggregate descendant world bounds.
if kitchen == nil || kitchen.ParentPath != "/World" || len(kitchen.SiblingNames) != 0 || len(kitchen.SemanticLabelSets) != 0 || kitchen.WorldPosition != [3]float64{10, 0, 0} || !kitchen.HasWorldBound || kitchen.WorldBoundDimensions != [3]float64{9.25, 4.25, 7.5} || kitchen.HasMassKg {
t.Fatalf("kitchen record=%+v", kitchen)
}
}

func TestUsdSemanticsLabels(t *testing.T) {
fixture := filepath.Join("..", "..", "tests", "fixtures", "parity_semantics_labels.usda")
st := OpenStageFromRootFile(fixture, RootSubDepthFirst)
if st == nil {
t.Fatalf("OpenStageFromRootFile: %s", LastErrorMessage())
}
defer st.Free()

sets, rc := st.ListSemanticLabelSets("/World/Kitchen/CupBlue")
if rc != 0 {
t.Fatalf("ListSemanticLabelSets rc=%d %s", rc, LastErrorMessage())
}
if len(sets) != 2 || !hasString(sets, "engine") || !hasString(sets, "somaHome") {
t.Fatalf("sets=%v", sets)
}
labels, rc := st.ReadSemanticLabels("/World/Kitchen/CupBlue", "somaHome")
if rc != 0 || len(labels) != 2 || labels[0] != "Crockery" || labels[1] != "DesignedContainer" {
t.Fatalf("labels=%v rc=%d", labels, rc)
}
stoveLabels, rc := st.ReadSemanticLabels("/World/Kitchen/Stove", "somaHome")
if rc != 0 || len(stoveLabels) != 1 || stoveLabels[0] != "Appliance" {
t.Fatalf("stoveLabels=%v rc=%d", stoveLabels, rc)
}
missing, rc := st.ReadSemanticLabels("/World/Kitchen/CupBlue", "missing")
if rc != 0 || len(missing) != 0 {
t.Fatalf("missing=%v rc=%d", missing, rc)
}
report, rc := st.AssessEngineRuntimeSupport()
if rc != 0 || !report.UsesSemanticLabels || report.RecommendedMode != EngineRuntimeHybrid {
t.Fatalf("semantic runtime report=%+v rc=%d", report, rc)
}
}

Expand Down
Loading
Loading