Skip to content

Commit

Permalink
Initial Public Release
Browse files Browse the repository at this point in the history
  • Loading branch information
ericcraft-mh committed Sep 9, 2022
1 parent aac4c95 commit 846d41f
Show file tree
Hide file tree
Showing 9 changed files with 94 additions and 57 deletions.
58 changes: 38 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,46 @@
# Extension Project Template

This project was automatically generated.
# Mead & Hunt Enscape Camera Loader
![Enscape Loader Screenshot](/exts/meadhunt.enscape.loader/data/preview_enscapeloader.png)

- `app` - It is a folder link to the location of your *Omniverse Kit* based app.
- `exts` - It is a folder where you can add new extensions. It was automatically added to extension search path. (Extension Manager -> Gear Icon -> Extension Search Path).
## Inspiration
`Enscape Loader` was created based on a tool I previously created, but was written from the ground up in Python for Omniverse.

Open this folder using Visual Studio Code. It will suggest you to install few extensions that will make python experience better.
## About
This tool was created as a way to exchange camera data from Enscape to Omniverse. Not all Designers/Architects may be comfortable in a tool like Omniverse so this allows them to do their work in Enscape, but bring it to Omniverse for fine tuning and advanced visualization.

Look for "meadhunt.enscape.loader" extension in extension manager and enable it. Try applying changes to any python files, it will hot-reload and you can observe results immediately.
## Usage
After installation the dialog can be opened from **`Window > Mead & Hunt > Enscape Camera Loader`**.

Alternatively, you can launch your app from console with this folder added to search path and your extension enabled, e.g.:
![Enscape Loader UI](images/enscapeloader_ui.png)

```
> app\omni.code.bat --ext-folder exts --enable omni.hello.world
```
**XML Path:** Path to the XML you want to import.

**Scene Path:** `/World/Cameras (default)`Path in the Omniverse Stage where you want the Cameras to be placed.

**Name:** `EnscapeCamera` `(default)`Name to be appended by Unique number (`EnscapeCamera_01`).

**Mode:** Drop-down of what to do with the XML file.
- **`NOTE:`** Currently only `Import` is supported. A future release may support `Export`.

**Method:** Drop-down of how to process the time/keyframes for the XML data.
- `Continuous: Smooth:` Currently in development.
- `Continuous: Linear:` One camera with linear animation between all key frames.
- `Multiple: Linear:` Multiple cameras with a Linear animation between every 2 keys.
- `Multiple: Static (default):` Each keyframe comes in as a static camera.

# App Link Setup
**Timeline:** Drop-down of how to adjust the current timeline.
- `Match XML (default):` Match the timeline time to the XML.
- `Grow to Fit:` Match the last keyframe if it is greater than the current timeline.
- `Shrink to Fit:` Match the last keyframe if it is less than the current timeline.

**Click Me:** Button to process the file.

## Adding This Extension
To add this extension to your Omniverse app:
1. Go into: Extension Manager -> Gear Icon -> Extension Search Path
2. Add this as a search path: `git://github.com/ericcraft-mh/meadhunt-enscape-loader.git?branch=main&dir=exts`

## App Link Setup
If `app` folder link doesn't exist or broken it can be created again. For better developer experience it is recommended to create a folder link named `app` to the *Omniverse Kit* app installed from *Omniverse Launcher*. Convenience script to use is included.

Run:
Expand All @@ -39,14 +63,8 @@ You can also just pass a path to create link to:
> link_app.bat --path "C:/Users/bob/AppData/Local/ov/pkg/create-2021.3.4"
```

## Contributing
The source code for this repository is provided as-is, but I am accepting outside contributions.

# Sharing Your Extensions

This folder is ready to be pushed to any git repository. Once pushed direct link to a git repository can be added to *Omniverse Kit* extension search paths.

Link might look like this: `git://github.com/ericcraft-mh/meadhunt-enscape-loader.git?branch=main&dir=exts`

Notice `exts` is repo subfolder with extensions. More information can be found in "Git URL as Extension Search Paths" section of developers manual.

To add a link to your *Omniverse Kit* based app go into: Extension Manager -> Gear Icon -> Extension Search Path
Issues, Feature Requests, and Pull Requests are welcomed.

7 changes: 6 additions & 1 deletion exts/meadhunt.enscape.loader/config/extension.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
version = "1.0.0"

# The title and description fields are primarily for displaying extension info in UI
title = "Mead & Hunt Enscape Camera IO"
title = "Mead & Hunt Enscape Camera Loader"
description="Importer/exporter to exchange Enscape camera data through animation .xml."

