• Randomization

Randomization Advanced Distribution

By: SKY ENGINE AI
scroll down ↓to find out morerandomization-advanced-distribution_6_resourcesTutorial

Randomization - Advanced Distribution

In this section you will get to know various Distribution tricks.

Agenda:

  • Passing Distributions into a Transform Provider
  • Practical control of Gaussian params
  • Modifying other existing Transform Providers
  • Custom plot-based Distributions
  • Random Gaussian use case
  • Custom Distribution trickery

Scene setup

Let's use custom scene composer to set up the scene.

    from skyrenderer.cases.utils import RandomizationAdvancedDistributionSceneComposer
    scene_composer = RandomizationAdvancedDistributionSceneComposer(antialiasing_level=64)
    scene_composer.setup_scene()
    scene_composer.visualize()
    rc = scene_composer.renderer_context
randomization-advanced-distribution_1_resourcesTutorial
2025-02-20 15:22:57,901 | skyrenderer.scene.renderer_context |  INFO: Root paths:
- root path: /home/skyengine/anaconda/lib/python3.6/site-packages/skyrenderer
- assets path: /dli/mount/assets
- config path: /home/skyengine/anaconda/lib/python3.6/site-packages/skyrenderer/config
- gpu sources path: /home/skyengine/anaconda/lib/python3.6/site-packages/skyrenderer/optix_sources/sources
- cache path: /dli/mount/cache
- ptx cache path: compiled_ptx/ptx
- ocio path: ocio_configs/aces_1.2/config.ocio

2025-02-20 15:22:58,446 | skyrenderer.basic_types.provider.unit_providers.hdr_texture_provider |  WARNING: Parameter light_adapt provided in HDR json is not supported

2025-02-20 15:22:58,447 | skyrenderer.basic_types.provider.unit_providers.hdr_texture_provider |  WARNING: Parameter color_adapt provided in HDR json is not supported

2025-02-20 15:22:58,448 | skyrenderer.scene.renderer_context |  WARNING: Light with light_id=back_LIGHT_NUL already exists in the scene and will be replace with a new one.There can only be a single light for a single node.

2025-02-20 15:22:58,448 | skyrenderer.scene.renderer_context |  WARNING: Light with light_id=front_LIGHT_NUL already exists in the scene and will be replace with a new one.There can only be a single light for a single node.

2025-02-20 15:22:58,449 | skyrenderer.scene.renderer_context |  WARNING: Light with light_id=moon_LIGHT_NUL already exists in the scene and will be replace with a new one.There can only be a single light for a single node.

2025-02-20 15:23:01,853 | skyrenderer.utils.time_measurement |  INFO: Setup time: 3.40 seconds

2025-02-20 15:23:02,184 | skyrenderer.utils.time_measurement |  INFO: Setup time: 327 ms

2025-02-20 15:23:03,241 | skyrenderer.utils.time_measurement |  INFO: Context update time: 1.06 seconds

2025-02-20 15:23:32,431 | skyrenderer.utils.time_measurement |  INFO: Key points calculation time: 0 ms

2025-02-20 15:23:32,432 | skyrenderer.utils.time_measurement |  INFO: Render time: 29.19 seconds

In our initial scene we can see an alley between two office buildings. There is a single firefly floating in the
middle (that lone yellow pixel, 1/3 from the bottom and 1/3 from the right edge). His name is Fred. He has the
following coordinates in meters:

    cx = -14.401  # negative x is deeper into the alley, front face of the left building is at -4.5
    cy = 6.0256  # positive y is vertically upwards, roof of the left building is at +11
    cz = 0.98872  # z is horizontal between the buildings, left facade is at +3.5, right at -1.5
    center = (cx, cy, cz)
    fred = rc.layout().get_node("firefly_GEO_NUL")
    fred_geometry = "firefly_GEO"

Passing Distributions into a Transform Provider

Fred has organized a meetup for his friends in this particular spot because there are many nice reflective windows
around, which allows everyone to show off their evening glow.

