Installation#
Python Package#
As of Kit 106.0, the application is available via python package.
pip install omniverse-kit
Kit App Template#
As of kit 106.0 release this extension can be called from one of the Sample App Templates. Installing the base kit_base_editor
template will work for running the command line version of Scene Optimizer as dependencies will be pulled on first launch of the CLI command.
Legacy Standalone Application#
Note
105.1.19 is the last supported version of this application.
This is the standalone application available in the exchange of the Omniverse Launcher.
Running the Scene Optimizer App#
In the examples for Python Package
and Kit App Template
a python script is needed to execute the Scene Optimizer operations. A Sample Python Script is provided in the documentation below and also takes a JSON configuration file as an argument.
Python Package#
python3 -m omni.kit_app --enable 'omni.scene.optimizer.core' --enable 'omni.usd' --exec '/path/to/python_script.py /path/to/input_dir /path/to/output_dir /path/to/json_config.json --input_glob=*.usd'
Kit App Template#
Linux
./kit --enable 'omni.scene.optimizer.core' --enable 'omni.usd' --exec '/path/to/python_script.py /path/to/input_dir /path/to/output_dir /path/to/json_config.json --input_glob=*.usd'
Windows
.\kit.exe --enable 'omni.scene.optimizer.core' --enable 'omni.usd' --exec '/path/to/python_script.py /path/to/input_dir /path/to/output_dir /path/to/json_config.json --input_glob=*.usd'
Note
Please use the kit
version inside the _build
directory of the applicable kit app template
Legacy Standalone Application#
Linux
~/.local/share/ov/pkg/scene_optimizer-105.1.19/omni.app.scene.optimizer.batch.kit.sh
Windows
C:\Users\<name>\AppData\Local\ov\pkg\scene_optimizer-105.1.19\omni.app.scene.optimizer.batch.kit.bat
Caution
If installation of Omniverse and related content is not using default settings, please use appropriate paths.
Running the tool using just the command line above will print output indicating the arguments needed for the command. There are three arguments required:
- Input USD file name
--/app/sceneOptimizer/input
- Output USD file name
--/app/sceneOptimizer/output
- JSON config file
--/app/sceneOptimizer/config
The config
file specifies the optimizations to be performed on the input
file. The result of the optimization will be written to the output
file.
It is also possible to define all the above arguments in a single file that can be loaded when the app starts.
Example Run of Legacy Standalone Application#
Linux
~/.local/share/ov/pkg/scene_optimizer-105.1.0/omni.app.scene.optimizer.batch.kit.sh --/app/sceneOptimizer/input=/tmp/testScene.usd --/app/sceneOptimizer/output=/tmp/merged.usd --/app/sceneOptimizer/config=/tmp/merge_all.json
Windows
C:\Users\<name>\AppData\Local\ov\pkg\scene_optimizer-105.1.0\omni.app.scene.optimizer.batch.kit.bat --/app/sceneOptimizer/input=testScene.usd --/app/sceneOptimizer/output=merged.usd --/app/sceneOptimizer/config=merge_all.json
Caution
If your installation of Omniverse and related content is not using default settings, please use appropriate paths.
Config File Description#
The config file is a JSON file that describes one or more optimizations to apply to the data.
Below is an example config file that first optimizes scene materials by replacing identical materials with a single material, then deduplicates geometry by replacing identical versions with geometry instances.
[
{
"operation": "optimizeMaterials",
"materialPrimPaths": [],
"optimizeMaterialsMode": 0
},
{
"operation": "deduplicateGeometry",
"meshPrimPaths": [],
"considerDeepTransforms": true,
"tolerance": 0.001,
"duplicateMethod": 2,
"fuzzy": false,
"useGpu": false,
"allowScaling": false,
}
]
Generating Config Files#
The file can be written by hand, but the easier way is to use the Scene Optimizer Kit extension to generate the file. The optimization steps can be defined in the Scene Optimizer UI, then saved to a JSON file.
See details on how to generate the JSON
file from the Scene Optimizer Kit extension
Sample Python Script#
The sample python script can be used to batch process directories of USD files with varying config files:
"""Script to batch process USD files with Scene Optimizer operations"""
import argparse
from pathlib import Path
import omni
import omni.usd
from pxr import UsdUtils
def optimize_files_in_dir(input_dir, output_dir, optimizer_json, input_glob="*"):
"""Runs optimization configurations over all USD files in single directory"""
input_files = list(Path(input_dir).glob(input_glob))
for i, input_file in enumerate(input_files):
output_file = Path(output_dir, input_file.name)
output_file = str(output_file)
input_file = str(input_file)
if not omni.usd.get_context().open_stage(input_file):
raise ValueError(f"Could not open file {input_file}")
stage = omni.usd.get_context().get_stage()
# Check to see if native prims exist along side payloads or references
for prim in stage.Traverse():
# check to see if prim is a payload or reference
if not (prim.HasAuthoredPayloads() or prim.HasAuthoredReferences()):
omni.log.warn(f"++ [{i}/{len(input_files)}] Optimizing {input_file} > {output_file}")
context = omni.scene.optimizer.core.ExecutionContext()
context.usdStageId = UsdUtils.StageCache().Get().Insert(stage).ToLongInt()
context.generateReport = 1
context.captureStats = 1
# If a config file exists for a specific file use that instead of default input
optimizer_json_file = Path(input_dir, Path(input_file).stem + ".json")
if optimizer_json_file.is_file():
myArgs = {"jsonFile": str(optimizer_json_file)}
else:
myArgs = {"jsonFile": optimizer_json}
omni.kit.commands.execute("SceneOptimizerJsonParser", context=context, args=myArgs)
# Export stage to a new file
stage.GetRootLayer().Export(output_file)
# Close each stage to avoid kit crashes
omni.usd.get_context().close_stage()
break
def main():
parser = argparse.ArgumentParser(
description="Optimize USD files in a directory.",
epilog="Example: /path/to/kit --enable 'omni.scene.optimizer.core' --enable 'omni.usd' --exec 'python_script_name.py /path/to/input /path/to/output /path/to/config.json --input_glob=*.usd' ",
)
parser.add_argument("input_dir", help="Directory containing input files")
parser.add_argument("output_dir", help="Directory to save optimized files")
parser.add_argument("json_config", help="JSON configuration file for the optimizer")
parser.add_argument("--input_glob", default="*", help="Glob pattern to match input files (default: *)")
args = parser.parse_args()
optimize_files_in_dir(args.input_dir, args.output_dir, args.json_config, input_glob=args.input_glob)
if __name__ == "__main__":
main()