# Path (relative to the root) or content of readme markdown file for UI.
readme = "docs/README.md"
changelog = "docs/CHANGELOG.md"

# URL of the extension source repository.
repository = "https://github.com/ericcraft-mh/meadhunt-enscape-loader"
Expand All @@ -18,6 +19,10 @@ category = "Other"
# Keywords for the extension
keywords = ["kit", "enscape"]

# Preview image and icon. Folder named "data" automatically goes in git lfs (see .gitattributes file).
# Preview image is shown in "Overview" of Extensions window. Screenshot of an extension might be a good preview image.
preview_image = "data/preview_enscapeloader.png"

# Use omni.ui to build simple UI
[dependencies]
"omni.kit.uiapp" = {}
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file.
39 changes: 39 additions & 0 deletions exts/meadhunt.enscape.loader/docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@

# Mead & Hunt Enscape Camera Loader

### Inspiration
Enscape Loader was created based on a tool I previously created, but was written from the ground up in Python for Omniverse.

### About
This tool was created as a way to exchange camera data from Enscape to Omniverse. Not all Designers/Architects may be comfortable in a tool like Omniverse so this allows them to do their work in Enscape, but bring it to Omniverse for fine tuning and advanced visualization.

### Usage
After installation the dialog can be opened from Window > Mead & Hunt > Enscape Camera Loader.

XML Path: Path to the XML you want to import.

Scene Path: /World/Cameras (default)Path in the Omniverse Stage where you want the Cameras to be placed.

Name: EnscapeCamera (default)Name to be appended by Unique number (EnscapeCamera_01).

Mode: Drop-down of what to do with the XML file.
- NOTE: Currently only Import is supported. A future release may support Export.

Method: Drop-down of how to process the time/keyframes for the XML data.
- Continuous: Smooth: Currently in development.
- Continuous: Linear: One camera with linear animation between all key frames.
- Multiple: Linear: Multiple cameras with a Linear animation between every 2 keys.
- Multiple: Static (default): Each keyframe comes in as a static camera.

Timeline: Drop-down of how to adjust the current timeline.
- Match XML (default): Match the timeline time to the XML.
- Grow to Fit: Match the last keyframe if it is greater than the current timeline.
- Shrink to Fit: Match the last keyframe if it is less than the current timeline.

Click Me: Button to process the file.

### Adding This Extension
To add this extension to your Omniverse app:
1. Go into: Extension Manager -> Gear Icon -> Extension Search Path
2. Add this as a search path: git://github.com/ericcraft-mh/meadhunt-enscape-loader.git?branch=main&dir=exts

Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ class EnscapeIO(omni.ext.IExt):

# Class Variables
DEBUG = True
WINDOW_TITLE = "Enscape Camera IO"
WINDOW_TITLE = "Enscape Camera Loader"

def __init__(self):
pass

def on_startup(self, ext_id):
print("[meadhunt.enscape.loader] Enscape Camera IO startup")
print("[meadhunt.enscape.loader] Enscape Camera Loader startup")

# Note the "Window" part of the path that directs the new menu item to the "Window" menu.
self._menu_path = f"Window/Mead & Hunt/{self.WINDOW_TITLE}"
Expand All @@ -33,7 +33,7 @@ def on_startup(self, ext_id):
omni.kit.ui.get_editor_menu().set_value(self._menu_path, False)

def on_shutdown(self):
print("[meadhunt.enscape.loader] Enscape Camera IO shutdown")
print("[meadhunt.enscape.loader] Enscape Camera Loader shutdown")

if self._window:
self._window.hide()
Expand Down
25 changes: 5 additions & 20 deletions exts/meadhunt.enscape.loader/meadhunt/enscape/loader/window.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@ def _build_ui(self):
with self.frame:
with ui.VStack(height=0):
with ui.VStack(spacing=5, name="frame_v_stack"):
# ui.Spacer(height=0)

self._create_path("XML Path:", "")
# ui.Spacer(height=0)

with ui.HStack():
ui.Label("Scene Path:", name="scenelabel", width=self.LABEL_WIDTH)
self._scene_path = ui.StringField(name="scenepath", height=self.BUTTON_SIZE).model
Expand All @@ -66,27 +66,20 @@ def _build_ui(self):
ui.Label("Name:", name="namelabel", width=self.LABEL_WIDTH)
self._camera_name = ui.StringField(name="namefield", height=self.BUTTON_SIZE).model
self._camera_name.set_value("EnscapeCamera")
# ui.Spacer(height=0)

self.COMBO_MODE = self._create_combo("Mode:", self.MODE_LIST, 0)
self.COMBO_MODE.enabled = False
# ui.Spacer(height=0)

