Python Usage Examples

# Copyright (c) 2021-2022, NVIDIA CORPORATION.  All rights reserved.
#
# NVIDIA CORPORATION and its licensors retain all intellectual property
# and proprietary rights in and to this software, related documentation
# and any modifications thereto.  Any use, reproduction, diui.scenelosure or
# distribution of this software and related documentation without an express
# license agreement from NVIDIA CORPORATION is strictly prohibited.
#

__all__ = ['SimpleWindow']

import omni.ui as ui
from pxr import Gf
from omni.kit.manipulator.camera.manipulator import CameraManipulatorBase, SceneViewCameraManipulator, adjust_center_of_interest


def _flatten_matrix(matrix: Gf.Matrix4d):
    return [matrix[0][0], matrix[0][1], matrix[0][2], matrix[0][3],
            matrix[1][0], matrix[1][1], matrix[1][2], matrix[1][3],
            matrix[2][0], matrix[2][1], matrix[2][2], matrix[2][3],
            matrix[3][0], matrix[3][1], matrix[3][2], matrix[3][3]]


class SimpleGrid():
    def __init__(self, lineCount: float = 100, lineStep: float = 10, thicknes: float = 1, color: ui.color = ui.color(0.25)):
        self.__transform = ui.scene.Transform()
        with self.__transform:
            for i in range(lineCount * 2 + 1):
                ui.scene.Line(
                    ((i - lineCount) * lineStep, 0, -lineCount * lineStep),
                    ((i - lineCount) * lineStep, 0, lineCount * lineStep),
                    color=color, thickness=thicknes,
                )
                ui.scene.Line(
                    (-lineCount * lineStep, 0, (i - lineCount) * lineStep),
                    (lineCount * lineStep, 0, (i - lineCount) * lineStep),
                    color=color, thickness=thicknes,
                )


class SimpleOrigin():
    def __init__(self, length: float = 5, thickness: float = 4):
        origin = (0, 0, 0)
        with ui.scene.Transform():
            ui.scene.Line(origin, (length, 0, 0), color=ui.color.red, thickness=thickness)
            ui.scene.Line(origin, (0, length, 0), color=ui.color.green, thickness=thickness)
            ui.scene.Line(origin, (0, 0, length), color=ui.color.blue, thickness=thickness)


# Create a few scenes with different camera-maniupulators (a general ui.scene manip and one that allows ortho-tumble )
class SimpleScene:
    def __init__(self, custom: bool = False, ortho: bool = False, *args, **kwargs):
        self.__scene_view = ui.scene.SceneView(*args, **kwargs)
        if ortho:
            view = [-1.0, -2.719262146893781e-32, -1.224646799147353e-16, 0.0, -1.2246467991473532e-16, 2.220446049250312e-16, 0.9999999999999998, 0.0, 0.0, 0.9999999999999998, -2.220446049250312e-16, 0.0, 0, 0, -2000, 1.0]
            projection = [0.0022443845736905463, 0.0, 0.0, 0.0, 0.0, 0.004, 0.0, 0.0, 0.0, 0.0, -2.000002000002e-06, 0.0, -0.0, -0.0, -1.000002000002, 1.0]
        else:
            view = [0.7071067811865476, -0.40557978767263897, 0.5792279653395693, 0.0, -2.775557561562892e-17, 0.8191520442889919, 0.5735764363510462, 0.0, -0.7071067811865477, -0.4055797876726389, 0.5792279653395692, 0.0, 6.838973831690966e-14, -3.996234471857009, -866.0161835150924, 1.0000000000000002]
            projection = [4.7602203407949375, 0.0, 0.0, 0.0, 0.0, 8.483787309173106, 0.0, 0.0, 0.0, 0.0, -1.000002000002, -1.0, 0.0, 0.0, -2.000002000002, 0.0]

        view = Gf.Matrix4d(*view)
        center_of_interest = [0, 0, -view.Transform((0, 0, 0)).GetLength()]
        with self.__scene_view.scene:
            self.items = [SimpleGrid(), ui.scene.Arc(100, axis=1, wireframe=True), SimpleOrigin()]

            if custom:
                self.items.append(CameraManipulatorBase())
            else:
                self.items.append(SceneViewCameraManipulator(center_of_interest))

        # Push the start values into the CameraManipulator
        self.setup_camera_model(self.items[-1].model, view, projection, center_of_interest, ortho)

    def setup_camera_model(self, cam_model, view, projection, center_of_interest, ortho):
        cam_model.set_floats('transform', _flatten_matrix(view.GetInverse()))
        cam_model.set_floats('projection', projection)
        cam_model.set_floats('center_of_interest', [0, 0, -view.Transform((0, 0, 0)).GetLength()])
        if ortho:
            cam_model.set_ints('orthographic', [ortho])

        # Setup up the subscription to the CameraModel so changes here get pushed to SceneView
        self.model_changed_sub = cam_model.subscribe_item_changed_fn(self.model_changed)
        # And pusht the view and projection into the SceneView.model
        cam_model._item_changed(cam_model.get_item('transform'))
        cam_model._item_changed(cam_model.get_item('projection'))

    def model_changed(self, model, item):
        if item == model.get_item('transform'):
            transform = Gf.Matrix4d(*model.get_as_floats(item))
            # Signal that this this is the final change block, adjust our center-of-interest then
            interaction_ended = model.get_as_ints('interaction_ended')
            if interaction_ended and interaction_ended[0]:
                transform = Gf.Matrix4d(*model.get_as_floats(item))
                # Adjust the center-of-interest if requested (zoom out in perspective does this)
                initial_transform = Gf.Matrix4d(*model.get_as_floats('initial_transform'))
                coi_start, coi_end = adjust_center_of_interest(model, initial_transform, transform)
                if coi_end:
                    model.set_floats('center_of_interest', [coi_end[0], coi_end[1], coi_end[2]])

            # Push the start values into the SceneView
            self.__scene_view.model.set_floats('view', _flatten_matrix(transform.GetInverse()))
        elif item == model.get_item('projection'):
            self.__scene_view.model.set_floats('projection', model.get_as_floats('projection'))


class SimpleWindow(ui.Window):
    def __init__(self, name: str, custom=False, ortho: bool = False):
        super().__init__(f'{name} Camera Manipulator', width=640, height=480 + 20, flags=ui.WINDOW_FLAGS_NO_SCROLLBAR)
        self.frame.set_style({"Window": {"background_color": 0xff000000}})
        with self.frame:
            self.__scene_view = SimpleScene(custom, ortho)

    def destroy(self):
        if self.__scene_view:
            self.__scene_view.destroy()
        super().destroy()


persp_win = SimpleWindow('Perspective')
ortho_win = SimpleWindow('Orthographic', ortho=True)
ortho_custom_win = SimpleWindow('Custom  Orthographic', custom=True, ortho=True)