浏览代码

Merge pull request #173 from Unity-Technologies/categorical-parameter-fixes

Fixed and polished a few Randomization UI elements
/main
GitHub 4 年前
当前提交
7b0d663a
共有 43 个文件被更改,包括 720 次插入570 次删除
  1. 12
      com.unity.perception/CHANGELOG.md
  2. 67
      com.unity.perception/Editor/Randomization/Editors/PerceptionEditorAnalytics.cs
  3. 32
      com.unity.perception/Editor/Randomization/Editors/RunInUnitySimulationWindow.cs
  4. 80
      com.unity.perception/Editor/Randomization/Editors/ScenarioBaseEditor.cs
  5. 5
      com.unity.perception/Editor/Randomization/PropertyDrawers/ColorHsvaDrawer.cs
  6. 4
      com.unity.perception/Editor/Randomization/PropertyDrawers/ParameterDrawer.cs
  7. 1
      com.unity.perception/Editor/Randomization/Uxml/Sampler/FloatRangeElement.uxml
  8. 7
      com.unity.perception/Editor/Randomization/Uxml/Sampler/SamplerElement.uxml
  9. 4
      com.unity.perception/Editor/Randomization/Uxml/Sampler/SamplerElement.uxml.meta
  10. 20
      com.unity.perception/Editor/Randomization/VisualElements/Parameter/CategoricalOptionElement.cs
  11. 9
      com.unity.perception/Editor/Randomization/VisualElements/Parameter/ColorHsvaField.cs
  12. 37
      com.unity.perception/Editor/Randomization/VisualElements/Parameter/DrawerParameterElement.cs
  13. 88
      com.unity.perception/Editor/Randomization/VisualElements/Parameter/ParameterElement.cs
  14. 166
      com.unity.perception/Editor/Randomization/VisualElements/Randomizer/AddRandomizerMenu.cs
  15. 12
      com.unity.perception/Editor/Randomization/VisualElements/Randomizer/DragToReorderManipulator.cs
  16. 72
      com.unity.perception/Editor/Randomization/VisualElements/Randomizer/RandomizerElement.cs
  17. 34
      com.unity.perception/Editor/Randomization/VisualElements/Randomizer/RandomizerList.cs
  18. 5
      com.unity.perception/Editor/Randomization/VisualElements/Randomizer/RandomizerReorderingIndicator.cs
  19. 6
      com.unity.perception/Editor/Randomization/VisualElements/Sampler/FloatRangeElement.cs
  20. 120
      com.unity.perception/Editor/Randomization/VisualElements/Sampler/SamplerElement.cs
  21. 14
      com.unity.perception/Editor/Randomization/VisualElements/Sampler/SamplerElement.cs.meta
  22. 12
      com.unity.perception/Runtime/Randomization/Parameters/CategoricalParameter.cs
  23. 2
      com.unity.perception/Runtime/Randomization/Randomizers/Randomizer.cs
  24. 2
      com.unity.perception/Runtime/Randomization/Samplers/ISampler.cs
  25. 10
      com.unity.perception/Tests/Runtime/Randomization/ParameterTests/CategoricalParameterTests.cs
  26. 26
      com.unity.perception/Editor/Randomization/PropertyDrawers/FloatRangeDrawer.cs
  27. 3
      com.unity.perception/Editor/Randomization/PropertyDrawers/FloatRangeDrawer.cs.meta
  28. 28
      com.unity.perception/Editor/Randomization/PropertyDrawers/SamplerDrawer.cs
  29. 3
      com.unity.perception/Editor/Randomization/PropertyDrawers/SamplerDrawer.cs.meta
  30. 10
      com.unity.perception/Editor/Randomization/Uxml/Sampler/SamplerInterfaceElement.uxml
  31. 3
      com.unity.perception/Editor/Randomization/Uxml/Sampler/SamplerInterfaceElement.uxml.meta
  32. 89
      com.unity.perception/Editor/Randomization/VisualElements/Sampler/SamplerInterfaceElement.cs
  33. 11
      com.unity.perception/Editor/Randomization/VisualElements/Sampler/SamplerInterfaceElement.cs.meta
  34. 22
      com.unity.perception/Editor/Randomization/Utilities/ParameterUIElementsEditor.cs
  35. 95
      com.unity.perception/Editor/Randomization/Utilities/StaticData.cs
  36. 75
      com.unity.perception/Editor/Randomization/Utilities/UIElementsEditorUtilities.cs
  37. 3
      com.unity.perception/Editor/Randomization/Utilities/UIElementsEditorUtilities.cs.meta
  38. 101
      com.unity.perception/Editor/Randomization/StaticData.cs
  39. 0
      /com.unity.perception/Editor/Randomization/Utilities/StaticData.cs.meta
  40. 0
      /com.unity.perception/Editor/Randomization/Utilities.meta
  41. 0
      /com.unity.perception/Editor/Randomization/Utilities/ParameterUIElementsEditor.cs.meta

12
com.unity.perception/CHANGELOG.md


* Can now render intermediate frames between captures.
* Capture can now be triggered manually using a function call, instead of automatic capturing on a schedule.
Categorical Parameters will now validate that their specified options are unique at runtime.
Randomizers now access their parent scenario through the static activeScenario property
Randomizers now access their parent scenario through the static activeScenario property.
Unique seeds per Sampler have been replaced with one global random seed configured via the ScenarioConstants of a Scenario

RandomizerTagManager.Query<T>() now returns RandomizerTags directly instead of the GameObjects attached to said tags
Semantic Segmentation Labeler now places data in folders with randomized filenames
Semantic Segmentation Labeler now places data in folders with randomized filenames.
The uniform toggle on Categorical Parameters will now reset the Parameter's probability weights to be uniform.
### Deprecated

Semantic Segmentation Labeler now produces output in the proper form for distributed data generation on Unity Simulation by placing output in randomized directory names
Texture Randomizer is now compatible with HDRP
Texture Randomizer is now compatible with HDRP.
Categorical Parameters no longer produce errors when deleting items from long options lists.
Parameter, ISampler, and non-generic Sampler class UIs now render properly in MonoBehaviours and ScriptableObjects.
## [0.6.0-preview.1] - 2020-12-03

67
com.unity.perception/Editor/Randomization/Editors/PerceptionEditorAnalytics.cs


