• Intro

Scene Layout

By: SKY ENGINE AI
scroll down ↓to find out morescene-layout_3_resourcesTutorial

Scene Layout Introduction

In this case you will get understanding of scene layout in SkyRenderer. You will learn about the scene tree and
how to create nodes in order to place geometry in 3D space. You will get a sample code with most common
functionalities related to manipulating scene nodes, scene tree and layout.

Agenda:

  • Scene tree hierarchy
  • SceneLayout and SceneLayoutNode
  • SceneTree and SceneNode
  • Example usage

Scene tree hierarchy

All elements placed in 3D space have their own transformation that specifies object's position and orientation in
3D space. For a reminder about coordinate space and object placement in the aforementioned space, check out
INTRO_CoordinateSpace tutorial.

In some cases, it is convenient to have several objects clustered into one group, and have these objects parented
to other object in order to have their transformation relative to the parent. Because of that, it is common in 3D
software to have objects stored in the tree hierarchy instead of the flat hierarchy container. In SkyRenderer, the
hierarchy of the objects on the scene with actual objects definitions is stored first in SceneLayout, then it is
moved to SceneTree upon scene setup.

SceneLayout and SceneLayoutNode

All objects are stored before setup in tree hierarchy called SceneLayout. Each node of the SceneLayout tree is
called SceneLayoutNode and in those nodes we can add new geometry. In the typical workflow, whenever we add any
object to the scene (e.g. geometry, light or camera), first we create new SceneLayoutNode for our object, then we
load the object and place it in the specific node.
Please note that if we want to place the object in already existing node, we can skip the node creation step.

Note: Every object have to be bound to a node (there cannot be an object without a node), but a node can have
multiple objects attached!

SceneTree and SceneNode

After the setup methods is called on the renderer context, all information from SceneLayout is moved into
SceneTree. Based on the existing SceneLayoutNodes, the nodes called SceneNode are created. They contain copied
data from corresponding SceneLayoutNode nodes.

Example usage

Creating a SceneLayoutNode

First, let's initialize the necessary objects to create the scene:

from skyrenderer.cases.utils import SceneLayoutSceneComposer scene_composer = SceneLayoutSceneComposer()
2025-02-04 14:39:13,623 | 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

The SceneLayout is right now empty. We can print it, it will contain only the root node called "top_node". To
see it, we will print the current state of the SceneLayout.

Note: The SceneLayout can be accessed via layout() method in renderer context.

renderer_context = scene_composer.renderer_context print(f"{renderer_context.layout()}")
top_node

In order to place any object into the scene in SkyRenderer, we will need a scene node. To add the node we call
add_node method from renderer_context:

renderer_context.add_node("plane_NUL") scene_composer.add_plane("plane_NUL") print(f"{renderer_context.layout()}")
top_node +-- plane_NUL

Now our plane_NUL locator node is present in the node tree hierarchy. In order to render the scene we have to add
another two nodes: node for the camera and for its target.
This time, we will create nodes with a specific location. Transformations in SceneLayoutNode is stored in
LocusDefinition and on the setup they are transformed into Locus in SceneNode, so we need to pass appropriate
LocusDefinition to add_node function:

from skyrenderer.scene.scene_layout.layout_elements_definitions import LocusDefinition from skyrenderer.basic_types.locus.transform import Transform renderer_context.add_node( "camera_CAM_NUL", locus_def=LocusDefinition(transform=Transform(translation_vector=[4, 4, 4])) ) renderer_context.add_node( "camera_target_NUL", locus_def=LocusDefinition(transform=Transform(translation_vector=[0, 0, 0])) ) print(f"{renderer_context.layout()}")
top_node |-- plane_NUL |-- camera_CAM_NUL +-- camera_target_NUL

We properly added plane geometry in created node and the camera, so now render will show our plane:

scene_composer.setup_scene(camera_node_name="camera_CAM_NUL", target_node_name="camera_target_NUL") scene_composer.visualize(scene_composer.get_render())
scene-layout_1_resourcesTutorial
2025-02-04 14:39:14,088 | skyrenderer.utils.time_measurement | INFO: Setup time: 398 ms 2025-02-04 14:39:14,219 | skyrenderer.utils.time_measurement | INFO: Context update time: 130 ms 2025-02-04 14:39:16,876 | skyrenderer.utils.time_measurement | INFO: Key points calculation time: 0 ms 2025-02-04 14:39:16,877 | skyrenderer.utils.time_measurement | INFO: Render time: 2.66 seconds

