Steven Leal
4 年前
当前提交
5e143e2b
共有 177 个文件被更改,包括 3528 次插入 和 17 次删除
-
4README.md
-
3com.unity.perception/Documentation~/TableOfContents.md
-
5com.unity.perception/Documentation~/index.md
-
3com.unity.perception/Editor/Unity.Perception.Editor.asmdef
-
2com.unity.perception/Runtime/GroundTruth/PerceptionCamera.cs
-
6com.unity.perception/Tests/Runtime/GroundTruthTests/DatasetCaptureSensorSchedulingTests.cs.meta
-
6com.unity.perception/Tests/Runtime/GroundTruthTests/DatasetCaptureTests.cs.meta
-
12com.unity.perception/package.json
-
8com.unity.perception/Editor/Randomization.meta
-
8com.unity.perception/Runtime/Randomization.meta
-
8com.unity.perception/Tests/Runtime/Randomization.meta
-
85com.unity.perception/Documentation~/Randomization/Images/ColorParameter.png
-
206com.unity.perception/Documentation~/Randomization/Images/ParameterConfiguration.png
-
101com.unity.perception/Documentation~/Randomization/Images/TestScenario.png
-
93com.unity.perception/Documentation~/Randomization/Images/TutorialBuild.png
-
57com.unity.perception/Documentation~/Randomization/Index.md
-
58com.unity.perception/Documentation~/Randomization/Parameters.md
-
87com.unity.perception/Documentation~/Randomization/Samplers.md
-
32com.unity.perception/Documentation~/Randomization/Scenarios.md
-
178com.unity.perception/Documentation~/Randomization/Tutorial.md
-
58com.unity.perception/Editor/Randomization/CategoricalOptionElement.cs
-
3com.unity.perception/Editor/Randomization/CategoricalOptionElement.cs.meta
-
24com.unity.perception/Editor/Randomization/FloatRangeElement.cs
-
3com.unity.perception/Editor/Randomization/FloatRangeElement.cs.meta
-
8com.unity.perception/Editor/Randomization/Icons.meta
-
3com.unity.perception/Editor/Randomization/Icons/DragHandle.png
-
140com.unity.perception/Editor/Randomization/Icons/DragHandle.png.meta
-
5com.unity.perception/Editor/Randomization/Icons/FoldoutClosed.png
-
140com.unity.perception/Editor/Randomization/Icons/FoldoutClosed.png.meta
-
3com.unity.perception/Editor/Randomization/Icons/FoldoutOpen.png
-
140com.unity.perception/Editor/Randomization/Icons/FoldoutOpen.png.meta
-
7com.unity.perception/Editor/Randomization/Icons/Search.png
-
140com.unity.perception/Editor/Randomization/Icons/Search.png.meta
-
8com.unity.perception/Editor/Randomization/Icons/X.png
-
140com.unity.perception/Editor/Randomization/Icons/X.png.meta
-
112com.unity.perception/Editor/Randomization/ParameterConfigurationEditor.cs
-
11com.unity.perception/Editor/Randomization/ParameterConfigurationEditor.cs.meta
-
12com.unity.perception/Editor/Randomization/ParameterDragBar.cs
-
3com.unity.perception/Editor/Randomization/ParameterDragBar.cs.meta
-
101com.unity.perception/Editor/Randomization/ParameterDragManipulator.cs
-
3com.unity.perception/Editor/Randomization/ParameterDragManipulator.cs.meta
-
86com.unity.perception/Editor/Randomization/ParameterDrawer.cs
-
3com.unity.perception/Editor/Randomization/ParameterDrawer.cs.meta
-
114com.unity.perception/Editor/Randomization/ParameterDrawerElement.cs
-
3com.unity.perception/Editor/Randomization/ParameterDrawerElement.cs.meta
-
270com.unity.perception/Editor/Randomization/ParameterElement.cs
-
3com.unity.perception/Editor/Randomization/ParameterElement.cs.meta
-
15com.unity.perception/Editor/Randomization/RandomSeedField.cs
-
3com.unity.perception/Editor/Randomization/RandomSeedField.cs.meta
-
118com.unity.perception/Editor/Randomization/SamplerElement.cs
-
3com.unity.perception/Editor/Randomization/SamplerElement.cs.meta
-
79com.unity.perception/Editor/Randomization/ScenarioBaseEditor.cs
-
3com.unity.perception/Editor/Randomization/ScenarioBaseEditor.cs.meta
-
67com.unity.perception/Editor/Randomization/StaticData.cs
-
3com.unity.perception/Editor/Randomization/StaticData.cs.meta
-
3com.unity.perception/Editor/Randomization/Uss.meta
-
213com.unity.perception/Editor/Randomization/Uss/Styles.uss
-
3com.unity.perception/Editor/Randomization/Uss/Styles.uss.meta
-
3com.unity.perception/Editor/Randomization/Uxml.meta
-
8com.unity.perception/Editor/Randomization/Uxml/CategoricalOptionElement.uxml
-
3com.unity.perception/Editor/Randomization/Uxml/CategoricalOptionElement.uxml.meta
-
7com.unity.perception/Editor/Randomization/Uxml/CategoricalParameterTemplate.uxml
-
3com.unity.perception/Editor/Randomization/Uxml/CategoricalParameterTemplate.uxml.meta
-
11com.unity.perception/Editor/Randomization/Uxml/FloatRangeElement.uxml
-
3com.unity.perception/Editor/Randomization/Uxml/FloatRangeElement.uxml.meta
-
21com.unity.perception/Editor/Randomization/Uxml/ParameterConfiguration.uxml
-
10com.unity.perception/Editor/Randomization/Uxml/ParameterConfiguration.uxml.meta
-
6com.unity.perception/Editor/Randomization/Uxml/ParameterDrawerElement.uxml
-
3com.unity.perception/Editor/Randomization/Uxml/ParameterDrawerElement.uxml.meta
-
31com.unity.perception/Editor/Randomization/Uxml/ParameterElement.uxml
-
3com.unity.perception/Editor/Randomization/Uxml/ParameterElement.uxml.meta
-
9com.unity.perception/Editor/Randomization/Uxml/SamplerElement.uxml
-
3com.unity.perception/Editor/Randomization/Uxml/SamplerElement.uxml.meta
-
20com.unity.perception/Editor/Randomization/Uxml/ScenarioBaseElement.uxml
-
3com.unity.perception/Editor/Randomization/Uxml/ScenarioBaseElement.uxml.meta
-
3com.unity.perception/Runtime/Randomization/Configuration.meta
-
146com.unity.perception/Runtime/Randomization/Configuration/ParameterConfiguration.cs
-
11com.unity.perception/Runtime/Randomization/Configuration/ParameterConfiguration.cs.meta
-
11com.unity.perception/Runtime/Randomization/Configuration/ParameterConfigurationException.cs
-
3com.unity.perception/Runtime/Randomization/Configuration/ParameterConfigurationException.cs.meta
-
8com.unity.perception/Runtime/Randomization/Parameters.meta
-
3com.unity.perception/Runtime/Randomization/Parameters/Attributes.meta
-
18com.unity.perception/Runtime/Randomization/Parameters/Attributes/ParameterMetaData.cs
-
3com.unity.perception/Runtime/Randomization/Parameters/Attributes/ParameterMetaData.cs.meta
-
104com.unity.perception/Runtime/Randomization/Parameters/CategoricalParameter.cs
-
3com.unity.perception/Runtime/Randomization/Parameters/CategoricalParameter.cs.meta
-
12com.unity.perception/Runtime/Randomization/Parameters/ICategoricalParameter.cs
-
3com.unity.perception/Runtime/Randomization/Parameters/ICategoricalParameter.cs.meta
-
55com.unity.perception/Runtime/Randomization/Parameters/Parameter.cs
|
|||
fileFormatVersion: 2 |
|||
guid: bc1c8d85f0374514ab4d1af6b3bbe6cd |
|||
folderAsset: yes |
|||
DefaultImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: 511b2251e3510cd48a26b8a61f6911f0 |
|||
folderAsset: yes |
|||
DefaultImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: 44d8bef3d43160b428851cccd5080624 |
|||
folderAsset: yes |
|||
DefaultImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
# Overview |
|||
|
|||
The perception package's randomization toolset enables users to incorporate domain randomization (DR) principles into Unity projects intended for synthetic training data generation. |
|||
|
|||
What is Domain Randomization? |
|||
|
|||
Domain Randomization (DR) is a technique involving the creation of a variety of simulated environments with randomized properties to train a model over a wider domain of environment conditions. The hypothesis behind DR is that models trained on randomized data sets are more likely to adapt to real-world enviroments than their non-randomized counterparts. It is expected that the larger domain of environment conditions generated through DR will encompase more characteristics of actual enviroments than non-randomization data sets. |
|||
|
|||
To this end, the perception package offers the following constructs to help facilitate the randomization of simulations: |
|||
1. Parameters |
|||
2. Samplers |
|||
3. Scenarios |
|||
|
|||
|
|||
## Parameters |
|||
|
|||
Parameters are used to map common types of simulation properties to random variables. For example, a Vector3 size parameter can be used to randomize the x, y, and z dimensions of an obstacle. Or a material parameter can be used to swap between different terrain surface materials. |
|||
|
|||
![Example Parameters](./Images/ParameterConfiguration.png) |
|||
|
|||
Parameters are configured and organized within a scene using a parameter configuration. Users can create new parameters, modify parameter randomization properties, and even assign target GameObjects to manipulate simulation properties directly from the inspector. Additionally, parameter sub-properties can be modified in playmode better visualize the impact of different randomization settings. |
|||
|
|||
To read more about how to create custom parameter types, navigate over to the [parameters doc](Parameters.md). |
|||
|
|||
|
|||
## Samplers |
|||
|
|||
Samplers are classes that deterministically generate random float values from bounded probability distributions. Samplers are considered bounded since each random sampler generates float values within a range defined by a minumum and maximum value. The values generated from samplers are often used to randomize the sub components of parameters. |
|||
|
|||
![Example Parameters](./Images/ColorParameter.png) |
|||
|
|||
For example, a color parameter has four independently randomizable components: hue, saturation, value, and alpha. Each of the four samplers attached to a color parameter can employ a unique probability distribution to customize how new colors are sampled within a simulation. Out of the box, the perception package supports uniform and normal distribution sampling. So in our color example, a user may choose a normal distribution for their hue, a uniform distribution for saturation, and a constant value sampler for the value and alpha color components. |
|||
|
|||
Take a look at the [samplers doc](Samplers.md) to learn more about implementing custom probability distributions and samplers that can integrate with the perception package. |
|||
|
|||
|
|||
## Scenarios |
|||
|
|||
Scenarios have three responsibilities: |
|||
1. Controlling the execution flow of your simulation |
|||
2. Customizing the application of random parameters in your project |
|||
3. Defining constants that can be configured externally from a built Unity player |
|||
|
|||
The fundamental principle of DR is to simulate environments under a variety of randomized conditions. To this end, scenarios have a concept of iterations. Each iteration of a scenario is intended to encapsulate one complete run of a simulated environment under uniquely randomized conditions. Scenarios determine how to setup a new iteration, what conditions determine the end of an iteration, how to clean up a completed iteration, and finally how many iterations to perform. Each of these behaviors can be customed for a new scenario by deriving the perception package's scenario class. |
|||
|
|||
It was mentioned before in the parameter section of this doc that you can configure parameters to affect simulation properties directly from the parameter configuration. While useful, this feature is constrained to a particular set of use cases. Instead, a user can reference existing parameters in their scenario to implement more intricate randomizations. For example, a user can reference a `SpawnCount` parameter and a `ObjectPosition` parameter to randomize the positions of a dynamic number of objects during the setup step of a scenario. |
|||
|
|||
![Example Parameters](./Images/TestScenario.png) |
|||
|
|||
Finally, scenarios define constants from which to expose global simulation behaviors automatically. By modifying serialized constants externally, users can customize their simulation runtime even after their project has been built. |
|||
|
|||
Take a look at the [scenarios doc](Scenarios.md) to learn more about creating custom scenarios. |
|||
|
|||
|
|||
## Getting Started |
|||
|
|||
Visit our [randomization tutorial doc](Tutorial.md) to get started using the perception package's randomization tools in an example project. |
|
|||
# Parameters |
|||
|
|||
All parameters are derived from one of three abstract classes: |
|||
1. Categorical parameters |
|||
2. Struct parameters |
|||
3. Typed parameters |
|||
|
|||
### Categorical Parameters |
|||
|
|||
Categorical parameters by definition choose a value from a list of options that have no intrinsic ordering. For example, a material paramater randomly chooses from a list of material options, but the list of material options itself can be rearranged into any particular order without affecting the distribution of materials selected. |
|||
|
|||
If your custom parameter is a categorical in nature, take a look at the [StringParameter]() class included in the perception package as a reference for how to derive the `CategoricalParameter` class: |
|||
``` |
|||
using UnityEngine.Perception.Randomization.Parameters.Attributes; |
|||
|
|||
namespace UnityEngine.Perception.Randomization.Parameters |
|||
{ |
|||
[AddComponentMenu("")] |
|||
[ParameterMetaData("String")] |
|||
public class StringParameter : CategoricalParameter<string> {} |
|||
} |
|||
``` |
|||
|
|||
**Note:** the AddComponentMenu attribute with an empty string prevents parameters from appearing in the Add Component GameObject menu. Randomization parameters should only be created with by a `ParameterConfiguration` |
|||
|
|||
### Struct Parameters |
|||
|
|||
If the intended output type of a parameter is a struct instead of a class, deriving the `StructParameter` class will create new parameter with access to the JobHandle overload of the Samples() method for increased sampling performance. Take a look at the [ColorHsvaParameter]() class included in the perception package for an example on how to implement a struct parameter. |
|||
|
|||
### Typed Parameters |
|||
|
|||
Typed parameters are the most generic form of parameter. To implement a typed parameter, derive the TypedParameter class and implement the Sample() and Samples() methods. |
|||
|
|||
## Performance |
|||
It is recommended to use the JobHandle overload of the Samples() method when generating a large number of samples. The JobHandle overload will utilize the Unity Burst Compiler and Job System to automatically optimize and multithread parameter sampling jobs. The code block below is an example of how to use this overload to sample two parameters in parallel: |
|||
``` |
|||
// Schedule sampling jobs |
|||
var currentIteration = ScenarioBase.ActiveScenario.currentIteration |
|||
var cubeColors = ObjectColor.Samples(currentIteration, constants.objectCount, out var colorHandle); |
|||
var cubePositions = ObjectPosition.Samples(currentIteration, constants.objectCount, out var positionHandle); |
|||
|
|||
// Combine job handles |
|||
var handles = JobHandle.CombineDependencies(colorHandle, positionHandle); |
|||
|
|||
// Wait for the jobs to complete |
|||
handles.Complete(); |
|||
|
|||
// Use the created samples |
|||
for (var i = 0; i < constants.objectCount; i++) |
|||
{ |
|||
m_ObjectMaterials[i].SetColor(k_BaseColorProperty, cubeColors[i]); |
|||
m_Objects[i].transform.position = cubePositions[i]; |
|||
} |
|||
|
|||
// Dispose of the generated samples |
|||
cubeColors.Dispose(); |
|||
cubePositions.Dispose(); |
|||
``` |
|
|||
# Samplers |
|||
Samplers in the perception package are classes that deterministically generate random float values from bounded probability distributions. Although samplers are often used in conjunction with parameters to generate arrays of typed random values, samplers can be instantiated and used from any ordinary script: |
|||
``` |
|||
var sampler = new NormalSampler(); |
|||
sampler.seed = 123456789u; |
|||
sampler.mean = 3; |
|||
sampler.stdDev = 2; |
|||
sampler.range = new FloatRange(-10, 10); |
|||
|
|||
// Generate a sample |
|||
var sample = sampler.NextSample(); |
|||
``` |
|||
|
|||
Four Samplers are included with the perception package: |
|||
1. Constant Sampler |
|||
2. Uniform Sampler |
|||
3. Normal Sampler |
|||
4. Placeholder Range Sampler |
|||
|
|||
#### Constant Sampler |
|||
Generates constant valued samples |
|||
|
|||
#### Uniform Sampler |
|||
Samples uniformly from a specified range |
|||
|
|||
#### Normal Sampler |
|||
Generates random samples from a truncated normal distribution bounded by a specified range |
|||
|
|||
#### Placeholder Range Sampler |
|||
Used to define a float range [minimum, maximum] for a particular component of a parameter (example: the hue component of a color parameter). This sampler is useful for configuring sample ranges for non-perception related scripts, particularly when these scripts have a public interface for manipulating a minimum and maximum bounds for their sample range but perform the actual sampling logic internally. |
|||
|
|||
|
|||
## Performance |
|||
|
|||
Samplers are designed to be Unity Burst Compiler and Job System compatible to increase simulation performance when generating large numbers of samples. Below is an example of a simple job that uses a NormalSampler directly to create 100 normally distributed samples: |
|||
``` |
|||
[BurstCompile] |
|||
public struct SampleJob : IJob |
|||
{ |
|||
NormalSampler sampler; |
|||
public NativeArray<float> samples; |
|||
|
|||
public void Execute() |
|||
{ |
|||
for (var i = 0; i < samples.Length; i++) |
|||
samples[i] = sampler.NextSample(); |
|||
} |
|||
} |
|||
``` |
|||
Additionally, samplers have a NativeSamples() method that can schedule a ready-made multi-threaded job intended for generating a large array of samples. Below is an example of how to combine two job handles returned by NativeSamples() to generate two arrays of samples simultaneously: |
|||
``` |
|||
// Create samplers |
|||
var uniformSampler = new UniformSampler |
|||
{ |
|||
range = new FloatRange(0, 1), |
|||
seed = 123456789u |
|||
}; |
|||
var normalSampler = new NormalSampler |
|||
{ |
|||
range = new FloatRange(0, 1), |
|||
mean = 0, |
|||
stdDev = 1, |
|||
seed = 987654321u |
|||
}; |
|||
|
|||
// Create sample jobs |
|||
var uniformSamples = uniformSampler.NativeSamples(1000, out var uniformHandle); |
|||
var normalSamples = normalSampler.NativeSamples(1000, out var normalHandle); |
|||
|
|||
// Combine job handles |
|||
var combinedJobHandles = JobHandle.CombineDependencies(uniformHandle, normalHandle); |
|||
|
|||
// Wait for jobs to complete |
|||
combinedJobHandles.Complete(); |
|||
|
|||
//... |
|||
// Use samples |
|||
//... |
|||
|
|||
// Dispose of sample arrays |
|||
uniformSamples.Dispose(); |
|||
normalSamples.Dispose(); |
|||
``` |
|||
|
|||
|
|||
## Custom Samplers |
|||
Take a look at the [UniformSampler](../../Runtime/Randomization/Samplers/SamplerTypes/UniformSampler) and [NormalSampler](../../Runtime/Randomization/Samplers/SamplerTypes/NormalSampler) structs as references for implementing your own [ISampler](../../Runtime/Randomization/Samplers/ISampler). Note that the NativeSamples() method in the ISampler interface requires the usage of the Unity Job System. Take a look [here](https://docs.unity3d.com/Manual/JobSystem.html) to learn more about how to create jobs using the Unity Job System. |
|
|||
# Scenarios |
|||
|
|||
Scenarios have three responsibilities: |
|||
1. Controlling the execution flow of your simulation |
|||
2. Customizing the application of random parameters in your project |
|||
3. Defining constants that can be configured externally from a built Unity player |
|||
|
|||
By default, the perception package includes one ready-made scenario, the `FixedFrameLengthScenario` class. This scenario is useful for when all created parameters have target GameObjects configured directly in the `ParameterConfiguration` and the scenario execution requires little modification. |
|||
|
|||
More commonly, users will find the need to create their own Scenario class. Below is an overview of the more common scenario properties and methods a user can override: |
|||
1. **isIterationComplete** - determines the conditions that cause the end of a scenario iteration |
|||
2. **isScenarioComplete** - determines the conditions that cause the end of a scenario |
|||
3. **Initialize** - actions to complete before the scenario has begun iterating |
|||
4. **Setup** - actions to complete at the beginning of each iteration |
|||
5. **Teardown** - actions to complete at the end of each iteration |
|||
6. **OnComplete** - actions to complete after the scenario as completed |
|||
|
|||
## Constants |
|||
Scenarios define constants from which to expose global simulation behaviors like a starting iteration value or a total iteration count. Users can serialize these scenario constants to JSON, modify them in an external program, and finally reimport the JSON constants at runtime to configure their simulation even after their project has been built. Below is an example of the constants used in the `FixedFrameLengthScenario` class: |
|||
``` |
|||
[Serializable] |
|||
public class Constants |
|||
{ |
|||
public int iterationFrameLength = 1; |
|||
public int startingIteration; |
|||
public int totalIterations = 1000; |
|||
} |
|||
``` |
|||
A few key things to note here: |
|||
1. Make sure to include the [Serializable] attribute on a constant class. This will ensure that the constants can be manipulated from the Unity inspector. |
|||
2. By default, UnityEngine.Object class references cannot be serialized to JSON in a meaningful way. This includes Monobehaviors and SerializedObjects. For more information on what can and can't be serialized, take a look at the [Unity JsonUtility manual](https://docs.unity3d.com/ScriptReference/JsonUtility.html). |
|||
3. A scenario class's Serialize() and Deserialized() methods can be overriden to implement custom serialization strategies. |
|
|||
# Randomization Tutorial |
|||
|
|||
This goal of this tutorial is to walk users through an example randomized perception project that explores the following activities: |
|||
1. Creating a parameter configuration |
|||
2. Customizing parameters and samplers |
|||
4. Configuring a scenario to run the simulation |
|||
5. Configure the perception camera |
|||
6. Building a simulation runtime |
|||
7. Modifying scenario constants |
|||
|
|||
By the end of this guide, the user should have a new project that generates the perception data necessary to train a model to recognize a cube from a solid colored background. |
|||
|
|||
Note: Before beginning the tutorial, follow [this guide](../SetupSteps.md) to install the perception package into a new Unity project. |
|||
|
|||
|
|||
## Step 1: Create Scene and GameObjects |
|||
1. Create a new scene using `File -> New Scene` |
|||
2. Use the key combo `Ctrl+S` to save and name the new scene |
|||
3. Create a new cube GameObject |
|||
1. Create a new cube GameObject by navigating to `GameObject -> 3D Object -> Cube` in the menubar |
|||
2. Rename the new cube GameObject "Cube" by double clicking on the new GameObject that appeared in the hierarchy |
|||
3. Reset the cube's transform component by right clicking on transform component in the cube's inpector and clicking `Reset` |
|||
4. Create a new background GameObject |
|||
1. Create a new quad GameObject and rename it "Background" |
|||
2. Set the background quad's position to (0, 0, 2) to set it behind the cube and make the quad large enough to fill the camera by change the quad's scale to (30, 30, 1) |
|||
5. In the *MeshRenderer* component of the *Cube* and *Background* GameObjects, set `Lighting -> Cast shadows -> Off` to prevent the two objects from casting shadows on each other |
|||
|
|||
|
|||
## Step 2: Create Parameter Configuration |
|||
1. Create a new empty GameObject by using `GameObject -> Create Empty` from the menubar |
|||
2. Rename the new empty GameObject "Config" by double clicking on the new GameObject that appeared in the hierarchy |
|||
3. To add a new Parameter Configuration component to the Config GameObject, click on the GameObject in the hierarchy and then click the `Add Component` button in the inspector window. Select `Randomization -> Parameter Configuration` to add the new component. |
|||
|
|||
|
|||
## Step 3: Create and Customize Parameters |
|||
In this step, we will configure 6 parameters to randomize the scene: *CubePosition*, *CubeRotation*, *CubeScale*, *CubeColor*, *BackgroundColor*, and *CameraRotation* |
|||
|
|||
#### Parameter 1: Cube Position |
|||
1. Create a new Vector3 parameter by clicking *Add New Parameter -> Vector3* on the parameter configuration inspector |
|||
2. Rename the parameter "CubePosition" by typing the text box next to the blue text indicating the parameter's type |
|||
3. Click the *Target GameObject* checkbox and select the *Cube* GameObject in the target object selector. Select the property *position* from the property dropdown. |
|||
4. Consider using the following sampler values: |
|||
* X : Uniform [-5, 5] |
|||
* Y : Uniform [-5, 5] |
|||
* Z : Constant [Value = 0] |
|||
|
|||
#### Parameter 2: Cube Rotation |
|||
1. Create a new Vector3 parameter named "CubeRotation" |
|||
2. Select the *Cube* GameObject as the target GameObject and select the property *Transform.eulerAngles* from the property dropdown |
|||
3. Consider using the following component values: |
|||
* X : Uniform [0, 360] |
|||
* Y : Uniform [0, 360] |
|||
* Z : Uniform [0, 360] |
|||
|
|||
#### Parameter 3: Cube Scale |
|||
1. Create a new Vector3 parameter named "CubeScale" |
|||
2. Select the *Cube* GameObject as the target GameObject and select the property *Transform.localScale* from the property dropdown |
|||
3. Consider using the following component values: |
|||
* X : Uniform [0.5, 2] |
|||
* Y : Uniform [0.5, 2] |
|||
* Z : Uniform [0.5, 2] |
|||
4. To ensure that the X, Y, and Z samplers all sample equal scale values, copy the X sampler's random seed to all three samplers |
|||
|
|||
#### Parameter 4: Cube Color |
|||
1. Create a new ColorHSVA parameter named "CubeColor" |
|||
2. Skip setting the target GameObject. We will be using this parameter from within the scenario instead. |
|||
3. Consider using the following component values: |
|||
* Hue : Uniform [0, 1] |
|||
* Saturation : Uniform [0, 1] |
|||
* Value : Uniform [0.25, 1] |
|||
* Alpha : Constant [Value = 0] |
|||
|
|||
#### Parameter 5: Background Color |
|||
1. Create a new ColorHSVA parameter named "BackgroundColor" |
|||
2. Skip setting the target GameObject. We will be using this parameter from within the scenario instead. |
|||
3. Consider using the following component values: |
|||
* Hue : Uniform [0, 1] |
|||
* Saturation : Uniform [0, 1] |
|||
* Value : Uniform [0.25, 1] |
|||
* Alpha : Constant [Value = 0] |
|||
|
|||
#### Parameter 6: Camera Rotation |
|||
1. Create a new Vector3 parameter named "CameraRotation" |
|||
2. Select the *Main Camera* GameObject as the target GameObject and select the property *Transform.eulerAngles* from the property dropdown |
|||
3. Consider using the following component values: |
|||
* X : Constant [Value = 0] |
|||
* Y : Constant [Value = 0] |
|||
* Z : Uniform [0, 360] |
|||
|
|||
|
|||
## Step 4: Configure Scenario |
|||
1. Right click on the *Scripts* folder in the project hierarchy and select `Create -> C# Script`. Name the script "CubeScenario" and press enter. |
|||
2. Double click on the new "CubeScenario" script to open it for edit |
|||
3. In your code editor, paste the following C# code in the CubeScenario script: |
|||
``` |
|||
using System; |
|||
using UnityEngine; |
|||
using UnityEngine.Perception.Randomization.Parameters; |
|||
using UnityEngine.Perception.Randomization.Scenarios; |
|||
|
|||
public class CubeScenario : Scenario<CubeScenario.Constants> |
|||
{ |
|||
[Serializable] |
|||
public class Constants |
|||
{ |
|||
public int totalIterations = 1000; |
|||
} |
|||
|
|||
public override bool isIterationComplete => framesSinceIterationSetup >= 1; |
|||
public override bool isScenarioComplete => currentIteration >= constants.totalIterations; |
|||
|
|||
public ColorHsvaParameter backgroundColorParameter; |
|||
public ColorHsvaParameter cubeColorParameter; |
|||
public GameObject background; |
|||
public GameObject cube; |
|||
|
|||
Material m_BackgroundMaterial; |
|||
Material m_CubeMaterial; |
|||
static readonly int k_BaseColor = Shader.PropertyToID("_BaseColor"); |
|||
|
|||
public override void OnInitialize() |
|||
{ |
|||
m_BackgroundMaterial = background.GetComponent<MeshRenderer>().material; |
|||
m_CubeMaterial = cube.GetComponent<MeshRenderer>().material; |
|||
} |
|||
|
|||
public override void OnIterationSetup() |
|||
{ |
|||
m_BackgroundMaterial.SetColor(k_BaseColor, backgroundColorParameter.Sample(currentIteration)); |
|||
m_CubeMaterial.SetColor(k_BaseColor, cubeColorParameter.Sample(currentIteration)); |
|||
} |
|||
} |
|||
``` |
|||
So what is this CubeScenario script accomplishing? |
|||
1. The *Constants* nested class in this scenario script determines what scenario parameters can be JSON serialized. Only these parameters can be changed externally from a built player. In this example, we expose the number of total iterations the scenario will complete. |
|||
2. The overrided properties *isIterationComplete* and *isScenarioComplete* are checked before every frame to control the scenario's execution flow. In this case, the scenario will execute for only one frame for each iteration and continue executing until reaching the total iteration limit set by the *totalIterations* field in the constants class. |
|||
3. In Unity, manipulating the color of a material is a shader specific task that cannot be accomplished directly from a color parameter's target GameObject setting. Instead we: |
|||
1. Expose references to the cube and background color parameters in this scenario's inspector as the public script variables *backgroundColorParameter* and *cubeColorParameter* |
|||
2. Lookup the ID of the *_BaseColor* shader property |
|||
3. Override the OnInitialize() method to cache references to the materials attached to the cube and background GameObjects when the simulation starts |
|||
4. Override the OnIterationSetup() method to apply randomly sampled color values to the shaders of the cached materials at the beginning of each scenario iteration |
|||
4. Back in the Unity editor, navigate to the inspector of the *Config* GameObject and use `Add Component -> CubeScenario` to add the new CubeScenario component to your parameter configuration. |
|||
5. Open the constants dropdown and confirm how many iterations the scenario should run (the default is 1000) |
|||
6. Use the *backgroundColorParameter* and *cubeColorParameter* dropdowns to inform the script of which parameters in the configuration to use for the BackgroundColor and CubeColor respectively. |
|||
7. Select the *Background* and *Cube* GameObjects from their respective GameObject field selectors |
|||
8. Confirm that the scenario and parameter configuration are composed properly by clicking the play button in the editor. In the Game window, a cube of different sizes, rotations, scales, and colors should be appearing against a color changing background. |
|||
9. To serialize the constants used in the scenario to JSON for external modification after this project has been built into a runtime, click the *Serialize Config* button on the parameter configuration |
|||
|
|||
|
|||
## Step 5: Configure Perception Camera |
|||
Read through the [general perception getting started guide](../GettingStarted.md) before completing the following steps: |
|||
1. (For URP projects) Add GroundTruthRendererFeature |
|||
2. Add a *PerceptionCamera* component to the MainCamera |
|||
3. Label the cube |
|||
1. Add a *Labeling* component to the cube GameObject |
|||
2. Create a *LabelingConfiguration* asset |
|||
3. Add the cube label to the new configuration |
|||
4. Select the new configuration asset from the perception camera |
|||
4. Enter play mode to confirm that labeled data is being generated |
|||
|
|||
|
|||
## Step 6: Build Simulation Runtime |
|||
1. Create a new sub-folder under "Assets" in the Project Hierarchy named "BuildConfigurations" |
|||
2. Right click on the BuildConfigurations folder and use `Create -> Build -> Empty Build Configuration` to create a new build configuration asset |
|||
3. Rename the build configuration asset "TutorialBuild" |
|||
4. Copy the settings from the example build configuration screenshot below: |
|||
![TutorialBuild](Images/TutorialBuild.png) |
|||
5. Click the "Build" button in the upper righthand corner of the build configuration inspector to create an executable of the tutorial scene. |
|||
|
|||
|
|||
## Step 7: Modify Scenario Constants |
|||
**Note**: Make sure that the "Deserialize On Start" field is checked in the scenario's inspector. A player built without this field checked will cause the player to not load serialized constants. |
|||
|
|||
1. Navigate to the folder created during the build from the previous step of this tutorial (example: C:\projects\RandomizationTutorial\Builds\Tutorial) |
|||
2. Open the "_Data" folder (example: Tutorial_Data) and then open the "StreamingAssets" folder |
|||
3. Inside the folder should be the JSON scenario constants serialized from the parameter configuration in Step 4 |
|||
4. Edit this JSON file to update the scenario constants used in the player |
|||
5. Confirm the new constants are deserialized at runtime by executing the simulation |
|
|||
using System; |
|||
using UnityEditor; |
|||
using UnityEditor.UIElements; |
|||
using UnityEngine.UIElements; |
|||
|
|||
namespace UnityEngine.Perception.Randomization.Editor |
|||
{ |
|||
public class CategoricalOptionElement : VisualElement |
|||
{ |
|||
int m_Index; |
|||
SerializedProperty m_OptionsProperty; |
|||
SerializedProperty m_ProbabilitiesProperty; |
|||
|
|||
public CategoricalOptionElement(SerializedProperty optionsProperty, SerializedProperty probabilitiesProperty, ListView view) |
|||
{ |
|||
m_OptionsProperty = optionsProperty; |
|||
m_ProbabilitiesProperty = probabilitiesProperty; |
|||
|
|||
var template = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>( |
|||
$"{StaticData.uxmlDir}/CategoricalOptionElement.uxml"); |
|||
template.CloneTree(this); |
|||
|
|||
var removeButton = this.Q<Button>("remove"); |
|||
removeButton.clicked += () => |
|||
{ |
|||
optionsProperty.DeleteArrayElementAtIndex(m_Index); |
|||
probabilitiesProperty.DeleteArrayElementAtIndex(m_Index); |
|||
optionsProperty.serializedObject.ApplyModifiedProperties(); |
|||
view.Refresh(); |
|||
}; |
|||
} |
|||
|
|||
// Called from categorical parameter
|
|||
public void BindProperties(int i) |
|||
{ |
|||
m_Index = i; |
|||
var indexLabel = this.Q<Label>("index-label"); |
|||
indexLabel.text = $"[{m_Index}]"; |
|||
|
|||
var optionProperty = m_OptionsProperty.GetArrayElementAtIndex(i); |
|||
var option = this.Q<PropertyField>("option"); |
|||
option.BindProperty(optionProperty); |
|||
var label = option.Q<Label>(); |
|||
label.parent.Remove(label); |
|||
|
|||
var probabilityProperty = m_ProbabilitiesProperty.GetArrayElementAtIndex(i); |
|||
var probability = this.Q<FloatField>("probability"); |
|||
probability.RegisterValueChangedCallback((evt) => |
|||
{ |
|||
if (evt.newValue < 0f) |
|||
probability.value = 0f; |
|||
}); |
|||
probability.labelElement.style.minWidth = 0; |
|||
probability.labelElement.style.marginRight = 4; |
|||
probability.BindProperty(probabilityProperty); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 3066f77d411047baafb6cc454adc6e37 |
|||
timeCreated: 1595535184 |
|
|||
using UnityEngine; |
|||
using UnityEditor; |
|||
using UnityEditor.UIElements; |
|||
using UnityEngine.UIElements; |
|||
|
|||
namespace UnityEngine.Perception.Randomization.Editor |
|||
{ |
|||
public class FloatRangeElement : VisualElement |
|||
{ |
|||
public FloatRangeElement(SerializedProperty property) |
|||
{ |
|||
var template = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>($"{StaticData.uxmlDir}/FloatRangeElement.uxml"); |
|||
template.CloneTree(this); |
|||
|
|||
var minimumField = this.Q<FloatField>("minimum"); |
|||
minimumField.bindingPath = property.propertyPath + ".minimum"; |
|||
|
|||
var maximumField = this.Q<FloatField>("maximum"); |
|||
maximumField.bindingPath = property.propertyPath + ".maximum"; |
|||
|
|||
this.Bind(property.serializedObject); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: e37f169c618d471d8ed9614a41096437 |
|||
timeCreated: 1595281335 |
|
|||
fileFormatVersion: 2 |
|||
guid: 7d1007e5e43ddb348826f6466e129f6f |
|||
folderAsset: yes |
|||
DefaultImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: d555aa5357abff5438d7aa10822c77f5 |
|||
TextureImporter: |
|||
internalIDToNameTable: [] |
|||
externalObjects: {} |
|||
serializedVersion: 11 |
|||
mipmaps: |
|||
mipMapMode: 0 |
|||
enableMipMap: 1 |
|||
sRGBTexture: 1 |
|||
linearTexture: 0 |
|||
fadeOut: 0 |
|||
borderMipMap: 0 |
|||
mipMapsPreserveCoverage: 0 |
|||
alphaTestReferenceValue: 0.5 |
|||
mipMapFadeDistanceStart: 1 |
|||
mipMapFadeDistanceEnd: 3 |
|||
bumpmap: |
|||
convertToNormalMap: 0 |
|||
externalNormalMap: 0 |
|||
heightScale: 0.25 |
|||
normalMapFilter: 0 |
|||
isReadable: 0 |
|||
streamingMipmaps: 0 |
|||
streamingMipmapsPriority: 0 |
|||
grayScaleToAlpha: 0 |
|||
generateCubemap: 6 |
|||
cubemapConvolution: 0 |
|||
seamlessCubemap: 0 |
|||
textureFormat: 1 |
|||
maxTextureSize: 2048 |
|||
textureSettings: |
|||
serializedVersion: 2 |
|||
filterMode: -1 |
|||
aniso: 2 |
|||
mipBias: -100 |
|||
wrapU: 0 |
|||
wrapV: 0 |
|||
wrapW: 0 |
|||
nPOTScale: 1 |
|||
lightmap: 0 |
|||
compressionQuality: 50 |
|||
spriteMode: 0 |
|||
spriteExtrude: 1 |
|||
spriteMeshType: 1 |
|||
alignment: 0 |
|||
spritePivot: {x: 0.5, y: 0.5} |
|||
spritePixelsToUnits: 100 |
|||
spriteBorder: {x: 0, y: 0, z: 0, w: 0} |
|||
spriteGenerateFallbackPhysicsShape: 1 |
|||
alphaUsage: 1 |
|||
alphaIsTransparency: 0 |
|||
spriteTessellationDetail: -1 |
|||
textureType: 0 |
|||
textureShape: 1 |
|||
singleChannelComponent: 0 |
|||
maxTextureSizeSet: 0 |
|||
compressionQualitySet: 0 |
|||
textureFormatSet: 0 |
|||
applyGammaDecoding: 0 |
|||
platformSettings: |
|||
- serializedVersion: 3 |
|||
buildTarget: DefaultTexturePlatform |
|||
maxTextureSize: 8192 |
|||
resizeAlgorithm: 0 |
|||
textureFormat: -1 |
|||
textureCompression: 1 |
|||
compressionQuality: 50 |
|||
crunchedCompression: 0 |
|||
allowsAlphaSplitting: 0 |
|||
overridden: 0 |
|||
androidETC2FallbackOverride: 0 |
|||
forceMaximumCompressionQuality_BC6H_BC7: 0 |
|||
- serializedVersion: 3 |
|||
buildTarget: Standalone |
|||
maxTextureSize: 8192 |
|||
resizeAlgorithm: 0 |
|||
textureFormat: -1 |
|||
textureCompression: 1 |
|||
compressionQuality: 50 |
|||
crunchedCompression: 0 |
|||
allowsAlphaSplitting: 0 |
|||
overridden: 0 |
|||
androidETC2FallbackOverride: 0 |
|||
forceMaximumCompressionQuality_BC6H_BC7: 0 |
|||
- serializedVersion: 3 |
|||
buildTarget: iPhone |
|||
maxTextureSize: 8192 |
|||
resizeAlgorithm: 0 |
|||
textureFormat: -1 |
|||
textureCompression: 1 |
|||
compressionQuality: 50 |
|||
crunchedCompression: 0 |
|||
allowsAlphaSplitting: 0 |
|||
overridden: 0 |
|||
androidETC2FallbackOverride: 0 |
|||
forceMaximumCompressionQuality_BC6H_BC7: 0 |
|||
- serializedVersion: 3 |
|||
buildTarget: Android |
|||
maxTextureSize: 8192 |
|||
resizeAlgorithm: 0 |
|||
textureFormat: -1 |
|||
textureCompression: 1 |
|||
compressionQuality: 50 |
|||
crunchedCompression: 0 |
|||
allowsAlphaSplitting: 0 |
|||
overridden: 0 |
|||
androidETC2FallbackOverride: 0 |
|||
forceMaximumCompressionQuality_BC6H_BC7: 0 |
|||
- serializedVersion: 3 |
|||
buildTarget: Windows Store Apps |
|||
maxTextureSize: 8192 |
|||
resizeAlgorithm: 0 |
|||
textureFormat: -1 |
|||
textureCompression: 1 |
|||
compressionQuality: 50 |
|||
crunchedCompression: 0 |
|||
allowsAlphaSplitting: 0 |
|||
overridden: 0 |
|||
androidETC2FallbackOverride: 0 |
|||
forceMaximumCompressionQuality_BC6H_BC7: 0 |
|||
spriteSheet: |
|||
serializedVersion: 2 |
|||
sprites: [] |
|||
outline: [] |
|||
physicsShape: [] |
|||
bones: [] |
|||
spriteID: |
|||
internalID: 0 |
|||
vertices: [] |
|||
indices: |
|||
edges: [] |
|||
weights: [] |
|||
secondaryTextures: [] |
|||
spritePackingTag: |
|||
pSDRemoveMatte: 0 |
|||
pSDShowRemoveMatteOption: 0 |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: 7818c5e4d2413b34482d07005d447bfc |
|||
TextureImporter: |
|||
internalIDToNameTable: [] |
|||
externalObjects: {} |
|||
serializedVersion: 11 |
|||
mipmaps: |
|||
mipMapMode: 0 |
|||
enableMipMap: 1 |
|||
sRGBTexture: 1 |
|||
linearTexture: 0 |
|||
fadeOut: 0 |
|||
borderMipMap: 0 |
|||
mipMapsPreserveCoverage: 0 |
|||
alphaTestReferenceValue: 0.5 |
|||
mipMapFadeDistanceStart: 1 |
|||
mipMapFadeDistanceEnd: 3 |
|||
bumpmap: |
|||
convertToNormalMap: 0 |
|||
externalNormalMap: 0 |
|||
heightScale: 0.25 |
|||
normalMapFilter: 0 |
|||
isReadable: 0 |
|||
streamingMipmaps: 0 |
|||
streamingMipmapsPriority: 0 |
|||
grayScaleToAlpha: 0 |
|||
generateCubemap: 6 |
|||
cubemapConvolution: 0 |
|||
seamlessCubemap: 0 |
|||
textureFormat: 1 |
|||
maxTextureSize: 2048 |
|||
textureSettings: |
|||
serializedVersion: 2 |
|||
filterMode: -1 |
|||
aniso: 2 |
|||
mipBias: -100 |
|||
wrapU: 0 |
|||
wrapV: 0 |
|||
wrapW: 0 |
|||
nPOTScale: 1 |
|||
lightmap: 0 |
|||
compressionQuality: 50 |
|||
spriteMode: 0 |
|||
spriteExtrude: 1 |
|||
spriteMeshType: 1 |
|||
alignment: 0 |
|||
spritePivot: {x: 0.5, y: 0.5} |
|||
spritePixelsToUnits: 100 |
|||
spriteBorder: {x: 0, y: 0, z: 0, w: 0} |
|||
spriteGenerateFallbackPhysicsShape: 1 |
|||
alphaUsage: 1 |
|||
alphaIsTransparency: 0 |
|||
spriteTessellationDetail: -1 |
|||
textureType: 0 |
|||
textureShape: 1 |
|||
singleChannelComponent: 0 |
|||
maxTextureSizeSet: 0 |
|||
compressionQualitySet: 0 |
|||
textureFormatSet: 0 |
|||
applyGammaDecoding: 0 |
|||
platformSettings: |
|||
- serializedVersion: 3 |
|||
buildTarget: DefaultTexturePlatform |
|||
maxTextureSize: 8192 |
|||
resizeAlgorithm: 0 |
|||
textureFormat: -1 |
|||
textureCompression: 1 |
|||
compressionQuality: 50 |
|||
crunchedCompression: 0 |
|||
allowsAlphaSplitting: 0 |
|||
overridden: 0 |
|||
androidETC2FallbackOverride: 0 |
|||
forceMaximumCompressionQuality_BC6H_BC7: 0 |
|||
- serializedVersion: 3 |
|||
buildTarget: Standalone |
|||
maxTextureSize: 8192 |
|||
resizeAlgorithm: 0 |
|||
textureFormat: -1 |
|||
textureCompression: 1 |
|||
compressionQuality: 50 |
|||
crunchedCompression: 0 |
|||
allowsAlphaSplitting: 0 |
|||
overridden: 0 |
|||
androidETC2FallbackOverride: 0 |
|||
forceMaximumCompressionQuality_BC6H_BC7: 0 |
|||
- serializedVersion: 3 |
|||
buildTarget: iPhone |
|||
maxTextureSize: 8192 |
|||
resizeAlgorithm: 0 |
|||
textureFormat: -1 |
|||
textureCompression: 1 |
|||
compressionQuality: 50 |
|||
crunchedCompression: 0 |
|||
allowsAlphaSplitting: 0 |
|||
overridden: 0 |
|||
androidETC2FallbackOverride: 0 |
|||
forceMaximumCompressionQuality_BC6H_BC7: 0 |
|||
- serializedVersion: 3 |
|||
buildTarget: Android |
|||
maxTextureSize: 8192 |
|||
resizeAlgorithm: 0 |
|||
textureFormat: -1 |
|||
textureCompression: 1 |
|||
compressionQuality: 50 |
|||
crunchedCompression: 0 |
|||
allowsAlphaSplitting: 0 |
|||
overridden: 0 |
|||
androidETC2FallbackOverride: 0 |
|||
forceMaximumCompressionQuality_BC6H_BC7: 0 |
|||
- serializedVersion: 3 |
|||
buildTarget: Windows Store Apps |
|||
maxTextureSize: 8192 |
|||
resizeAlgorithm: 0 |
|||
textureFormat: -1 |
|||
textureCompression: 1 |
|||
compressionQuality: 50 |
|||
crunchedCompression: 0 |
|||
allowsAlphaSplitting: 0 |
|||
overridden: 0 |
|||
androidETC2FallbackOverride: 0 |
|||
forceMaximumCompressionQuality_BC6H_BC7: 0 |
|||
spriteSheet: |
|||
serializedVersion: 2 |
|||
sprites: [] |
|||
outline: [] |
|||
physicsShape: [] |
|||
bones: [] |
|||
spriteID: |
|||
internalID: 0 |
|||
vertices: [] |
|||
indices: |
|||
edges: [] |
|||
weights: [] |
|||
secondaryTextures: [] |
|||
spritePackingTag: |
|||
pSDRemoveMatte: 0 |
|||
pSDShowRemoveMatteOption: 0 |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: 0960d5f2a553d8f4fbb79f2a4c362c45 |
|||
TextureImporter: |
|||
internalIDToNameTable: [] |
|||
externalObjects: {} |
|||
serializedVersion: 11 |
|||
mipmaps: |
|||
mipMapMode: 0 |
|||
enableMipMap: 1 |
|||
sRGBTexture: 1 |
|||
linearTexture: 0 |
|||
fadeOut: 0 |
|||
borderMipMap: 0 |
|||
mipMapsPreserveCoverage: 0 |
|||
alphaTestReferenceValue: 0.5 |
|||
mipMapFadeDistanceStart: 1 |
|||
mipMapFadeDistanceEnd: 3 |
|||
bumpmap: |
|||
convertToNormalMap: 0 |
|||
externalNormalMap: 0 |
|||
heightScale: 0.25 |
|||
normalMapFilter: 0 |
|||
isReadable: 0 |
|||
streamingMipmaps: 0 |
|||
streamingMipmapsPriority: 0 |
|||
grayScaleToAlpha: 0 |
|||
generateCubemap: 6 |
|||
cubemapConvolution: 0 |
|||
seamlessCubemap: 0 |
|||
textureFormat: 1 |
|||
maxTextureSize: 2048 |
|||
textureSettings: |
|||
serializedVersion: 2 |
|||
filterMode: -1 |
|||
aniso: 2 |
|||
mipBias: -100 |
|||
wrapU: 0 |
|||
wrapV: 0 |
|||
wrapW: 0 |
|||
nPOTScale: 1 |
|||
lightmap: 0 |
|||
compressionQuality: 50 |
|||
spriteMode: 0 |
|||
spriteExtrude: 1 |
|||
spriteMeshType: 1 |
|||
alignment: 0 |
|||
spritePivot: {x: 0.5, y: 0.5} |
|||
spritePixelsToUnits: 100 |
|||
spriteBorder: {x: 0, y: 0, z: 0, w: 0} |
|||
spriteGenerateFallbackPhysicsShape: 1 |
|||
alphaUsage: 1 |
|||
alphaIsTransparency: 0 |
|||
spriteTessellationDetail: -1 |
|||
textureType: 0 |
|||
textureShape: 1 |
|||
singleChannelComponent: 0 |
|||
maxTextureSizeSet: 0 |
|||
compressionQualitySet: 0 |
|||
textureFormatSet: 0 |
|||
applyGammaDecoding: 0 |
|||
platformSettings: |
|||
- serializedVersion: 3 |
|||
buildTarget: DefaultTexturePlatform |
|||
maxTextureSize: 8192 |
|||
resizeAlgorithm: 0 |
|||
textureFormat: -1 |
|||
textureCompression: 1 |
|||
compressionQuality: 50 |
|||
crunchedCompression: 0 |
|||
allowsAlphaSplitting: 0 |
|||
overridden: 0 |
|||
androidETC2FallbackOverride: 0 |
|||
forceMaximumCompressionQuality_BC6H_BC7: 0 |
|||
- serializedVersion: 3 |
|||
buildTarget: Standalone |
|||
maxTextureSize: 8192 |
|||
resizeAlgorithm: 0 |
|||
textureFormat: -1 |
|||
textureCompression: 1 |
|||
compressionQuality: 50 |
|||
crunchedCompression: 0 |
|||
allowsAlphaSplitting: 0 |
|||
overridden: 0 |
|||
androidETC2FallbackOverride: 0 |
|||
forceMaximumCompressionQuality_BC6H_BC7: 0 |
|||
- serializedVersion: 3 |
|||
buildTarget: iPhone |
|||
maxTextureSize: 8192 |
|||
resizeAlgorithm: 0 |
|||
textureFormat: -1 |
|||
textureCompression: 1 |
|||
compressionQuality: 50 |
|||
crunchedCompression: 0 |
|||
allowsAlphaSplitting: 0 |
|||
overridden: 0 |
|||
androidETC2FallbackOverride: 0 |
|||
forceMaximumCompressionQuality_BC6H_BC7: 0 |
|||
- serializedVersion: 3 |
|||
buildTarget: Android |
|||
maxTextureSize: 8192 |
|||
resizeAlgorithm: 0 |
|||
textureFormat: -1 |
|||
textureCompression: 1 |
|||
compressionQuality: 50 |
|||
crunchedCompression: 0 |
|||
allowsAlphaSplitting: 0 |
|||
overridden: 0 |
|||
androidETC2FallbackOverride: 0 |
|||
forceMaximumCompressionQuality_BC6H_BC7: 0 |
|||
- serializedVersion: 3 |
|||
buildTarget: Windows Store Apps |
|||
maxTextureSize: 8192 |
|||
resizeAlgorithm: 0 |
|||
textureFormat: -1 |
|||
textureCompression: 1 |
|||
compressionQuality: 50 |
|||
crunchedCompression: 0 |
|||
allowsAlphaSplitting: 0 |
|||
overridden: 0 |
|||
androidETC2FallbackOverride: 0 |
|||
forceMaximumCompressionQuality_BC6H_BC7: 0 |
|||
spriteSheet: |
|||
serializedVersion: 2 |
|||
sprites: [] |
|||
outline: [] |
|||
physicsShape: [] |
|||
bones: [] |
|||
spriteID: |
|||
internalID: 0 |
|||
vertices: [] |
|||
indices: |
|||
edges: [] |
|||
weights: [] |
|||
secondaryTextures: [] |
|||
spritePackingTag: |
|||
pSDRemoveMatte: 0 |
|||
pSDShowRemoveMatteOption: 0 |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: 0ae23578b45dce7478d3364d8b237294 |
|||
TextureImporter: |
|||
internalIDToNameTable: [] |
|||
externalObjects: {} |
|||
serializedVersion: 11 |
|||
mipmaps: |
|||
mipMapMode: 0 |
|||
enableMipMap: 1 |
|||
sRGBTexture: 1 |
|||
linearTexture: 0 |
|||
fadeOut: 0 |
|||
borderMipMap: 0 |
|||
mipMapsPreserveCoverage: 0 |
|||
alphaTestReferenceValue: 0.5 |
|||
mipMapFadeDistanceStart: 1 |
|||
mipMapFadeDistanceEnd: 3 |
|||
bumpmap: |
|||
convertToNormalMap: 0 |
|||
externalNormalMap: 0 |
|||
heightScale: 0.25 |
|||
normalMapFilter: 0 |
|||
isReadable: 0 |
|||
streamingMipmaps: 0 |
|||
streamingMipmapsPriority: 0 |
|||
grayScaleToAlpha: 0 |
|||
generateCubemap: 6 |
|||
cubemapConvolution: 0 |
|||
seamlessCubemap: 0 |
|||
textureFormat: 1 |
|||
maxTextureSize: 2048 |
|||
textureSettings: |
|||
serializedVersion: 2 |
|||
filterMode: -1 |
|||
aniso: 2 |
|||
mipBias: -100 |
|||
wrapU: 0 |
|||
wrapV: 0 |
|||
wrapW: 0 |
|||
nPOTScale: 1 |
|||
lightmap: 0 |
|||
compressionQuality: 50 |
|||
spriteMode: 0 |
|||
spriteExtrude: 1 |
|||
spriteMeshType: 1 |
|||
alignment: 0 |
|||
spritePivot: {x: 0.5, y: 0.5} |
|||
spritePixelsToUnits: 100 |
|||
spriteBorder: {x: 0, y: 0, z: 0, w: 0} |
|||
spriteGenerateFallbackPhysicsShape: 1 |
|||
alphaUsage: 1 |
|||
alphaIsTransparency: 0 |
|||
spriteTessellationDetail: -1 |
|||
textureType: 0 |
|||
textureShape: 1 |
|||
singleChannelComponent: 0 |
|||
maxTextureSizeSet: 0 |
|||
compressionQualitySet: 0 |
|||
textureFormatSet: 0 |
|||
applyGammaDecoding: 0 |
|||
platformSettings: |
|||
- serializedVersion: 3 |
|||
buildTarget: DefaultTexturePlatform |
|||
maxTextureSize: 8192 |
|||
resizeAlgorithm: 0 |
|||
textureFormat: -1 |
|||
textureCompression: 1 |
|||
compressionQuality: 50 |
|||
crunchedCompression: 0 |
|||
allowsAlphaSplitting: 0 |
|||
overridden: 0 |
|||
androidETC2FallbackOverride: 0 |
|||
forceMaximumCompressionQuality_BC6H_BC7: 0 |
|||
- serializedVersion: 3 |
|||
buildTarget: Standalone |
|||
maxTextureSize: 8192 |
|||
resizeAlgorithm: 0 |
|||
textureFormat: -1 |
|||
textureCompression: 1 |
|||
compressionQuality: 50 |
|||
crunchedCompression: 0 |
|||
allowsAlphaSplitting: 0 |
|||
overridden: 0 |
|||
androidETC2FallbackOverride: 0 |
|||
forceMaximumCompressionQuality_BC6H_BC7: 0 |
|||
- serializedVersion: 3 |
|||
buildTarget: iPhone |
|||
maxTextureSize: 8192 |
|||
resizeAlgorithm: 0 |
|||
textureFormat: -1 |
|||
textureCompression: 1 |
|||
compressionQuality: 50 |
|||
crunchedCompression: 0 |
|||
allowsAlphaSplitting: 0 |
|||
overridden: 0 |
|||
androidETC2FallbackOverride: 0 |
|||
forceMaximumCompressionQuality_BC6H_BC7: 0 |
|||
- serializedVersion: 3 |
|||
buildTarget: Android |
|||
maxTextureSize: 8192 |
|||
resizeAlgorithm: 0 |
|||
textureFormat: -1 |
|||
textureCompression: 1 |
|||
compressionQuality: 50 |
|||
crunchedCompression: 0 |
|||
allowsAlphaSplitting: 0 |
|||
overridden: 0 |
|||
androidETC2FallbackOverride: 0 |
|||
forceMaximumCompressionQuality_BC6H_BC7: 0 |
|||
- serializedVersion: 3 |
|||
buildTarget: Windows Store Apps |
|||
maxTextureSize: 8192 |
|||
resizeAlgorithm: 0 |
|||
textureFormat: -1 |
|||
textureCompression: 1 |
|||
compressionQuality: 50 |
|||
crunchedCompression: 0 |
|||
allowsAlphaSplitting: 0 |
|||
overridden: 0 |
|||
androidETC2FallbackOverride: 0 |
|||
forceMaximumCompressionQuality_BC6H_BC7: 0 |
|||
spriteSheet: |
|||
serializedVersion: 2 |
|||
sprites: [] |
|||
outline: [] |
|||
physicsShape: [] |
|||
bones: [] |
|||
spriteID: |
|||
internalID: 0 |
|||
vertices: [] |
|||
indices: |
|||
edges: [] |
|||
weights: [] |
|||
secondaryTextures: [] |
|||
spritePackingTag: |
|||
pSDRemoveMatte: 0 |
|||
pSDShowRemoveMatteOption: 0 |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: 26335dfb433170348ad78bfe72dc07ff |
|||
TextureImporter: |
|||
internalIDToNameTable: [] |
|||
externalObjects: {} |
|||
serializedVersion: 11 |
|||
mipmaps: |
|||
mipMapMode: 0 |
|||
enableMipMap: 1 |
|||
sRGBTexture: 1 |
|||
linearTexture: 0 |
|||
fadeOut: 0 |
|||
borderMipMap: 0 |
|||
mipMapsPreserveCoverage: 0 |
|||
alphaTestReferenceValue: 0.5 |
|||
mipMapFadeDistanceStart: 1 |
|||
mipMapFadeDistanceEnd: 3 |
|||
bumpmap: |
|||
convertToNormalMap: 0 |
|||
externalNormalMap: 0 |
|||
heightScale: 0.25 |
|||
normalMapFilter: 0 |
|||
isReadable: 0 |
|||
streamingMipmaps: 0 |
|||
streamingMipmapsPriority: 0 |
|||
grayScaleToAlpha: 0 |
|||
generateCubemap: 6 |
|||
cubemapConvolution: 0 |
|||
seamlessCubemap: 0 |
|||
textureFormat: 1 |
|||
maxTextureSize: 2048 |
|||
textureSettings: |
|||
serializedVersion: 2 |
|||
filterMode: -1 |
|||
aniso: 2 |
|||
mipBias: -100 |
|||
wrapU: 0 |
|||
wrapV: 0 |
|||
wrapW: 0 |
|||
nPOTScale: 1 |
|||
lightmap: 0 |
|||
compressionQuality: 50 |
|||
spriteMode: 0 |
|||
spriteExtrude: 1 |
|||
spriteMeshType: 1 |
|||
alignment: 0 |
|||
spritePivot: {x: 0.5, y: 0.5} |
|||
spritePixelsToUnits: 100 |
|||
spriteBorder: {x: 0, y: 0, z: 0, w: 0} |
|||
spriteGenerateFallbackPhysicsShape: 1 |
|||
alphaUsage: 1 |
|||
alphaIsTransparency: 0 |
|||
spriteTessellationDetail: -1 |
|||
textureType: 0 |
|||
textureShape: 1 |
|||
singleChannelComponent: 0 |
|||
maxTextureSizeSet: 0 |
|||
compressionQualitySet: 0 |
|||
textureFormatSet: 0 |
|||
applyGammaDecoding: 0 |
|||
platformSettings: |
|||
- serializedVersion: 3 |
|||
buildTarget: DefaultTexturePlatform |
|||
maxTextureSize: 8192 |
|||
resizeAlgorithm: 0 |
|||
textureFormat: -1 |
|||
textureCompression: 1 |
|||
compressionQuality: 50 |
|||
crunchedCompression: 0 |
|||
allowsAlphaSplitting: 0 |
|||
overridden: 0 |
|||
androidETC2FallbackOverride: 0 |
|||
forceMaximumCompressionQuality_BC6H_BC7: 0 |
|||
- serializedVersion: 3 |
|||
buildTarget: Standalone |
|||
maxTextureSize: 8192 |
|||
resizeAlgorithm: 0 |
|||
textureFormat: -1 |
|||
textureCompression: 1 |
|||
compressionQuality: 50 |
|||
crunchedCompression: 0 |
|||
allowsAlphaSplitting: 0 |
|||
overridden: 0 |
|||
androidETC2FallbackOverride: 0 |
|||
forceMaximumCompressionQuality_BC6H_BC7: 0 |
|||
- serializedVersion: 3 |
|||
buildTarget: iPhone |
|||
maxTextureSize: 8192 |
|||
resizeAlgorithm: 0 |
|||
textureFormat: -1 |
|||
textureCompression: 1 |
|||
compressionQuality: 50 |
|||
crunchedCompression: 0 |
|||
allowsAlphaSplitting: 0 |
|||
overridden: 0 |
|||
androidETC2FallbackOverride: 0 |
|||
forceMaximumCompressionQuality_BC6H_BC7: 0 |
|||
- serializedVersion: 3 |
|||
buildTarget: Android |
|||
maxTextureSize: 8192 |
|||
resizeAlgorithm: 0 |
|||
textureFormat: -1 |
|||
textureCompression: 1 |
|||
compressionQuality: 50 |
|||
crunchedCompression: 0 |
|||
allowsAlphaSplitting: 0 |
|||
overridden: 0 |
|||
androidETC2FallbackOverride: 0 |
|||
forceMaximumCompressionQuality_BC6H_BC7: 0 |
|||
- serializedVersion: 3 |
|||
buildTarget: Windows Store Apps |
|||
maxTextureSize: 8192 |
|||
resizeAlgorithm: 0 |
|||
textureFormat: -1 |
|||
textureCompression: 1 |
|||
compressionQuality: 50 |
|||
crunchedCompression: 0 |
|||
allowsAlphaSplitting: 0 |
|||
overridden: 0 |
|||
androidETC2FallbackOverride: 0 |
|||
forceMaximumCompressionQuality_BC6H_BC7: 0 |
|||
spriteSheet: |
|||
serializedVersion: 2 |
|||
sprites: [] |
|||
outline: [] |
|||
physicsShape: [] |
|||
bones: [] |
|||
spriteID: |
|||
internalID: 0 |
|||
vertices: [] |
|||
indices: |
|||
edges: [] |
|||
weights: [] |
|||
secondaryTextures: [] |
|||
spritePackingTag: |
|||
pSDRemoveMatte: 0 |
|||
pSDShowRemoveMatteOption: 0 |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System; |
|||
using UnityEngine; |
|||
using UnityEditor; |
|||
using UnityEditor.UIElements; |
|||
using UnityEngine.Perception.Randomization.Configuration; |
|||
using UnityEngine.Perception.Randomization.Parameters.Attributes; |
|||
using UnityEngine.Perception.Randomization.Samplers; |
|||
using UnityEngine.UIElements; |
|||
|
|||
namespace UnityEngine.Perception.Randomization.Editor |
|||
{ |
|||
[CustomEditor(typeof(ParameterConfiguration))] |
|||
public class ParameterConfigurationEditor : UnityEditor.Editor |
|||
{ |
|||
ParameterConfiguration m_Config; |
|||
VisualElement m_Root; |
|||
VisualElement m_ParameterContainer; |
|||
|
|||
string m_FilterString = string.Empty; |
|||
public string FilterString |
|||
{ |
|||
get => m_FilterString; |
|||
private set |
|||
{ |
|||
m_FilterString = value; |
|||
var lowerFilter = m_FilterString.ToLower(); |
|||
foreach (var child in m_ParameterContainer.Children()) |
|||
{ |
|||
var paramIndex = m_ParameterContainer.IndexOf(child); |
|||
var param = m_Config.parameters[paramIndex]; |
|||
((ParameterElement)child).Filtered = param.parameterName.ToLower().Contains(lowerFilter); |
|||
} |
|||
} |
|||
} |
|||
|
|||
public override VisualElement CreateInspectorGUI() |
|||
{ |
|||
m_Config = (ParameterConfiguration)target; |
|||
m_Root = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>( |
|||
$"{StaticData.uxmlDir}/ParameterConfiguration.uxml").CloneTree(); |
|||
|
|||
m_ParameterContainer = m_Root.Q<VisualElement>("parameters-container"); |
|||
|
|||
foreach (var parameter in m_Config.parameters) |
|||
m_ParameterContainer.Add(new ParameterElement(parameter, this)); |
|||
|
|||
var parameterTypeMenu = m_Root.Q<ToolbarMenu>("parameter-type-menu"); |
|||
foreach (var parameterType in StaticData.parameterTypes) |
|||
{ |
|||
parameterTypeMenu.menu.AppendAction( |
|||
ParameterMetaData.GetMetaData(parameterType).typeDisplayName, |
|||
a => { AddParameter(parameterType); }, |
|||
a => DropdownMenuAction.Status.Normal); |
|||
} |
|||
|
|||
var filter = m_Root.Q<TextField>("filter-parameters"); |
|||
filter.RegisterValueChangedCallback((e) => { FilterString = e.newValue; }); |
|||
|
|||
var collapseAllButton = m_Root.Q<Button>("collapse-all"); |
|||
collapseAllButton.clicked += () => CollapseParameters(true); |
|||
|
|||
var expandAllButton = m_Root.Q<Button>("expand-all"); |
|||
expandAllButton.clicked += () => CollapseParameters(false); |
|||
|
|||
return m_Root; |
|||
} |
|||
|
|||
void CollapseParameters(bool collapsed) |
|||
{ |
|||
foreach (var child in m_ParameterContainer.Children()) |
|||
((ParameterElement)child).Collapsed = collapsed; |
|||
} |
|||
|
|||
void AddParameter(Type parameterType) |
|||
{ |
|||
var parameter = m_Config.AddParameter(parameterType); |
|||
foreach (var sampler in parameter.Samplers) |
|||
sampler.seed = SamplerUtility.GenerateRandomSeed(); |
|||
parameter.hideFlags = HideFlags.HideInInspector; |
|||
m_ParameterContainer.Add(new ParameterElement(parameter, this)); |
|||
} |
|||
|
|||
public void RemoveParameter(VisualElement template) |
|||
{ |
|||
var paramIndex = m_ParameterContainer.IndexOf(template); |
|||
m_ParameterContainer.RemoveAt(paramIndex); |
|||
|
|||
var param = m_Config.parameters[paramIndex]; |
|||
m_Config.parameters.RemoveAt(paramIndex); |
|||
|
|||
DestroyImmediate(param); |
|||
} |
|||
|
|||
public void ReorderParameter(int currentIndex, int nextIndex) |
|||
{ |
|||
if (currentIndex == nextIndex) |
|||
return; |
|||
|
|||
if (nextIndex > currentIndex) |
|||
nextIndex--; |
|||
|
|||
var parameterElement = m_ParameterContainer[currentIndex]; |
|||
var parameter = m_Config.parameters[currentIndex]; |
|||
|
|||
parameterElement.RemoveFromHierarchy(); |
|||
m_Config.parameters.RemoveAt(currentIndex); |
|||
|
|||
m_ParameterContainer.Insert(nextIndex, parameterElement); |
|||
m_Config.parameters.Insert(nextIndex, parameter); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: dd62abede5784c84f90495b367408ced |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using UnityEngine.UIElements; |
|||
|
|||
namespace UnityEngine.Perception.Randomization.Editor |
|||
{ |
|||
public class ParameterDragBar : VisualElement |
|||
{ |
|||
public ParameterDragBar() |
|||
{ |
|||
AddToClassList("parameter-drag-bar"); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 7c1e08b02e5a4c55875f34baf32f8e76 |
|||
timeCreated: 1596143672 |
|
|||
using UnityEngine.UIElements; |
|||
|
|||
namespace UnityEngine.Perception.Randomization.Editor |
|||
{ |
|||
public class ParameterDragManipulator : MouseManipulator |
|||
{ |
|||
bool m_Active; |
|||
float m_Offset; |
|||
ParameterElement m_ParameterElement; |
|||
VisualElement m_DragHandle; |
|||
VisualElement m_DragBar; |
|||
VisualElement m_ParameterContainer; |
|||
|
|||
protected override void RegisterCallbacksOnTarget() |
|||
{ |
|||
m_DragHandle = target.Q<VisualElement>("drag-handle"); |
|||
m_ParameterElement = (ParameterElement)target; |
|||
m_DragHandle.RegisterCallback<MouseDownEvent>(OnMouseDown); |
|||
m_DragHandle.RegisterCallback<MouseMoveEvent>(OnMouseMove); |
|||
m_DragHandle.RegisterCallback<MouseUpEvent>(OnMouseUp); |
|||
} |
|||
|
|||
protected override void UnregisterCallbacksFromTarget() |
|||
{ |
|||
m_DragHandle.UnregisterCallback<MouseDownEvent>(OnMouseDown); |
|||
m_DragHandle.UnregisterCallback<MouseMoveEvent>(OnMouseMove); |
|||
m_DragHandle.UnregisterCallback<MouseUpEvent>(OnMouseUp); |
|||
} |
|||
|
|||
void OnMouseDown(MouseDownEvent evt) |
|||
{ |
|||
if (m_Active) |
|||
{ |
|||
evt.StopImmediatePropagation(); |
|||
return; |
|||
} |
|||
|
|||
if (m_ParameterElement.ConfigEditor.FilterString != string.Empty) |
|||
return; |
|||
|
|||
m_ParameterContainer = target.parent; |
|||
m_DragBar = new ParameterDragBar(); |
|||
m_DragBar.style.width = new StyleLength(m_ParameterContainer.resolvedStyle.width); |
|||
target.parent.Add(m_DragBar); |
|||
|
|||
m_Offset = m_DragHandle.worldBound.position.y - m_ParameterContainer.worldBound.position.y; |
|||
m_DragBar.style.top = evt.localMousePosition.y + m_Offset; |
|||
|
|||
m_Active = true; |
|||
m_DragHandle.CaptureMouse(); |
|||
evt.StopPropagation(); |
|||
} |
|||
|
|||
void OnMouseMove(MouseMoveEvent evt) |
|||
{ |
|||
if (!m_Active || !m_DragHandle.HasMouseCapture()) |
|||
return; |
|||
|
|||
m_DragBar.style.top = evt.localMousePosition.y + m_Offset; |
|||
|
|||
evt.StopPropagation(); |
|||
} |
|||
|
|||
void OnMouseUp(MouseUpEvent evt) |
|||
{ |
|||
if (!m_Active || !m_DragHandle.HasMouseCapture() || !CanStopManipulation(evt)) |
|||
return; |
|||
|
|||
var dragBarY = evt.localMousePosition.y + m_Offset; |
|||
m_DragBar.RemoveFromHierarchy(); |
|||
|
|||
m_Active = false; |
|||
m_DragHandle.ReleaseMouse(); |
|||
evt.StopPropagation(); |
|||
|
|||
var p = 0; |
|||
var middlePoints = new float[m_ParameterContainer.childCount]; |
|||
foreach (var parameterElement in m_ParameterContainer.Children()) |
|||
{ |
|||
var middleHeight = parameterElement.worldBound.height / 2; |
|||
var localY = parameterElement.worldBound.y - m_ParameterContainer.worldBound.position.y; |
|||
middlePoints[p++] = middleHeight + localY; |
|||
} |
|||
|
|||
for (var i = 0; i < middlePoints.Length; i++) |
|||
{ |
|||
if (dragBarY < middlePoints[i]) |
|||
{ |
|||
ReorderParameter(m_ParameterElement.ParameterIndex, i); |
|||
return; |
|||
} |
|||
} |
|||
ReorderParameter(m_ParameterElement.ParameterIndex, middlePoints.Length); |
|||
} |
|||
|
|||
void ReorderParameter(int currentIndex, int nextIndex) |
|||
{ |
|||
m_ParameterElement.ConfigEditor.ReorderParameter(currentIndex, nextIndex); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: f2b59fa8baf440f597257d8eb8219afa |
|||
timeCreated: 1596140810 |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using UnityEditor; |
|||
using UnityEngine.Perception.Randomization.Parameters; |
|||
using UnityEngine.Perception.Randomization.Parameters.Attributes; |
|||
using UnityEngine.UIElements; |
|||
|
|||
namespace UnityEngine.Perception.Randomization.Editor |
|||
{ |
|||
[CustomPropertyDrawer(typeof(Parameter), true)] |
|||
public class ParameterDrawer : PropertyDrawer |
|||
{ |
|||
List<Parameter> m_Parameters; |
|||
string[] m_Options; |
|||
int m_SelectedOptionIndex; |
|||
|
|||
public override VisualElement CreatePropertyGUI(SerializedProperty property) |
|||
{ |
|||
return new ParameterDrawerElement(property, fieldInfo); |
|||
} |
|||
|
|||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) |
|||
{ |
|||
GatherParameterOptions(); |
|||
GetParameterOptionIndex(property); |
|||
|
|||
EditorGUI.BeginProperty(position, label, property); |
|||
var originalOption = m_SelectedOptionIndex; |
|||
m_SelectedOptionIndex = EditorGUI.Popup(position, fieldInfo.Name, m_SelectedOptionIndex, m_Options); |
|||
if (originalOption != m_SelectedOptionIndex) |
|||
{ |
|||
property.objectReferenceValue = m_SelectedOptionIndex == 0 |
|||
? null |
|||
: m_Parameters[m_SelectedOptionIndex - 1]; |
|||
property.serializedObject.ApplyModifiedProperties(); |
|||
} |
|||
EditorGUI.EndProperty(); |
|||
} |
|||
|
|||
void GatherParameterOptions() |
|||
{ |
|||
var parameterType = fieldInfo.FieldType; |
|||
|
|||
m_Parameters = new List<Parameter>(); |
|||
|
|||
if (parameterType == typeof(Parameter)) |
|||
m_Parameters = Resources.FindObjectsOfTypeAll<Parameter>().ToList(); |
|||
else |
|||
{ |
|||
var genericParameters = Resources.FindObjectsOfTypeAll<Parameter>(); |
|||
foreach (var parameter in genericParameters) |
|||
{ |
|||
if (parameter.GetType() == parameterType) |
|||
m_Parameters.Add(parameter); |
|||
} |
|||
} |
|||
m_Parameters.Sort((p1, p2) => p1.parameterName.CompareTo(p2.parameterName)); |
|||
|
|||
m_Options = new string[m_Parameters.Count + 1]; |
|||
m_Options[0] = "None"; |
|||
for (var i = 1; i <= m_Parameters.Count; i++) |
|||
{ |
|||
var parameter = m_Parameters[i - 1]; |
|||
var metadata = ParameterMetaData.GetMetaData(parameter.GetType()); |
|||
m_Options[i] = $"{parameter.parameterName} ({metadata.typeDisplayName})"; |
|||
} |
|||
} |
|||
|
|||
void GetParameterOptionIndex(SerializedProperty property) |
|||
{ |
|||
var selectedParameter = property.objectReferenceValue; |
|||
if (selectedParameter != null) |
|||
{ |
|||
for (var i = 0; i < m_Parameters.Count; i++) |
|||
if (m_Parameters[i].GetInstanceID() == selectedParameter.GetInstanceID()) |
|||
{ |
|||
m_SelectedOptionIndex = i + 1; |
|||
break; |
|||
} |
|||
} |
|||
else |
|||
m_SelectedOptionIndex = 0; |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 4723714765b74b33850e58baa73bf9c2 |
|||
timeCreated: 1595428457 |
|
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Reflection; |
|||
using UnityEditor; |
|||
using UnityEditor.UIElements; |
|||
using UnityEngine.Perception.Randomization.Parameters; |
|||
using UnityEngine.Perception.Randomization.Parameters.Attributes; |
|||
using UnityEngine.UIElements; |
|||
|
|||
namespace UnityEngine.Perception.Randomization.Editor |
|||
{ |
|||
public class ParameterDrawerElement : BindableElement |
|||
{ |
|||
SerializedProperty m_Property; |
|||
FieldInfo m_FieldInfo; |
|||
ToolbarMenu m_ParameterMenu; |
|||
|
|||
public ParameterDrawerElement(SerializedProperty property, FieldInfo fieldInfo) |
|||
{ |
|||
m_Property = property; |
|||
m_FieldInfo = fieldInfo; |
|||
var template = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>( |
|||
$"{StaticData.uxmlDir}/ParameterDrawerElement.uxml"); |
|||
template.CloneTree(this); |
|||
|
|||
var propertyLabel = this.Q<Label>(); |
|||
propertyLabel.text = property.displayName; |
|||
m_ParameterMenu = this.Q<ToolbarMenu>(); |
|||
binding = new ParameterDrawerBinding(this); |
|||
} |
|||
|
|||
string GetSelectedOptionText() |
|||
{ |
|||
var parameter = m_Property.objectReferenceValue as Parameter; |
|||
if (parameter == null) |
|||
return "None"; |
|||
return DisplayName(parameter); |
|||
} |
|||
|
|||
static string DisplayName(Parameter parameter) |
|||
{ |
|||
return $"{parameter.parameterName} ({parameter.MetaData.typeDisplayName})"; |
|||
} |
|||
|
|||
void UpdateMenuOptions() |
|||
{ |
|||
m_ParameterMenu.menu.MenuItems().Clear(); |
|||
var parameters = GatherParameterOptions(); |
|||
var options = GetStringOptions(parameters); |
|||
for (var i = 0; i < options.Length; i++) |
|||
{ |
|||
var index = i; |
|||
var option = options[i]; |
|||
m_ParameterMenu.menu.AppendAction(option, action => |
|||
{ |
|||
m_Property.objectReferenceValue = option == "None" ? null : parameters[index - 1]; |
|||
m_Property.serializedObject.ApplyModifiedProperties(); |
|||
m_ParameterMenu.text = GetSelectedOptionText(); |
|||
}); |
|||
} |
|||
} |
|||
|
|||
Parameter[] GatherParameterOptions() |
|||
{ |
|||
var parameterType = m_FieldInfo.FieldType; |
|||
var parameters = new List<Parameter>(); |
|||
|
|||
if (parameterType == typeof(Parameter)) |
|||
parameters = Resources.FindObjectsOfTypeAll<Parameter>().ToList(); |
|||
else |
|||
{ |
|||
var genericParameters = Resources.FindObjectsOfTypeAll<Parameter>(); |
|||
foreach (var parameter in genericParameters) |
|||
{ |
|||
if (parameter.GetType() == parameterType) |
|||
parameters.Add(parameter); |
|||
} |
|||
} |
|||
parameters.Sort((p1, p2) => p1.parameterName.CompareTo(p2.parameterName)); |
|||
|
|||
return parameters.ToArray(); |
|||
} |
|||
|
|||
string[] GetStringOptions(Parameter[] parameters) |
|||
{ |
|||
var options = new string[parameters.Length + 1]; |
|||
options[0] = "None"; |
|||
for (var i = 1; i <= parameters.Length; i++) |
|||
{ |
|||
var parameter = parameters[i - 1]; |
|||
var metadata = ParameterMetaData.GetMetaData(parameter.GetType()); |
|||
options[i] = $"{parameter.parameterName} ({metadata.typeDisplayName})"; |
|||
} |
|||
return options; |
|||
} |
|||
|
|||
class ParameterDrawerBinding : IBinding |
|||
{ |
|||
ParameterDrawerElement m_Element; |
|||
|
|||
public ParameterDrawerBinding(ParameterDrawerElement element) => m_Element = element; |
|||
|
|||
public void PreUpdate() { } |
|||
|
|||
public void Update() |
|||
{ |
|||
m_Element.UpdateMenuOptions(); |
|||
m_Element.m_ParameterMenu.text = m_Element.GetSelectedOptionText(); |
|||
} |
|||
|
|||
public void Release() { } |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 3fd3617d27b14531a75a7a0ef1e45452 |
|||
timeCreated: 1596417699 |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using UnityEditor; |
|||
using UnityEditor.UIElements; |
|||
using UnityEngine.Perception.Randomization.Parameters; |
|||
using UnityEngine.UIElements; |
|||
|
|||
namespace UnityEngine.Perception.Randomization.Editor |
|||
{ |
|||
public class ParameterElement : VisualElement |
|||
{ |
|||
bool m_Filtered; |
|||
Parameter m_Parameter; |
|||
VisualElement m_Properties; |
|||
VisualElement m_ExtraProperties; |
|||
VisualElement m_TargetContainer; |
|||
ToolbarMenu m_TargetPropertyMenu; |
|||
SerializedObject m_SerializedObject; |
|||
|
|||
const string k_CollapsedParameterClass = "collapsed-parameter"; |
|||
|
|||
public int ParameterIndex => parent.IndexOf(this); |
|||
public ParameterConfigurationEditor ConfigEditor { get; private set; } |
|||
|
|||
public bool Collapsed |
|||
{ |
|||
get => ClassListContains(k_CollapsedParameterClass); |
|||
set |
|||
{ |
|||
if (value) |
|||
AddToClassList(k_CollapsedParameterClass); |
|||
else |
|||
RemoveFromClassList(k_CollapsedParameterClass); |
|||
} |
|||
} |
|||
|
|||
public bool Filtered |
|||
{ |
|||
get => m_Filtered; |
|||
set |
|||
{ |
|||
m_Filtered = value; |
|||
style.display = value |
|||
? new StyleEnum<DisplayStyle>(DisplayStyle.Flex) |
|||
: new StyleEnum<DisplayStyle>(DisplayStyle.None); |
|||
} |
|||
} |
|||
|
|||
public ParameterElement(Parameter parameter, ParameterConfigurationEditor paramConfigEditor) |
|||
{ |
|||
ConfigEditor = paramConfigEditor; |
|||
m_Parameter = parameter; |
|||
var template = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>( |
|||
$"{StaticData.uxmlDir}/ParameterElement.uxml"); |
|||
template.CloneTree(this); |
|||
|
|||
m_SerializedObject = new SerializedObject(parameter); |
|||
this.Bind(m_SerializedObject); |
|||
|
|||
this.AddManipulator(new ParameterDragManipulator()); |
|||
|
|||
var removeButton = this.Q<Button>("remove-parameter"); |
|||
removeButton.RegisterCallback<MouseUpEvent>(evt => paramConfigEditor.RemoveParameter(this)); |
|||
|
|||
var parameterTypeLabel = this.Query<Label>("parameter-type-label").First(); |
|||
parameterTypeLabel.text = parameter.MetaData.typeDisplayName; |
|||
|
|||
m_TargetContainer = this.Q<VisualElement>("target-container"); |
|||
ToggleTargetContainer(); |
|||
|
|||
m_TargetPropertyMenu = this.Q<ToolbarMenu>("property-select-menu"); |
|||
var targetField = this.Q<PropertyField>("target-field"); |
|||
targetField.RegisterCallback<ChangeEvent<Object>>((evt) => |
|||
{ |
|||
ClearTarget(); |
|||
parameter.target.gameObject = (GameObject)evt.newValue; |
|||
ToggleTargetContainer(); |
|||
FillPropertySelectMenu(); |
|||
}); |
|||
FillPropertySelectMenu(); |
|||
|
|||
var collapseToggle = this.Q<VisualElement>("collapse"); |
|||
collapseToggle.RegisterCallback<MouseUpEvent>(evt => Collapsed = !Collapsed); |
|||
|
|||
m_ExtraProperties = this.Q<VisualElement>("extra-properties"); |
|||
CreatePropertyFields(); |
|||
} |
|||
|
|||
void ToggleTargetContainer() |
|||
{ |
|||
m_TargetContainer.style.display = m_Parameter.hasTarget |
|||
? new StyleEnum<DisplayStyle>(DisplayStyle.Flex) |
|||
: new StyleEnum<DisplayStyle>(DisplayStyle.None); |
|||
} |
|||
|
|||
void ClearTarget() |
|||
{ |
|||
m_SerializedObject.FindProperty("target.component").objectReferenceValue = null; |
|||
m_SerializedObject.FindProperty("target.propertyName").stringValue = string.Empty; |
|||
m_SerializedObject.ApplyModifiedProperties(); |
|||
} |
|||
|
|||
void SetTarget(ParameterTarget newTarget) |
|||
{ |
|||
m_SerializedObject.FindProperty("target.gameObject").objectReferenceValue = newTarget.gameObject; |
|||
m_SerializedObject.FindProperty("target.component").objectReferenceValue = newTarget.component; |
|||
m_SerializedObject.FindProperty("target.propertyName").stringValue = newTarget.propertyName; |
|||
m_SerializedObject.FindProperty("target.fieldOrProperty").enumValueIndex = (int)newTarget.fieldOrProperty; |
|||
m_SerializedObject.ApplyModifiedProperties(); |
|||
m_TargetPropertyMenu.text = TargetPropertyDisplayText(m_Parameter.target); |
|||
} |
|||
|
|||
static string TargetPropertyDisplayText(ParameterTarget target) |
|||
{ |
|||
return $"{target.component.GetType().Name}.{target.propertyName}"; |
|||
} |
|||
|
|||
void FillPropertySelectMenu() |
|||
{ |
|||
if (!m_Parameter.hasTarget) |
|||
return; |
|||
|
|||
m_TargetPropertyMenu.menu.MenuItems().Clear(); |
|||
m_TargetPropertyMenu.text = m_Parameter.target.propertyName == string.Empty |
|||
? "Select a property" |
|||
: TargetPropertyDisplayText(m_Parameter.target); |
|||
|
|||
var options = GatherPropertyOptions(m_Parameter.target.gameObject, m_Parameter.OutputType); |
|||
foreach (var option in options) |
|||
{ |
|||
m_TargetPropertyMenu.menu.AppendAction( |
|||
TargetPropertyDisplayText(option), |
|||
a => { SetTarget(option); }, |
|||
a => DropdownMenuAction.Status.Normal); |
|||
} |
|||
} |
|||
|
|||
static List<ParameterTarget> GatherPropertyOptions(GameObject obj, Type propertyType) |
|||
{ |
|||
var options = new List<ParameterTarget>(); |
|||
foreach (var component in obj.GetComponents<Component>()) |
|||
{ |
|||
if (component == null) |
|||
continue; |
|||
var componentType = component.GetType(); |
|||
var fieldInfos = componentType.GetFields(); |
|||
foreach (var fieldInfo in fieldInfos) |
|||
{ |
|||
if (fieldInfo.FieldType == propertyType) |
|||
options.Add(new ParameterTarget() |
|||
{ |
|||
gameObject = obj, |
|||
component = component, |
|||
propertyName = fieldInfo.Name, |
|||
fieldOrProperty = FieldOrProperty.Field |
|||
}); |
|||
} |
|||
|
|||
var propertyInfos = componentType.GetProperties(); |
|||
foreach (var propertyInfo in propertyInfos) |
|||
{ |
|||
if (propertyInfo.PropertyType == propertyType) |
|||
options.Add(new ParameterTarget() |
|||
{ |
|||
gameObject = obj, |
|||
component = component, |
|||
propertyName = propertyInfo.Name, |
|||
fieldOrProperty = FieldOrProperty.Property |
|||
}); |
|||
} |
|||
} |
|||
return options; |
|||
} |
|||
|
|||
void CreatePropertyFields() |
|||
{ |
|||
m_ExtraProperties.Clear(); |
|||
|
|||
if (m_Parameter is ICategoricalParameter) |
|||
{ |
|||
CreateCategoricalParameterFields(); |
|||
return; |
|||
} |
|||
|
|||
var iterator = m_SerializedObject.GetIterator(); |
|||
if (iterator.NextVisible(true)) |
|||
{ |
|||
do |
|||
{ |
|||
if (iterator.propertyPath == "m_Script" || iterator.propertyPath == "parameterName") |
|||
continue; |
|||
if (iterator.type.Contains("managedReference") && |
|||
iterator.managedReferenceFieldTypename == StaticData.SamplerSerializedFieldType) |
|||
m_ExtraProperties.Add(new SamplerElement(iterator.Copy())); |
|||
else |
|||
{ |
|||
var propertyField = new PropertyField(iterator.Copy()); |
|||
propertyField.Bind(m_SerializedObject); |
|||
m_ExtraProperties.Add(propertyField); |
|||
} |
|||
} while (iterator.NextVisible(false)); |
|||
} |
|||
} |
|||
|
|||
void CreateCategoricalParameterFields() |
|||
{ |
|||
var categoricalParameter = (ICategoricalParameter)m_Parameter; |
|||
var categoricalParameterTemplate = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>( |
|||
$"{StaticData.uxmlDir}/CategoricalParameterTemplate.uxml").CloneTree(); |
|||
|
|||
var optionsProperty = m_SerializedObject.FindProperty("options"); |
|||
var probabilitiesProperty = m_SerializedObject.FindProperty("probabilities"); |
|||
var probabilities = categoricalParameter.Probabilities; |
|||
|
|||
var listView = categoricalParameterTemplate.Q<ListView>("options"); |
|||
listView.itemsSource = probabilities; |
|||
listView.itemHeight = 22; |
|||
listView.selectionType = SelectionType.None; |
|||
listView.style.flexGrow = 1.0f; |
|||
listView.style.height = new StyleLength(listView.itemHeight * 4); |
|||
|
|||
VisualElement MakeItem() => new CategoricalOptionElement(optionsProperty, probabilitiesProperty, listView); |
|||
listView.makeItem = MakeItem; |
|||
|
|||
void BindItem(VisualElement e, int i) |
|||
{ |
|||
var optionElement = (CategoricalOptionElement)e; |
|||
optionElement.BindProperties(i); |
|||
} |
|||
listView.bindItem = BindItem; |
|||
|
|||
var scrollView = listView.Q<ScrollView>(); |
|||
listView.RegisterCallback<WheelEvent>(evt => |
|||
{ |
|||
if (Mathf.Approximately(scrollView.verticalScroller.highValue, 0f)) |
|||
return; |
|||
if ((scrollView.scrollOffset.y <= 0f && evt.delta.y < 0f) || |
|||
scrollView.scrollOffset.y >= scrollView.verticalScroller.highValue && evt.delta.y > 0f) |
|||
evt.StopImmediatePropagation(); |
|||
}); |
|||
|
|||
var addOptionButton = categoricalParameterTemplate.Q<Button>("add-option"); |
|||
addOptionButton.clicked += () => |
|||
{ |
|||
optionsProperty.arraySize++; |
|||
probabilitiesProperty.arraySize++; |
|||
m_SerializedObject.ApplyModifiedProperties(); |
|||
listView.Refresh(); |
|||
listView.ScrollToItem(probabilitiesProperty.arraySize); |
|||
}; |
|||
|
|||
var uniformToggle = categoricalParameterTemplate.Q<Toggle>("uniform"); |
|||
uniformToggle.BindProperty(m_SerializedObject.FindProperty("uniform")); |
|||
void ToggleProbabilityFields(bool toggle) |
|||
{ |
|||
if (toggle) |
|||
listView.AddToClassList("uniform-probability"); |
|||
else |
|||
listView.RemoveFromClassList("uniform-probability"); |
|||
} |
|||
uniformToggle.RegisterCallback<ChangeEvent<bool>>(evt => |
|||
{ |
|||
ToggleProbabilityFields(evt.newValue); |
|||
}); |
|||
ToggleProbabilityFields(uniformToggle.value); |
|||
|
|||
m_ExtraProperties.Add(categoricalParameterTemplate); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: ea72d77c64d1447aa195e2068f02cf74 |
|||
timeCreated: 1595279847 |
|
|||
using UnityEditor; |
|||
using UnityEditor.UIElements; |
|||
using UnityEngine.UIElements; |
|||
|
|||
namespace UnityEngine.Perception.Randomization.Editor |
|||
{ |
|||
public class RandomSeedField : IntegerField |
|||
{ |
|||
public RandomSeedField(SerializedProperty property) |
|||
{ |
|||
label = "Seed"; |
|||
this.BindProperty(property.FindPropertyRelative("state")); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: b4fa54f5ed5d4d67a278fa8b42dc55cb |
|||
timeCreated: 1596171029 |
|
|||
using System; |
|||
using UnityEditor; |
|||
using UnityEditor.UIElements; |
|||
using UnityEngine.Perception.Randomization.Parameters; |
|||
using UnityEngine.Perception.Randomization.Samplers; |
|||
using UnityEngine.UIElements; |
|||
|
|||
namespace UnityEngine.Perception.Randomization.Editor |
|||
{ |
|||
public class SamplerElement : VisualElement |
|||
{ |
|||
Parameter m_Parameter; |
|||
ISampler m_Sampler; |
|||
SerializedProperty m_Property; |
|||
SerializedProperty m_RangeProperty; |
|||
SerializedObject m_ParameterSo; |
|||
VisualElement m_Properties; |
|||
ToolbarMenu m_SamplerTypeDropdown; |
|||
|
|||
public SamplerElement(SerializedProperty property) |
|||
{ |
|||
m_Property = property; |
|||
var template = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>($"{StaticData.uxmlDir}/SamplerElement.uxml"); |
|||
template.CloneTree(this); |
|||
|
|||
m_ParameterSo = property.serializedObject; |
|||
m_Parameter = (Parameter)m_ParameterSo.targetObject; |
|||
m_Sampler = GetSamplerFromSerializedObject(); |
|||
|
|||
if (m_Sampler == null) |
|||
CreateSampler(typeof(UniformSampler)); |
|||
|
|||
var samplerName = this.Q<Label>("sampler-name"); |
|||
samplerName.text = UppercaseFirstLetter(m_Property.propertyPath); |
|||
|
|||
m_Properties = this.Q<VisualElement>("fields-container"); |
|||
m_SamplerTypeDropdown = this.Q<ToolbarMenu>("sampler-type-dropdown"); |
|||
m_SamplerTypeDropdown.text = SamplerMetaData.GetMetaData(m_Sampler.GetType()).displayName; |
|||
foreach (var samplerType in StaticData.samplerTypes) |
|||
{ |
|||
var displayName = SamplerMetaData.GetMetaData(samplerType).displayName; |
|||
m_SamplerTypeDropdown.menu.AppendAction( |
|||
displayName, |
|||
a => { ReplaceSampler(samplerType); }, |
|||
a => DropdownMenuAction.Status.Normal); |
|||
} |
|||
CreatePropertyFields(); |
|||
} |
|||
|
|||
void ReplaceSampler(Type samplerType) |
|||
{ |
|||
CreateSampler(samplerType); |
|||
m_SamplerTypeDropdown.text = SamplerMetaData.GetMetaData(m_Sampler.GetType()).displayName; |
|||
CreatePropertyFields(); |
|||
} |
|||
|
|||
void CreateSampler(Type samplerType) |
|||
{ |
|||
var newSampler = (ISampler)Activator.CreateInstance(samplerType); |
|||
newSampler.seed = SamplerUtility.GenerateRandomSeed(); |
|||
|
|||
if (m_RangeProperty != null) |
|||
newSampler.range = new FloatRange( |
|||
m_RangeProperty.FindPropertyRelative("minimum").floatValue, |
|||
m_RangeProperty.FindPropertyRelative("maximum").floatValue); |
|||
|
|||
m_Sampler = newSampler; |
|||
m_Property.managedReferenceValue = newSampler; |
|||
m_ParameterSo.ApplyModifiedProperties(); |
|||
} |
|||
|
|||
void CreatePropertyFields() |
|||
{ |
|||
m_RangeProperty = null; |
|||
m_Properties.Clear(); |
|||
var currentProperty = m_Property.Copy(); |
|||
var nextSiblingProperty = m_Property.Copy(); |
|||
nextSiblingProperty.Next(false); |
|||
|
|||
if (currentProperty.Next(true)) |
|||
{ |
|||
do |
|||
{ |
|||
if (SerializedProperty.EqualContents(currentProperty, nextSiblingProperty)) |
|||
break; |
|||
if (currentProperty.type == "Random") |
|||
{ |
|||
m_Properties.Add(new RandomSeedField(currentProperty.Copy())); |
|||
} |
|||
else if (currentProperty.type == "FloatRange") |
|||
{ |
|||
m_RangeProperty = currentProperty.Copy(); |
|||
m_Properties.Add(new FloatRangeElement(m_RangeProperty)); |
|||
} |
|||
else |
|||
{ |
|||
var propertyField = new PropertyField(currentProperty.Copy()); |
|||
propertyField.Bind(m_Property.serializedObject); |
|||
m_Properties.Add(propertyField); |
|||
} |
|||
} |
|||
while (currentProperty.Next(false)); |
|||
} |
|||
} |
|||
|
|||
static string UppercaseFirstLetter(string s) |
|||
{ |
|||
return string.IsNullOrEmpty(s) ? string.Empty : char.ToUpper(s[0]) + s.Substring(1); |
|||
} |
|||
|
|||
ISampler GetSamplerFromSerializedObject() |
|||
{ |
|||
var propertyPath = m_Property.propertyPath; |
|||
var parameterType = m_Parameter.GetType(); |
|||
return (ISampler)parameterType.GetField(propertyPath).GetValue(m_Parameter); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: b367f8f2cb8e465ca2d60ccbd5414a14 |
|||
timeCreated: 1595277943 |
|
|||
using UnityEditor; |
|||
using UnityEditor.UIElements; |
|||
using UnityEngine.Perception.Randomization.Scenarios; |
|||
using UnityEngine.UIElements; |
|||
|
|||
namespace UnityEngine.Perception.Randomization.Editor |
|||
{ |
|||
[CustomEditor(typeof(ScenarioBase), true)] |
|||
public class ScenarioBaseEditor : UnityEditor.Editor |
|||
{ |
|||
ScenarioBase m_Scenario; |
|||
SerializedObject m_SerializedObject; |
|||
VisualElement m_Root; |
|||
VisualElement m_InspectorPropertiesContainer; |
|||
VisualElement m_ConstantsContainer; |
|||
SerializedProperty m_ConstantsProperty; |
|||
|
|||
public override VisualElement CreateInspectorGUI() |
|||
{ |
|||
m_Scenario = (ScenarioBase)target; |
|||
m_SerializedObject = new SerializedObject(m_Scenario); |
|||
m_Root = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>( |
|||
$"{StaticData.uxmlDir}/ScenarioBaseElement.uxml").CloneTree(); |
|||
CreatePropertyFields(); |
|||
CheckIfConstantsExist(); |
|||
|
|||
var serializeConstantsButton = m_Root.Query<Button>("serialize-constants").First(); |
|||
serializeConstantsButton.clicked += () => m_Scenario.Serialize(); |
|||
|
|||
var deserializeConstantsButton = m_Root.Query<Button>("deserialize-constants").First(); |
|||
deserializeConstantsButton.clicked += () => m_Scenario.Deserialize(); |
|||
|
|||
return m_Root; |
|||
} |
|||
|
|||
void CreatePropertyFields() |
|||
{ |
|||
m_InspectorPropertiesContainer = m_Root.Q<VisualElement>("inspector-properties"); |
|||
m_InspectorPropertiesContainer.Clear(); |
|||
|
|||
var iterator = m_SerializedObject.GetIterator(); |
|||
var foundProperties = false; |
|||
if (iterator.NextVisible(true)) |
|||
{ |
|||
do |
|||
{ |
|||
if (iterator.name == "m_Script") |
|||
{ |
|||
// Skip this property
|
|||
} |
|||
else if (iterator.name == "constants") |
|||
{ |
|||
m_ConstantsProperty = iterator.Copy(); |
|||
} |
|||
else |
|||
{ |
|||
foundProperties = true; |
|||
var propertyField = new PropertyField(iterator.Copy()); |
|||
propertyField.Bind(m_SerializedObject); |
|||
m_InspectorPropertiesContainer.Add(propertyField); |
|||
} |
|||
} while (iterator.NextVisible(false)); |
|||
} |
|||
|
|||
if (!foundProperties) |
|||
m_InspectorPropertiesContainer.style.display = new StyleEnum<DisplayStyle>(DisplayStyle.None); |
|||
} |
|||
|
|||
void CheckIfConstantsExist() |
|||
{ |
|||
m_ConstantsContainer = m_Root.Q<VisualElement>("constants-container"); |
|||
if (m_ConstantsProperty == null) |
|||
{ |
|||
m_InspectorPropertiesContainer.style.marginBottom = 0; |
|||
m_ConstantsContainer.style.display = new StyleEnum<DisplayStyle>(DisplayStyle.None); |
|||
} |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: face5e97e23d402cbf6fafadb39fa0c3 |
|||
timeCreated: 1596213301 |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Reflection; |
|||
using Newtonsoft.Json; |
|||
using UnityEngine.Perception.Randomization.Parameters; |
|||
using UnityEngine.Perception.Randomization.Parameters.Attributes; |
|||
using UnityEngine.Perception.Randomization.Samplers; |
|||
|
|||
namespace UnityEngine.Perception.Randomization.Editor |
|||
{ |
|||
public static class StaticData |
|||
{ |
|||
const string k_RandomizationDir = "Packages/com.unity.perception/Editor/Randomization"; |
|||
public const string uxmlDir = k_RandomizationDir + "/Uxml"; |
|||
|
|||
public static readonly string SamplerSerializedFieldType; |
|||
|
|||
public static Type[] parameterTypes; |
|||
public static Type[] samplerTypes; |
|||
|
|||
static StaticData() |
|||
{ |
|||
GatherParameterAndSamplerTypes(); |
|||
var samplerType = typeof(ISampler); |
|||
SamplerSerializedFieldType = $"{samplerType.Assembly.GetName().Name} {samplerType.FullName}"; |
|||
} |
|||
|
|||
static void GatherParameterAndSamplerTypes() |
|||
{ |
|||
var paramAssembly = typeof(Parameter).Assembly; |
|||
var allAssemblies = AppDomain.CurrentDomain.GetAssemblies(); |
|||
var assemblies = new List<Assembly> { paramAssembly }; |
|||
foreach (var assembly in allAssemblies) |
|||
{ |
|||
foreach (var asm in assembly.GetReferencedAssemblies()) |
|||
{ |
|||
if (asm.FullName == paramAssembly.GetName().FullName) |
|||
{ |
|||
assemblies.Add(assembly); |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
|
|||
var parameterTypesList = new List<Type>(); |
|||
var samplerTypesList = new List<Type>(); |
|||
foreach (var assembly in assemblies) |
|||
{ |
|||
foreach (var type in assembly.GetTypes()) |
|||
{ |
|||
var isNotAbstract = (type.Attributes & TypeAttributes.Abstract) == 0; |
|||
if (typeof(Parameter).IsAssignableFrom(type) && isNotAbstract && |
|||
ParameterMetaData.GetMetaData(type) != null) |
|||
parameterTypesList.Add(type); |
|||
else if (typeof(ISampler).IsAssignableFrom(type) && |
|||
isNotAbstract && SamplerMetaData.GetMetaData(type) != null) |
|||
{ |
|||
samplerTypesList.Add(type); |
|||
} |
|||
} |
|||
} |
|||
|
|||
parameterTypes = parameterTypesList.ToArray(); |
|||
samplerTypes = samplerTypesList.ToArray(); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 63e6a339ad0c4a2e8d110f120397a17b |
|||
timeCreated: 1595278931 |
|
|||
fileFormatVersion: 2 |
|||
guid: fcf9d543882d491e9b2c1e9a32f18763 |
|||
timeCreated: 1590479034 |
|
|||
.dark-viewport { |
|||
border-radius: 5px; |
|||
background-color: #191919; |
|||
padding: 2px; |
|||
} |
|||
|
|||
.parameter-container { |
|||
border-width: 2px; |
|||
border-radius: 5px; |
|||
flex-direction: row; |
|||
margin: 2px 1px; |
|||
} |
|||
|
|||
.parameter-type-menu { |
|||
margin: 1px 3px; |
|||
border-width: 1px; |
|||
border-radius: 3px; |
|||
background-color: #585858; |
|||
} |
|||
|
|||
#parameter-type-menu .unity-toolbar-menu__text { |
|||
font-size: 13px; |
|||
padding: 3px; |
|||
} |
|||
|
|||
.sampler-type-menu { |
|||
flex-grow: 1.5; |
|||
border-radius: 3px; |
|||
border-width: 1px; |
|||
margin-top: 2px; |
|||
margin-right: 3px; |
|||
} |
|||
|
|||
.sampler-name { |
|||
/*color: lightgreen;*/ |
|||
-unity-font-style: bold; |
|||
} |
|||
|
|||
.parameter-type-label-container { |
|||
flex-direction: row; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
margin-bottom: 1px; |
|||
} |
|||
|
|||
.parameter-type-label-box { |
|||
flex-direction: row; |
|||
align-items: center; |
|||
justify-content: flex-start; |
|||
flex-grow: 0; |
|||
-unity-text-align: middle-center; |
|||
border-width: 0; |
|||
padding: 1px; |
|||
font-size: 13px; |
|||
-unity-font-style: bold; |
|||
} |
|||
|
|||
.parameter-type-label { |
|||
color: cornflowerblue; |
|||
/*min-width: 120px;*/ |
|||
-unity-text-align: middle-left; |
|||
} |
|||
|
|||
.parameter-type-label-box .unity-base-text-field__input { |
|||
padding-left: 6px; |
|||
padding-right: 6px; |
|||
} |
|||
|
|||
.unity-toggle { |
|||
margin-left: 0; |
|||
} |
|||
|
|||
.property-selection-container { |
|||
flex-direction: row; |
|||
} |
|||
|
|||
.property-select-menu { |
|||
flex-grow: 1; |
|||
border-width: 1px; |
|||
padding-bottom: 1px; |
|||
border-radius: 3px; |
|||
margin-right: 1px; |
|||
} |
|||
|
|||
.remove-parameter-button { |
|||
background-image: resource("Packages/com.unity.perception/Editor/Randomization/Icons/X.png"); |
|||
width: 16px; |
|||
height: 16px; |
|||
} |
|||
|
|||
.move-buttons-container { |
|||
width: auto; |
|||
margin-right: 6px; |
|||
border-color: black; |
|||
border-top-left-radius: 3px; |
|||
border-bottom-left-radius: 3px; |
|||
background-color: #2A2A2A; |
|||
padding: 3px 2px; |
|||
justify-content: center; |
|||
} |
|||
|
|||
.drag-handle { |
|||
width: 16px; |
|||
height: 70%; |
|||
min-height: 20px; |
|||
background-image: resource("Packages/com.unity.perception/Editor/Randomization/Icons/DragHandle.png"); |
|||
} |
|||
|
|||
.move-button { |
|||
border-width: 0; |
|||
width: 42px; |
|||
height: 16px; |
|||
padding: 9px; |
|||
-unity-background-scale-mode: scale-to-fit; |
|||
} |
|||
|
|||
.unity-imgui-container { |
|||
margin-left: 1px; |
|||
margin-right: 3px; |
|||
} |
|||
|
|||
.search-icon { |
|||
width: 16px; |
|||
height: 16px; |
|||
margin-top: 2px; |
|||
flex-shrink: 0; |
|||
background-image: resource("Packages/com.unity.perception/Editor/Randomization/Icons/Search.png"); |
|||
} |
|||
|
|||
.collapse-parameter-toggle { |
|||
flex-shrink: 0; |
|||
margin-right: 2px; |
|||
width: 12px; |
|||
height: 12px; |
|||
background-image: resource("Packages/com.unity.perception/Editor/Randomization/Icons/FoldoutOpen.png"); |
|||
} |
|||
|
|||
.collapsed-parameter .collapse-parameter-toggle { |
|||
background-image: resource("Packages/com.unity.perception/Editor/Randomization/Icons/FoldoutClosed.png"); |
|||
} |
|||
|
|||
.collapsed-parameter .parameter-properties-container { |
|||
display: none; |
|||
} |
|||
|
|||
.collapsed-parameter .move-buttons-container { |
|||
flex-direction: row; |
|||
} |
|||
|
|||
.collapsed-parameter .move-button { |
|||
width: 16px; |
|||
} |
|||
|
|||
.categorical-option { |
|||
flex-direction: row; |
|||
background-color: #3F3F3F; |
|||
margin: 1px; |
|||
border-radius: 4px; |
|||
} |
|||
|
|||
.options-list-view { |
|||
background-color: #191919; |
|||
border-radius: 4px; |
|||
margin-right: 2px; |
|||
padding: 3px; |
|||
border-bottom-right-radius: 0; |
|||
} |
|||
|
|||
.option-property-field { |
|||
width: 0; |
|||
flex-grow: 1; |
|||
flex-shrink: 0; |
|||
} |
|||
|
|||
.uniform-probability .hide-when-uniform { |
|||
display: none; |
|||
} |
|||
|
|||
.add-option-button { |
|||
align-self: flex-end; |
|||
border-width: 0; |
|||
border-top-right-radius: 0; |
|||
border-top-left-radius: 0; |
|||
background-color: #191919; |
|||
margin-top: 0; |
|||
margin-right: 2px; |
|||
} |
|||
|
|||
.add-option-button:hover { |
|||
background-color: #2A2A2A; |
|||
} |
|||
|
|||
.add-option-button:active { |
|||
color: cornflowerblue; |
|||
} |
|||
|
|||
.remove-option-button { |
|||
width: 12px; |
|||
height: 14px; |
|||
background-image: resource("Packages/com.unity.perception/Editor/Randomization/Icons/X.png"); |
|||
} |
|||
|
|||
.parameter-drag-bar { |
|||
width: 100px; |
|||
height: 6px; |
|||
background-color: rgba(100,149,237,0.4); |
|||
position: absolute; |
|||
} |
|||
|
|||
.float-range .unity-base-field__label { |
|||
min-width: auto; |
|||
margin-right: 4px; |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 5e1a10e7ee7a46898d0138a9d08615ee |
|||
timeCreated: 1589577216 |
|
|||
fileFormatVersion: 2 |
|||
guid: 36c3e81fb3034cce8b3f05ceac6bae70 |
|||
timeCreated: 1590479019 |
|
|||
<UXML xmlns="UnityEngine.UIElements" xmlns:editor="UnityEditor.UIElements"> |
|||
<VisualElement class="categorical-option "> |
|||
<Button name="remove" class="remove-option-button"/> |
|||
<Label name="index-label" text="[0]" style="min-width: 50px;"/> |
|||
<editor:PropertyField name="option" class="option-property-field"/> |
|||
<editor:FloatField label="p:" name="probability" tooltip="Probability" class="hide-when-uniform" style="min-width: 40px; flex-grow: 0.15;"/> |
|||
</VisualElement> |
|||
</UXML> |
|
|||
fileFormatVersion: 2 |
|||
guid: 460abe2d28664087a03451ba6e6aded7 |
|||
timeCreated: 1595535174 |
|
|||
<UXML xmlns="UnityEngine.UIElements" xmlns:editor="UnityEditor.UIElements"> |
|||
<Toggle label="Uniform" name="uniform"/> |
|||
<VisualElement class="options-list-view"> |
|||
<ListView name="options"/> |
|||
</VisualElement> |
|||
<Button name="add-option" text="+ Add New Option" class="add-option-button"/> |
|||
</UXML> |
|
|||
fileFormatVersion: 2 |
|||
guid: 9fa2b0cf20234dfb803b8cc006803416 |
|||
timeCreated: 1595539730 |
|
|||
<UXML xmlns="UnityEngine.UIElements" xmlns:editor="UnityEditor.UIElements"> |
|||
<VisualElement> |
|||
<VisualElement style="flex-direction: row; margin: 1px, 1px, 1px, 3px;"> |
|||
<Label text="Range" class="unity-base-field__label" style="min-width: 147;"/> |
|||
<VisualElement class="float-range" style="flex-grow: 1; flex-direction: row;"> |
|||
<editor:FloatField label="Min" tooltip="Minimum" name="minimum" style="flex-grow: 1; margin-bottom: 0;"/> |
|||
<editor:FloatField label="Max" tooltip="Maximum" name="maximum" style="flex-grow: 1; margin-right: 2px; margin-bottom: 0;"/> |
|||
</VisualElement> |
|||
</VisualElement> |
|||
</VisualElement> |
|||
</UXML> |
|
|||
fileFormatVersion: 2 |
|||
guid: fa52ef1fb8f14ef388dbed7e2a67c570 |
|||
timeCreated: 1594857611 |
|
|||
<UXML xmlns="UnityEngine.UIElements" xmlns:editor="UnityEditor.UIElements"> |
|||
<VisualElement> |
|||
<Style src="../Uss/Styles.uss"/> |
|||
|
|||
<VisualElement style="flex-direction: row; align-items: center; margin-bottom: 2px; margin-top: 2px;"> |
|||
<VisualElement class="search-icon" style="margin-left: 3px; margin-right: 2px;"/> |
|||
<TextField name="filter-parameters" style="flex-grow: 1; flex-shrink: 1;"/> |
|||
</VisualElement> |
|||
<ScrollView name="parameter-scroll-view" class="dark-viewport" style="min-height: 100px; max-height: 600px;"> |
|||
<VisualElement name="parameters-container" style="flex-shrink: 0;"/> |
|||
</ScrollView> |
|||
|
|||
<VisualElement style="flex-direction: row; justify-content: space-between;"> |
|||
<VisualElement style="flex-grow: 1"/> |
|||
<editor:ToolbarMenu text="Add New Parameter" name="parameter-type-menu" class="parameter-type-menu"/> |
|||
<Button name="collapse-all" text="Collapse All" style="font-size: 13px; padding: 4px;"/> |
|||
<Button name="expand-all" text="Expand All" style="font-size: 13px; padding: 4px;"/> |
|||
<VisualElement style="flex-grow: 1"/> |
|||
</VisualElement> |
|||
</VisualElement> |
|||
</UXML> |
|
|||
fileFormatVersion: 2 |
|||
guid: 6b8a21614fbae12468cb42ada0df200f |
|||
ScriptedImporter: |
|||
internalIDToNameTable: [] |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|||
script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0} |
|
|||
<UXML xmlns="UnityEngine.UIElements" xmlns:editor="UnityEditor.UIElements"> |
|||
<VisualElement style="flex-direction: row;"> |
|||
<Label style="width: 150px;"/> |
|||
<editor:ToolbarMenu style="flex-grow: 1; margin-left: 3px; margin-right: 2px; border-top-width: 1px; border-bottom-width: 1px; border-radius: 3px;"/> |
|||
</VisualElement> |
|||
</UXML> |
|
|||
fileFormatVersion: 2 |
|||
guid: 18765b47a76c4adcb639d0d247b8bd34 |
|||
timeCreated: 1596419194 |
|
|||
<UXML xmlns="UnityEngine.UIElements" xmlns:editor="UnityEditor.UIElements"> |
|||
<Box name="parameter-container" class="parameter-container"> |
|||
<VisualElement name="drag-handle" class="move-buttons-container"> |
|||
<VisualElement class="drag-handle"/> |
|||
</VisualElement> |
|||
<VisualElement style="flex-grow: 1; justify-content: center; margin-right: 6px;"> |
|||
<VisualElement class="parameter-type-label-container"> |
|||
<Box class="parameter-type-label-box"> |
|||
<VisualElement name="collapse" class="collapse-parameter-toggle foldout-open"/> |
|||
<Label name="parameter-type-label" text="Type:" class="parameter-type-label"/> |
|||
<TextField binding-path="parameterName" name="parameter-name" text="Parameter Name"/> |
|||
</Box> |
|||
<Button name="remove-parameter" class="remove-parameter-button"/> |
|||
</VisualElement> |
|||
|
|||
<VisualElement name="properties" class="parameter-properties-container" style="margin-bottom: 2px;"> |
|||
<Box> |
|||
<editor:PropertyField label="Target GameObject" binding-path="target.gameObject" name="target-field"/> |
|||
<VisualElement name="target-container"> |
|||
<VisualElement class="unity-base-field"> |
|||
<Label text="Target Property" class="unity-base-field__label"/> |
|||
<editor:ToolbarMenu text="Select A Property" name="property-select-menu" class="property-select-menu"/> |
|||
</VisualElement> |
|||
<editor:PropertyField binding-path="target.applicationFrequency"/> |
|||
</VisualElement> |
|||
</Box> |
|||
<Box name="extra-properties" style="padding-left: 4px; border-top-width: 0px;"/> |
|||
</VisualElement> |
|||
</VisualElement> |
|||
</Box> |
|||
</UXML> |
|
|||
fileFormatVersion: 2 |
|||
guid: be31f9fb5f9b43ad835fdcf99969b9df |
|||
timeCreated: 1589576576 |
|
|||
<UXML xmlns="UnityEngine.UIElements" xmlns:editor="UnityEditor.UIElements"> |
|||
<VisualElement name="sampler-template" style="margin-bottom: 4px;"> |
|||
<VisualElement style="flex-direction: row; align-items: center;"> |
|||
<Label name="sampler-name" text="Sampler Name" class="unity-base-field__label sampler-name"/> |
|||
<editor:ToolbarMenu name="sampler-type-dropdown" text="Placeholder Sampler Type" class="sampler-type-menu"/> |
|||
</VisualElement> |
|||
<VisualElement name="fields-container" style="margin-left: 18px;"/> |
|||
</VisualElement> |
|||
</UXML> |
|
|||
fileFormatVersion: 2 |
|||
guid: e91be9c80e944358b231c125be80a749 |
|||
timeCreated: 1594847524 |
|
|||
<UXML xmlns="UnityEngine.UIElements" xmlns:editor="UnityEditor.UIElements"> |
|||
<VisualElement> |
|||
<Style src="../Uss/Styles.uss"/> |
|||
|
|||
<VisualElement name="inspector-properties" style="margin-bottom: 20px;"/> |
|||
|
|||
<VisualElement name="configuration-container" class="dark-viewport"> |
|||
<Toggle label="Quit On Complete" tooltip="Quit the application when the scenario completes" binding-path="quitOnComplete" style="margin-left: 3px"/> |
|||
<VisualElement name="constants-container"> |
|||
<editor:PropertyField binding-path="constants"/> |
|||
<editor:PropertyField name="configuration-file-name" label="Constants File Name" binding-path="serializedConstantsFileName"/> |
|||
<editor:PropertyField tooltip="Read constants from JSON when the application starts" name="deserialize-on-start" label="Deserialize On Start" binding-path="deserializeOnStart" style="padding-left: 4px;"/> |
|||
<VisualElement style="flex-direction: row;"> |
|||
<Button name="serialize-constants" text="Serialize Constants" style="flex-grow: 1;"/> |
|||
<Button name="deserialize-constants" text="Deserialize Constants" style="flex-grow: 1;"/> |
|||
</VisualElement> |
|||
</VisualElement> |
|||
</VisualElement> |
|||
</VisualElement> |
|||
</UXML> |
|
|||
fileFormatVersion: 2 |
|||
guid: edfeb68a9e894552845fba6fa1246b32 |
|||
timeCreated: 1596213495 |
|
|||
fileFormatVersion: 2 |
|||
guid: b5afd2495bca4fdca95b86d9113f27b2 |
|||
timeCreated: 1594059945 |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using UnityEditor; |
|||
using UnityEngine; |
|||
using UnityEngine.Perception.Randomization.Parameters; |
|||
using UnityEngine.SceneManagement; |
|||
|
|||
namespace UnityEngine.Perception.Randomization.Configuration |
|||
{ |
|||
/// <summary>
|
|||
/// Creates parameter interfaces for randomizing simulations
|
|||
/// </summary>
|
|||
[ExecuteInEditMode] |
|||
[AddComponentMenu("Randomization/ParameterConfiguration")] |
|||
public class ParameterConfiguration : MonoBehaviour |
|||
{ |
|||
public static HashSet<ParameterConfiguration> configurations = new HashSet<ParameterConfiguration>(); |
|||
|
|||
[SerializeReference] |
|||
public List<Parameter> parameters = new List<Parameter>(); |
|||
|
|||
/// <summary>
|
|||
/// Find a parameter in this configuration by name
|
|||
/// </summary>
|
|||
public Parameter GetParameter(string parameterName) |
|||
{ |
|||
foreach (var parameter in parameters) |
|||
{ |
|||
if (parameter.parameterName == parameterName) |
|||
return parameter; |
|||
} |
|||
throw new ParameterConfigurationException( |
|||
$"Parameter with name {parameterName} not found"); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Find a parameter in this configuration by name
|
|||
/// </summary>
|
|||
public T GetParameter<T>(string parameterName) where T : Parameter |
|||
{ |
|||
foreach (var parameter in parameters) |
|||
{ |
|||
if (parameter.parameterName == parameterName && parameter is T typedParameter) |
|||
return typedParameter; |
|||
} |
|||
throw new ParameterConfigurationException( |
|||
$"Parameter with name {parameterName} and type {typeof(T).Name} not found"); |
|||
} |
|||
|
|||
void NameAndAddParameterToList(Parameter parameter) |
|||
{ |
|||
parameter.parameterName = $"Parameter{parameters.Count}"; |
|||
parameters.Add(parameter); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Adds a new typed parameter to this configuration
|
|||
/// </summary>
|
|||
public T AddParameter<T>() where T : Parameter |
|||
{ |
|||
var parameter = gameObject.AddComponent<T>(); |
|||
NameAndAddParameterToList(parameter); |
|||
return parameter; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Adds a new parameter to this configuration
|
|||
/// </summary>
|
|||
public Parameter AddParameter(Type parameterType) |
|||
{ |
|||
if (!parameterType.IsSubclassOf(typeof(Parameter))) |
|||
throw new ParameterConfigurationException($"Cannot add non-parameter types ({parameterType})"); |
|||
var parameter = (Parameter)gameObject.AddComponent(parameterType); |
|||
NameAndAddParameterToList(parameter); |
|||
return parameter; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Calls apply on all parameters with GameObject targets in this configuration
|
|||
/// </summary>
|
|||
public void ApplyParameters(int seedOffset, ParameterApplicationFrequency frequency) |
|||
{ |
|||
foreach (var parameter in parameters) |
|||
if (parameter.target.applicationFrequency == frequency) |
|||
parameter.ApplyToTarget(seedOffset); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Calls Validate() on all parameters within this configuration
|
|||
/// </summary>
|
|||
public void ValidateParameters() |
|||
{ |
|||
var parameterNames = new HashSet<string>(); |
|||
foreach (var parameter in parameters) |
|||
{ |
|||
if (parameterNames.Contains(parameter.parameterName)) |
|||
throw new ParameterConfigurationException($"Two or more parameters cannot share the same name " + |
|||
$"(\"{parameter.parameterName}\")"); |
|||
parameterNames.Add(parameter.parameterName); |
|||
parameter.Validate(); |
|||
} |
|||
} |
|||
|
|||
void OnEnable() |
|||
{ |
|||
configurations.Add(this); |
|||
} |
|||
|
|||
void OnDisable() |
|||
{ |
|||
configurations.Remove(this); |
|||
} |
|||
|
|||
void OnDestroy() |
|||
{ |
|||
#if UNITY_EDITOR
|
|||
// Cleaning up child parameters requires detecting if the scene is changing.
|
|||
// A scene change causes all objects to be destroyed and destroying objects twice throws an error.
|
|||
|
|||
// Check if in play mode and not changing from play mode to edit mode
|
|||
if (EditorApplication.isPlayingOrWillChangePlaymode && EditorApplication.isPlaying) |
|||
{ |
|||
foreach(var parameter in parameters) |
|||
if (parameter != null) Destroy(parameter); |
|||
} |
|||
// Check if in the editor and not changing from edit mode to play mode
|
|||
else if (!EditorApplication.isPlayingOrWillChangePlaymode && !EditorApplication.isPlaying) |
|||
{ |
|||
// Delaying the destroy call avoids the issue of destroying child parameters
|
|||
// twice when the user changes scenes in the editor
|
|||
EditorApplication.delayCall += () => |
|||
{ |
|||
foreach (var parameter in parameters) |
|||
{ |
|||
var param = parameter; |
|||
if (param != null) DestroyImmediate(param); |
|||
} |
|||
}; |
|||
} |
|||
#else
|
|||
foreach(var parameter in parameters) |
|||
if (parameter != null) Destroy(parameter); |
|||
#endif
|
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: ca07567b4377a1f41a9bcaf56d0ce8df |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System; |
|||
|
|||
namespace UnityEngine.Perception.Randomization.Configuration |
|||
{ |
|||
[Serializable] |
|||
class ParameterConfigurationException : Exception |
|||
{ |
|||
public ParameterConfigurationException(string message) : base(message) { } |
|||
public ParameterConfigurationException(string message, Exception innerException) : base(message, innerException) { } |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 17957711f996479c98d1bdf7f153f791 |
|||
timeCreated: 1594069464 |
|
|||
fileFormatVersion: 2 |
|||
guid: 5a083fd64edd63b489c90e6e560b7b64 |
|||
folderAsset: yes |
|||
DefaultImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: 61fd0d1421574ffd9f04d82f82744743 |
|||
timeCreated: 1594662190 |
|
|||
using System; |
|||
|
|||
namespace UnityEngine.Perception.Randomization.Parameters.Attributes |
|||
{ |
|||
[AttributeUsage(AttributeTargets.Class)] |
|||
public class ParameterMetaData : Attribute |
|||
{ |
|||
public static ParameterMetaData GetMetaData(Type type) => |
|||
(ParameterMetaData)GetCustomAttribute(type, typeof(ParameterMetaData)); |
|||
|
|||
public string typeDisplayName; |
|||
|
|||
public ParameterMetaData(string typeDisplayName) |
|||
{ |
|||
this.typeDisplayName = typeDisplayName; |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 3f3c59805737435194cbbba3039a8805 |
|||
timeCreated: 1594662345 |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using UnityEngine.Perception.Randomization.Samplers; |
|||
|
|||
namespace UnityEngine.Perception.Randomization.Parameters |
|||
{ |
|||
/// <summary>
|
|||
/// Generates samples by choosing one option from a weighted list of choices.
|
|||
/// </summary>
|
|||
public abstract class CategoricalParameter<T> : TypedParameter<T>, ICategoricalParameter |
|||
{ |
|||
public bool uniform; |
|||
[Min(0)] public uint seed; |
|||
public List<T> options = new List<T>(); |
|||
public List<float> probabilities = new List<float>(); |
|||
|
|||
float[] m_NormalizedProbabilities; |
|||
|
|||
public List<float> Probabilities => probabilities; |
|||
public override ISampler[] Samplers => new ISampler[0]; |
|||
|
|||
public override void Validate() |
|||
{ |
|||
base.Validate(); |
|||
if (!uniform) |
|||
{ |
|||
if (probabilities.Count != options.Count) |
|||
throw new ParameterValidationException( |
|||
"Number of options must be equal to the number of probabilities"); |
|||
NormalizeProbabilities(); |
|||
} |
|||
} |
|||
|
|||
void NormalizeProbabilities() |
|||
{ |
|||
var totalProbability = 0f; |
|||
for (var i = 0; i < probabilities.Count; i++) |
|||
{ |
|||
var probability = probabilities[i]; |
|||
if (probability < 0f) |
|||
throw new ParameterValidationException($"Found negative probability at index {i}"); |
|||
totalProbability += probability; |
|||
} |
|||
|
|||
if (totalProbability <= 0f) |
|||
throw new ParameterValidationException("Total probability must be greater than 0"); |
|||
|
|||
var sum = 0f; |
|||
m_NormalizedProbabilities = new float[probabilities.Count]; |
|||
for (var i = 0; i < probabilities.Count; i++) |
|||
{ |
|||
sum += probabilities[i] / totalProbability; |
|||
m_NormalizedProbabilities[i] = sum; |
|||
} |
|||
} |
|||
|
|||
int BinarySearch(float key) { |
|||
var minNum = 0; |
|||
var maxNum = m_NormalizedProbabilities.Length - 1; |
|||
|
|||
while (minNum <= maxNum) { |
|||
var mid = (minNum + maxNum) / 2; |
|||
// ReSharper disable once CompareOfFloatsByEqualityOperator
|
|||
if (key == m_NormalizedProbabilities[mid]) { |
|||
return ++mid; |
|||
} |
|||
if (key < m_NormalizedProbabilities[mid]) { |
|||
maxNum = mid - 1; |
|||
} |
|||
else { |
|||
minNum = mid + 1; |
|||
} |
|||
} |
|||
return minNum; |
|||
} |
|||
|
|||
T Sample(ref Unity.Mathematics.Random rng) |
|||
{ |
|||
var randomValue = rng.NextFloat(); |
|||
return uniform |
|||
? options[(int)(randomValue * options.Count)] |
|||
: options[BinarySearch(randomValue)]; |
|||
} |
|||
|
|||
public override T Sample(int index) |
|||
{ |
|||
NormalizeProbabilities(); |
|||
var iteratedSeed = SamplerUtility.IterateSeed((uint)index, seed); |
|||
var rng = new Unity.Mathematics.Random(iteratedSeed); |
|||
return Sample(ref rng); |
|||
} |
|||
|
|||
public override T[] Samples(int index, int sampleCount) |
|||
{ |
|||
NormalizeProbabilities(); |
|||
var samples = new T[sampleCount]; |
|||
var iteratedSeed = SamplerUtility.IterateSeed((uint)index, seed); |
|||
var rng = new Unity.Mathematics.Random(iteratedSeed); |
|||
for (var i = 0; i < sampleCount; i++) |
|||
samples[i] = Sample(ref rng); |
|||
return samples; |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 3673221b57c94c6894685beadbcf04d1 |
|||
timeCreated: 1594872373 |
|
|||
using System.Collections.Generic; |
|||
|
|||
namespace UnityEngine.Perception.Randomization.Parameters |
|||
{ |
|||
/// <summary>
|
|||
/// Exposes the probabilities property of categorical parameters for UI purposes
|
|||
/// </summary>
|
|||
public interface ICategoricalParameter |
|||
{ |
|||
List<float> Probabilities { get; } |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 747fbbdb7a6e4eae87ea193025685e5e |
|||
timeCreated: 1595536474 |
|
|||
using System; |
|||
using UnityEngine; |
|||
using UnityEngine.Perception.Randomization.Parameters.Attributes; |
|||
using UnityEngine.Perception.Randomization.Samplers; |
|||
|
|||
namespace UnityEngine.Perception.Randomization.Parameters |
|||
{ |
|||
/// <summary>
|
|||
/// Parameters, in conjunction with a parameter configuration, are used to create convenient interfaces for
|
|||
/// randomizing simulations.
|
|||
/// </summary>
|
|||
[Serializable] |
|||
public abstract class Parameter : MonoBehaviour |
|||
{ |
|||
public string parameterName = "Parameter"; |
|||
[HideInInspector] public ParameterTarget target = new ParameterTarget(); |
|||
|
|||
public bool hasTarget => target.gameObject != null; |
|||
|
|||
/// <summary>
|
|||
/// Returns meta information regarding this type of parameter
|
|||
/// </summary>
|
|||
public ParameterMetaData MetaData => |
|||
(ParameterMetaData)Attribute.GetCustomAttribute(GetType(), typeof(ParameterMetaData)); |
|||
|
|||
/// <summary>
|
|||
/// An array containing a reference to each sampler field in this parameter
|
|||
/// </summary>
|
|||
public abstract ISampler[] Samplers { get; } |
|||
|
|||
/// <summary>
|
|||
/// The sample type generated by this parameter
|
|||
/// </summary>
|
|||
public abstract Type OutputType { get; } |
|||
|
|||
/// <summary>
|
|||
/// Applies one sampled value to this parameters assigned target gameobject
|
|||
/// </summary>
|
|||
public abstract void ApplyToTarget(int seedOffset); |
|||
|
|||
/// <summary>
|
|||
/// Validates parameter settings
|
|||
/// </summary>
|
|||
public virtual void Validate() |
|||
{ |
|||
if (hasTarget) |
|||
{ |
|||
if (target.component == null) |
|||
throw new ParameterException($"Null component target on parameter \"{parameterName}\""); |
|||
if (string.IsNullOrEmpty(target.propertyName)) |
|||
throw new ParameterException($"Invalid property target on parameter \"{parameterName}\""); |
|||
} |
|||
} |
|||
} |
|||
} |
部分文件因为文件数量过多而无法显示
撰写
预览
正在加载...
取消
保存
Reference in new issue