using System;
using JetBrains.Annotations;
using UnityEditor;
namespace UnityEngine.Perception.Randomization.Editor
namespace UnityEditor.Experimental.Perception.Randomization
const string k_VendorKey = "unity.perception";
const string k_RunInUnitySimulationName = "runinunitysimulation";
const string k_VendorKey = "unity.perception";
const string k_RunInUnitySimulationName = "runinunitysimulation";
static bool s_IsRegistered = false;
static bool s_IsRegistered;
static bool TryRegisterEvents()
{

bool success = true;
var success = true;
success &= EditorAnalytics.RegisterEventWithLimit(k_RunInUnitySimulationName, k_MaxEventsPerHour, k_MaxItems,
k_VendorKey) == AnalyticsResult.Ok;

enum RunStatus
{
Started,
Failed,
Succeeded
}
struct RunInUnitySimulationData
{
[UsedImplicitly]
public string runId;
[UsedImplicitly]
public int totalIterations;
[UsedImplicitly]
public int instanceCount;
[UsedImplicitly]
public string existingBuildId;
[UsedImplicitly]
public string errorMessage;
[UsedImplicitly]
public string runExecutionId;
[UsedImplicitly]
public string runStatus;
}
var data = new RunInUnitySimulationData()
var data = new RunInUnitySimulationData
{
runId = runId.ToString(),
totalIterations = totalIterations,

if (!TryRegisterEvents())
return;
var data = new RunInUnitySimulationData()
var data = new RunInUnitySimulationData
{
runId = runId.ToString(),
errorMessage = errorMessage,

if (!TryRegisterEvents())
return;
var data = new RunInUnitySimulationData()
var data = new RunInUnitySimulationData
{
runId = runId.ToString(),
runExecutionId = runExecutionId,

}
enum RunStatus
{
Started,
Failed,
Succeeded
}
struct RunInUnitySimulationData
{
[UsedImplicitly]
public string runId;
[UsedImplicitly]
public int totalIterations;
[UsedImplicitly]
public int instanceCount;
[UsedImplicitly]
public string existingBuildId;
[UsedImplicitly]
public string errorMessage;
[UsedImplicitly]
public string runExecutionId;
[UsedImplicitly]
public string runStatus;
}
}
}

32
com.unity.perception/Editor/Randomization/Editors/RunInUnitySimulationWindow.cs


using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Unity.Simulation.Client;
using UnityEditor;
using UnityEngine.Experimental.Perception.Randomization.Editor;
using UnityEngine;
namespace UnityEngine.Perception.Randomization.Editor
namespace UnityEditor.Experimental.Perception.Randomization
{
class RunInUnitySimulationWindow : EditorWindow
{

SysParamDefinition m_SysParam;
IntegerField m_InstanceCountField;
ObjectField m_MainSceneField;
Button m_RunButton;
ObjectField m_ScenarioField;
SysParamDefinition m_SysParam;
IntegerField m_InstanceCountField;
ObjectField m_MainSceneField;
ObjectField m_ScenarioField;
Button m_RunButton;
[MenuItem("Window/Run in Unity Simulation")]
static void ShowWindow()

}
/// <summary>
/// Enables a visual element to remember values between editor sessions
/// Enables a visual element to remember values between editor sessions
/// </summary>
/// <param name="element">The visual element to enable view data for</param>
static void SetViewDataKey(VisualElement element)

var sysParamDefinitions = API.GetSysParams();
var sysParamMenu = root.Q<ToolbarMenu>("sys-param");
foreach (var definition in sysParamDefinitions)
{
sysParamMenu.menu.AppendAction(
definition.description,
action =>

});
}
sysParamMenu.text = sysParamDefinitions[0].description;
m_SysParam = sysParamDefinitions[0];

runGuid,
m_TotalIterationsField.value,
m_InstanceCountField.value,
existingBuildId: null);
null);
try
{
ValidateSettings();

var appParamsString = JsonConvert.SerializeObject(configuration, Formatting.Indented);
var appParamId = API.UploadAppParam(appParamName, appParamsString);
appParamIds.Add(new AppParam()
appParamIds.Add(new AppParam
{
id = appParamId,
name = appParamName,

EditorUtility.DisplayProgressBar("Unity Simulation Run", $"Uploading app-param-ids for instances: {i + 1}/{m_InstanceCountField.value}", progressStart + progressIncrement * i);
EditorUtility.DisplayProgressBar(
"Unity Simulation Run",
$"Uploading app-param-ids for instances: {i + 1}/{m_InstanceCountField.value}",
progressStart + progressIncrement * i);
}
return appParamIds;

Debug.Log($"Generated app-param ids: {appParams.Count}");
EditorUtility.DisplayProgressBar("Unity Simulation Run", $"Uploading run definition...", 0.9f);
EditorUtility.DisplayProgressBar("Unity Simulation Run", "Uploading run definition...", 0.9f);
var runDefinitionId = API.UploadRunDefinition(new RunDefinition
{

});
Debug.Log($"Run definition upload complete: run definition id {runDefinitionId}");
EditorUtility.DisplayProgressBar("Unity Simulation Run", $"Executing run...", 0.95f);
EditorUtility.DisplayProgressBar("Unity Simulation Run", "Executing run...", 0.95f);
var run = Run.CreateFromDefinitionId(runDefinitionId);
run.Execute();

80
com.unity.perception/Editor/Randomization/Editors/ScenarioBaseEditor.cs


using System.Collections;
using System.Linq;
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.Experimental.Perception.Randomization.VisualElements;
using Object = UnityEngine.Object;
namespace UnityEngine.Experimental.Perception.Randomization.Editor
namespace UnityEditor.Experimental.Perception.Randomization
class ScenarioBaseEditor : UnityEditor.Editor
class ScenarioBaseEditor : Editor
VisualElement m_ConstantsListVisualContainer;
VisualElement m_InspectorPropertiesContainer;
VisualElement m_RandomizerListPlaceholder;
VisualElement m_Root;
VisualElement m_Root;
VisualElement m_InspectorPropertiesContainer;
VisualElement m_ConstantsListVisualContainer;
VisualElement m_RandomizerListPlaceholder;
public override VisualElement CreateInspectorGUI()
{

m_ConstantsListVisualContainer = m_Root.Q<VisualElement>("constants-list");
m_ConstantsListVisualContainer.Clear();
var iterator = m_SerializedObject.GetIterator();
if (iterator.NextVisible(true))
var iterator = m_SerializedObject.GetIterator();
iterator.NextVisible(true);
iterator.NextVisible(false);
do
do
switch (iterator.name)
switch (iterator.name)
case "m_Randomizers":
m_RandomizerListPlaceholder.Add(new RandomizerList(iterator.Copy()));
break;
case "constants":
m_HasConstantsField = true;
UIElementsEditorUtilities.CreatePropertyFields(iterator.Copy(), m_ConstantsListVisualContainer);
break;
default:
case "m_Script":
break;
case "m_Randomizers":
m_RandomizerListPlaceholder.Add(new RandomizerList(iterator.Copy()));
break;
case "constants":
m_HasConstantsField = true;
CreateConstantsFieldsWithToolTips(iterator.Copy());
break;
default:
{
foundProperties = true;
var propertyField = new PropertyField(iterator.Copy());
propertyField.Bind(m_SerializedObject);
m_InspectorPropertiesContainer.Add(propertyField);
break;
}
foundProperties = true;
var propertyField = UIElementsEditorUtilities.CreatePropertyField(iterator, m_Scenario.GetType());
m_InspectorPropertiesContainer.Add(propertyField);
break;
} while (iterator.NextVisible(false));
}
}
} while (iterator.NextVisible(false));
if (!foundProperties)
m_InspectorPropertiesContainer.style.display = new StyleEnum<DisplayStyle>(DisplayStyle.None);

m_InspectorPropertiesContainer.style.marginBottom = 0;
m_ConstantsListVisualContainer.style.display = new StyleEnum<DisplayStyle>(DisplayStyle.None);
}
}
void CreateConstantsFieldsWithToolTips(SerializedProperty constantsProperty)
{
constantsProperty.NextVisible(true);
do
{
var constantsPropertyField = new PropertyField(constantsProperty.Copy());
constantsPropertyField.Bind(m_SerializedObject);
var originalField = target.GetType().GetField("constants").FieldType.GetField(constantsProperty.name);
var tooltipAttribute = originalField.GetCustomAttributes(true).ToList().Find(att => att.GetType() == typeof(TooltipAttribute));
if (tooltipAttribute != null)
constantsPropertyField.tooltip = (tooltipAttribute as TooltipAttribute)?.tooltip;
m_ConstantsListVisualContainer.Add(constantsPropertyField);
} while (constantsProperty.NextVisible(true));
}
}
}