Fred's friends have arrived:

    fred.n_instances = 500

They all want to greet Fred, so they queued up.

    from skyrenderer.basic_types.provider import SimpleTransformProvider
    from skyrenderer.randomization.strategy import DrawingStrategy, UniformRandomInput, RelativeGaussianRandomInput
    def greet_fred():
        fred.modify_locus_definition(
            transform_provider=SimpleTransformProvider(
                rc,
                translation_range_x=(cx, cx + 15),
                translation_range_y=(cy, cy),
                translation_range_z=(cz - 2, cz + 2),
            ),
            strategy=DrawingStrategy(
                rc,
                inputs_strategies={
                    "translation_x": UniformRandomInput(),
                    "translation_z": RelativeGaussianRandomInput(relative_mu=0.5, relative_sigma=0.02),
                },
            ),
        )
    greet_fred()
    scene_composer.visualize()
randomization-advanced-distribution_2_resourcesTutorial
2025-02-20 15:23:34,096 | skyrenderer.utils.time_measurement |  INFO: Setup time: 843 ms

2025-02-20 15:23:36,505 | skyrenderer.utils.time_measurement |  INFO: Context update time: 2.41 seconds

2025-02-20 15:24:07,695 | skyrenderer.utils.time_measurement |  INFO: Key points calculation time: 0 ms

2025-02-20 15:24:07,695 | skyrenderer.utils.time_measurement |  INFO: Render time: 31.19 seconds

For the courteous beginning of the party they want to be evenly spaced out to be able to mingle properly. Time for
really spacing out will come later. Let's define an aquarium-shaped volume within which the fireflies are
allowed to move about.

    rx = 10.65  # +/- range in meters, so in this case from (-14.401 - 10.65 = -25.051) to (-14.401 + 10.65 = -3.751)
    ry = 3.64
    rz = 2.3
    uniform = UniformRandomInput()
    def disperse():
        fred.modify_locus_definition(
            transform_provider=SimpleTransformProvider(
                rc,
                translation_range_x=(cx - rx, cx + rx),
                translation_range_y=(cy - ry, cy + ry),
                translation_range_z=(cz - rz, cz + rz),
            ),
            strategy=DrawingStrategy(
                rc,
                inputs_strategies={
                    "translation_x": uniform,
                    "translation_y": uniform,
                    "translation_z": uniform,
                },
            ),
        )
    disperse()
    scene_composer.visualize()
randomization-advanced-distribution_3_resourcesTutorial
2025-02-20 15:24:09,432 | skyrenderer.utils.time_measurement |  INFO: Setup time: 921 ms

2025-02-20 15:24:11,848 | skyrenderer.utils.time_measurement |  INFO: Context update time: 2.42 seconds

2025-02-20 15:24:42,964 | skyrenderer.utils.time_measurement |  INFO: Key points calculation time: 0 ms

2025-02-20 15:24:42,965 | skyrenderer.utils.time_measurement |  INFO: Render time: 31.12 seconds

Practical control of Gaussian params

Turns out one firefly is Elon's cousin - Felon. Everyone suddenly wants a selfie with him, but Felon is an
introvert, just like Elon, so he tries to hide in the corner. Now Fred's friends' hyped friends joined the party
and everyone piles up on Felon.

    fred.n_instances = 2000
    front_of_depth_gauss = RelativeGaussianRandomInput(relative_mu=1, relative_sigma=0.1)
    mid_of_height_gauss = RelativeGaussianRandomInput(relative_mu=0.5, relative_sigma=0.2)
    left_of_width_gauss = RelativeGaussianRandomInput(relative_mu=1, relative_sigma=0.2)
    def pile():
        fred.modify_locus_definition(
            transform_provider=SimpleTransformProvider(
                rc,
                translation_range_x=(cx - rx, cx + rx),
                translation_range_y=(cy - ry, cy + ry),
                translation_range_z=(cz - rz, cz + rz),
            ),
            strategy=DrawingStrategy(
                rc,
                inputs_strategies={
                    "translation_x": front_of_depth_gauss,  # end of x range is the alley entrance
                    "translation_y": mid_of_height_gauss,  # poor Felon is trapped by the crowd from above and below
                    "translation_z": left_of_width_gauss,  # end of z range is the left facade
                },
            ),
        )
    pile()
    scene_composer.visualize()
