mirror of
https://github.com/lighttransport/tinyusdz.git
synced 2026-01-18 01:11:17 +01:00
add missing files.
This commit is contained in:
28
examples/js-script/CMakeLists.txt
Normal file
28
examples/js-script/CMakeLists.txt
Normal file
@@ -0,0 +1,28 @@
|
||||
# JavaScript Scripting Example - Load USD as Layer and query LayerMetas
|
||||
# Assume this cmake is called from tinyusdz root(../../)
|
||||
|
||||
set(EXAMPLE_TARGET "js-script")
|
||||
|
||||
set(JS_SCRIPT_SOURCES
|
||||
main.cc
|
||||
)
|
||||
|
||||
add_executable(${EXAMPLE_TARGET} ${JS_SCRIPT_SOURCES})
|
||||
add_sanitizers(${EXAMPLE_TARGET})
|
||||
|
||||
target_include_directories(${EXAMPLE_TARGET} PRIVATE ${PROJECT_SOURCE_DIR}/src)
|
||||
target_link_libraries(${EXAMPLE_TARGET} tinyusdz_static)
|
||||
|
||||
# This example requires QuickJS support
|
||||
if(NOT TINYUSDZ_WITH_QJS)
|
||||
message(WARNING "js-script example requires QuickJS support. Enable with -DTINYUSDZ_WITH_QJS=ON")
|
||||
endif()
|
||||
|
||||
set_target_properties(${EXAMPLE_TARGET} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}")
|
||||
|
||||
# Copy JavaScript files to binary directory for easy access
|
||||
configure_file(
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/query_layer.js"
|
||||
"${CMAKE_BINARY_DIR}/query_layer.js"
|
||||
COPYONLY
|
||||
)
|
||||
161
examples/js-script/README.md
Normal file
161
examples/js-script/README.md
Normal file
@@ -0,0 +1,161 @@
|
||||
# JavaScript Scripting Example
|
||||
|
||||
This example demonstrates how to load a USD file as a Layer in C++ and query LayerMeta information through the Tydra JavaScript interface.
|
||||
|
||||
## Overview
|
||||
|
||||
The example shows how to:
|
||||
1. Load a USD file using TinyUSDZ's C++ API
|
||||
2. Access the LayerMetas from the loaded Stage
|
||||
3. Execute JavaScript code that can query layer metadata through the Tydra interface
|
||||
4. Use the `getLayerMetas()` function from JavaScript to access USD layer properties
|
||||
|
||||
## Requirements
|
||||
|
||||
- TinyUSDZ built with QuickJS support (`-DTINYUSDZ_WITH_QJS=ON`)
|
||||
- A USD file to query (sample provided)
|
||||
|
||||
## Building
|
||||
|
||||
From the TinyUSDZ root directory:
|
||||
|
||||
```bash
|
||||
mkdir build && cd build
|
||||
cmake -DTINYUSDZ_WITH_QJS=ON -DTINYUSDZ_BUILD_EXAMPLES=ON ..
|
||||
make js-script
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
./js-script <USD_FILE> <JAVASCRIPT_FILE>
|
||||
```
|
||||
|
||||
### Example Usage
|
||||
|
||||
```bash
|
||||
# Use the provided sample files
|
||||
./js-script examples/js-script/sample.usda examples/js-script/query_layer.js
|
||||
|
||||
# Or use your own USD file
|
||||
./js-script path/to/your/model.usd query_layer.js
|
||||
```
|
||||
|
||||
## Files
|
||||
|
||||
- **`main.cc`** - C++ application that loads USD and executes JavaScript
|
||||
- **`query_layer.js`** - Example JavaScript that demonstrates LayerMetas querying
|
||||
- **`sample.usda`** - Sample USD file with various metadata for testing
|
||||
- **`CMakeLists.txt`** - Build configuration
|
||||
|
||||
## JavaScript API
|
||||
|
||||
The JavaScript environment provides access to:
|
||||
|
||||
### `getLayerMetas()`
|
||||
|
||||
Returns a JavaScript object containing USD layer metadata:
|
||||
|
||||
```javascript
|
||||
var layerMetas = getLayerMetas();
|
||||
console.log("Up Axis: " + layerMetas.upAxis);
|
||||
console.log("Default Prim: " + layerMetas.defaultPrim);
|
||||
console.log("Meters Per Unit: " + layerMetas.metersPerUnit);
|
||||
```
|
||||
|
||||
### Available LayerMetas Properties
|
||||
|
||||
- `upAxis` - Coordinate system up axis ("X", "Y", or "Z")
|
||||
- `defaultPrim` - Name of the default prim
|
||||
- `metersPerUnit` - Scale conversion factor
|
||||
- `timeCodesPerSecond` - Time sampling rate
|
||||
- `framesPerSecond` - Animation frame rate
|
||||
- `startTimeCode` - Animation start time
|
||||
- `endTimeCode` - Animation end time (null if infinite)
|
||||
- `kilogramsPerUnit` - Mass unit conversion
|
||||
- `comment` - Layer comment string
|
||||
- `doc` - Layer documentation string
|
||||
- `autoPlay` - USDZ auto-play setting
|
||||
- `playbackMode` - USDZ playback mode
|
||||
- `subLayers` - Array of sub-layer references
|
||||
- `primChildren` - Array of root-level prim names
|
||||
|
||||
### Example Output
|
||||
|
||||
```
|
||||
=== USD Layer Metadata Query Script ===
|
||||
LayerMetas successfully retrieved!
|
||||
|
||||
=== Basic Layer Metadata ===
|
||||
Up Axis: Y
|
||||
Default Prim: Scene
|
||||
Meters Per Unit: 1
|
||||
Time Codes Per Second: 24
|
||||
Frames Per Second: 24
|
||||
|
||||
=== Time Range ===
|
||||
Start Time Code: 1
|
||||
End Time Code: 100
|
||||
|
||||
=== Root Prim Children ===
|
||||
Number of root prims: 1
|
||||
Prim 0: Scene
|
||||
|
||||
=== Analysis ===
|
||||
Has default prim: true
|
||||
Has time range: true
|
||||
Is animated: true
|
||||
```
|
||||
|
||||
## Extending the Example
|
||||
|
||||
You can create your own JavaScript files to:
|
||||
|
||||
1. **Analyze USD structure** - Check metadata patterns, validate settings
|
||||
2. **Report generation** - Extract metadata for external tools
|
||||
3. **Conditional processing** - Make decisions based on USD properties
|
||||
4. **Validation** - Verify USD files meet specific requirements
|
||||
|
||||
### Custom JavaScript Example
|
||||
|
||||
```javascript
|
||||
// Custom validation script
|
||||
var layerMetas = getLayerMetas();
|
||||
|
||||
// Check for required metadata
|
||||
if (!layerMetas.defaultPrim) {
|
||||
console.log("WARNING: No default prim set");
|
||||
}
|
||||
|
||||
if (layerMetas.upAxis !== "Y") {
|
||||
console.log("INFO: Using " + layerMetas.upAxis + " as up-axis");
|
||||
}
|
||||
|
||||
// Generate report
|
||||
console.log("=== USD File Report ===");
|
||||
console.log("File appears to be: " +
|
||||
(layerMetas.endTimeCode > layerMetas.startTimeCode ? "Animated" : "Static"));
|
||||
console.log("Scale: " + layerMetas.metersPerUnit + " meters per unit");
|
||||
console.log("Frame rate: " + layerMetas.framesPerSecond + " fps");
|
||||
```
|
||||
|
||||
## Technical Notes
|
||||
|
||||
- The example uses QuickJS for JavaScript execution
|
||||
- LayerMetas are converted to JSON and parsed in the JavaScript context
|
||||
- The C++ side sets up a global `getLayerMetas()` function accessible from JavaScript
|
||||
- JavaScript execution is sandboxed and stateless
|
||||
- All USD data types are converted to appropriate JavaScript types
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**Error: "JavaScript is not supported in this build"**
|
||||
- Rebuild TinyUSDZ with `-DTINYUSDZ_WITH_QJS=ON`
|
||||
|
||||
**Error: "Failed to load USD file"**
|
||||
- Check that the USD file path is correct
|
||||
- Verify the USD file is valid
|
||||
|
||||
**Error: "Failed to load JavaScript file"**
|
||||
- Check that the JavaScript file path is correct
|
||||
- Verify the JavaScript file contains valid JavaScript code
|
||||
100
examples/js-script/main.cc
Normal file
100
examples/js-script/main.cc
Normal file
@@ -0,0 +1,100 @@
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
|
||||
// TinyUSDZ core
|
||||
#include "tinyusdz.hh"
|
||||
#include "pprinter.hh"
|
||||
|
||||
#if defined(TINYUSDZ_WITH_QJS)
|
||||
#include "tydra/js-script.hh"
|
||||
#endif
|
||||
|
||||
static std::string LoadJavaScriptFile(const std::string& filename) {
|
||||
std::ifstream file(filename);
|
||||
if (!file.is_open()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string content;
|
||||
std::string line;
|
||||
while (std::getline(file, line)) {
|
||||
content += line + "\n";
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (argc < 3) {
|
||||
std::cout << "Usage: " << argv[0] << " <USD_FILE> <JS_SCRIPT>" << std::endl;
|
||||
std::cout << "Example: " << argv[0] << " model.usd query_layer.js" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::string usd_filename = argv[1];
|
||||
std::string js_filename = argv[2];
|
||||
|
||||
std::cout << "Loading USD file: " << usd_filename << std::endl;
|
||||
std::cout << "Loading JavaScript: " << js_filename << std::endl;
|
||||
|
||||
#if defined(TINYUSDZ_WITH_QJS)
|
||||
|
||||
// Load USD file as Stage (which contains Layer metadata)
|
||||
tinyusdz::Stage stage;
|
||||
std::string warn, err;
|
||||
|
||||
bool ret = tinyusdz::LoadUSDFromFile(usd_filename, &stage, &warn, &err);
|
||||
|
||||
if (!warn.empty()) {
|
||||
std::cerr << "WARN: " << warn << std::endl;
|
||||
}
|
||||
|
||||
if (!ret) {
|
||||
std::cerr << "ERROR: Failed to load USD file: " << err << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::cout << "Successfully loaded USD file" << std::endl;
|
||||
|
||||
// Get LayerMetas from the Stage
|
||||
const tinyusdz::LayerMetas& layer_metas = stage.metas();
|
||||
|
||||
std::cout << "Stage LayerMetas loaded" << std::endl;
|
||||
std::cout << " - upAxis: " << tinyusdz::to_string(layer_metas.upAxis.get_value()) << std::endl;
|
||||
std::cout << " - defaultPrim: " << layer_metas.defaultPrim.str() << std::endl;
|
||||
std::cout << " - metersPerUnit: " << layer_metas.metersPerUnit.get_value() << std::endl;
|
||||
std::cout << " - timeCodesPerSecond: " << layer_metas.timeCodesPerSecond.get_value() << std::endl;
|
||||
|
||||
// Load JavaScript code
|
||||
std::string js_code = LoadJavaScriptFile(js_filename);
|
||||
if (js_code.empty()) {
|
||||
std::cerr << "ERROR: Failed to load JavaScript file: " << js_filename << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::cout << "Loaded JavaScript code (" << js_code.length() << " bytes)" << std::endl;
|
||||
|
||||
// Execute JavaScript with LayerMetas access
|
||||
std::cout << "Executing JavaScript with LayerMetas access..." << std::endl;
|
||||
std::cout << "----------------------------------------" << std::endl;
|
||||
|
||||
std::string js_err;
|
||||
bool js_ret = tinyusdz::tydra::RunJSScriptWithLayerMetas(js_code, &layer_metas, js_err);
|
||||
|
||||
std::cout << "----------------------------------------" << std::endl;
|
||||
|
||||
if (!js_ret) {
|
||||
std::cerr << "ERROR: JavaScript execution failed: " << js_err << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::cout << "JavaScript executed successfully" << std::endl;
|
||||
|
||||
#else
|
||||
std::cerr << "ERROR: This example requires QuickJS support (TINYUSDZ_WITH_QJS=ON)" << std::endl;
|
||||
std::cerr << "Please rebuild TinyUSDZ with QuickJS enabled." << std::endl;
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
116
examples/js-script/query_layer.js
Normal file
116
examples/js-script/query_layer.js
Normal file
@@ -0,0 +1,116 @@
|
||||
// Example JavaScript script to query LayerMeta information
|
||||
// This script demonstrates how to access USD Layer metadata through the Tydra JavaScript interface
|
||||
|
||||
console.log("=== USD Layer Metadata Query Script ===");
|
||||
console.log("This script demonstrates querying LayerMetas through the Tydra JavaScript interface.");
|
||||
console.log("");
|
||||
|
||||
// Get the LayerMetas object from the C++ side
|
||||
var layerMetas = getLayerMetas();
|
||||
|
||||
if (layerMetas === null) {
|
||||
console.log("ERROR: No LayerMetas available");
|
||||
} else {
|
||||
console.log("LayerMetas successfully retrieved!");
|
||||
console.log("");
|
||||
|
||||
// Display basic metadata
|
||||
console.log("=== Basic Layer Metadata ===");
|
||||
console.log("Up Axis: " + layerMetas.upAxis);
|
||||
console.log("Default Prim: " + layerMetas.defaultPrim);
|
||||
console.log("Meters Per Unit: " + layerMetas.metersPerUnit);
|
||||
console.log("Time Codes Per Second: " + layerMetas.timeCodesPerSecond);
|
||||
console.log("Frames Per Second: " + layerMetas.framesPerSecond);
|
||||
console.log("Kilograms Per Unit: " + layerMetas.kilogramsPerUnit);
|
||||
console.log("");
|
||||
|
||||
// Display time range information
|
||||
console.log("=== Time Range ===");
|
||||
console.log("Start Time Code: " + layerMetas.startTimeCode);
|
||||
if (layerMetas.endTimeCode === null) {
|
||||
console.log("End Time Code: (infinite/not set)");
|
||||
} else {
|
||||
console.log("End Time Code: " + layerMetas.endTimeCode);
|
||||
}
|
||||
console.log("");
|
||||
|
||||
// Display documentation and comments
|
||||
console.log("=== Documentation ===");
|
||||
if (layerMetas.comment && layerMetas.comment.length > 0) {
|
||||
console.log("Comment: " + layerMetas.comment);
|
||||
} else {
|
||||
console.log("Comment: (none)");
|
||||
}
|
||||
|
||||
if (layerMetas.doc && layerMetas.doc.length > 0) {
|
||||
console.log("Documentation: " + layerMetas.doc);
|
||||
} else {
|
||||
console.log("Documentation: (none)");
|
||||
}
|
||||
console.log("");
|
||||
|
||||
// Display USDZ-specific metadata
|
||||
console.log("=== USDZ Extensions ===");
|
||||
console.log("Auto Play: " + layerMetas.autoPlay);
|
||||
console.log("Playback Mode: " + layerMetas.playbackMode);
|
||||
console.log("");
|
||||
|
||||
// Display sub-layers information
|
||||
console.log("=== Sub-Layers ===");
|
||||
if (layerMetas.subLayers.length > 0) {
|
||||
console.log("Number of sub-layers: " + layerMetas.subLayers.length);
|
||||
for (var i = 0; i < layerMetas.subLayers.length; i++) {
|
||||
var subLayer = layerMetas.subLayers[i];
|
||||
console.log(" Sub-layer " + i + ":");
|
||||
console.log(" Asset Path: " + subLayer.assetPath);
|
||||
console.log(" Layer Offset: " + subLayer.layerOffset.offset);
|
||||
console.log(" Layer Scale: " + subLayer.layerOffset.scale);
|
||||
}
|
||||
} else {
|
||||
console.log("No sub-layers defined");
|
||||
}
|
||||
console.log("");
|
||||
|
||||
// Display root prim children
|
||||
console.log("=== Root Prim Children ===");
|
||||
if (layerMetas.primChildren.length > 0) {
|
||||
console.log("Number of root prims: " + layerMetas.primChildren.length);
|
||||
for (var i = 0; i < layerMetas.primChildren.length; i++) {
|
||||
console.log(" Prim " + i + ": " + layerMetas.primChildren[i]);
|
||||
}
|
||||
} else {
|
||||
console.log("No root prims defined");
|
||||
}
|
||||
console.log("");
|
||||
|
||||
// Perform some analysis
|
||||
console.log("=== Analysis ===");
|
||||
|
||||
// Check if this looks like a typical scene setup
|
||||
var hasDefaultPrim = layerMetas.defaultPrim && layerMetas.defaultPrim.length > 0;
|
||||
var hasTimeRange = layerMetas.startTimeCode !== undefined && layerMetas.endTimeCode !== null;
|
||||
var isAnimated = hasTimeRange && (layerMetas.endTimeCode > layerMetas.startTimeCode);
|
||||
|
||||
console.log("Has default prim: " + hasDefaultPrim);
|
||||
console.log("Has time range: " + hasTimeRange);
|
||||
console.log("Is animated: " + isAnimated);
|
||||
|
||||
if (layerMetas.upAxis !== "Y") {
|
||||
console.log("NOTE: This USD file uses " + layerMetas.upAxis + " as up-axis (not Y)");
|
||||
}
|
||||
|
||||
if (layerMetas.metersPerUnit !== 1.0) {
|
||||
console.log("NOTE: This USD file has custom scale: " + layerMetas.metersPerUnit + " meters per unit");
|
||||
}
|
||||
|
||||
if (layerMetas.subLayers.length > 0) {
|
||||
console.log("NOTE: This USD file references " + layerMetas.subLayers.length + " sub-layer(s)");
|
||||
}
|
||||
|
||||
console.log("");
|
||||
console.log("=== JSON Representation ===");
|
||||
console.log(JSON.stringify(layerMetas, null, 2));
|
||||
}
|
||||
|
||||
console.log("");
|
||||
console.log("=== Script Complete ===");
|
||||
39
examples/js-script/sample.usda
Normal file
39
examples/js-script/sample.usda
Normal file
@@ -0,0 +1,39 @@
|
||||
#usda 1.0
|
||||
(
|
||||
comment = "Simple USD sample file for JavaScript LayerMetas demo"
|
||||
defaultPrim = "Scene"
|
||||
doc = "This USD file demonstrates basic layer metadata that can be queried via JavaScript"
|
||||
endTimeCode = 100
|
||||
framesPerSecond = 24
|
||||
metersPerUnit = 1
|
||||
startTimeCode = 1
|
||||
timeCodesPerSecond = 24
|
||||
upAxis = "Y"
|
||||
)
|
||||
|
||||
def Xform "Scene"
|
||||
{
|
||||
def Sphere "Ball"
|
||||
{
|
||||
float3[] extent = [(-1, -1, -1), (1, 1, 1)]
|
||||
double radius = 1
|
||||
|
||||
# Animated transform
|
||||
float3 xformOp:translate.timeSamples = {
|
||||
1: (0, 0, 0),
|
||||
50: (2, 1, 0),
|
||||
100: (0, 0, 0)
|
||||
}
|
||||
uniform token[] xformOpOrder = ["xformOp:translate"]
|
||||
}
|
||||
|
||||
def Cube "Box"
|
||||
{
|
||||
float3[] extent = [(-1, -1, -1), (1, 1, 1)]
|
||||
double size = 2
|
||||
|
||||
# Static transform
|
||||
float3 xformOp:translate = (3, 0, 0)
|
||||
uniform token[] xformOpOrder = ["xformOp:translate"]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user