Files
tinyusdz/primspec-search-demo.md
2025-08-25 22:50:55 +09:00

9.3 KiB

PrimSpec JavaScript Functions Demo

This demonstrates the new JavaScript functions that have been added to the TinyUSDZ JavaScript scripting interface for working with PrimSpecs:

  1. findPrimSpecByPath() - Search for PrimSpec by absolute path
  2. getPrimSpecMetadata() - Get PrimSpec metadata by absolute path

Function Overview

1. findPrimSpecByPath(pathString)

Searches for and retrieves basic PrimSpec information by absolute path string.

Function Signature:

findPrimSpecByPath(pathString) -> PrimSpec object | null
  • Parameters:
    • pathString (string): Absolute USD path string (e.g., "/root/child/prim")
  • Returns:
    • PrimSpec object if found
    • null if not found or invalid path

2. getPrimSpecMetadata(pathString)

Retrieves detailed metadata information for a PrimSpec by absolute path string.

Function Signature:

getPrimSpecMetadata(pathString) -> Metadata object | null
  • Parameters:
    • pathString (string): Absolute USD path string (e.g., "/root/child/prim")
  • Returns:
    • Metadata object if found
    • null if not found or invalid path

PrimSpec Object Structure

When found, the function returns a JSON object with the following structure:

{
  "name": "primName",           // Name of the PrimSpec
  "typeName": "Mesh",          // Type name (e.g., "Mesh", "Xform", etc.)
  "specifier": "def",          // Specifier: "def", "over", "class", or "invalid"
  "propertyCount": 5,          // Number of properties
  "childrenCount": 2,          // Number of child PrimSpecs
  "propertyNames": [           // Array of property names
    "points",
    "faceVertexIndices",
    "extent"
  ],
  "childrenNames": [           // Array of child PrimSpec names
    "material",
    "childPrim"
  ]
}

Metadata Object Structure

When found, the getPrimSpecMetadata() function returns a JSON object with the following structure:

{
  "active": true,                    // Active state (true/false/null)
  "hidden": false,                   // Hidden state (true/false/null)
  "instanceable": null,              // Instanceable state (true/false/null)
  "kind": "component",               // USD Kind (string)
  "documentation": "This is a mesh",  // Documentation (string/null)
  "comment": "Auto-generated",       // Comment (string/null)
  "displayName": "My Mesh",          // Display name (string/null)
  "sceneName": "Scene1",             // Scene name (string/null)
  "hasReferences": true,             // Whether prim has references
  "referencesCount": 2,              // Number of references
  "hasPayload": false,               // Whether prim has payload
  "payloadCount": 0,                 // Number of payloads
  "hasInherits": false,              // Whether prim has inherits
  "inheritsCount": 0,                // Number of inherits
  "hasVariants": true,               // Whether prim has variants
  "variantsCount": 2,                // Number of variant selections
  "variantNames": ["modelingVariant", "shadingVariant"],  // Variant names
  "hasVariantSets": true,            // Whether prim has variant sets
  "variantSetsCount": 1,             // Number of variant sets
  "variantSetNames": ["material"],   // Variant set names
  "hasCustomData": true,             // Whether prim has custom data
  "hasAssetInfo": false,             // Whether prim has asset info
  "unregisteredMetasCount": 3,       // Number of unregistered metadata
  "unregisteredMetaNames": ["myCustomMeta1", "myCustomMeta2"],  // Custom metadata names
  "authored": true                   // Whether metadata is authored
}

Usage Example

// Search for a specific PrimSpec
var rootPrim = findPrimSpecByPath("/Root");
if (rootPrim) {
    console.log("Found root prim:", rootPrim.name);
    console.log("Type:", rootPrim.typeName);
    console.log("Properties:", rootPrim.propertyNames);
    console.log("Children:", rootPrim.childrenNames);
} else {
    console.log("Root prim not found");
}

// Get metadata for the same PrimSpec
var rootMeta = getPrimSpecMetadata("/Root");
if (rootMeta) {
    console.log("Root prim is active:", rootMeta.active);
    console.log("Kind:", rootMeta.kind);
    console.log("Has references:", rootMeta.hasReferences);
    console.log("Variant sets:", rootMeta.variantSetNames);
    
    if (rootMeta.documentation) {
        console.log("Documentation:", rootMeta.documentation);
    }
    
    if (rootMeta.unregisteredMetasCount > 0) {
        console.log("Custom metadata:", rootMeta.unregisteredMetaNames);
    }
} else {
    console.log("Root prim metadata not found");
}

// Search for a nested PrimSpec and its metadata
var meshPrim = findPrimSpecByPath("/Root/Geometry/Mesh");
var meshMeta = getPrimSpecMetadata("/Root/Geometry/Mesh");

