Skip to content

Commit 84c0a07

Browse files
KumoLiupre-commit-ci[bot]Copilot
authored
Fix omniverse integration notebook (#1980)
Fixes # . ### Description - Add material for each mesh - update comment to using kit template instead of Usd Composer as omniverse launcher has been deprecated ### Checks <!--- Put an `x` in all the boxes that apply, and remove the not applicable items --> - [ ] Avoid including large-size files in the PR. - [ ] Clean up long text outputs from code cells in the notebook. - [ ] For security purposes, please check the contents and remove any sensitive info such as user names and private key. - [ ] Ensure (1) hyperlinks and markdown anchors are working (2) use relative paths for tutorial repo files (3) put figure and graphs in the `./figure` folder - [ ] Notebook runs automatically `./runner.sh -t <path to .ipynb file>` --------- Signed-off-by: YunLiu <55491388+KumoLiu@users.noreply.github.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 1d4b31d commit 84c0a07

File tree

2 files changed

+74
-24
lines changed

2 files changed

+74
-24
lines changed

modules/omniverse/omniverse_integration.ipynb

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -484,7 +484,10 @@
484484
"source": [
485485
"## Convert 3D model contain all organs to USD format\n",
486486
"\n",
487-
"[Universal Scene Description (OpenUSD)](https://openusd.org/release/index.html) is an extensible ecosystem of file formats, compositors, renderers, and other plugins for comprehensive 3D scene description."
487+
"[Universal Scene Description (OpenUSD)](https://openusd.org/release/index.html) is an extensible ecosystem of file formats, compositors, renderers, and other plugins for comprehensive 3D scene description.\n",
488+
"\n",
489+
"Instead of using code to convert, you can also use the built-in converter in NVIDIA Omniverse to perform the conversion. For more details on using the CAD Converter extension, please refer to the official documentation:\n",
490+
"https://docs.omniverse.nvidia.com/extensions/latest/ext_cad-converter/manual.html"
488491
]
489492
},
490493
{
@@ -501,7 +504,7 @@
501504
}
502505
],
503506
"source": [
504-
"obj_filename = f\"{bundle_root}/datasets/monai/obj/all_organs.gltf\"\n",
507+
"obj_filename = f\"{bundle_root}/datasets/monai/obj/all_organs_modified.gltf\"\n",
505508
"usd_filename = f\"{bundle_root}/datasets/monai/obj/all_organs.usd\"\n",
506509
"\n",
507510
"convert_mesh_to_usd(obj_filename, usd_filename)"
@@ -570,7 +573,11 @@
570573
"source": [
571574
"## Visualization in the Omniverse\n",
572575
"\n",
573-
"Download the [NVIDIA Omniverse](https://www.nvidia.com/en-us/omniverse/) launcher to explore applications such as USD Composer for viewing and manipulating the OpenUSD output file.\n",
576+
"Since the Omniverse Launcher has been deprecated, you can use USD Composer to view and manipulate the OpenUSD output files.\n",
577+
"\n",
578+
"To download the latest version of USD Composer, you can follow the instructions here to build and launch:\n",
579+
"\n",
580+
"https://github.com/NVIDIA-Omniverse/kit-app-template/tree/main/templates/apps/usd_composer#getting-started\n",
574581
"\n",
575582
"![omniverse](./omniverse.png)"
576583
]

modules/omniverse/utility.py

Lines changed: 64 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,12 @@
1414
import os
1515
import vtk
1616
import json
17-
from pxr import Usd, UsdGeom, Gf, Sdf
17+
from pxr import Usd, UsdGeom, Gf, Sdf, UsdShade
1818
import trimesh
1919
import numpy as np
2020
import matplotlib.pyplot as plt
21+
import random
22+
import colorsys
2123

2224

2325
def convert_to_mesh(
@@ -186,30 +188,71 @@ def convert_mesh_to_usd(input_file, output_file):
186188

187189
# Create a new USD stage
188190
stage = Usd.Stage.CreateNew(output_file)
191+
root = UsdGeom.Xform.Define(stage, "/World")
192+
stage.SetDefaultPrim(root.GetPrim())
193+
materials_path = "/World/Materials"
194+
UsdGeom.Scope.Define(stage, materials_path)
189195

190196
# If the mesh is a Scene, process each geometry
191197
if isinstance(mesh, trimesh.Scene):
192-
for name, geometry in mesh.geometry.items():
193-
# Create a unique path for each mesh
194-
mesh_path = f"/{name}"
195-
usd_mesh = UsdGeom.Mesh.Define(stage, mesh_path)
198+
for node_name in mesh.graph.nodes:
199+
if node_name == "world":
200+
continue
201+
geom_name = mesh.graph.get(node_name)[1]
202+
if geom_name is not None and geom_name.startswith("mesh"):
203+
print(f"Processing mesh: {node_name} {geom_name}")
204+
# Create a unique path for each mesh
205+
node_path = f"/World/{node_name}"
206+
xform = UsdGeom.Xform.Define(stage, node_path)
207+
# Define the Mesh under the Xform
208+
mesh_path = f"{node_path}/Mesh"
209+
usd_mesh = UsdGeom.Mesh.Define(stage, mesh_path)
210+
# get the geometry of the node
211+
geometry = mesh.geometry[geom_name]
212+
213+
# Create a random color for this mesh
214+
# Using HSV for better color distribution
215+
h = random.random() # Random hue
216+
s = 0.7 + 0.3 * random.random() # Saturation between 0.7-1.0
217+
v = 0.7 + 0.3 * random.random() # Value between 0.7-1.0
218+
r, g, b = colorsys.hsv_to_rgb(h, s, v)
219+
220+
# Create a material with the random color
221+
mat_name = f"{node_name}_material"
222+
mat_path = f"{materials_path}/{mat_name}"
223+
material = UsdShade.Material.Define(stage, mat_path)
224+
225+
# Create shader
226+
shader = UsdShade.Shader.Define(stage, f"{mat_path}/PreviewSurface")
227+
shader.CreateIdAttr("UsdPreviewSurface")
228+
229+
# Set the random color
230+
shader.CreateInput("diffuseColor", Sdf.ValueTypeNames.Color3f).Set(Gf.Vec3f(r, g, b))
231+
shader.CreateInput("roughness", Sdf.ValueTypeNames.Float).Set(0.4)
232+
233+
# Connect shader to material
234+
material_output = material.CreateOutput("surface", Sdf.ValueTypeNames.Token)
235+
shader_output = shader.CreateOutput("surface", Sdf.ValueTypeNames.Token)
236+
material_output.ConnectToSource(shader_output)
237+
238+
# Bind material to mesh
239+
UsdShade.MaterialBindingAPI(usd_mesh).Bind(material)
240+
241+
# Set vertex positions
242+
usd_mesh.GetPointsAttr().Set([Gf.Vec3f(*vertex) for vertex in geometry.vertices])
243+
244+
# Set face indices and counts
245+
face_vertex_indices = geometry.faces.flatten().tolist()
246+
face_vertex_counts = [len(face) for face in geometry.faces]
247+
248+
usd_mesh.GetFaceVertexIndicesAttr().Set(face_vertex_indices)
249+
usd_mesh.GetFaceVertexCountsAttr().Set(face_vertex_counts)
250+
251+
# Optionally, set normals
252+
if geometry.vertex_normals is not None:
253+
usd_mesh.GetNormalsAttr().Set([Gf.Vec3f(*normal) for normal in geometry.vertex_normals])
254+
usd_mesh.SetNormalsInterpolation("vertex")
196255

197-
# Set vertex positions
198-
usd_mesh.GetPointsAttr().Set([Gf.Vec3f(*vertex) for vertex in geometry.vertices])
199-
200-
# Set face indices and counts
201-
face_vertex_indices = geometry.faces.flatten().tolist()
202-
face_vertex_counts = [len(face) for face in geometry.faces]
203-
204-
usd_mesh.GetFaceVertexIndicesAttr().Set(face_vertex_indices)
205-
usd_mesh.GetFaceVertexCountsAttr().Set(face_vertex_counts)
206-
207-
# Optionally, set normals
208-
if geometry.vertex_normals is not None:
209-
usd_mesh.GetNormalsAttr().Set([Gf.Vec3f(*normal) for normal in geometry.vertex_normals])
210-
usd_mesh.SetNormalsInterpolation("vertex")
211-
212-
# Handle materials and other attributes if needed
213256
else:
214257
# It's a single mesh, proceed as before
215258
usd_mesh = UsdGeom.Mesh.Define(stage, "/Mesh")

0 commit comments

Comments
 (0)