randomization-advanced-distribution_4_resourcesTutorial
2025-02-20 15:24:43,780 | skyrenderer.basic_types.provider.iprovider |  WARNING: Provider for this config has been already initialized! There should be just one Provider created per unit source, consider fixing the scene.
Config:
{'translation_range_x': (-25.051000000000002, -3.7509999999999994), 'translation_range_y': (2.3855999999999997, 9.6656), 'translation_range_z': (-1.3112799999999998, 3.2887199999999996), 'rotation_range_x': (0.0, 0.0), 'rotation_range_y': (0.0, 0.0), 'rotation_range_z': (0.0, 0.0), 'scale_range_x': (1, 1), 'scale_range_y': (1, 1), 'scale_range_z': (1, 1), 'number_of_steps': 1000}

2025-02-20 15:24:47,126 | skyrenderer.utils.time_measurement |  INFO: Setup time: 3.34 seconds

2025-02-20 15:24:53,693 | skyrenderer.utils.time_measurement |  INFO: Context update time: 6.57 seconds

2025-02-20 15:25:24,434 | skyrenderer.utils.time_measurement |  INFO: Key points calculation time: 1 ms

2025-02-20 15:25:24,435 | skyrenderer.utils.time_measurement |  INFO: Render time: 30.74 seconds

Modifying other existing Transform Providers

To rescue Felon, Fred recruits Fiona to give a keynote speech about success and work-life balance. All guests are
asked to gather around.

    from skyrenderer.basic_types.provider.transform_providers.ball_transform_provider import BallTransformProvider
    def around():
        fred.modify_locus_definition(transform_provider=BallTransformProvider(rc, radius=rz, center=(cx + 5, cy, cz)))
    around()
    scene_composer.visualize()
randomization-advanced-distribution_5_resourcesTutorial
2025-02-20 15:25:28,706 | skyrenderer.utils.time_measurement |  INFO: Setup time: 3.45 seconds

2025-02-20 15:25:34,861 | skyrenderer.utils.time_measurement |  INFO: Context update time: 6.15 seconds

2025-02-20 15:26:05,783 | skyrenderer.utils.time_measurement |  INFO: Key points calculation time: 1 ms

2025-02-20 15:26:05,784 | skyrenderer.utils.time_measurement |  INFO: Render time: 30.92 seconds

Fiona tells the crowd that while it's nice to feel like a supernova, it'd be better for them to back up some, so
everyone can have a chance to see and hear her.

    def around_away():
        fred.modify_locus_definition(
            transform_provider=BallTransformProvider(rc, radius=rz, center=(cx + 5, cy, cz)),
            strategy=DrawingStrategy(
                rc,
                inputs_strategies={
                    "radius": RelativeGaussianRandomInput(
                        # we are affecting the internal "radius" param of the BallTransformProvider,
                        # which controls how far from the center the positions are drawn
                        relative_mu=1,  # 0~1 range represents from center to ball surface
                        relative_sigma=0.1,  # we want the guests packed somewhat tightly at ~equal distance from Fiona
                    )
                },
            ),
        )
    around_away()
    scene_composer.visualize()
randomization-advanced-distribution_6_resourcesTutorial
2025-02-20 15:26:06,604 | skyrenderer.basic_types.provider.iprovider |  WARNING: Provider for this config has been already initialized! There should be just one Provider created per unit source, consider fixing the scene.
Config:
{'center': (-9.401, 6.0256, 0.98872), 'radius': 2.3, 'number_of_points': 1000000}