5
com.unity.perception/Editor/Randomization/PropertyDrawers/ColorHsvaDrawer.cs


using UnityEditor;
using System;
using UnityEngine;
namespace UnityEngine.Perception.Randomization.Editor.PropertyDrawers
namespace UnityEditor.Experimental.Perception.Randomization.PropertyDrawers
{
[CustomPropertyDrawer(typeof(ColorHsva), true)]
class ColorHsvaDrawer : PropertyDrawer

4
com.unity.perception/Editor/Randomization/PropertyDrawers/ParameterDrawer.cs


using System;
using UnityEditor;
using UnityEngine;
namespace UnityEngine.Perception.Randomization.Editor.PropertyDrawers
namespace UnityEditor.Experimental.Perception.Randomization.PropertyDrawers
{
[CustomPropertyDrawer(typeof(Parameter), true)]
class ParameterDrawer : PropertyDrawer

1
com.unity.perception/Editor/Randomization/Uxml/Sampler/FloatRangeElement.uxml


<UXML xmlns="UnityEngine.UIElements" xmlns:editor="UnityEditor.UIElements">
<VisualElement>
<Style src="../../Uss/Styles.uss"/>
<VisualElement style="flex-direction: row; margin: 1px, 1px, 1px, 3px;">
<Label text="Range" class="unity-base-field__label" style="min-width: 147;"/>
<VisualElement class="sampler__float-range" style="flex-grow: 1; flex-direction: row;">

7
com.unity.perception/Editor/Randomization/Uxml/Sampler/SamplerElement.uxml


<UXML xmlns="UnityEngine.UIElements" xmlns:editor="UnityEditor.UIElements">
<VisualElement name="sampler-template" style="margin-bottom: 4px;">
<VisualElement style="margin-bottom: 4px;">
<VisualElement style="flex-direction: row; align-items: center;">
<Label name="sampler-name" text="Sampler Name" class="unity-base-field__label"/>
<editor:ToolbarMenu name="sampler-type-dropdown" text="Placeholder Sampler Type" class="sampler__type-menu"/>
</VisualElement>
<Label name="display-name" text="Sampler Name" class="unity-base-field__label"/>
<VisualElement name="fields-container" style="margin-left: 18px;"/>
</VisualElement>
</UXML>

4
com.unity.perception/Editor/Randomization/Uxml/Sampler/SamplerElement.uxml.meta


fileFormatVersion: 2
guid: e91be9c80e944358b231c125be80a749
timeCreated: 1594847524
guid: a4752f9d99d8497e9a147942da225b5f
timeCreated: 1612043461

20
com.unity.perception/Editor/Randomization/VisualElements/Parameter/CategoricalOptionElement.cs


using System;
using UnityEditor;
using UnityEngine;
namespace UnityEngine.Experimental.Perception.Randomization.Editor
namespace UnityEditor.Experimental.Perception.Randomization
int m_Index;
int m_Index;
SerializedProperty m_ProbabilitiesProperty;
internal CategoricalOptionElement(

m_CategoryProperty = categoryProperty;
m_ProbabilitiesProperty = probabilitiesProperty;
var template = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(
$"{StaticData.uxmlDir}/Parameter/CategoricalOptionElement.uxml");
template.CloneTree(this);
// Reset this categorical item's UI
Clear();
var template = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(
$"{StaticData.uxmlDir}/Parameter/CategoricalOptionElement.uxml");
template.CloneTree(this);
m_Index = i;
var indexLabel = this.Q<Label>("index-label");
indexLabel.text = $"[{m_Index}]";

option.BindProperty(optionProperty);
// Remove the redundant element label to save space
var label = option.Q<Label>();
label.parent.Remove(label);

else
{
probability.SetEnabled(true);
probability.RegisterValueChangedCallback((evt) =>
probability.RegisterValueChangedCallback(evt =>
{
if (evt.newValue < 0f)
probability.value = 0f;

9
com.unity.perception/Editor/Randomization/VisualElements/Parameter/ColorHsvaField.cs


using UnityEditor;
using System;
using UnityEngine;
namespace UnityEngine.Perception.Randomization.Editor
namespace UnityEditor.Experimental.Perception.Randomization
SerializedProperty m_Property;
SerializedProperty m_A;
SerializedProperty m_Property;
SerializedProperty m_A;
public ColorHsvaField(SerializedProperty property)
{

37
com.unity.perception/Editor/Randomization/VisualElements/Parameter/DrawerParameterElement.cs


using UnityEditor;
using UnityEngine.Experimental.Perception.Randomization.Editor;
using UnityEngine.Experimental.Perception.Randomization.Parameters;
using System;
namespace UnityEngine.Perception.Randomization.Editor
namespace UnityEditor.Experimental.Perception.Randomization
Parameter m_Parameter;
const string k_CollapsedParameterClass = "collapsed";
const string k_CollapsedParameterClass = "collapsed";
bool collapsed
{
get => m_Collapsed.boolValue;
set
{
m_Collapsed.boolValue = value;
m_Property.serializedObject.ApplyModifiedPropertiesWithoutUndo();
if (value)
AddToClassList(k_CollapsedParameterClass);
else
RemoveFromClassList(k_CollapsedParameterClass);
}
}
public DrawerParameterElement(SerializedProperty property)
{

var drawer = this.Q<VisualElement>("drawer");
drawer.Add(new ParameterElement(property));
}
bool collapsed
{
get => m_Collapsed.boolValue;
set
{
m_Collapsed.boolValue = value;
m_Property.serializedObject.ApplyModifiedPropertiesWithoutUndo();
if (value)
AddToClassList(k_CollapsedParameterClass);
else
RemoveFromClassList(k_CollapsedParameterClass);
}
}
}
}

88
com.unity.perception/Editor/Randomization/VisualElements/Parameter/ParameterElement.cs


using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine.Experimental.Perception.Randomization.Editor;
using UnityEngine;
using Object = UnityEngine.Object;
namespace UnityEngine.Perception.Randomization.Editor
namespace UnityEditor.Experimental.Perception.Randomization
{
class ParameterElement : VisualElement
{

Parameter parameter => (Parameter)StaticData.GetManagedReferenceValue(m_SerializedProperty);
CategoricalParameterBase categoricalParameter => (CategoricalParameterBase)parameter;
public ParameterElement(SerializedProperty property)
{
var template = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(

CreatePropertyFields();
}
Parameter parameter => (Parameter)StaticData.GetManagedReferenceValue(m_SerializedProperty);
CategoricalParameterBase categoricalParameter => (CategoricalParameterBase)parameter;
void CreatePropertyFields()
{
m_PropertiesContainer.Clear();

return;
}
var currentProperty = m_SerializedProperty.Copy();
var currentProperty = m_SerializedProperty.Copy();
{
if (currentProperty.type.Contains("managedReference") &&
currentProperty.managedReferenceFieldTypename == StaticData.samplerSerializedFieldType)
m_PropertiesContainer.Add(new SamplerElement(currentProperty.Copy(), parameter));
else
{
var propertyField = new PropertyField(currentProperty.Copy());
propertyField.Bind(currentProperty.serializedObject);
m_PropertiesContainer.Add(propertyField);
}
var propertyField = new PropertyField(currentProperty.Copy());
propertyField.Bind(currentProperty.serializedObject);
m_PropertiesContainer.Add(propertyField);
}
}
void CreateCategoricalParameterFields()

listView.style.flexGrow = 1.0f;
listView.style.height = new StyleLength(listView.itemHeight * 4);
VisualElement MakeItem() => new CategoricalOptionElement(
optionsProperty, probabilitiesProperty);
VisualElement MakeItem()
{
return new CategoricalOptionElement(
optionsProperty, probabilitiesProperty);
}
listView.makeItem = MakeItem;
void BindItem(VisualElement e, int i)

listView.Refresh();
};
}
listView.bindItem = BindItem;
var addOptionButton = template.Q<Button>("add-option");

optionsProperty.arraySize++;
var newOption = optionsProperty.GetArrayElementAtIndex(optionsProperty.arraySize - 1);
switch (newOption.propertyType)
{
case SerializedPropertyType.ObjectReference:
newOption.objectReferenceValue = null;
break;
case SerializedPropertyType.String:
newOption.stringValue = string.Empty;
break;
}
m_SerializedProperty.serializedObject.ApplyModifiedProperties();
listView.itemsSource = categoricalParameter.probabilities;
listView.Refresh();

var addFolderButton = template.Q<Button>("add-folder");
if (categoricalParameter.sampleType.IsSubclassOf(typeof(Object)))
{
addFolderButton.clicked += () =>
{
var folderPath = EditorUtility.OpenFolderPanel(

optionProperty.objectReferenceValue = categories[i];
probabilityProperty.floatValue = uniformProbability;
}
}
else
addFolderButton.style.display = new StyleEnum<DisplayStyle>(DisplayStyle.None);

{
if (Mathf.Approximately(scrollView.verticalScroller.highValue, 0f))
return;
if ((scrollView.scrollOffset.y <= 0f && evt.delta.y < 0f) ||
if (scrollView.scrollOffset.y <= 0f && evt.delta.y < 0f ||
scrollView.scrollOffset.y >= scrollView.verticalScroller.highValue && evt.delta.y > 0f)
evt.StopImmediatePropagation();
});

uniformToggle.BindProperty(uniformProperty);
void ToggleProbabilityFields(bool toggle)
{
if (toggle)
listView.AddToClassList("collapsed");
else
listView.RemoveFromClassList("collapsed");
}
ToggleProbabilityFields(uniformToggle.value);
if (uniformToggle.value)
listView.AddToClassList("collapsed");
else
listView.RemoveFromClassList("collapsed");
uniformToggle.RegisterCallback<ChangeEvent<bool>>(evt => ToggleProbabilityFields(evt.newValue));
uniformToggle.RegisterCallback<ChangeEvent<bool>>(evt =>
{
listView.ToggleInClassList("collapsed");
if (!evt.newValue)
return;
var numOptions = optionsProperty.arraySize;
var uniformProbabilityValue = 1f / numOptions;
for (var i = 0; i < numOptions; i++)
{
var probability = probabilitiesProperty.GetArrayElementAtIndex(i);
probability.floatValue = uniformProbabilityValue;
}
m_SerializedProperty.serializedObject.ApplyModifiedProperties();
listView.itemsSource = categoricalParameter.probabilities;
listView.Refresh();
});
m_PropertiesContainer.Add(template);
}

if (!folderPath.StartsWith(Application.dataPath))
throw new ApplicationException("Selected folder is not an asset folder in this project");
var assetsPath = "Assets" + folderPath.Remove(0, Application.dataPath.Length);
var assetIds = AssetDatabase.FindAssets($"t:{assetType.Name}", new []{assetsPath});
var assetIds = AssetDatabase.FindAssets($"t:{assetType.Name}", new[] { assetsPath });
var assets = new List<Object>();
foreach (var guid in assetIds)
assets.Add(AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(guid), assetType));

166
com.unity.perception/Editor/Randomization/VisualElements/Randomizer/AddRandomizerMenu.cs


using System.Collections.Generic;
using NUnit.Framework;
using Unity.Mathematics;
using UnityEditor;
using UnityEngine.Experimental.Perception.Randomization.Editor;
namespace UnityEngine.Experimental.Perception.Randomization.VisualElements
namespace UnityEditor.Experimental.Perception.Randomization
VisualElement m_DirectoryChevron;
TextElement m_DirectoryLabelText;
Dictionary<string, HashSet<string>> m_MenuDirectories = new Dictionary<string, HashSet<string>>();
VisualElement m_MenuElements;
List<MenuItem> m_MenuItems = new List<MenuItem>();
Dictionary<string, List<MenuItem>> m_MenuItemsMap = new Dictionary<string, List<MenuItem>>();
RandomizerList m_RandomizerList;
string m_SearchString = string.Empty;
public AddRandomizerMenu(VisualElement parentElement, VisualElement button, RandomizerList randomizerList)
{
m_RandomizerList = randomizerList;
var template = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(
$"{StaticData.uxmlDir}/Randomizer/AddRandomizerMenu.uxml");
template.CloneTree(this);
style.position = new StyleEnum<Position>(Position.Absolute);
var buttonPosition = button.worldBound.position;
var top = math.min(buttonPosition.y, parentElement.worldBound.height - 300);
style.top = top;
style.left = buttonPosition.x;
focusable = true;
RegisterCallback<FocusOutEvent>(evt =>
{
if (evt.relatedTarget == null || ((VisualElement)evt.relatedTarget).FindCommonAncestor(this) != this)
ExitMenu();
});
var directoryLabel = this.Q<VisualElement>("directory-label");
directoryLabel.RegisterCallback<MouseUpEvent>(evt => { AscendDirectory(); });
m_DirectoryLabelText = this.Q<TextElement>("directory-label-text");
m_DirectoryChevron = this.Q<VisualElement>("directory-chevron");
var searchBar = this.Q<TextField>("search-bar");
searchBar.schedule.Execute(() => searchBar.ElementAt(0).Focus());
searchBar.RegisterValueChangedCallback(evt => searchString = evt.newValue);
m_MenuElements = this.Q<VisualElement>("menu-options");
CreateMenuItems();
DrawDirectoryItems();
}
string currentPath
{
get => m_CurrentPath;

}
}
string m_SearchString = string.Empty;
string searchString
{
get => m_SearchString;

}
}
RandomizerList m_RandomizerList;
VisualElement m_MenuElements;
TextElement m_DirectoryLabelText;
VisualElement m_DirectoryChevron;
Dictionary<string, List<MenuItem>> m_MenuItemsMap = new Dictionary<string, List<MenuItem>>();
Dictionary<string, HashSet<string>> m_MenuDirectories = new Dictionary<string, HashSet<string>>();
List<MenuItem> m_MenuItems = new List<MenuItem>();
class MenuItem
{
public Type randomizerType;
public string itemName;
public MenuItem(Type randomizerType, string itemName)
{
this.randomizerType = randomizerType;
this.itemName = itemName;
}
}
sealed class MenuItemElement : TextElement
{
public MenuItemElement(MenuItem menuItem, AddRandomizerMenu menu)
{
text = menuItem.itemName;
AddToClassList("randomizer__add-menu-directory-item");
RegisterCallback<MouseUpEvent>(evt => menu.AddRandomizer(menuItem.randomizerType));
}
}
sealed class MenuDirectoryElement : VisualElement
{
public MenuDirectoryElement(string directory, AddRandomizerMenu menu)
{
AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(
$"{StaticData.uxmlDir}/Randomizer/MenuDirectoryElement.uxml").CloneTree(this);
var pathItems = directory.Split('/');
this.Q<TextElement>("directory").text = pathItems[pathItems.Length - 1];
RegisterCallback<MouseUpEvent>(evt => menu.currentPath = directory);
}
}
public AddRandomizerMenu(VisualElement parentElement, VisualElement button, RandomizerList randomizerList)
{
m_RandomizerList = randomizerList;
var template = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(
$"{StaticData.uxmlDir}/Randomizer/AddRandomizerMenu.uxml");
template.CloneTree(this);
style.position = new StyleEnum<Position>(Position.Absolute);
var buttonPosition = button.worldBound.position;
var top = math.min(buttonPosition.y, parentElement.worldBound.height - 300);
style.top = top;
style.left = buttonPosition.x;
focusable = true;
RegisterCallback<FocusOutEvent>(evt =>
{
if (evt.relatedTarget == null || ((VisualElement)evt.relatedTarget).FindCommonAncestor(this) != this)
ExitMenu();
});
var directoryLabel = this.Q<VisualElement>("directory-label");
directoryLabel.RegisterCallback<MouseUpEvent>(evt => { AscendDirectory(); });
m_DirectoryLabelText = this.Q<TextElement>("directory-label-text");
m_DirectoryChevron = this.Q<VisualElement>("directory-chevron");
var searchBar = this.Q<TextField>("search-bar");
searchBar.schedule.Execute(() => searchBar.ElementAt(0).Focus());
searchBar.RegisterValueChangedCallback(evt => searchString = evt.newValue);
m_MenuElements = this.Q<VisualElement>("menu-options");
CreateMenuItems();
DrawDirectoryItems();
}
void ExitMenu()
{
parent.Remove(this);

var upperSearchString = searchString.ToUpper();
foreach (var menuItem in m_MenuItems)
{
}
}
void CreateMenuItems()

m_MenuDirectories.Add(path, new HashSet<string>());
m_MenuDirectories[path].Add(childPath);
}
path = childPath;
}

rootList.Add(new MenuItem(randomizerType, randomizerType.Name));
}
}
}
class MenuItem
{
public string itemName;
public Type randomizerType;
public MenuItem(Type randomizerType, string itemName)
{
this.randomizerType = randomizerType;
this.itemName = itemName;
}
}
sealed class MenuItemElement : TextElement
{
public MenuItemElement(MenuItem menuItem, AddRandomizerMenu menu)
{
text = menuItem.itemName;
AddToClassList("randomizer__add-menu-directory-item");
RegisterCallback<MouseUpEvent>(evt => menu.AddRandomizer(menuItem.randomizerType));
}
}
sealed class MenuDirectoryElement : VisualElement
{
public MenuDirectoryElement(string directory, AddRandomizerMenu menu)
{
AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(
$"{StaticData.uxmlDir}/Randomizer/MenuDirectoryElement.uxml").CloneTree(this);
var pathItems = directory.Split('/');
this.Q<TextElement>("directory").text = pathItems[pathItems.Length - 1];
RegisterCallback<MouseUpEvent>(evt => menu.currentPath = directory);
}
}
}
}

