Omni Activity Freeze Progress#
Overview#
The omni.activity.freeze_progress extension provides a non-blocking progress window for NVIDIA Omniverse Kit applications. It displays visual feedback during long-running operations without freezing the UI, ensuring users understand that the application is actively processing rather than hanging.
This extension is essential for operations that may take several seconds or minutes, such as:
Loading large USD scenes
Processing complex geometries
Importing/exporting assets
Optimizing materials and textures
Building acceleration structures
Any blocking operation that would otherwise make the UI unresponsive
Why Use This Extension?#
The Problem#
When Kit applications perform intensive operations that block the main thread, the entire UI becomes unresponsive. Users can’t distinguish between an application that’s working hard and one that has crashed, leading to frustration and premature termination of valid operations.
The Solution#
This extension renders a progress window from a separate thread using its own ImGui context, maintaining visual feedback even when the main thread is blocked. The progress window shows:
A progress bar indicating completion status
Current activity being performed
Elapsed time
Optional helpful tips during long operations
Operating Modes#
The extension supports two distinct progress tracking modes, each optimized for different use cases:
1. Time-Based Progress#
Time-based mode is ideal when you know approximately how long an operation will take. The progress bar fills based on elapsed time rather than discrete events.
When to use:
Operations with predictable duration
Continuous processing without discrete steps
Tasks where measuring individual events is impractical
Blocking operations where event emission is not possible
Key Features:
Adaptive Progress: After reaching 80%, the progress slows down gracefully using an arctangent curve, preventing the jarring experience of a stuck progress bar if the operation takes longer than expected
Dynamic Updates: Activity text can be updated during operation to show different stages
Tips System: Display rotating helpful hints to keep users engaged during long waits
Example:
import omni.activity.freeze_progress as freeze_progress
import time
# Simple time-based progress
freeze_progress.start_time_based(
duration=10.0,
activity="Optimizing Scene"
)
time.sleep(10)
freeze_progress.stop_time_based()
# With tips to keep users informed
tips = [
"Press F to frame selected objects",
"Use Ctrl+S to save your work",
"Hold Alt to orbit the camera"
]
freeze_progress.start_time_based(
duration=20.0,
activity="Building Acceleration Structures",
tips=tips,
tip_duration=3.0 # Rotate tips every 3 seconds
)
# Perform work...
freeze_progress.stop_time_based()
2. Event-Based Progress#
Event-based mode tracks actual activity events emitted by the system, providing accurate progress based on real work completion.
When to use:
Operations with discrete, measurable steps
When accurate progress tracking is critical
Integration with existing Kit activity system
Multiple concurrent operations that emit events
Key Features:
Automatic Filtering: Tracks relevant events (USD loading, texture loading, material setup)
Accurate Progress: Based on actual work completed, not estimates
System Integration: Leverages Kit’s built-in activity tracking
Example:
import omni.activity.freeze_progress as freeze_progress
import omni.activity.core as act
# Start progress tracking
freeze_progress.start()
act.enable()
# Emit events as work progresses
act.began("USD|Read|scene.usd")
# ... perform USD loading ...
act.ended("USD|Read|scene.usd")
act.began("Textures|Load|diffuse.dds")
# ... load texture ...
act.ended("Textures|Load|diffuse.dds")
# Cleanup
act.disable()
freeze_progress.stop()
API Reference#
Time-Based Functions#
start_time_based(duration, activity, tips, tip_duration)#
Starts a time-based progress window.
Parameters:
duration(float, optional): Expected duration in seconds (default: 10.0)activity(str, optional): Activity description to displaytips(list[str], optional): List of tips to rotate throughtip_duration(float, optional): Seconds to display each tip (default: 5.0)
update_activity(activity)#
Updates the activity text during progress.
Parameters:
activity(str): New activity description
stop_time_based()#
Stops the time-based progress window.
Event-Based Functions#
start()#
Starts event-based progress tracking. The window will automatically track relevant activity events.
stop()#
Stops event-based progress tracking and closes the window.
Implementation Details#
Thread Safety#
The extension uses a separate thread with its own ImGui context for rendering, ensuring the progress window remains responsive even when the main thread is blocked.
Event Filtering#
In event-based mode, the extension automatically filters and tracks:
USD Operations:
USD|Read|*patternsTexture Loading:
Textures|Load|*patternsMaterial Processing:
Materials|*patterns (excluding compilation and texture loading sub-events)
Adaptive Progress Algorithm#
The time-based mode uses an arctangent curve after 80% completion to handle time overruns gracefully:
if progress < 0.8:
display_progress = elapsed_time / total_duration
else:
# Slow down using arctangent curve
excess_ratio = (elapsed_time - 0.8 * total_duration) / (0.2 * total_duration)
additional = 0.199 * atan(excess_ratio * π) / (π/2)
display_progress = min(0.999, 0.8 + additional)
This ensures the progress bar never appears stuck at 99% and provides smooth visual feedback even when estimates are incorrect.
Visual Design#
Rounded corners on window and progress bar for modern appearance
Dark background frame for tips display
No spinning indicators to maintain clean, professional interface
Automatic sizing to accommodate content without scrollbars
Best Practices#
Choose the Right Mode: Use time-based for predictable operations, event-based for discrete steps
Provide Meaningful Updates: Keep activity text descriptive but concise
Use Tips Wisely: Include helpful, contextual tips for operations longer than 10 seconds
Always Clean Up: Ensure you call stop functions in finally blocks or exception handlers
Test Time Estimates: For time-based mode, test your duration estimates under various conditions
Integration Example#
Here’s a complete example showing both modes in a real workflow:
import omni.activity.freeze_progress as freeze_progress
import omni.activity.core as act
import time
def load_complex_scene(scene_path):
"""Load a complex scene with progress feedback"""
# Phase 1: Event-based loading of discrete files
freeze_progress.start()
act.enable()
try:
# Load main USD
act.began(f"USD|Read|{scene_path}")
# ... actual USD loading code ...
act.ended(f"USD|Read|{scene_path}")
# Load associated textures
for texture in find_textures(scene_path):
act.began(f"Textures|Load|{texture}")
load_texture(texture)
act.ended(f"Textures|Load|{texture}")
finally:
act.disable()
freeze_progress.stop()
# Phase 2: Time-based optimization
tips = [
"Optimization improves rendering performance",
"This process analyzes all geometry in the scene",
"Complex scenes may take several minutes"
]
freeze_progress.start_time_based(
duration=30.0,
activity="Optimizing Scene",
tips=tips,
tip_duration=5.0
)
try:
time.sleep(5)
freeze_progress.update_activity("Building BVH structures")
build_bvh()
time.sleep(5)
freeze_progress.update_activity("Optimizing materials")
optimize_materials()
finally:
freeze_progress.stop_time_based()
Conclusion#
The omni.activity.freeze_progress extension is an essential tool for maintaining responsive user experience during long operations. By providing clear visual feedback through either time-based or event-based tracking, it ensures users remain informed and confident that their application is working correctly.