2025-02-20 15:26:10,290 | skyrenderer.utils.time_measurement |  INFO: Setup time: 3.69 seconds

2025-02-20 15:26:16,177 | skyrenderer.utils.time_measurement |  INFO: Context update time: 5.89 seconds

2025-02-20 15:26:47,868 | skyrenderer.utils.time_measurement |  INFO: Key points calculation time: 1 ms

2025-02-20 15:26:47,869 | skyrenderer.utils.time_measurement |  INFO: Render time: 31.69 seconds

Custom plot-based Distributions

After the keynote, fireflies took a drink break and flocked to two opposite bars: cocktails on the left and
pumpkin spice soy latte decaf with stevia on the right. That's right, the right one serves precisely only that.

    def two_sides(x):
        # Create any continuous plot in the square between 0,0 and 1,1 - it will become your distribution.
        # In this example we will use: y=(2x-1)^4
        return (2 * x - 1) ** 4
        # https://www.desmos.com/calculator/v3x50bgtwb
    from skyrenderer.randomization.strategy import ProbabilityShapeFunctionRandomInput
    def sides():
        fred.modify_locus_definition(
            transform_provider=SimpleTransformProvider(
                rc,
                translation_range_x=(cx + rx - 3, cx + rx),
                translation_range_y=(cy - ry, cy + ry),
                translation_range_z=(cz - rz, cz + rz),
            ),
            strategy=DrawingStrategy(
                rc,
                inputs_strategies={
                    "translation_x": uniform,
                    "translation_y": mid_of_height_gauss,  # bars are near the middle, that's why Felon stayed nearby
                    "translation_z": ProbabilityShapeFunctionRandomInput(two_sides),  # see func definition above
                },
            ),
        )
    sides()
    scene_composer.visualize()
randomization-advanced-distribution_7_resourcesTutorial
2025-02-20 15:26:52,808 | skyrenderer.utils.time_measurement |  INFO: Setup time: 4.11 seconds

2025-02-20 15:26:59,417 | skyrenderer.utils.time_measurement |  INFO: Context update time: 6.61 seconds

2025-02-20 15:27:30,392 | skyrenderer.utils.time_measurement |  INFO: Key points calculation time: 1 ms

2025-02-20 15:27:30,393 | skyrenderer.utils.time_measurement |  INFO: Render time: 30.98 seconds

As they got buzzed, the guests decided they no longer need to be politically correct, so they went on to join
their respective groups of self-perceived social status.

    import math
    def four_levels(x):
        # In this example we will use: y=2sin(7pix)-1
        return 2 * math.sin(7 * math.pi * x) - 1
        # Again, focus on the 0,0 ~ 1,1 square - there are 4 distinct bumps.
        # https://www.desmos.com/calculator/osnqrxkk3w
    def strata():
        fred.modify_locus_definition(
            transform_provider=SimpleTransformProvider(
                rc,
                translation_range_x=(-10, -8),
                translation_range_y=(cy - ry, cy + ry),
                translation_range_z=(cz - rz, cz + rz),
            ),
            strategy=DrawingStrategy(
                rc,
                inputs_strategies={
                    "translation_x": uniform,
                    "translation_y": ProbabilityShapeFunctionRandomInput(four_levels),
                    "translation_z": uniform,
                },
            ),
        )

They also let go of their inhibitions and came out with their true colors. There is no judgment among fireflies.
Or is there?

    from skyrenderer.scene.scene_layout.layout_elements_definitions import MaterialDefinition
    from skyrenderer.basic_types.procedure import PBRShader
    from skyrenderer.basic_types.provider.provider_inputs import HSVColorInput
    def diversity():
        rc.instancers[fred_geometry].set_material_definition(
            material_definition=MaterialDefinition(
                shader=PBRShader(rc),
                parameter_set=PBRShader.create_parameter_provider(
                    rc,
                    specular_factor=0,
                    roughness=1,
                    base_color=HSVColorInput(
                        hue_range=(0.466, 0.006), saturation_range=(0.903, 0.903), value_range=(1, 1)
                    ),
                    ambient_gain=6,
                    casts_shadows=False,
                ),
            )
        )
    strata()
    diversity()
    scene_composer.visualize()