12
com.unity.perception/Editor/Randomization/VisualElements/Randomizer/DragToReorderManipulator.cs


using UnityEngine.Experimental.Perception.Randomization.VisualElements;
using System;
using UnityEditor.Experimental.Perception.Randomization;
namespace UnityEngine.Experimental.Perception.Randomization.Editor
namespace UnityEditor.Experimental.Perception.Randomization
VisualElement m_DragHandle;
VisualElement m_ParameterContainer;
VisualElement m_DragHandle;
VisualElement m_ParameterContainer;
protected override void RegisterCallbacksOnTarget()
{

var randomizerIndex = m_RandomizerElement.parent.IndexOf(m_RandomizerElement);
for (var i = 0; i < middlePoints.Length; i++)
{
}
ReorderParameter(randomizerIndex, middlePoints.Length);
}

72
com.unity.perception/Editor/Randomization/VisualElements/Randomizer/RandomizerElement.cs


using System;
using UnityEditor;
using UnityEngine.Experimental.Perception.Randomization.Editor;
using UnityEngine.Experimental.Perception.Randomization.Randomizers;
namespace UnityEngine.Experimental.Perception.Randomization.VisualElements
namespace UnityEditor.Experimental.Perception.Randomization
const string k_CollapsedParameterClass = "collapsed";
SerializedProperty m_Property;
Randomizers.Randomizer randomizer => (Randomizers.Randomizer)StaticData.GetManagedReferenceValue(m_Property);
public Type randomizerType => randomizer.GetType();
const string k_CollapsedParameterClass = "collapsed";
public RandomizerList randomizerList { get; }
public bool collapsed
{
get => m_Collapsed.boolValue;
set
{
m_Collapsed.boolValue = value;
m_Property.serializedObject.ApplyModifiedPropertiesWithoutUndo();
if (value)
AddToClassList(k_CollapsedParameterClass);
else
RemoveFromClassList(k_CollapsedParameterClass);
}
}
SerializedProperty m_Property;
public RandomizerElement(SerializedProperty property, RandomizerList randomizerList)
{

FillPropertiesContainer();
}
void FillPropertiesContainer()
{
m_PropertiesContainer.Clear();
var iterator = m_Property.Copy();
var nextSiblingProperty = m_Property.Copy();
nextSiblingProperty.NextVisible(false);
Randomizer randomizer => (Randomizer)StaticData.GetManagedReferenceValue(m_Property);
public Type randomizerType => randomizer.GetType();
public RandomizerList randomizerList { get; }
var foundProperties = false;
if (iterator.NextVisible(true))
public bool collapsed
{
get => m_Collapsed.boolValue;
set
do
{
if (SerializedProperty.EqualContents(iterator, nextSiblingProperty))
break;
if (iterator.name == "<enabled>k__BackingField")
continue;
foundProperties = true;
var propertyField = new PropertyField(iterator.Copy());
propertyField.Bind(m_Property.serializedObject);
m_PropertiesContainer.Add(propertyField);
} while (iterator.NextVisible(false));
m_Collapsed.boolValue = value;
m_Property.serializedObject.ApplyModifiedPropertiesWithoutUndo();
if (value)
AddToClassList(k_CollapsedParameterClass);
else
RemoveFromClassList(k_CollapsedParameterClass);
}
if (!foundProperties)
void FillPropertiesContainer()
{
m_PropertiesContainer.Clear();
UIElementsEditorUtilities.CreatePropertyFields(m_Property, m_PropertiesContainer);
if (m_PropertiesContainer.childCount == 0)
m_PropertiesContainer.style.display = new StyleEnum<DisplayStyle>(DisplayStyle.None);
}
}