self.COMBO_METHOD = self._create_combo("Method:", self.METHOD_LIST, 3)
self.COMBO_METHOD.enabled = True
# ui.Spacer(height=0)

self.COMBO_FIT = self._create_combo("Timeline:", self.FIT_LIST, 0)
self.COMBO_FIT.enabled = True
self.btn_click = ui.Button("Click Me", name="BtnClick", clicked_fn=lambda: self._on_click(), style={"color": cl.shade("aqua", transparent=0x20FFFFFF, white=0xFFFFFFFF)}, enabled=False)
ui.set_shade("transparent")
# ui.Spacer(height=2)
# with ui.CollapsableFrame(title="About", collapsed=True, alignment=ui.Alignment.CENTER):
# with ui.VStack():
# ui.Label("Author: Eric Craft")
# ui.Label("Company: Mead & Hunt")

def _on_filter_xml(self, item) -> bool:
"""Callback to filter the choices of file names in the open or save dialog"""
# if self.DEBUG:
# print(f"current_filter_option: {self._open_file_dialog.current_filter_option}")
if not item or item.is_folder:
return True
if self._open_file_dialog.current_filter_option == 0:
Expand Down Expand Up @@ -158,14 +151,6 @@ def _on_click_cancel(file_name: str, directory_path: str):
self._open_file_dialog.hide()
self._open_file_dialog.destroy()

# self._open_file_dialog = FilePickerDialog(
# "Select XML File",
# apply_button_label="Select",
# click_apply_handler=lambda f, d: _on_click_open(f, d),
# click_cancel_handler=lambda f, d: _on_click_cancel(f, d),
# file_extension_options = [("*.xml", "Files (*.xml)")],
# item_filter_fn=lambda item: self._on_filter_xml(item)
# )
self._open_file_dialog = FilePickerDialog(
"Open XML File",
apply_button_label="Open",
Expand Down
16 changes: 3 additions & 13 deletions exts/meadhunt.enscape.loader/meadhunt/enscape/loader/xml_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,17 +66,13 @@ def valid_xml(self) -> bool:
return False

def total_time(self):
# try:
if self._root.attrib.get("durationSeconds"):
outval = float(self._root.attrib.get("durationSeconds"))
elif self._root[0][self.keys_count()-1].attrib.get("timestampSeconds"):
outval = float(self._root[0][self.keys_count()-1].attrib.get("timestampSeconds"))
else:
timeval = float(self._root[0][self.keys_count()-2].attrib.get("timestampSeconds"))
outval = (timeval/(self.keys_count()-1))+timeval
# except:
# print("ERROR: Total Time not calculated")
# outval = float(0)
return outval

def time_key(self):
Expand Down Expand Up @@ -204,20 +200,16 @@ def create_cameras(self, index=0):
xscale = camera_prim.GetAttribute("xformOp:scale")
else:
xform = UsdGeom.Xformable(camera_prim)
# transform = xform.AddTransformOp()
xposition = xform.AddTranslateOp()
xrotation = xform.AddRotateXYZOp()
xscale = xform.AddScaleOp()
# Set the Camera transform matrix
xform = UsdGeom.Xformable(camera_prim)
# transform = xform.AddTransformOp()
# xposition = xform.AddTranslateOp()
# xrotation = xform.AddRotateXYZOp()
# xscale = xform.AddScaleOp()

xposition.Set(self.get_pos(index))
xrotation.Set(self.get_rot(index))
xscale.Set(Gf.Vec3d(1,1,1))
# transform.Set(self.get_xform(index))

# Debug
if self._debug:
print(f"Camera Path: {camera_path}")
Expand Down Expand Up @@ -248,7 +240,7 @@ def parse_xml(self):
if newcam.HasAttribute("xformOp:translate"):
tpath = f"{newcampath}.xformOp:translate"
rpath = f"{newcampath}.xformOp:rotateXYZ"
# omni.kit.commands.execute("AddAnimCurves",paths=[tpath,rpath])

for index in range(0, self._keys_total):
# Set Anim Curve Keys for translate
print(index,": ",self.get_keyTime(index))
Expand Down Expand Up @@ -291,5 +283,3 @@ def parse_xml(self):
camerasList[index].GetAttribute("focalLength").Set(self.get_focalLength(camerasList[index],fovList[0]))
if len(fovList) == 0:
camerasList[index].GetAttribute("focalLength").Set(self.get_focalLength(camerasList[index],math.radians(90.0)))
# print(camerasList)
# print(f"{self._root.tag}")
Binary file added images/enscapeloader_ui.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 846d41f

Please sign in to comment.