if (meshPrim && meshMeta) {
    console.log("Found mesh with", meshPrim.propertyCount, "properties");
    console.log("Mesh is instanceable:", meshMeta.instanceable);
    console.log("Mesh variants:", meshMeta.variantNames);
} else {
    console.log("Mesh or its metadata not found");
}

// Example: Check if a prim has composition arcs
var composedPrimMeta = getPrimSpecMetadata("/ComposedPrim");
if (composedPrimMeta) {
    var hasComposition = composedPrimMeta.hasReferences || 
                        composedPrimMeta.hasPayload || 
                        composedPrimMeta.hasInherits;
    
    if (hasComposition) {
        console.log("Prim has composition arcs:");
        if (composedPrimMeta.hasReferences) {
            console.log("- References:", composedPrimMeta.referencesCount);
        }
        if (composedPrimMeta.hasPayload) {
            console.log("- Payloads:", composedPrimMeta.payloadCount);
        }
        if (composedPrimMeta.hasInherits) {
            console.log("- Inherits:", composedPrimMeta.inheritsCount);
        }
    }
}

C++ Integration

To use these functions from C++, you need to:

  1. Create or load a USD Layer
  2. Use RunJSScriptWithLayer() to execute JavaScript code with access to the Layer
#include "src/tydra/js-script.hh"

// Assuming you have a Layer object
tinyusdz::Layer layer;
// ... populate layer with PrimSpecs ...

std::string jsCode = R"(
    // Find PrimSpec basic info
    var prim = findPrimSpecByPath("/myPrim");
    if (prim) {
        console.log("Found:", prim.name, "type:", prim.typeName);
        console.log("Properties:", prim.propertyCount);
        console.log("Children:", prim.childrenCount);
    }
    
    // Get detailed metadata
    var meta = getPrimSpecMetadata("/myPrim");
    if (meta) {
        console.log("Active:", meta.active);
        console.log("Kind:", meta.kind);
        console.log("Has composition:", 
            meta.hasReferences || meta.hasPayload || meta.hasInherits);
        
        if (meta.hasVariants) {
            console.log("Variants:", meta.variantNames);
        }
    }
)";

std::string err;
bool success = tinyusdz::tydra::RunJSScriptWithLayer(jsCode, &layer, err);
if (!success) {
    std::cerr << "JavaScript error: " << err << std::endl;
}

Implementation Details

Both functions are implemented in src/tydra/js-script.cc and include:

Common Features:

  • Path validation: Ensures the input string is a valid USD path
  • Layer search: Uses the existing Layer::find_primspec_at() method
  • Error handling: Returns null for invalid paths or missing PrimSpecs

findPrimSpecByPath():

  • JSON conversion: Converts basic PrimSpec data to JSON
  • Structure info: Provides name, type, properties, and children info

getPrimSpecMetadata():

  • Comprehensive metadata: Extracts all USD metadata fields
  • Composition info: Details about references, payloads, inherits
  • Variant info: Information about variants and variant sets
  • Custom metadata: Handles unregistered metadata fields
  • Boolean flags: Convenient flags for common checks

Requirements

  • TinyUSDZ must be built with TINYUSDZ_WITH_QJS=ON to enable QuickJS support
  • The functions are only available when using RunJSScriptWithLayer()

Error Cases

Both functions return null in these cases:

  • Invalid path string (empty, malformed)
  • Path not found in the Layer
  • Relative paths (not yet supported)
  • No Layer context available

Metadata Fields Reference

The getPrimSpecMetadata() function provides access to the following USD metadata:

Core Metadata:

  • active - Whether the prim is active in the scene
  • hidden - Whether the prim is hidden from traversal
  • instanceable - Whether the prim can be instanced
  • kind - USD Kind classification (model, component, assembly, etc.)

Documentation:

  • documentation - Formal documentation string
  • comment - Informal comment string
  • displayName - Human-readable display name (extension)
  • sceneName - Scene name (USDZ extension)

Composition Arcs:

  • hasReferences / referencesCount - Reference composition
  • hasPayload / payloadCount - Payload composition
  • hasInherits / inheritsCount - Inheritance composition

Variants:

  • hasVariants / variantsCount / variantNames - Variant selections
  • hasVariantSets / variantSetsCount / variantSetNames - Variant set definitions

Custom Data:

  • hasCustomData - Whether prim has custom data dictionary
  • hasAssetInfo - Whether prim has asset info dictionary
  • unregisteredMetasCount / unregisteredMetaNames - Custom metadata fields
  • authored - Whether any metadata is authored