34
com.unity.perception/Editor/Randomization/VisualElements/Randomizer/RandomizerList.cs


using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine.Experimental.Perception.Randomization.Editor;
namespace UnityEngine.Experimental.Perception.Randomization.VisualElements
namespace UnityEditor.Experimental.Perception.Randomization
SerializedProperty m_Property;
public ScenarioBase scenario => (ScenarioBase)m_Property.serializedObject.targetObject;
VisualElement inspectorContainer
{
get
{
var viewport = parent;
while (!viewport.ClassListContains("unity-inspector-main-container"))
viewport = viewport.parent;
return viewport;
}
}
SerializedProperty m_Property;
public RandomizerList(SerializedProperty property)
{

m_Property.serializedObject.Update();
RefreshList();
};
}
public ScenarioBase scenario => (ScenarioBase)m_Property.serializedObject.targetObject;
VisualElement inspectorContainer
{
get
{
var viewport = parent;
while (!viewport.ClassListContains("unity-inspector-main-container"))
viewport = viewport.parent;
return viewport;
}
}
void RefreshList()

5
com.unity.perception/Editor/Randomization/VisualElements/Randomizer/RandomizerReorderingIndicator.cs


using UnityEngine.UIElements;
using System;
using UnityEngine.UIElements;
namespace UnityEngine.Experimental.Perception.Randomization.Editor
namespace UnityEditor.Experimental.Perception.Randomization
{
class RandomizerReorderingIndicator : VisualElement
{

6
com.unity.perception/Editor/Randomization/VisualElements/Sampler/FloatRangeElement.cs


using UnityEngine;
using UnityEditor;
using System;
using UnityEngine;
namespace UnityEngine.Experimental.Perception.Randomization.Editor
namespace UnityEditor.Experimental.Perception.Randomization
{
class FloatRangeElement : VisualElement
{

120
com.unity.perception/Editor/Randomization/VisualElements/Sampler/SamplerElement.cs


using System;
using System.Linq;
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine.Experimental.Perception.Randomization.Parameters;
using UnityEngine.Experimental.Perception.Randomization.Samplers;
namespace UnityEngine.Experimental.Perception.Randomization.Editor
namespace UnityEditor.Experimental.Perception.Randomization
Parameter m_Parameter;
ISampler m_Sampler;
SerializedProperty m_Property;
SerializedProperty m_RangeProperty;
VisualElement m_Properties;
ToolbarMenu m_SamplerTypeDropdown;
public SamplerElement(SerializedProperty property, Parameter parameter)
public SamplerElement(SerializedProperty property)
m_Property = property;
m_Parameter = parameter;
m_Sampler = GetSamplerFromSerializedObject();
if (m_Sampler == null)
CreateSampler(typeof(UniformSampler));
var samplerName = this.Q<Label>("sampler-name");
samplerName.text = UppercaseFirstLetter(m_Property.name);
m_Properties = this.Q<VisualElement>("fields-container");
m_SamplerTypeDropdown = this.Q<ToolbarMenu>("sampler-type-dropdown");
m_SamplerTypeDropdown.text = SamplerUtility.GetSamplerDisplayName(m_Sampler.GetType());;
foreach (var samplerType in StaticData.samplerTypes)
{
var displayName = SamplerUtility.GetSamplerDisplayName(samplerType);;
m_SamplerTypeDropdown.menu.AppendAction(
displayName,
a => { ReplaceSampler(samplerType); },
a => DropdownMenuAction.Status.Normal);
}
CreatePropertyFields();
}
void ReplaceSampler(Type samplerType)
{
CreateSampler(samplerType);
m_SamplerTypeDropdown.text = SamplerUtility.GetSamplerDisplayName(samplerType);
CreatePropertyFields();
}
void CreateSampler(Type samplerType)
{
var newSampler = (ISampler)Activator.CreateInstance(samplerType);
CopyFloatRangeToNewSampler(newSampler);
m_Sampler = newSampler;
m_Property.managedReferenceValue = newSampler;
m_Property.serializedObject.ApplyModifiedProperties();
}
void CopyFloatRangeToNewSampler(ISampler newSampler)
{
if (m_RangeProperty == null)
return;
var rangeField = newSampler.GetType().GetField(m_RangeProperty.name);
if (rangeField == null)
return;
var range = new FloatRange(
m_RangeProperty.FindPropertyRelative("minimum").floatValue,
m_RangeProperty.FindPropertyRelative("maximum").floatValue);
rangeField.SetValue(newSampler, range);
}
void CreatePropertyFields()
{
m_RangeProperty = null;
m_Properties.Clear();
var currentProperty = m_Property.Copy();
var nextSiblingProperty = m_Property.Copy();
nextSiblingProperty.NextVisible(false);
if (currentProperty.NextVisible(true))
{
do
{
if (SerializedProperty.EqualContents(currentProperty, nextSiblingProperty))
break;
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);
var originalField = m_Sampler.GetType().GetField(currentProperty.name);
var tooltipAttribute = originalField.GetCustomAttributes(true).ToList().Find(att => att.GetType() == typeof(TooltipAttribute));
if (tooltipAttribute != null)
{
propertyField.tooltip = (tooltipAttribute as TooltipAttribute)?.tooltip;
}
m_Properties.Add(propertyField);
}
}
while (currentProperty.NextVisible(false));
}
}
var displayName = this.Q<Label>("display-name");
displayName.text = property.displayName;
static string UppercaseFirstLetter(string s)
{
return string.IsNullOrEmpty(s) ? string.Empty : char.ToUpper(s[0]) + s.Substring(1);
}
ISampler GetSamplerFromSerializedObject()
{
var configType = m_Parameter.GetType();
var field = configType.GetField(m_Property.name);
return (ISampler)field.GetValue(m_Parameter);
var fieldsContainer = this.Q<VisualElement>("fields-container");
UIElementsEditorUtilities.CreatePropertyFields(property, fieldsContainer);
}
}
}

