In Phase 1 of the tutorial, we learned how to use the Randomizers that are bundled with the Perception package to spawn background and foreground objects, and randomize their position, rotation, texture, and hue offset (color). In this phase, we will build a custom light Randomizer for the `Directional Light` object, affecting the light's intensity and color on each Iteration of the Scenario. We will also learn how to include certain data or logic inside a randomized object (such as the light) in order to more explicitly define and restrict its randomization behaviors.
In Phase 1 of the tutorial, we learned how to use the Randomizers that are bundled with the Perception package to spawn background and foreground objects, and randomize their position, rotation, texture, and hue offset (color). In this phase, we will build a custom light Randomizer for the `Directional Light` object, affecting the light's intensity and color on each `Iteration`. We will also learn how to include certain data or logic inside a randomized object (such as the light) in order to more explicitly define and restrict its randomization behaviors.
Steps included this phase of the tutorial:
- [Step 1: Build a Lighting Randomizer](#step-1)
- [Step 2: Bundle Data and Logic Inside Randomization Tags](#step-2)
We need to create two C# classes for our light randomization, `MyLightRandomizer` and `MyLightRandomizerTag`. The first of these will sample random values and assign them to various aspects of the light, and the second class will be the component that will be added to `Directional Light`, making it a target of `MyLightRandomizer`.
### <aname="step-1">Step 1: Build a Lighting Randomizer</a>
We need to create two C# classes for our light randomization, `MyLightRandomizer` and `MyLightRandomizerTag`. The first of these will sample random values and assign them to the intensity and color of the light, and the second class will be the component that will be added to `Directional Light`, making it a target of `MyLightRandomizer`.
Note that while _**Visual Studio**_ is the default option, you can choose any C# compatible editor of your choice. You can change the default settings in _**Preferences -> External Tools -> External Script Editor**_.
Note that while _**Visual Studio**_ is the default option, you can choose any text editor of your choice. You can change the this setting in _**Preferences -> External Tools -> External Script Editor**_.
* **Action**: Remove the contents of the class and copy/paste the code below:
}
```
The purpose of this piece of code is to obtain a random float parameter and assign it to the light's `Intensity` field. Let's go through the code above and understand each part. The `FloatParameter` field makes it possible for us to define a randomized float parameter and modify its properties within the UI, similar to how we already modified the properties for the previous Randomizers we used.
The purpose of this piece of code is to obtain a random float parameter and assign it to the light's `Intensity` field on the start of every Iteration. Let's go through the code above and understand each part. The `FloatParameter` field makes it possible for us to define a randomized float parameter and modify its properties from the editor UI, similar to how we already modified the properties for the previous Randomizers we used.
If you return to your list of Randomizers in the _**Inspector**_ view of `SimulationScenario`, you can now add this new Randomizer.
</p>
* **Action**: In the UI snippet for `MyLightRandomzier`, set range minimum and maximum to 0.5 and 3.
* **Action**: In the UI snippet for `MyLightRandomzier`, set the minimum and maximum for range to 0.5 and 3.
The `MyLightRandomizer` class extends `Randomizer`, which is the base class for all Randomizers that can be added to a `Scenario`. This base class provides a plethora of useful functions and properties that can help catalyze the process of creating new Randomziers.
The `MyLightRandomizer` class extends `Randomizer`, which is the base class for all Randomizers that can be added to a Scenario. This base class provides a plethora of useful functions and properties that can help catalyze the process of creating new Randomziers.
The `OnIterationStart()` function is used for telling the Randomizer what actions to perform at the start of each `Iteration` of the `Scenario`. As seen in the code block, in each `Iteration` this class queries the `tagManager` object for all objects that carry the `MyLightRandomizerTag` component. Then, for each object inside the queried list, it first tries to get the `Light` component, and if this component exists, the next line sets its intensity to a new random float sampled from `lightIntensityParamter`.
The `OnIterationStart()` function is used for telling the Randomizer what actions to perform at the start of each Iteration of the Scenario. As seen in the code block, at the start of each Iteration, this class queries the `tagManager` object for all objects that carry the `MyLightRandomizerTag` component. Then, for each object inside the queried list, it first tries to get the `Light` component, and if this component exists, the code sets its intensity to a new random float sampled from `lightIntensityParamter`.
Note that the `if (light)` is not a requirement if you make sure to only add the `MyLightRandomizerTag` component to objects that have a `Light` component; however, it is good practice to guard against possible mistakes by always make sure a component exists and is not null before using it.
Note that the `if (light)`line is not a requirement if you only add the `MyLightRandomizerTag` component to objects that have a `Light` component; however, it is good practice to guard against possible mistakes by always making sure a component exists and is not null before try to use it.
* **Action**: Open `MyLightRandomizerTag.cs` and replace its contents with the code below:
```
Yes, the Randomizer tags can be this simple if you just need to attach objects to Randomizers. Later, you will learn how to add code here to encapsulate more data and logic within the randomized objects.
Yes, a RandomizerTag can be this simple if you just need it for helping Randomizers query for target objects. Later, you will learn how to add code here to encapsulate more data and logic within the randomized objects.
* **Action**: Define a new `ColorRgbParameter`:
* **Action**: Back inside `MyLightRandomizer.cs`, define a new `ColorRgbParameter`:
`public ColorRgbParameter lightColorParameter`
`public ColorRgbParameter lightColorParameter;`
* **Action**: Inside the code block that intensity was previously applied, add code for sampling color from the above Parameter and applying it:
}
```
If you now check the UI snippet for `MyLightRandomizer`, you will notice that `Color Parameter` is added. This Parameter includes four separate values for `Red`, `Green`, `Blue` and `Alpha`. The range for these is currently set between 0 to 1. A color with (0,0,0) RGB components essentially emits no light. So let's increase the minimum a bit to avoid such a scenario.
If you now check the UI snippet for `MyLightRandomizer`, you will notice that `Color Parameter` is added. This Parameter includes four separate randomized values for `Red`, `Green`, `Blue` and `Alpha`. Note that the meaningful range for all of these values is 0-1 (and not 0-255). You can see that the sampling range for red, green, and blue is currently also set to 0-1, which means the parameter covers a full range of colors. A color with (0,0,0) RGB components essentially emits no light. So let's increase the minimum a bit to avoid such a scenario..
* **Action**: Increase the minimum value for red, green, and blue components to 0.4 (this is an arbitrary number that produce good results).
* **Action**: Increase the minimum value for red, green, and blue components to 0.4 (this is an arbitrary number that typically produces good-looking results).
. Each value should also already have a unique `Seed` specified. This is the seed which the sampler will use to produce a random value. If two random parameters have the same seed, range, and distribution, they will always have the samle random value. In this case, this would lead to the red, green, and blue components having equal values, and thus the produced color always being a shade grey. As such, in order to get varied colors and not just grey, we need to make sure the seed values are different for our red, green, and blue values.
Each value should also already have a unique `Seed` specified. This is the seed which the sampler will use to produce a random value from the specifed distribution. If two random parameters have the same seed, range, and distribution, they will always have the same value. In the case of this color, this would lead to the red, green, and blue components having equal values, and thus the produced color always being a shade of grey. As such, in order to get varied colors and not just grey, we need to make sure the seed values are different for our red, green, and blue components.
* **Action**: In the UI snippet for `MyLightRandomizer`, make sure the red, green, and blue components have different and unique `Seed` values. Set the distribution and value for Alpha to `Constant` and 1, as we do not want to randomize the alpha component of the color.
* **Action**: In the UI snippet for `MyLightRandomizer`, make sure the red, green, and blue components have different `Seed` values. Set the distribution and value for Alpha to `Constant` and 1, as we do not want to randomize the alpha component of the color.
The UI for `My Light Randomizer` should now look like this image:
The UI for `My Light Randomizer` should now look like this:
<palign="center">
<imgsrc="Images/light_rand_2.png"width="420"/>
* **Action**: Run the simulation to observe the lighting color changing on each iteration.
* **Action**: Run the simulation for a few frames to observe the lighting color changing on each iteration.
### <aname="step-2">Step 2: Bundle Data and Logic Inside Randomization Tags</a>
### Step 2: Bundle Data and Logic Inside Randomization Tags
Let's try this approach with our `Directional Light` object. We will create a duplicate of this light and then have the two lights use different ranges of intensity while they both use the same float Parameter from `MyLightRandomizer.cs`.
Let's try this approach with our `Directional Light` object. We will create a duplicate of this light and then have the two lights use different ranges of intensity while both using the exact same float Parameter from `MyLightRandomizer.cs`.
* **Action**: Right-click on `Directional Light` in the Scene _**Hierarchy**_, and select _**Duplicate**_. The new light will automatically be named `Directional Light (1)`.
* **Action**: Change the Y rotation of `Directional Light (1)` to 60, as shown below:
}
}
```
In the above code, we have created a new `SetIntensity` function that first scales the incoming intensity (assumed to be between 0 and 1) to our desired range and then assigns it to the light's intensity. The `Light` component is now fetched from the GameObject that this Randomizer tag is attached to. This works because both this tag component and the `Light` component are attached to the same object in the Scene.
In the above code, we have created a new `SetIntensity` function that first scales the incoming intensity (assumed to be between 0 and 1) to our desired range and then assigns it to the light's intensity. The `Light` component is now fetched from the GameObject that this Randomizer tag is attached to. This works because both this tag component and the `Light` component are attached to the same object in the Scene (which is one of the lights).
This component is already added to both our lights. We now need to set our desired minimum and maximum intensities, which can be done through the _**Inspector**_ view.
This component is already added to both our lights. We now need to set our desired minimum and maximum intensities, and this can be done through the _**Inspector**_ view.
Note that with this change, we fully transfer the responsibility for the light's intensity range to `MyLightRandomizerTag.cs` and assume the intensity value coming from `My Light Randomizer` is between 0 and 1. Therefore, we now need to change the range for the corresponding Parameter in `My Light Randomizer` to (0,1).
Note that with this change, we fully transfer the responsibility for the light's intensity range to `MyLightRandomizerTag.cs` and assume the intensity value coming from `My Light Randomizer` is always between 0 and 1. Therefore, we now need to change the range for the corresponding Parameter in `My Light Randomizer` to (0,1).
* **Action**: Select `SimulationScenario` and from the UI snippet for `My Light Randomizer`, change the range for `Light Intensity Parameter` from (0.5,3.5) to (0,1).
Notice how we now fetch the `MyLightRandomizerTag` component from the tagged object and use its `SetIntensity` function instead of directly setting the intensity of the `Light` component.
* **Action**: Run your simulation, then pause it. Go to the _**Scene**_ view and inspect the color and intensity of each of the lights. Try turning each on and off to see how it affects the current frame.
* **Action**: Run your simulation, then pause it. Go to the _**Scene**_ view and inspect the color and intensity of each of the lights. Try turning each on and off to see how they affect the current frame.
By this point in the tutorial, we have learned how to set-up a Perception Scene, randomize our simulation, and verify our generated datasets using Dataset Insights. That said, the size of the dataset we created was only 1000 captures, which is not sufficient for model-training purposes. It is now time to generate a large-scale synthetic dataset with hundreds of thousands of frames using Unity Simulation.
By this point in the tutorial, we have learned how to set-up a Perception Scene, randomize our simulation, and verify our generated datasets using Dataset Insights. That said, the size of the dataset we created was only 100 captures, which is not sufficient for model-training purposes. It is now time to generate a large-scale synthetic dataset with tens of thousands of frames using Unity Simulation.
[Click here to continue to Phase 3: Cloud](Phase3.md)