• Transform Provider

Transform Path Provider

By: SKY ENGINE AI
scroll down ↓to find out moretransform-path-provider_4_resourcesTutorial

Transform Path Provider Introduction

In this case you will get familiar with a TransformPathProvider.

Agenda:

  • Transform Path Provider introduction
  • Initialize a Transform Path provider with a Transform List
  • Initialize a Transform Path provider with a Cumulative Transform List
  • Create custom Transform Path

Scene setup

Let's use custom scene composer to set up the scene.
Scene consists of:

  • shaderballs - locations will be steered by TransformPathProvider
  • plane - location: (0, 0, 0)
  • camera - location: (7, 7, 7)
    from skyrenderer.cases.utils import TransformPathProviderSceneComposer
    scene_composer = TransformPathProviderSceneComposer()
    scene_composer.setup_scene()
2025-02-05 12:01:46,233 | skyrenderer.scene.renderer_context |  INFO: Root paths:
- root path: /dli/skyenvironment/skyrenderer/skyrenderer
- assets path: /dli/mount/assets
- config path: /dli/skyenvironment/skyrenderer/skyrenderer/config
- gpu sources path: /dli/skyenvironment/skyrenderer/skyrenderer/optix_sources/sources
- cache path: /dli/mount/cache
- ptx cache path: compiled_ptx/ptx
- ocio path: ocio_configs/aces_1.2/config.ocio

Transform Path Provider introduction

Transform Path Provider allows objects allocation on a given curve or line, or a custom list of positions.
Simple Transform Provider draws random values within ranges and if we want to achieve a smooth movement effect
we should use Transform Path Provider.

In order to create a Transform Path Provider we will need an implementation of TransformPath class. We can use
predefined classes like TransformList or CumulativeTransformList, or create our own implementation.

Initialize a Transform Path provider with a Transform List

TransformList is a predefined TransformPath that takes a list of transforms as in input.
We can initialize TransformList in 3 ways: providing full transformation matrices, separate
translation/rotation/scale lists or just values describing one of the dimensions.

Provide full transformations

We will create a list of transformation matrices and pass it to constructor.

    from skyrenderer.basic_types.transform_path.transform_list import TransformList
    from skyrenderer.utils.common import get_transformation_matrix
    translations_list = [(0, 0, 2), (0, 0, 1), (0, 0, 0), (0, 0, -1), (0, 0, -2)]
    transformation_matrices = [get_transformation_matrix(translation=translation) for translation in translations_list]
    transform_list = TransformList(transformation_matrices)

Provide x, y, z translations

    transform_list = TransformList.from_translation_rotation_scale(translations_list)

Provide z translations

    z_list = [2, 1, 0, -1, -2]
    transform_list = TransformList.from_translation_rotation_scale_per_axis(translation_z_list=z_list)

Each of the examples above will have the same effect.
Let's visualize frames 0, 1 and 3 which correspond to the locations defined above.

    from skyrenderer.basic_types.provider.transform_providers.transform_path_provider import TransformPathProvider
    transform_path_provider = TransformPathProvider(scene_composer.renderer_context, transform_list)
    scene_composer.renderer_context.layout().get_node("shaderball_GEO").modify_locus_definition(
        transform_provider=transform_path_provider
    )
    render_dict = {
        "Frame 0": scene_composer.get_render(0),
        "Frame 1": scene_composer.get_render(1),
        "Frame 3": scene_composer.get_render(3),
    }
    scene_composer.visualize_grid_desc(render_dict, (500, 1500), 3)
transform-path-provider_1_resourcesTutorial
2025-02-05 12:01:46,733 | skyrenderer.utils.time_measurement |  INFO: Setup time: 435 ms

2025-02-05 12:01:49,448 | skyrenderer.utils.time_measurement |  INFO: Context update time: 2.71 seconds

2025-02-05 12:01:51,191 | skyrenderer.utils.time_measurement |  INFO: Key points calculation time: 0 ms

2025-02-05 12:01:51,191 | skyrenderer.utils.time_measurement |  INFO: Render time: 1.74 seconds

2025-02-05 12:01:51,249 | skyrenderer.utils.time_measurement |  INFO: Setup time: 50 ms