Now let's add four spheres representing coord axes to the scene. We can add a new node for this:

renderer_context.add_node("coord_NUL", locus_def=LocusDefinition(transform=Transform(translation_vector=[0, 1, 0]))) scene_composer.add_coord_axes_spheres("coord_NUL") print(f"{renderer_context.layout()}")
top_node |-- plane_NUL |-- camera_CAM_NUL |-- camera_target_NUL +-- coord_NUL |-- sphere_center_GEO_NUL | +-- sphere_center_GEO |-- sphere_x_GEO_NUL | +-- sphere_x_GEO |-- sphere_y_GEO_NUL | +-- sphere_y_GEO +-- sphere_z_GEO_NUL +-- sphere_z_GEO

Render will now consist of previously added plane and 4 spheres with center in [0, 1, 0]:

scene_composer.visualize(scene_composer.get_render())
scene-layout_2_resourcesTutorial
2025-02-04 14:39:17,423 | skyrenderer.utils.time_measurement | INFO: Setup time: 71 ms 2025-02-04 14:39:17,544 | skyrenderer.utils.time_measurement | INFO: Context update time: 121 ms 2025-02-04 14:39:20,029 | skyrenderer.utils.time_measurement | INFO: Key points calculation time: 0 ms 2025-02-04 14:39:20,030 | skyrenderer.utils.time_measurement | INFO: Render time: 2.48 seconds

Another operation commonly performed on the scene layout is duplicating the whole subtree:

renderer_context.layout().duplicate_subtree(renderer_context, "coord_NUL", suffix="duplicated") print(f"{renderer_context.layout()}")
top_node |-- plane_NUL |-- camera_CAM_NUL |-- camera_target_NUL |-- coord_NUL | |-- sphere_center_GEO_NUL | | +-- sphere_center_GEO | |-- sphere_x_GEO_NUL | | +-- sphere_x_GEO | |-- sphere_y_GEO_NUL | | +-- sphere_y_GEO | +-- sphere_z_GEO_NUL | +-- sphere_z_GEO +-- coord_NUL_duplicated |-- sphere_center_GEO_NUL_duplicated | +-- sphere_center_GEO_duplicated |-- sphere_x_GEO_NUL_duplicated | +-- sphere_x_GEO_duplicated |-- sphere_y_GEO_NUL_duplicated | +-- sphere_y_GEO_duplicated +-- sphere_z_GEO_NUL_duplicated +-- sphere_z_GEO_duplicated

All nodes in the subtree starting with coord_NUL were duplicated with a proper suffix.
We will move the subtree so that both will be visible on the render.
To get the node to perform operations on it, you can use get_node function in SceneLayout.

renderer_context.layout().get_node("coord_NUL_duplicated").translation = [3, 1, 0] scene_composer.visualize(scene_composer.get_render())
scene-layout_3_resourcesTutorial
2025-02-04 14:39:20,565 | skyrenderer.utils.time_measurement | INFO: Setup time: 75 ms 2025-02-04 14:39:20,702 | skyrenderer.utils.time_measurement | INFO: Context update time: 137 ms 2025-02-04 14:39:23,222 | skyrenderer.utils.time_measurement | INFO: Key points calculation time: 0 ms 2025-02-04 14:39:23,223 | skyrenderer.utils.time_measurement | INFO: Render time: 2.52 seconds

To remove a subtree in the SceneLayout, we can use remove_subtree method in SceneLayout.

renderer_context.layout().remove_subtree("plane_NUL") scene_composer.visualize(scene_composer.get_render())
scene-layout_4_resourcesTutorial
2025-02-04 14:39:23,871 | skyrenderer.utils.time_measurement | INFO: Setup time: 198 ms 2025-02-04 14:39:23,979 | skyrenderer.utils.time_measurement | INFO: Context update time: 108 ms 2025-02-04 14:39:25,766 | skyrenderer.utils.time_measurement | INFO: Key points calculation time: 0 ms 2025-02-04 14:39:25,768 | skyrenderer.utils.time_measurement | INFO: Render time: 1.79 seconds

Summary

In this section you have learnt:

  • Scene Layout Tree is used in SkyRenderer to store information about scene's elements.
  • There are methods enabling to access in RendererContext scene tree and perform on its elements operations like
    duplication, removal and change of transformations.