14
com.unity.perception/Editor/Randomization/VisualElements/Sampler/SamplerElement.cs.meta


fileFormatVersion: 2
guid: 134b50014b9f4c0694a087d3529ea4c2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
fileFormatVersion: 2
guid: a5920440efa84756a581dda95394a14f
timeCreated: 1612042675

12
com.unity.perception/Runtime/Randomization/Parameters/CategoricalParameter.cs


public override void Validate()
{
base.Validate();
// Check for a non-zero amount of specified categories
// Check for duplicate categories
var uniqueCategories = new HashSet<T>();
foreach (var option in m_Categories)
if (uniqueCategories.Contains(option))
throw new ParameterValidationException("Duplicate categories");
else
uniqueCategories.Add(option);
// Check if the number of specified probabilities is different from the number of listed categories
if (!uniform)
{
if (probabilities.Count != m_Categories.Count)

2
com.unity.perception/Runtime/Randomization/Randomizers/Randomizer.cs


/// <summary>
/// Enabled Randomizers are updated, disabled Randomizers are not.
/// </summary>
[field: SerializeField] public bool enabled { get; set; } = true;
[field: SerializeField, HideInInspector] public bool enabled { get; set; } = true;
/// <summary>
/// Returns the scenario containing this Randomizer

2
com.unity.perception/Runtime/Randomization/Samplers/ISampler.cs


using System;
using Unity.Collections;
using Unity.Jobs;
using UnityEngine;
namespace UnityEngine.Experimental.Perception.Randomization.Samplers

10
com.unity.perception/Tests/Runtime/Randomization/ParameterTests/CategoricalParameterTests.cs


public void NegativeProbabilities()
{
var parameter = new StringParameter();
var optionsArray = new [] { ("option1", 1f), ("option1", -1f) };
var optionsArray = new [] { ("option1", 1f), ("option2", -1f) };
{
var parameter = new StringParameter();
var optionsArray = new [] { ("option1", 0f), ("option2", 0f) };
Assert.Throws<ParameterValidationException>(() => parameter.SetOptions(optionsArray));
}
[Test]
public void DuplicateCategoriesTest()
{
var parameter = new StringParameter();
var optionsArray = new [] { ("option1", 0f), ("option1", 0f) };

26
com.unity.perception/Editor/Randomization/PropertyDrawers/FloatRangeDrawer.cs


using System;
using UnityEngine;
using UnityEngine.Experimental.Perception.Randomization.Samplers;
using UnityEngine.UIElements;
namespace UnityEditor.Experimental.Perception.Randomization.PropertyDrawers
{
[CustomPropertyDrawer(typeof(FloatRange))]
class FloatRangeDrawer : PropertyDrawer
{
public override VisualElement CreatePropertyGUI(SerializedProperty property)
{
return new FloatRangeElement(property);
}
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.PropertyField(position, property, label, true);
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
return EditorGUI.GetPropertyHeight(property);
}
}
}

3
com.unity.perception/Editor/Randomization/PropertyDrawers/FloatRangeDrawer.cs.meta


fileFormatVersion: 2
guid: 2aaf69aad9c844a592283d36b3c14d8f
timeCreated: 1612042769

28
com.unity.perception/Editor/Randomization/PropertyDrawers/SamplerDrawer.cs


using System;
using UnityEngine;
using UnityEngine.Experimental.Perception.Randomization.Samplers;
using UnityEngine.UIElements;
namespace UnityEditor.Experimental.Perception.Randomization.PropertyDrawers
{
[CustomPropertyDrawer(typeof(ISampler), true)]
class SamplerDrawer : PropertyDrawer
{
public override VisualElement CreatePropertyGUI(SerializedProperty property)
{
return fieldInfo.FieldType.IsInterface
? new SamplerInterfaceElement(property) as VisualElement
: new SamplerElement(property);
}
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.PropertyField(position, property, label, true);
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
return EditorGUI.GetPropertyHeight(property);
}
}
}

3
com.unity.perception/Editor/Randomization/PropertyDrawers/SamplerDrawer.cs.meta


fileFormatVersion: 2
guid: 87021ed3ca1241f8953af2ee975504c4
timeCreated: 1612040428

10
com.unity.perception/Editor/Randomization/Uxml/Sampler/SamplerInterfaceElement.uxml


<UXML xmlns="UnityEngine.UIElements" xmlns:editor="UnityEditor.UIElements">
<VisualElement name="sampler-template" style="margin-bottom: 4px;">
<Style src="../../Uss/Styles.uss"/>
<VisualElement style="flex-direction: row; align-items: center;">
<Label name="sampler-name" text="Sampler Name" class="unity-base-field__label"/>
<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>

3
com.unity.perception/Editor/Randomization/Uxml/Sampler/SamplerInterfaceElement.uxml.meta


fileFormatVersion: 2
guid: e91be9c80e944358b231c125be80a749
timeCreated: 1594847524

89
com.unity.perception/Editor/Randomization/VisualElements/Sampler/SamplerInterfaceElement.cs


using System;
using UnityEditor.UIElements;
using UnityEngine.Experimental.Perception.Randomization.Samplers;
using UnityEngine.UIElements;
namespace UnityEditor.Experimental.Perception.Randomization
{
class SamplerInterfaceElement : VisualElement
{
VisualElement m_PropertiesContainer;
SerializedProperty m_Property;
SerializedProperty m_RangeProperty;
ToolbarMenu m_SamplerTypeDropdown;
public SamplerInterfaceElement(SerializedProperty property)
{
m_Property = property;
var template = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(
$"{StaticData.uxmlDir}/Sampler/SamplerInterfaceElement.uxml");
template.CloneTree(this);
if (sampler == null)
CreateSampler(typeof(UniformSampler));
var samplerName = this.Q<Label>("sampler-name");
samplerName.text = UppercaseFirstLetter(m_Property.name);
m_PropertiesContainer = this.Q<VisualElement>("fields-container");
m_SamplerTypeDropdown = this.Q<ToolbarMenu>("sampler-type-dropdown");
m_SamplerTypeDropdown.text = SamplerUtility.GetSamplerDisplayName(sampler.GetType());
;
foreach (var samplerType in StaticData.samplerTypes)
{
var displayName = SamplerUtility.GetSamplerDisplayName(samplerType);
;
m_SamplerTypeDropdown.menu.AppendAction(
displayName,
a => { ReplaceSampler(samplerType); },
a => DropdownMenuAction.Status.Normal);
}
CreatePropertyFields();
}
ISampler sampler => (ISampler)StaticData.GetManagedReferenceValue(m_Property);
void ReplaceSampler(Type samplerType)
{
CreateSampler(samplerType);
m_SamplerTypeDropdown.text = SamplerUtility.GetSamplerDisplayName(samplerType);
CreatePropertyFields();
}
void CreateSampler(Type samplerType)
{
var newSampler = (ISampler)Activator.CreateInstance(samplerType);
CopyFloatRangeToNewSampler(newSampler);
m_Property.managedReferenceValue = newSampler;
m_Property.serializedObject.ApplyModifiedProperties();
}
void CopyFloatRangeToNewSampler(ISampler newSampler)
{
if (m_RangeProperty == null)
return;
var rangeField = newSampler.GetType().GetField(m_RangeProperty.name);
if (rangeField == null)
return;
var range = new FloatRange(
m_RangeProperty.FindPropertyRelative("minimum").floatValue,
m_RangeProperty.FindPropertyRelative("maximum").floatValue);
rangeField.SetValue(newSampler, range);
}
void CreatePropertyFields()
{
m_RangeProperty = null;
m_PropertiesContainer.Clear();
UIElementsEditorUtilities.CreatePropertyFields(m_Property, m_PropertiesContainer);
}
static string UppercaseFirstLetter(string s)
{
return string.IsNullOrEmpty(s) ? string.Empty : char.ToUpper(s[0]) + s.Substring(1);
}
}
}

11
com.unity.perception/Editor/Randomization/VisualElements/Sampler/SamplerInterfaceElement.cs.meta


fileFormatVersion: 2
guid: 134b50014b9f4c0694a087d3529ea4c2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

22
com.unity.perception/Editor/Randomization/Utilities/ParameterUIElementsEditor.cs


using System;
using UnityEngine;
using UnityEngine.UIElements;
namespace UnityEditor.Experimental.Perception.Randomization
{
/// <summary>
/// Derive this class to force the Unity Editor to render the default inspector using UIElements for an Object that
/// includes a Parameter field.
/// to allow parameter UIs to render properly
/// </summary>
public abstract class ParameterUIElementsEditor : Editor
{
///<inheritdoc/>
public override VisualElement CreateInspectorGUI()
{
var rootElement = new VisualElement();
UIElementsEditorUtilities.CreatePropertyFields(serializedObject, rootElement);
return rootElement;
}
}
}

95
com.unity.perception/Editor/Randomization/Utilities/StaticData.cs


using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEngine.Experimental.Perception.Randomization.Randomizers;
using UnityEngine.Experimental.Perception.Randomization.Samplers;
namespace UnityEditor.Experimental.Perception.Randomization
{
static class StaticData
{
const string k_RandomizationDir = "Packages/com.unity.perception/Editor/Randomization";
internal const string uxmlDir = k_RandomizationDir + "/Uxml";
internal static Type[] randomizerTypes;
internal static Type[] samplerTypes;
static StaticData()
{
randomizerTypes = GetConstructableDerivedTypes<Randomizer>();
samplerTypes = GetConstructableDerivedTypes<ISampler>();
}
static Type[] GetConstructableDerivedTypes<T>()
{
var collection = TypeCache.GetTypesDerivedFrom<T>();
var types = new List<Type>();
foreach (var type in collection)
if (!type.IsAbstract && !type.IsInterface)
types.Add(type);
return types.ToArray();
}
public static object GetManagedReferenceValue(SerializedProperty prop, bool parent = false)
{
var path = prop.propertyPath.Replace(".Array.data[", "[");
object obj = prop.serializedObject.targetObject;
var elements = path.Split('.');
if (parent)
elements = elements.Take(elements.Count() - 1).ToArray();
foreach (var element in elements)
if (element.Contains("["))
{
var elementName = element.Substring(0, element.IndexOf("["));
var index = Convert.ToInt32(element.Substring(element.IndexOf("[")).Replace("[", "").Replace("]", ""));
obj = GetArrayValue(obj, elementName, index);
}
else
{
obj = GetValue(obj, element);
}
return obj;
}
static object GetValue(object source, string name)
{
if (source == null)
return null;
var type = source.GetType();
var f = type.GetField(name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
if (f == null)
{
var p = type.GetProperty(name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
return p == null ? null : p.GetValue(source, null);
}
return f.GetValue(source);
}
static object GetArrayValue(object source, string name, int index)
{
var value = GetValue(source, name);
if (!(value is IEnumerable enumerable))
return null;
var enumerator = enumerable.GetEnumerator();
while (index-- >= 0)
enumerator.MoveNext();
return enumerator.Current;
}
public static bool IsSubclassOfRawGeneric(Type generic, Type toCheck)
{
while (toCheck != null && toCheck != typeof(object))
{
var cur = toCheck.IsGenericType ? toCheck.GetGenericTypeDefinition() : toCheck;
if (generic == cur) return true;
toCheck = toCheck.BaseType;
}
return false;
}
}
}

75
com.unity.perception/Editor/Randomization/Utilities/UIElementsEditorUtilities.cs


using System;
using System.Linq;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;
namespace UnityEditor.Experimental.Perception.Randomization
{
/// <summary>
/// This class contains a set of helper functions for simplifying the creation of UI Elements editors
/// </summary>
public static class UIElementsEditorUtilities
{
/// <summary>
/// Creates a list of PropertyFields from the class fields of the given SerializedObject
/// and adds them to the specified container element
/// </summary>
/// <param name="serializedObj">The SerializedObject to create property fields for</param>
/// <param name="containerElement">The element to place the created PropertyFields in</param>
public static void CreatePropertyFields(SerializedObject serializedObj, VisualElement containerElement)
{
var fieldType = serializedObj.targetObject.GetType();
var iterator = serializedObj.GetIterator();
iterator.NextVisible(true);
iterator.NextVisible(false);
do
{
var propertyField = CreatePropertyField(iterator, fieldType);
containerElement.Add(propertyField);
} while (iterator.NextVisible(false));
}
/// <summary>
/// Creates a list of PropertyFields from the sub-fields of the given SerializedProperty
/// and adds them to the specified container element
/// </summary>
/// <param name="property">The SerializedProperty to create sub property fields for</param>
/// <param name="containerElement">The element to place the created PropertyFields in</param>
public static void CreatePropertyFields(SerializedProperty property, VisualElement containerElement)
{
var fieldType = StaticData.GetManagedReferenceValue(property).GetType();
var iterator = property.Copy();
var nextSiblingProperty = property.Copy();
nextSiblingProperty.NextVisible(false);
if (iterator.NextVisible(true))
do
{
if (SerializedProperty.EqualContents(iterator, nextSiblingProperty))
break;
var propertyField = CreatePropertyField(iterator, fieldType);
containerElement.Add(propertyField);
} while (iterator.NextVisible(false));
}
/// <summary>
/// Creates a PropertyField from a given SerializedProperty (with tooltips!)
/// </summary>
/// <param name="iterator">The SerializedProperty to create a PropertyField</param>
/// <param name="parentPropertyType">The Type of the class encapsulating the provided SerializedProperty</param>
/// <returns></returns>
public static PropertyField CreatePropertyField(SerializedProperty iterator, Type parentPropertyType)
{
var propertyField = new PropertyField(iterator.Copy());
propertyField.Bind(iterator.serializedObject);
var originalField = parentPropertyType.GetField(iterator.name);
var tooltipAttribute = originalField.GetCustomAttributes(true)
.ToList().Find(att => att.GetType() == typeof(TooltipAttribute));
if (tooltipAttribute != null)
propertyField.tooltip = (tooltipAttribute as TooltipAttribute)?.tooltip;
return propertyField;
}
}
}

3
com.unity.perception/Editor/Randomization/Utilities/UIElementsEditorUtilities.cs.meta


fileFormatVersion: 2
guid: 9ed5513847d3486dbf017c9fb30186b9
timeCreated: 1612048047

101
com.unity.perception/Editor/Randomization/StaticData.cs


using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEditor;
using UnityEngine.Experimental.Perception.Randomization.Parameters;
using UnityEngine.Experimental.Perception.Randomization.Randomizers;
using UnityEngine.Experimental.Perception.Randomization.Samplers;
namespace UnityEngine.Experimental.Perception.Randomization.Editor
{
static class StaticData
{
const string k_RandomizationDir = "Packages/com.unity.perception/Editor/Randomization";
internal const string uxmlDir = k_RandomizationDir + "/Uxml";
internal static readonly string samplerSerializedFieldType;
internal static Type[] randomizerTypes;
internal static Type[] samplerTypes;
static StaticData()
{
randomizerTypes = GetConstructableDerivedTypes<Randomizer>();
samplerTypes = GetConstructableDerivedTypes<ISampler>();
var samplerType = typeof(ISampler);
samplerSerializedFieldType = $"{samplerType.Assembly.GetName().Name} {samplerType.FullName}";
}
static Type[] GetConstructableDerivedTypes<T>()
{
var collection = TypeCache.GetTypesDerivedFrom<T>();
var types = new List<Type>();
foreach (var type in collection)
{
if (!type.IsAbstract && !type.IsInterface)
types.Add(type);
}
return types.ToArray();
}
internal static object GetManagedReferenceValue(SerializedProperty prop, bool parent=false)
{
var path = prop.propertyPath.Replace(".Array.data[", "[");
object obj = prop.serializedObject.targetObject;
var elements = path.Split('.');
if (parent)
elements = elements.Take(elements.Count() - 1).ToArray();
foreach (var element in elements)
{
if (element.Contains("["))
{
var elementName = element.Substring(0, element.IndexOf("["));
var index = Convert.ToInt32(element.Substring(element.IndexOf("[")).Replace("[","").Replace("]",""));
obj = GetArrayValue(obj, elementName, index);
}
else
obj = GetValue(obj, element);
}
return obj;
}
static object GetValue(object source, string name)
{
if (source == null)
return null;
var type = source.GetType();
var f = type.GetField(name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
if (f == null)
{
var p = type.GetProperty(name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
return p == null ? null : p.GetValue(source, null);
}
return f.GetValue(source);
}
static object GetArrayValue(object source, string name, int index)
{
var value = GetValue(source, name);
if (!(value is IEnumerable enumerable))
return null;
var enumerator = enumerable.GetEnumerator();
while (index-- >= 0)
enumerator.MoveNext();
return enumerator.Current;
}
public static bool IsSubclassOfRawGeneric(Type generic, Type toCheck) {
while (toCheck != null && toCheck != typeof(object)) {
var cur = toCheck.IsGenericType ? toCheck.GetGenericTypeDefinition() : toCheck;
if (generic == cur) {
return true;
}
toCheck = toCheck.BaseType;
}
return false;
}
}
}

/com.unity.perception/Editor/Randomization/StaticData.cs.meta → /com.unity.perception/Editor/Randomization/Utilities/StaticData.cs.meta

/com.unity.perception/Editor/Utilities.meta → /com.unity.perception/Editor/Randomization/Utilities.meta

/com.unity.perception/Editor/Utilities/ParameterUIElementsEditor.cs.meta → /com.unity.perception/Editor/Randomization/Utilities/ParameterUIElementsEditor.cs.meta

正在加载...
取消
保存