2025-02-05 12:01:54,109 | skyrenderer.utils.time_measurement |  INFO: Context update time: 2.86 seconds

2025-02-05 12:01:56,364 | skyrenderer.utils.time_measurement |  INFO: Key points calculation time: 0 ms

2025-02-05 12:01:56,365 | skyrenderer.utils.time_measurement |  INFO: Render time: 2.26 seconds

2025-02-05 12:01:56,416 | skyrenderer.utils.time_measurement |  INFO: Setup time: 47 ms

2025-02-05 12:01:59,283 | skyrenderer.utils.time_measurement |  INFO: Context update time: 2.87 seconds

2025-02-05 12:02:01,343 | skyrenderer.utils.time_measurement |  INFO: Key points calculation time: 0 ms

2025-02-05 12:02:01,344 | skyrenderer.utils.time_measurement |  INFO: Render time: 2.06 seconds

Initialize a Transform Path provider with a Cumulative Transform List

We initialized TransformList using a defined locations, in case of CumulativeTransformList we will provide
the changes in transformations that will be accumulated in the next frames.
We will use a list of transformation matrices, but it is also possible to use translation list or a list of
one-dimensional values, like in a previous example.

    from skyrenderer.basic_types.transform_path.cumulative_transform_list import CumulativeTransformList
    changes_in_translations = [get_transformation_matrix(translation=[0, 0, -1]) for _ in range(5)]
    transform_path = CumulativeTransformList(changes_in_translations)
    transform_path_provider = TransformPathProvider(scene_composer.renderer_context, transform_path)
    scene_composer.renderer_context.layout().get_node("shaderball_GEO").modify_locus_definition(
        transform_provider=transform_path_provider
    )
    render_dict = {
        "Cumul: Frame 0": scene_composer.get_render(0),
        "Cumul: Frame 1": scene_composer.get_render(1),
        "Cumul: Frame 2": scene_composer.get_render(2),
    }
    scene_composer.visualize_grid_desc(render_dict, (500, 1500), 3)
transform-path-provider_2_resourcesTutorial
2025-02-05 12:02:01,766 | skyrenderer.utils.time_measurement |  INFO: Setup time: 48 ms

2025-02-05 12:02:04,626 | skyrenderer.utils.time_measurement |  INFO: Context update time: 2.86 seconds

2025-02-05 12:02:06,010 | skyrenderer.utils.time_measurement |  INFO: Key points calculation time: 0 ms

2025-02-05 12:02:06,011 | skyrenderer.utils.time_measurement |  INFO: Render time: 1.38 seconds

2025-02-05 12:02:06,061 | skyrenderer.utils.time_measurement |  INFO: Setup time: 46 ms

2025-02-05 12:02:08,922 | skyrenderer.utils.time_measurement |  INFO: Context update time: 2.86 seconds

2025-02-05 12:02:11,081 | skyrenderer.utils.time_measurement |  INFO: Key points calculation time: 0 ms

2025-02-05 12:02:11,081 | skyrenderer.utils.time_measurement |  INFO: Render time: 2.16 seconds

2025-02-05 12:02:11,131 | skyrenderer.utils.time_measurement |  INFO: Setup time: 46 ms

2025-02-05 12:02:13,859 | skyrenderer.utils.time_measurement |  INFO: Context update time: 2.73 seconds

2025-02-05 12:02:15,957 | skyrenderer.utils.time_measurement |  INFO: Key points calculation time: 0 ms

2025-02-05 12:02:15,958 | skyrenderer.utils.time_measurement |  INFO: Render time: 2.10 seconds

Create custom Transform Path

We need to create a class that inherits TransformPath and implements 2 methods: __len__(self) and
_get_transform(self, index). Index parameter will be limited by the path length. _get_transform will return
z-axis position equal to the negative index value.

    from skyrenderer.basic_types.transform_path.transform_path import TransformPath
    class CustomSimpleTransformPath(TransformPath):
        def __len__(self):
            return 3

        def _get_transform(self, index):
            return get_transformation_matrix(translation=[0, 0, -index])
    custom_path_provider = TransformPathProvider(scene_composer.renderer_context, CustomSimpleTransformPath())
    scene_composer.renderer_context.layout().get_node("shaderball_GEO").modify_locus_definition(
        transform_provider=custom_path_provider
    )
    render_dict = {
        "Custom - Frame 0": scene_composer.get_render(0),
        "Custom - Frame 1": scene_composer.get_render(1),
        "Custom - Frame 2": scene_composer.get_render(2),
    }
    scene_composer.visualize_grid_desc(render_dict, (500, 1500), 3)