randomization-advanced-distribution_8_resourcesTutorial
2025-02-20 15:27:31,206 | skyrenderer.randomization.strategy.input_drawing_strategy |  WARNING: Probability shape function: four_levels() yields negative y values, they have been clamped to 0.

2025-02-20 15:27:34,835 | skyrenderer.utils.time_measurement |  INFO: Setup time: 3.63 seconds

2025-02-20 15:27:41,494 | skyrenderer.utils.time_measurement |  INFO: Context update time: 6.66 seconds

2025-02-20 15:28:12,869 | skyrenderer.utils.time_measurement |  INFO: Key points calculation time: 1 ms

2025-02-20 15:28:12,869 | skyrenderer.utils.time_measurement |  INFO: Render time: 31.37 seconds

Random Gaussian usecase

Fireflies from the lower levels got offended by some smug looks and posh utterances from above. Their leader
Farquaad decided to invite everyone into a drunken brawl.

    from skyrenderer.randomization.strategy import RandomGaussianRandomInput
    random_gauss = RandomGaussianRandomInput(sigma_relative_limits=(0.05, 0.2))
    def brawl():
        fred.modify_locus_definition(
            transform_provider=SimpleTransformProvider(
                rc,
                translation_range_x=(-12, -6),
                translation_range_y=(cy - ry, cy + ry),
                translation_range_z=(cz - rz, cz + rz),
            ),
            strategy=DrawingStrategy(
                rc,
                inputs_strategies={
                    # by using RandomGaussianRandomInput, mu and sigma will be randomized each frame,
                    # so the furious crowd will keep moving from one place to the next
                    "translation_x": random_gauss,
                    "translation_y": random_gauss,
                    "translation_z": random_gauss,
                },
            ),
        )
    brawl()
    scene_composer.visualize(frame=1)
    scene_composer.visualize(frame=2)
    scene_composer.visualize(frame=3)
randomization-advanced-distribution_9_resourcesTutorial
randomization-advanced-distribution_10_resourcesTutorial
randomization-advanced-distribution_11_resourcesTutorial
2025-02-20 15:28:17,547 | skyrenderer.utils.time_measurement |  INFO: Setup time: 3.84 seconds

2025-02-20 15:28:24,510 | skyrenderer.utils.time_measurement |  INFO: Context update time: 6.96 seconds

2025-02-20 15:28:55,367 | skyrenderer.utils.time_measurement |  INFO: Key points calculation time: 1 ms

2025-02-20 15:28:55,368 | skyrenderer.utils.time_measurement |  INFO: Render time: 30.86 seconds

2025-02-20 15:28:59,800 | skyrenderer.utils.time_measurement |  INFO: Setup time: 3.64 seconds

2025-02-20 15:29:06,843 | skyrenderer.utils.time_measurement |  INFO: Context update time: 7.04 seconds

2025-02-20 15:29:37,669 | skyrenderer.utils.time_measurement |  INFO: Key points calculation time: 1 ms

2025-02-20 15:29:37,670 | skyrenderer.utils.time_measurement |  INFO: Render time: 30.83 seconds

2025-02-20 15:29:42,605 | skyrenderer.utils.time_measurement |  INFO: Setup time: 4.16 seconds

2025-02-20 15:29:49,687 | skyrenderer.utils.time_measurement |  INFO: Context update time: 7.08 seconds

2025-02-20 15:30:21,630 | skyrenderer.utils.time_measurement |  INFO: Key points calculation time: 1 ms

2025-02-20 15:30:21,631 | skyrenderer.utils.time_measurement |  INFO: Render time: 31.94 seconds

Custom Distribution trickery