transform-path-provider_3_resourcesTutorial
2025-02-05 12:02:16,376 | skyrenderer.utils.time_measurement |  INFO: Setup time: 47 ms

2025-02-05 12:02:19,302 | skyrenderer.utils.time_measurement |  INFO: Context update time: 2.93 seconds

2025-02-05 12:02:20,777 | skyrenderer.utils.time_measurement |  INFO: Key points calculation time: 0 ms

2025-02-05 12:02:20,778 | skyrenderer.utils.time_measurement |  INFO: Render time: 1.47 seconds

2025-02-05 12:02:20,828 | skyrenderer.utils.time_measurement |  INFO: Setup time: 47 ms

2025-02-05 12:02:23,582 | skyrenderer.utils.time_measurement |  INFO: Context update time: 2.75 seconds

2025-02-05 12:02:25,690 | skyrenderer.utils.time_measurement |  INFO: Key points calculation time: 0 ms

2025-02-05 12:02:25,691 | skyrenderer.utils.time_measurement |  INFO: Render time: 2.11 seconds

2025-02-05 12:02:25,742 | skyrenderer.utils.time_measurement |  INFO: Setup time: 47 ms

2025-02-05 12:02:28,547 | skyrenderer.utils.time_measurement |  INFO: Context update time: 2.80 seconds

2025-02-05 12:02:29,904 | skyrenderer.utils.time_measurement |  INFO: Key points calculation time: 0 ms

2025-02-05 12:02:29,906 | skyrenderer.utils.time_measurement |  INFO: Render time: 1.36 seconds

If the frame number exceeds 3 (length of the transform_list) we simply loop back to the first transformation

    render_dict = {
        "Custom - Frame 1": scene_composer.get_render(1),
        "Custom - Frame 2": scene_composer.get_render(2),
        "Custom - Frame 3": scene_composer.get_render(3),
    }
    scene_composer.visualize_grid_desc(render_dict, (500, 1500), 3)
transform-path-provider_4_resourcesTutorial
2025-02-05 12:02:30,310 | skyrenderer.utils.time_measurement |  INFO: Setup time: 48 ms

2025-02-05 12:02:33,196 | skyrenderer.utils.time_measurement |  INFO: Context update time: 2.88 seconds

2025-02-05 12:02:34,771 | skyrenderer.utils.time_measurement |  INFO: Key points calculation time: 0 ms

2025-02-05 12:02:34,772 | skyrenderer.utils.time_measurement |  INFO: Render time: 1.58 seconds

2025-02-05 12:02:34,823 | skyrenderer.utils.time_measurement |  INFO: Setup time: 47 ms

2025-02-05 12:02:37,640 | skyrenderer.utils.time_measurement |  INFO: Context update time: 2.82 seconds

2025-02-05 12:02:39,682 | skyrenderer.utils.time_measurement |  INFO: Key points calculation time: 0 ms

2025-02-05 12:02:39,684 | skyrenderer.utils.time_measurement |  INFO: Render time: 2.04 seconds

2025-02-05 12:02:39,735 | skyrenderer.utils.time_measurement |  INFO: Setup time: 47 ms

2025-02-05 12:02:42,692 | skyrenderer.utils.time_measurement |  INFO: Context update time: 2.96 seconds

2025-02-05 12:02:44,922 | skyrenderer.utils.time_measurement |  INFO: Key points calculation time: 0 ms

2025-02-05 12:02:44,922 | skyrenderer.utils.time_measurement |  INFO: Render time: 2.23 seconds

Summary

In this section you have learnt:

  • We can move objects on a curve or line using Transform Path Provider.
  • We can use two predefined transform paths - Transform List or Cumulative Transform List.
  • If the predefined classes are not enough, we can create a custom implementation of Transform Path.