Situation quickly spiraled out of control.

    from skyrenderer.randomization.strategy import CustomRandomInput
    import random
    last_x_seed = -1
    def spiral_generator(seed, number_of_states, input_name, y_func, z_func):
        # note the use of input_name
        fuzz = 0.002
        global last_x_seed
        if input_name == "translation_x":
            last_x_seed = seed
        else:
            seed = last_x_seed
        max_seed = 2**32 - 1
        frac = seed / max_seed
        frac += fuzz * (random.random() - 0.5)
        if input_name == "translation_x":
            ret_val = round(frac * number_of_states)
        elif input_name == "translation_y":
            ret_val = round(y_func(frac) * number_of_states)
        elif input_name == "translation_z":
            ret_val = round(z_func(frac) * number_of_states)
        if ret_val < 0:
            ret_val = 0
        elif ret_val >= number_of_states:
            ret_val = number_of_states - 1
        return ret_val
    def normal_spiral(seed, number_of_states, input_name, *args):
        freq = 10
        # https://www.desmos.com/calculator/tdzig3kpme

        def normal_y(x):
            return math.sin(freq * math.pi * x) / 2 + 0.5

        def normal_z(x):
            return math.cos(freq * math.pi * x) / 2 + 0.5

        return spiral_generator(seed, number_of_states, input_name, normal_y, normal_z)
    def spiral(spiral_func):
        fred.modify_locus_definition(
            transform_provider=SimpleTransformProvider(
                rc,
                translation_range_x=(cx - rx, cx + rx),
                translation_range_y=(cy - ry, cy + ry),
                translation_range_z=(cz - rz, cz + rz),
            ),
            strategy=DrawingStrategy(
                rc,
                inputs_strategies={
                    "translation_x": CustomRandomInput(spiral_func),
                    "translation_y": CustomRandomInput(spiral_func),
                    "translation_z": CustomRandomInput(spiral_func),
                },
            ),
        )
    spiral(normal_spiral)
    scene_composer.visualize()
randomization-advanced-distribution_12_resourcesTutorial
2025-02-20 15:30:22,459 | skyrenderer.basic_types.provider.iprovider |  WARNING: Provider for this config has been already initialized! There should be just one Provider created per unit source, consider fixing the scene.
Config:
{'translation_range_x': (-25.051000000000002, -3.7509999999999994), 'translation_range_y': (2.3855999999999997, 9.6656), 'translation_range_z': (-1.3112799999999998, 3.2887199999999996), 'rotation_range_x': (0.0, 0.0), 'rotation_range_y': (0.0, 0.0), 'rotation_range_z': (0.0, 0.0), 'scale_range_x': (1, 1), 'scale_range_y': (1, 1), 'scale_range_z': (1, 1), 'number_of_steps': 1000}

2025-02-20 15:30:26,318 | skyrenderer.utils.time_measurement |  INFO: Setup time: 3.86 seconds

2025-02-20 15:30:33,259 | skyrenderer.utils.time_measurement |  INFO: Context update time: 6.94 seconds

2025-02-20 15:31:03,996 | skyrenderer.utils.time_measurement |  INFO: Key points calculation time: 1 ms

2025-02-20 15:31:03,997 | skyrenderer.utils.time_measurement |  INFO: Render time: 30.74 seconds

    def bonkers_spiral(seed, number_of_states, input_name, *args):
        freq = 10
        phase = 0.02
        # https://www.desmos.com/calculator/0rizu1fihh

        def bonkers_y(x):
            return (math.sin(freq * math.pi * (x - phase)) / 2) / (2 - math.sin((freq + 1) * math.pi * x)) + 0.5

        def bonkers_z(x):
            return (math.cos(freq * math.pi * (x - phase)) / 2) / (
                2 - math.cos((freq / 2 - 0.4) * math.pi * (x - phase - 0.1))
            ) + 0.5

        return spiral_generator(seed, number_of_states, input_name, bonkers_y, bonkers_z)
    spiral(bonkers_spiral)
    scene_composer.visualize()
randomization-advanced-distribution_13_resourcesTutorial
2025-02-20 15:31:04,833 | skyrenderer.basic_types.provider.iprovider |  WARNING: Provider for this config has been already initialized! There should be just one Provider created per unit source, consider fixing the scene.
Config:
{'translation_range_x': (-25.051000000000002, -3.7509999999999994), 'translation_range_y': (2.3855999999999997, 9.6656), 'translation_range_z': (-1.3112799999999998, 3.2887199999999996), 'rotation_range_x': (0.0, 0.0), 'rotation_range_y': (0.0, 0.0), 'rotation_range_z': (0.0, 0.0), 'scale_range_x': (1, 1), 'scale_range_y': (1, 1), 'scale_range_z': (1, 1), 'number_of_steps': 1000}

2025-02-20 15:31:08,547 | skyrenderer.utils.time_measurement |  INFO: Setup time: 3.71 seconds

2025-02-20 15:31:15,390 | skyrenderer.utils.time_measurement |  INFO: Context update time: 6.84 seconds

2025-02-20 15:31:46,105 | skyrenderer.utils.time_measurement |  INFO: Key points calculation time: 1 ms

2025-02-20 15:31:46,106 | skyrenderer.utils.time_measurement |  INFO: Render time: 30.71 seconds

Epilogue

Finally, Fred, Fiona, Felon and Farquaad managed to convince everyone to chill. Fireflies put some festive lights
on and flew away, singing merry tunes.

    from skyrenderer.basic_types.provider.transform_providers.disc_transform_provider import DiscTransformProvider
    def waves(x):
        # https://www.desmos.com/calculator/ilfdueawyl
        return (2 * math.sin(12 * math.pi * x) * math.sin(8 * x)) / (39 * (x + 0.01)) + 0.65 - 1.5 * x
    def milky_way():
        fred.modify_locus_definition(
            transform_provider=DiscTransformProvider(
                rc,
                center=(cx + 2, cy - 2, cz - rz - 1),
                radius=3 * rz,
                normal_vector=(1, 1, -0.2),
                number_of_points=1000000,
            ),
            strategy=DrawingStrategy(
                rc,
                inputs_strategies={
                    "radius": RelativeGaussianRandomInput(relative_mu=0.7, relative_sigma=0.1),
                    "phi": ProbabilityShapeFunctionRandomInput(waves),
                },
            ),
        )
        rc.instancers[fred_geometry].set_material_definition(
            material_definition=MaterialDefinition(
                shader=PBRShader(rc),
                parameter_set=PBRShader.create_parameter_provider(
                    rc,
                    specular_factor=0,
                    roughness=1,
                    base_color=HSVColorInput(hue_range=(0, 1), saturation_range=(1, 1), value_range=(1, 1)),
                    ambient_gain=6,
                    casts_shadows=False,
                ),
            )
        )
    milky_way()
    scene_composer.visualize()
randomization-advanced-distribution_14_resourcesTutorial
2025-02-20 15:31:46,944 | skyrenderer.randomization.strategy.input_drawing_strategy |  WARNING: Probability shape function: waves() yields negative y values, they have been clamped to 0.

2025-02-20 15:31:50,300 | skyrenderer.utils.time_measurement |  INFO: Setup time: 3.35 seconds

2025-02-20 15:31:56,421 | skyrenderer.utils.time_measurement |  INFO: Context update time: 6.12 seconds

2025-02-20 15:32:28,502 | skyrenderer.utils.time_measurement |  INFO: Key points calculation time: 1 ms

2025-02-20 15:32:28,503 | skyrenderer.utils.time_measurement |  INFO: Render time: 32.08 seconds

Summary

In this section you have learnt:

  • There are many ways to use Distributions, aside from the default Uniform.
  • Built-in Gaussians with sensible parameters will cover many common cases.
  • Understanding Custom callbacks enables handling unusual scenarios with arbitrary math.