浏览代码

Merge branch 'master' into add_imageLink_field

/add_imageLink_field
Mohsen Kamalzadeh 3 年前
当前提交
e9ac2316
共有 61 个文件被更改,包括 1339 次插入157 次删除
  1. 4
      com.unity.perception/CHANGELOG.md
  2. 13
      com.unity.perception/Editor/Randomization/Utilities/UIElementsEditorUtilities.cs
  3. 5
      com.unity.perception/Editor/Randomization/Utilities/StaticData.cs
  4. 2
      com.unity.perception/Editor/Randomization/Uxml/Sampler/SamplerInterfaceElement.uxml
  5. 7
      com.unity.perception/Editor/Randomization/Uxml/ScenarioBaseElement.uxml
  6. 8
      com.unity.perception/Editor/Randomization/Uxml/RunInUnitySimulationWindow.uxml
  7. 16
      com.unity.perception/Editor/Randomization/VisualElements/Parameter/ParameterElement.cs
  8. 15
      com.unity.perception/Editor/Randomization/VisualElements/Sampler/SamplerInterfaceElement.cs
  9. 2
      com.unity.perception/Editor/Randomization/VisualElements/Basic/UIntField.cs
  10. 2
      com.unity.perception/Editor/Randomization/VisualElements/Basic/UxmlUIntAttributeDescription.cs
  11. 188
      com.unity.perception/Editor/Randomization/Editors/RunInUnitySimulationWindow.cs
  12. 14
      com.unity.perception/Editor/Randomization/Editors/ScenarioBaseEditor.cs
  13. 6
      com.unity.perception/Runtime/GroundTruth/Labelers/ObjectCountLabeler.cs
  14. 51
      com.unity.perception/Runtime/GroundTruth/Labelers/CameraLabeler.cs
  15. 109
      com.unity.perception/Runtime/Randomization/Randomizers/RandomizerExamples/Utilities/GameObjectOneWayCache.cs
  16. 117
      com.unity.perception/Runtime/Randomization/Scenarios/ScenarioBase.cs
  17. 1
      com.unity.perception/Runtime/Randomization/Scenarios/Serialization/ScenarioSerializer.cs
  18. 18
      com.unity.perception/Runtime/Randomization/Scenarios/UnitySimulationScenario.cs
  19. 2
      com.unity.perception/Tests/Runtime/GroundTruthTests/VisualizationTests.cs
  20. 4
      com.unity.perception/Tests/Runtime/Randomization/ScenarioTests/ScenarioTests.cs
  21. 8
      com.unity.perception/Editor/Pyrception.meta
  22. 11
      com.unity.perception/Editor/Randomization/PropertyDrawers/AssetSourceDrawer.cs.meta
  23. 26
      com.unity.perception/Editor/Randomization/PropertyDrawers/AssetSourceDrawer.cs
  24. 22
      com.unity.perception/Editor/Randomization/Utilities/AssetLoadingUtilities.cs
  25. 11
      com.unity.perception/Editor/Randomization/Utilities/AssetLoadingUtilities.cs.meta
  26. 8
      com.unity.perception/Editor/Randomization/Uxml/AssetSource.meta
  27. 8
      com.unity.perception/Editor/Randomization/VisualElements/AssetSource.meta
  28. 8
      com.unity.perception/Runtime/Randomization/Randomizers/AssetSources.meta
  29. 8
      com.unity.perception/Tests/Runtime/Randomization/AssetSourceTests.meta
  30. 8
      com.unity.perception/Editor/Pyrception/pyrception-utils.meta
  31. 10
      com.unity.perception/Editor/Randomization/Uxml/AssetSource/AssetListElement.uxml
  32. 10
      com.unity.perception/Editor/Randomization/Uxml/AssetSource/AssetListElement.uxml.meta
  33. 7
      com.unity.perception/Editor/Randomization/Uxml/AssetSource/AssetListItemElement.uxml
  34. 10
      com.unity.perception/Editor/Randomization/Uxml/AssetSource/AssetListItemElement.uxml.meta
  35. 10
      com.unity.perception/Editor/Randomization/Uxml/AssetSource/AssetSourceElement.uxml.meta
  36. 26
      com.unity.perception/Editor/Randomization/Uxml/AssetSource/AssetSourceElement.uxml
  37. 11
      com.unity.perception/Editor/Randomization/VisualElements/AssetSource/AssetListElement.cs.meta
  38. 39
      com.unity.perception/Editor/Randomization/VisualElements/AssetSource/AssetListItemElement.cs
  39. 11
      com.unity.perception/Editor/Randomization/VisualElements/AssetSource/AssetListItemElement.cs.meta
  40. 11
      com.unity.perception/Editor/Randomization/VisualElements/AssetSource/AssetSourceElement.cs.meta
  41. 93
      com.unity.perception/Editor/Randomization/VisualElements/AssetSource/AssetListElement.cs
  42. 153
      com.unity.perception/Editor/Randomization/VisualElements/AssetSource/AssetSourceElement.cs
  43. 3
      com.unity.perception/Runtime/Randomization/Randomizers/AssetSources/AssetSource.cs.meta
  44. 35
      com.unity.perception/Runtime/Randomization/Randomizers/AssetSources/AssetSourceLocation.cs
  45. 3
      com.unity.perception/Runtime/Randomization/Randomizers/AssetSources/AssetSourceLocation.cs.meta
  46. 3
      com.unity.perception/Runtime/Randomization/Randomizers/AssetSources/LocalAssetSourceLocation.cs.meta
  47. 22
      com.unity.perception/Runtime/Randomization/Randomizers/AssetSources/AssetRole.cs
  48. 11
      com.unity.perception/Runtime/Randomization/Randomizers/AssetSources/AssetRole.cs.meta
  49. 152
      com.unity.perception/Runtime/Randomization/Randomizers/AssetSources/AssetSource.cs
  50. 34
      com.unity.perception/Runtime/Randomization/Randomizers/AssetSources/LocalAssetSourceLocation.cs
  51. 24
      com.unity.perception/Runtime/Randomization/Randomizers/AssetSources/AssetSourceEditorDescriptionAttribute.cs
  52. 11
      com.unity.perception/Runtime/Randomization/Randomizers/AssetSources/AssetSourceEditorDescriptionAttribute.cs.meta
  53. 11
      com.unity.perception/Runtime/Randomization/Randomizers/AssetSources/IAssetRoleBase.cs.meta
  54. 20
      com.unity.perception/Runtime/Randomization/Randomizers/AssetSources/IAssetRoleBase.cs
  55. 11
      com.unity.perception/Tests/Runtime/Randomization/AssetSourceTests/LocalAssetSourceTests.cs.meta
  56. 63
      com.unity.perception/Tests/Runtime/Randomization/AssetSourceTests/LocalAssetSourceTests.cs

4
com.unity.perception/CHANGELOG.md


The user can now choose the base folder location to store their generated datasets.
Added the AssetSource class for loading assets from generic sources inside randomizers.
Users can now choose the base folder location to store their generated datasets.
Added a `projection` field in the capture.sensor metadata. Values are either "perspective" or "orthographic".
### Changed

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


{
var propertyField = new PropertyField(iterator.Copy());
propertyField.Bind(iterator.serializedObject);
var originalField = parentPropertyType.GetField(iterator.name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance );
FieldInfo originalField;
do
{
originalField = parentPropertyType.GetField(iterator.name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance );
parentPropertyType = parentPropertyType.BaseType;
}
while (originalField == null && parentPropertyType != null) ;
if (originalField == null)
return null;
var tooltipAttribute = originalField.GetCustomAttributes(true)
.ToList().Find(att => att.GetType() == typeof(TooltipAttribute));
if (tooltipAttribute != null)

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


using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEngine.Perception.Randomization;
using UnityEngine.Perception.Randomization.Randomizers;
using UnityEngine.Perception.Randomization.Samplers;

internal static Type[] randomizerTypes;
internal static Type[] samplerTypes;
internal static Type[] assetSourceLocationTypes;
internal static Type[] assetRoleTypes;
assetSourceLocationTypes = GetConstructableDerivedTypes<AssetSourceLocation>();
assetRoleTypes = GetConstructableDerivedTypes<IAssetRoleBase>();
}
static Type[] GetConstructableDerivedTypes<T>()

2
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;">
<VisualElement 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"/>

7
com.unity.perception/Editor/Randomization/Uxml/ScenarioBaseElement.uxml


class="scenario__info-box"
text="Scenarios control the execution flow of your simulation by applying randomization parameters. Make sure to always have only one scenario active within your scene."/>
<VisualElement name="constants-container">
<editor:PropertyField
name="configuration-asset"
label="Configuration"
binding-path="configuration"
style="margin-left: 13 px;"
tooltip="References a JSON configuration text asset to load at runtime before the scenario starts executing. Scenario configuration files can be created using the Generate JSON Config button below."/>
<editor:PropertyField name="configuration-file-name" label="Constants File Name" binding-path="serializedConstantsFileName"/>
<VisualElement style="flex-direction: row;">
<Button name="generate-json-config" text="Generate JSON Config" style="flex-grow: 1;"
tooltip="Serializes scenario constants and randomizer settings to a JSON configuration file"/>

8
com.unity.perception/Editor/Randomization/Uxml/RunInUnitySimulationWindow.uxml


tooltip="Selects a scenario JSON configuration to load during the run.
You can leave this option blank to use the scenario settings currently configured in the editor."/>
<editor:EnumField name="build-type-menu" label="Build type" style="flex-grow:1; margin:0; border-width: 1px;"/>
<VisualElement name="build-select-controls" style="margin-bottom: 0; flex-direction: row; justify-content: space-between; align-items: center;">
<TextField name="selected-build-path" label="Build Zip Path" style="flex-grow: 1; flex-shrink: 1;" />
<Button name="select-build-file-button" text="Browse..." style="margin: 0; align-items: flex-end; margin-top: 0; width: 70px;" />
</VisualElement>
<TextField name="build-id" label="Build ID" style="flex-grow: 1; flex-shrink: 1;" />
<VisualElement style="align-items: center; margin-top: 8px;">
<Button name="run-button" text="Build and Run" style="margin: 10px; padding: 2 20; font-size: 13px;"/>
</VisualElement>

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


var listView = template.Q<ListView>("options");
listView.itemsSource = probabilities;
listView.itemHeight = 22;
listView.itemHeight = 44;
listView.selectionType = SelectionType.None;
listView.style.flexGrow = 1.0f;
listView.style.height = new StyleLength(listView.itemHeight * 4);

"Add Options From Folder", Application.dataPath, string.Empty);
if (folderPath == string.Empty)
return;
var categories = LoadAssetsFromFolder(folderPath, categoricalParameter.sampleType);
var categories = AssetLoadingUtilities.LoadAssetsFromFolder(folderPath, categoricalParameter.sampleType);
var optionsIndex = optionsProperty.arraySize;
optionsProperty.arraySize += categories.Count;

});
m_PropertiesContainer.Add(template);
}
static List<Object> LoadAssetsFromFolder(string folderPath, Type assetType)
{
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 assets = new List<Object>();
foreach (var guid in assetIds)
assets.Add(AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(guid), assetType));
return assets;
}
}
}

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


SerializedProperty m_RangeProperty;
ToolbarMenu m_SamplerTypeDropdown;
ISampler sampler => (ISampler)StaticData.GetManagedReferenceValue(m_Property);
public SamplerInterfaceElement(SerializedProperty property)
{
m_Property = property;

CreateSampler(typeof(UniformSampler));
var samplerName = this.Q<Label>("sampler-name");
samplerName.text = UppercaseFirstLetter(m_Property.name);
samplerName.text = m_Property.displayName;
;
foreach (var samplerType in StaticData.samplerTypes)
{
var displayName = SamplerUtility.GetSamplerDisplayName(samplerType);

a => { ReplaceSampler(samplerType); },
a => ReplaceSampler(samplerType),
ISampler sampler => (ISampler)StaticData.GetManagedReferenceValue(m_Property);
void ReplaceSampler(Type samplerType)
{

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);
}
}
}

2
com.unity.perception/Editor/Randomization/VisualElements/Basic/UIntField.cs


/// <summary>
/// <para>Makes a text field for entering an unsigned integer.</para>
/// </summary>
public class UIntField : TextValueField<uint>
class UIntField : TextValueField<uint>
{
/// <summary>
/// <para>USS class name of elements of this type.</para>

2
com.unity.perception/Editor/Randomization/VisualElements/Basic/UxmlUIntAttributeDescription.cs


/// <summary>
/// <para>Describes a XML int attribute.</para>
/// </summary>
public class UxmlUIntAttributeDescription : TypedUxmlAttributeDescription<uint>
class UxmlUIntAttributeDescription : TypedUxmlAttributeDescription<uint>
{
/// <summary>
/// <para>Constructor.</para>

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


{
class RunInUnitySimulationWindow : EditorWindow
{
private const string m_SupportedGPUString = "Tesla";
string m_BuildDirectory;
string m_BuildZipPath;
SysParamDefinition[] m_SysParamDefinitions;

Label m_PrevRandomSeedLabel;
RunParameters m_RunParameters;
const string k_SupportedGPUString = "NVIDIA";
EnumField m_BuildTypeMenu;
VisualElement m_BuildSelectControls;
TextField m_BuildPathField;
TextField m_SelectedBuildPathTextField;
TextField m_BuildIdField;
[MenuItem("Window/Run in Unity Simulation")]
static void ShowWindow()

}
}
enum BuildIdKind
{
BuildPlayer,
ExistingBuildID,
ExistingBuildZip
}
void CreateRunInUnitySimulationUI()
{
var root = rootVisualElement;

copyPrevRandomSeedButton.clicked += () =>
EditorGUIUtility.systemCopyBuffer = PlayerPrefs.GetString("SimWindow/prevRandomSeed");
m_BuildTypeMenu = root.Q<EnumField>("build-type-menu");
m_BuildTypeMenu.Init(BuildIdKind.BuildPlayer);
m_BuildTypeMenu.RegisterValueChangedCallback(evt => { UpdateBuildIdElements((BuildIdKind) evt.newValue); });
m_BuildSelectControls = root.Q<VisualElement>("build-select-controls");
m_SelectedBuildPathTextField = root.Q<TextField>("selected-build-path");
m_SelectedBuildPathTextField.isReadOnly = true;
m_BuildPathField = root.Q<TextField>("selected-build-path");
m_BuildIdField = root.Q<TextField>("build-id");
UpdateBuildIdElements((BuildIdKind) m_BuildTypeMenu.value);
var selectBuildButton = root.Q<Button>("select-build-file-button");
selectBuildButton.clicked += () =>
{
var path = EditorUtility.OpenFilePanel("Select build ZIP file", "", "zip");
if (path.Length != 0)
{
m_SelectedBuildPathTextField.value = path;
}
};
private void UpdateBuildIdElements(BuildIdKind buildIdKind)
{
switch (buildIdKind)
{
case BuildIdKind.ExistingBuildID:
m_BuildSelectControls.SetEnabled(false);
m_BuildIdField.SetEnabled(true);
break;
case BuildIdKind.ExistingBuildZip:
m_BuildSelectControls.SetEnabled(true);
m_BuildIdField.SetEnabled(false);
break;
case BuildIdKind.BuildPlayer:
m_BuildSelectControls.SetEnabled(false);
m_BuildIdField.SetEnabled(false);
break;
}
}
void SetFieldsFromPlayerPreferences()
{
m_RunNameField.value = IncrementRunName(PlayerPrefs.GetString("SimWindow/runName"));

null);
try
{
m_RunButton.SetEnabled(false);
// Upload build
var cancellationTokenSource = new CancellationTokenSource();
var token = cancellationTokenSource.Token;
CreateLinuxBuildAndZip();
await StartUnitySimulationRun(runGuid);
string buildId = null;
var buildIdKind = (BuildIdKind)m_BuildTypeMenu.value;
switch (buildIdKind)
{
case BuildIdKind.BuildPlayer:
if (CreateLinuxBuildAndZip())
{
buildId = await UploadBuild(cancellationTokenSource, token);
}
break;
case BuildIdKind.ExistingBuildZip:
m_BuildZipPath = m_BuildPathField.value;
buildId = await UploadBuild(cancellationTokenSource, token);
break;
case BuildIdKind.ExistingBuildID:
buildId = m_BuildIdField.value;
break;
}
if (buildId == null)
return;
StartUnitySimulationRun(runGuid, buildId);
EditorUtility.ClearProgressBar();
}
finally
{
m_RunButton.SetEnabled(true);
EditorUtility.ClearProgressBar();
private async Task<string> UploadBuild(CancellationTokenSource cancellationTokenSource, CancellationToken token)
{
var buildId = await API.UploadBuildAsync(
m_RunParameters.runName,
m_BuildZipPath,
null, null,
cancellationTokenSource,
progress =>
{
EditorUtility.DisplayProgressBar(
"Unity Simulation Run", "Uploading build...", progress * 0.90f);
});
if (token.IsCancellationRequested)
{
Debug.Log("The build upload process has been cancelled. Aborting Unity Simulation launch.");
EditorUtility.ClearProgressBar();
return null;
}
return buildId;
}
void ValidateSettings()
{
if (string.IsNullOrEmpty(m_RunParameters.runName))

if (m_RunParameters.totalIterations <= 0)
throw new NotSupportedException("Invalid total iteration count specified");
if (string.IsNullOrEmpty(m_RunParameters.currentOpenScenePath))
throw new MissingFieldException("Invalid scene path");
if (m_RunParameters.currentScenario == null)
throw new MissingFieldException(
"There is not a Unity Simulation compatible scenario present in the scene");

Path.GetExtension(m_RunParameters.scenarioConfigAssetPath) != ".json")
throw new NotSupportedException(
"Scenario configuration must be a JSON text asset");
if (((BuildIdKind)m_BuildTypeMenu.value) == BuildIdKind.ExistingBuildZip &&
!File.Exists(m_SelectedBuildPathTextField.value))
{
throw new NotSupportedException(
"Selected build path does not exist");
}
if (((BuildIdKind)m_BuildTypeMenu.value) == BuildIdKind.ExistingBuildID &&
String.IsNullOrEmpty(m_BuildIdField.value))
{
throw new NotSupportedException("Empty Build ID");
}
void CreateLinuxBuildAndZip()
bool CreateLinuxBuildAndZip()
List<string> scenes = new List<string>();
foreach(var scene in EditorBuildSettings.scenes)
{
if(scene.enabled)
scenes.Add(scene.path);
}
if (scenes.Count == 0)
{
if (EditorUtility.DisplayDialog("No Scenes Found", "Could not find any enabled Scenes in build settings. Open File -> Build Settings and add all your required Scenes.", "Use Currently Open Scene", "Cancel Build"))
{
var currentOpenScenePath = SceneManager.GetSceneAt(0).path;
if (string.IsNullOrEmpty(currentOpenScenePath))
{
EditorUtility.DisplayDialog("Build Failed", "Could not find an active Scene.", "OK");
throw new Exception($"Could not find an active Scene.");
}
scenes.Add(currentOpenScenePath);
}
else
{
return false;
}
}
scenes = new[] { m_RunParameters.currentOpenScenePath },
scenes = scenes.ToArray(),
locationPathName = Path.Combine(projectBuildDirectory, $"{m_RunParameters.runName}.x86_64"),
#if PLATFORM_CLOUD_RENDERING
target = BuildTarget.CloudRendering,

EditorUtility.DisplayProgressBar("Unity Simulation Run", "Zipping Linux build...", 0f);
Zip.DirectoryContents(projectBuildDirectory, m_RunParameters.runName);
m_BuildZipPath = projectBuildDirectory + ".zip";
return true;
}
List<AppParam> UploadAppParam()

return appParamIds;
}
async Task StartUnitySimulationRun(Guid runGuid)
void StartUnitySimulationRun(Guid runGuid, string buildId)
m_RunButton.SetEnabled(false);
// Upload build
var cancellationTokenSource = new CancellationTokenSource();
var token = cancellationTokenSource.Token;
var buildId = await API.UploadBuildAsync(
m_RunParameters.runName,
m_BuildZipPath,
null, null,
cancellationTokenSource,
progress =>
{
EditorUtility.DisplayProgressBar(
"Unity Simulation Run", "Uploading build...", progress * 0.90f);
});
if (token.IsCancellationRequested)
{
Debug.Log("The build upload process has been cancelled. Aborting Unity Simulation launch.");
EditorUtility.ClearProgressBar();
return;
}
// Generate and upload app-params
EditorUtility.DisplayProgressBar("Unity Simulation Run", "Uploading app-params...", 0.90f);
var appParams = UploadAppParam();

run.Execute();
// Cleanup
m_RunButton.SetEnabled(true);
EditorUtility.ClearProgressBar();
PerceptionEditorAnalytics.ReportRunInUnitySimulationSucceeded(runGuid, run.executionId);
// Set new Player Preferences

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


m_Root = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(
$"{StaticData.uxmlDir}/ScenarioBaseElement.uxml").CloneTree();
#if !ENABLE_SCENARIO_APP_PARAM_CONFIG
var configuration = m_Root.Q<PropertyField>("configuration-asset");
configuration.style.display = DisplayStyle.None;
m_Scenario.configuration = null;
EditorUtility.SetDirty(m_Scenario);
#endif
m_RandomizerListPlaceholder = m_Root.Q<VisualElement>("randomizer-list-placeholder");
CreatePropertyFields();

if (string.IsNullOrEmpty(filePath))
return;
Undo.RecordObject(m_Scenario, "Deserialized scenario configuration");
m_Scenario.DeserializeFromFile(filePath);
var originalConfig = m_Scenario.configuration;
m_Scenario.LoadConfigurationFromFile(filePath);
m_Scenario.DeserializeConfigurationInternal();
m_Scenario.configuration = originalConfig;
Debug.Log($"Deserialized scenario configuration from {Path.GetFullPath(filePath)}. " +
"Using undo in the editor will revert these changes to your scenario.");
PlayerPrefs.SetString(k_ConfigFilePlayerPrefKey, filePath);

case "constants":
m_HasConstantsField = true;
UIElementsEditorUtilities.CreatePropertyFields(iterator.Copy(), m_ConstantsListVisualContainer);
break;
case "configuration":
break;
default:
{

6
com.unity.perception/Runtime/GroundTruth/Labelers/ObjectCountLabeler.cs


/// <summary>
/// The <see cref="IdLabelConfig"/> which associates objects with labels.
/// </summary>
public IdLabelConfig labelConfig => m_LabelConfig;
public IdLabelConfig labelConfig
{
get => m_LabelConfig;
set => m_LabelConfig = value;
}
/// <summary>
/// Fired when the object counts are computed for a frame.

51
com.unity.perception/Runtime/GroundTruth/Labelers/CameraLabeler.cs


/// </summary>
protected virtual void Cleanup() {}
/// <summary>
/// Initializes labeler with the target perception camera
/// </summary>
/// <param name="camera">The target perception camera</param>
internal void Init(PerceptionCamera camera)
{
try
{
perceptionCamera = camera;
sensorHandle = camera.SensorHandle;
Setup();
isInitialized = true;
}
catch (Exception)
{
enabled = false;
throw;
}
}
internal void InternalSetup() => Setup();
internal bool InternalVisualizationEnabled

internal void InternalCleanup() => Cleanup();
internal void InternalVisualize() => OnVisualize();
private bool m_ShowVisualizations = false;
bool m_ShowVisualizationsForLabeler;
/// <summary>
/// Turns on/off the labeler's realtime visualization capability. If a labeler does not support realtime

{
get
{
return supportsVisualization && m_ShowVisualizations;
if (!supportsVisualization)
return false;
return perceptionCamera && perceptionCamera.showVisualizations && m_ShowVisualizationsForLabeler;
if (value != m_ShowVisualizations)
if (value != m_ShowVisualizationsForLabeler)
m_ShowVisualizations = value;
m_ShowVisualizationsForLabeler = value;
OnVisualizerEnabledChanged(m_ShowVisualizations);
OnVisualizerEnabledChanged(m_ShowVisualizationsForLabeler);
}
}
}

internal void Visualize()
{
if (visualizationEnabled) OnVisualize();
}
internal void Init(PerceptionCamera newPerceptionCamera)
{
try
{
this.perceptionCamera = newPerceptionCamera;
sensorHandle = newPerceptionCamera.SensorHandle;
Setup();
isInitialized = true;
m_ShowVisualizations = supportsVisualization && perceptionCamera.showVisualizations;
}
catch (Exception)
{
this.enabled = false;
throw;
}
}
}
}

109
com.unity.perception/Runtime/Randomization/Randomizers/RandomizerExamples/Utilities/GameObjectOneWayCache.cs


using System.Collections.Generic;
using Unity.Profiling;
using UnityEngine;
using UnityEngine.Perception.Randomization.Samplers;
namespace UnityEngine.Perception.Randomization.Randomizers.Utilities
{

{
static ProfilerMarker s_ResetAllObjectsMarker = new ProfilerMarker("ResetAllObjects");
GameObject[] m_GameObjects;
UniformSampler m_Sampler = new UniformSampler();
Transform m_CacheParent;
Dictionary<int, int> m_InstanceIdToIndex;
List<CachedObjectData>[] m_InstantiatedObjects;

/// Creates a new GameObjectOneWayCache
/// </summary>
/// <param name="parent">The parent object all cached instances will be parented under</param>
/// <param name="prefabs">The prefabs to cache</param>
public GameObjectOneWayCache(Transform parent, GameObject[] prefabs)
/// <param name="gameObjects">The gameObjects to cache</param>
public GameObjectOneWayCache(Transform parent, GameObject[] gameObjects)
if (gameObjects.Length == 0)
throw new ArgumentException(
"A non-empty array of GameObjects is required to initialize this GameObject cache");
m_GameObjects = gameObjects;
m_InstantiatedObjects = new List<CachedObjectData>[prefabs.Length];
m_NumObjectsActive = new int[prefabs.Length];
m_InstantiatedObjects = new List<CachedObjectData>[gameObjects.Length];
m_NumObjectsActive = new int[gameObjects.Length];
foreach (var prefab in prefabs)
foreach (var obj in gameObjects)
var instanceId = prefab.GetInstanceID();
if (!IsPrefab(obj))
{
obj.transform.parent = parent;
obj.SetActive(false);
}
var instanceId = obj.GetInstanceID();
m_InstanceIdToIndex.Add(instanceId, index);
m_InstantiatedObjects[index] = new List<CachedObjectData>();
m_NumObjectsActive[index] = 0;

/// <summary>
/// Retrieves an existing instance of the given prefab from the cache if available.
/// Otherwise, instantiate a new instance of the given prefab.
/// Retrieves an existing instance of the given gameObject from the cache if available.
/// Otherwise, instantiate a new instance of the given gameObject.
/// <param name="prefab"></param>
/// <param name="gameObject"></param>
public GameObject GetOrInstantiate(GameObject prefab)
public GameObject GetOrInstantiate(GameObject gameObject)
if (!m_InstanceIdToIndex.TryGetValue(prefab.GetInstanceID(), out var index))
throw new ArgumentException($"Prefab {prefab.name} (ID: {prefab.GetInstanceID()}) is not in cache.");
if (!m_InstanceIdToIndex.TryGetValue(gameObject.GetInstanceID(), out var index))
throw new ArgumentException($"GameObject {gameObject.name} (ID: {gameObject.GetInstanceID()}) is not in cache.");
++NumObjectsActive;
if (m_NumObjectsActive[index] < m_InstantiatedObjects[index].Count)

}
++NumObjectsInCache;
var newObject = Object.Instantiate(prefab, m_CacheParent);
var newObject = Object.Instantiate(gameObject, m_CacheParent);
newObject.SetActive(true);
++m_NumObjectsActive[index];
m_InstantiatedObjects[index].Add(new CachedObjectData(newObject));
return newObject;

/// Retrieves an existing instance of the given gameObject from the cache if available.
/// Otherwise, instantiate a new instance of the given gameObject.
/// </summary>
/// <param name="index">The index of the gameObject to instantiate</param>
/// <returns></returns>
/// <exception cref="ArgumentException"></exception>
public GameObject GetOrInstantiate(int index)
{
var gameObject = m_GameObjects[index];
return GetOrInstantiate(gameObject);
}
/// <summary>
/// Retrieves an existing instance of a random gameObject from the cache if available.
/// Otherwise, instantiate a new instance of the random gameObject.
/// </summary>
/// <returns>A random cached GameObject</returns>
public GameObject GetOrInstantiateRandomCachedObject()
{
return GetOrInstantiate(m_GameObjects[(int)(m_Sampler.Sample() * m_GameObjects.Length)]);
}
/// <summary>
/// Return all active cache objects back to an inactive state
/// </summary>
public void ResetAllObjects()

m_NumObjectsActive[i] = 0;
foreach (var cachedObjectData in m_InstantiatedObjects[i])
{
// Position outside the frame
cachedObjectData.instance.transform.localPosition = new Vector3(10000, 0, 0);
foreach (var tag in cachedObjectData.randomizerTags)
tag.Unregister();
ResetObjectState(cachedObjectData);
}
/// <summary>
/// Returns the given cache object back to an inactive state
/// </summary>
/// <param name="gameObject">The object to make inactive</param>
/// <exception cref="ArgumentException">Thrown when gameObject is not an active cached object.</exception>
public void ResetObject(GameObject gameObject)
{
for (var i = 0; i < m_InstantiatedObjects.Length; ++i)
{
var instantiatedObjectList = m_InstantiatedObjects[i];
int indexFound = -1;
for (var j = 0; j < instantiatedObjectList.Count && indexFound < 0; j++)
{
if (instantiatedObjectList[j].instance == gameObject)
indexFound = j;
}
if (indexFound >= 0)
{
ResetObjectState(instantiatedObjectList[indexFound]);
m_NumObjectsActive[i]--;
return;
}
}
throw new ArgumentException("Passed GameObject is not an active object in the cache.");
}
private static void ResetObjectState(CachedObjectData cachedObjectData)
{
// Position outside the frame
cachedObjectData.instance.transform.localPosition = new Vector3(10000, 0, 0);
foreach (var tag in cachedObjectData.randomizerTags)
tag.Unregister();
}
static bool IsPrefab(GameObject obj)
{
return obj.scene.rootCount == 0;
}
struct CachedObjectData

117
com.unity.perception/Runtime/Randomization/Scenarios/ScenarioBase.cs


[SerializeReference] List<Randomizer> m_Randomizers = new List<Randomizer>();
/// <summary>
/// An external text asset that is loaded when the scenario starts to configure scenario settings
/// </summary>
public TextAsset configuration;
private bool m_ShouldRestartIteration;
private const int k_MaxIterationStartCount = 100;
/// <summary>
/// Enumerates over all enabled randomizers
/// </summary>
public IEnumerable<Randomizer> activeRandomizers

}
/// <summary>
/// Overwrites this scenario's randomizer settings and scenario constants from a JSON serialized configuration
/// Loads a scenario configuration from a file located at the given file path
/// <param name="json">The JSON string to deserialize</param>
public virtual void DeserializeFromJson(string json)
/// <param name="filePath">The file path of the scenario configuration file</param>
/// <exception cref="FileNotFoundException"></exception>
public void LoadConfigurationFromFile(string filePath)
ScenarioSerializer.Deserialize(this, json);
}
/// <summary>
/// Overwrites this scenario's randomizer settings and scenario constants using a configuration file located at
/// the provided file path
/// </summary>
/// <param name="configFilePath">The file path to the configuration file to deserialize</param>
public virtual void DeserializeFromFile(string configFilePath)
{
if (string.IsNullOrEmpty(configFilePath))
throw new ArgumentException($"{nameof(configFilePath)} is null or empty");
if (!File.Exists(configFilePath))
throw new ArgumentException($"No configuration file found at {configFilePath}");
var jsonText = File.ReadAllText(configFilePath);
DeserializeFromJson(jsonText);
#if !UNITY_EDITOR
Debug.Log($"Deserialized scenario configuration from {Path.GetFullPath(configFilePath)}");
#endif
if (!File.Exists(filePath))
throw new FileNotFoundException($"No configuration file found at {filePath}");
var jsonText = File.ReadAllText(filePath);
configuration = new TextAsset(jsonText);
}
/// <summary>

protected virtual void DeserializeFromCommandLine(string commandLineArg="--scenario-config-file")
protected void LoadConfigurationFromCommandLine(string commandLineArg="--scenario-config-file")
{
var args = Environment.GetCommandLineArgs();
var filePath = string.Empty;

return;
}
try { DeserializeFromFile(filePath); }
catch (Exception exception)
{
Debug.LogException(exception);
Debug.LogError("An exception was caught while attempting to parse a " +
$"scenario configuration file at {filePath}. Cleaning up and exiting simulation.");
}
LoadConfigurationFromFile(filePath);
}
/// <summary>
/// Loads and stores a JSON scenario settings configuration file before the scenario starts
/// </summary>
protected virtual void LoadConfigurationAsset()
{
LoadConfigurationFromCommandLine();
}
/// <summary>
/// Overwrites this scenario's randomizer settings and scenario constants from a JSON serialized configuration
/// </summary>
protected virtual void DeserializeConfiguration()
{
if (configuration != null)
ScenarioSerializer.Deserialize(this, configuration.text);
}
internal void DeserializeConfigurationInternal()
{
DeserializeConfiguration();
}
/// <summary>

/// OnAwake is called when this scenario MonoBehaviour is created or instantiated
/// </summary>
protected virtual void OnAwake() { }
/// <summary>
/// OnConfigurationImport is called before OnStart in the same frame. This method by default loads a scenario
/// settings from a file before the scenario begins.
/// </summary>
protected virtual void OnConfigurationImport()
{
#if !UNITY_EDITOR
DeserializeFromCommandLine();
#endif
}
/// <summary>
/// OnStart is called when the scenario first begins playing

void Awake()
{
activeScenario = this;
#if !UNITY_EDITOR
LoadConfigurationAsset();
#endif
DeserializeConfiguration();
foreach (var randomizer in m_Randomizers)
foreach (var randomizer in activeRandomizers)
randomizer.Awake();
ValidateParameters();
}

case State.Initializing:
if (isScenarioReadyToStart)
{
OnConfigurationImport();
foreach (var randomizer in m_Randomizers)
foreach (var randomizer in activeRandomizers)
randomizer.ScenarioStart();
IterationLoop();
}

{
ResetRandomStateOnIteration();
OnIterationStart();
foreach (var randomizer in activeRandomizers)
randomizer.IterationStart();
int iterationStartCount = 0;
do
{
m_ShouldRestartIteration = false;
iterationStartCount++;
foreach (var randomizer in activeRandomizers)
{
randomizer.IterationStart();
if (m_ShouldRestartIteration)
break;
}
} while (m_ShouldRestartIteration && iterationStartCount < k_MaxIterationStartCount);
if (m_ShouldRestartIteration)
{
Debug.LogError($"The iteration was restarted {k_MaxIterationStartCount} times. Continuing the scenario to prevent an infinite loop.");
m_ShouldRestartIteration = false;
}
}
// Perform new frame tasks

/// The scenario has finished and is idle
/// </summary>
Idle
}
public void RestartIteration()
{
m_ShouldRestartIteration = true;
}
}
}

1
com.unity.perception/Runtime/Randomization/Scenarios/Serialization/ScenarioSerializer.cs


using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

18
com.unity.perception/Runtime/Randomization/Scenarios/UnitySimulationScenario.cs


protected sealed override bool isScenarioComplete => currentIteration >= constants.totalIterations;
/// <inheritdoc/>
protected override void OnConfigurationImport()
protected override void LoadConfigurationAsset()
DeserializeFromFile(new Uri(Configuration.Instance.SimulationConfig.app_param_uri).LocalPath);
constants.instanceIndex = int.Parse(Configuration.Instance.GetInstanceId()) - 1;
var filePath = new Uri(Configuration.Instance.SimulationConfig.app_param_uri).LocalPath;
LoadConfigurationFromFile(filePath);
base.OnConfigurationImport();
{
base.LoadConfigurationAsset();
}
}
/// <inheritdoc/>
protected override void DeserializeConfiguration()
{
base.DeserializeConfiguration();
if (Configuration.Instance.IsSimulationRunningInCloud())
constants.instanceIndex = int.Parse(Configuration.Instance.GetInstanceId()) - 1;
currentIteration = constants.instanceIndex;
}

2
com.unity.perception/Tests/Runtime/GroundTruthTests/VisualizationTests.cs


var labeler1 = new ObjectCountLabeler(cfg);
labeler1.objectCountMetricId = "a1da3c27-369d-4929-aea6-d01614635ce2";
var labeler2 = new ObjectCountLabeler(cfg);
labeler1.objectCountMetricId = "b1da3c27-369d-4929-aea6-d01614635ce2";
labeler2.objectCountMetricId = "b1da3c27-369d-4929-aea6-d01614635ce2";
perceptionCamera.AddLabeler(labeler1);
perceptionCamera.AddLabeler(labeler2);

4
com.unity.perception/Tests/Runtime/Randomization/ScenarioTests/ScenarioTests.cs


// Serialize some values
m_Scenario.constants = constants;
var serializedConfig = m_Scenario.SerializeToJson();
m_Scenario.configuration = new TextAsset(m_Scenario.SerializeToJson());
m_Scenario.DeserializeFromJson(serializedConfig);
m_Scenario.DeserializeConfigurationInternal();
// Check if the values reverted correctly
Assert.AreEqual(m_Scenario.constants.framesPerIteration, constants.framesPerIteration);

8
com.unity.perception/Editor/Pyrception.meta


fileFormatVersion: 2
guid: 5000b0088702b4f589e73939e27aa132
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

11
com.unity.perception/Editor/Randomization/PropertyDrawers/AssetSourceDrawer.cs.meta


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

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


using Editor.Randomization.VisualElements.AssetSource;
using UnityEngine;
using UnityEngine.Perception.Randomization;
using UnityEngine.UIElements;
namespace UnityEditor.Perception.Randomization.PropertyDrawers
{
[CustomPropertyDrawer(typeof(AssetSource<>))]
class AssetSourceDrawer : PropertyDrawer
{
public override VisualElement CreatePropertyGUI(SerializedProperty property)
{
return new AssetSourceElement(property, fieldInfo);
}
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);
}
}
}

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


using System;
using System.Collections.Generic;
using UnityEngine;
using Object = UnityEngine.Object;
namespace UnityEditor.Perception.Randomization
{
static class AssetLoadingUtilities
{
public static List<Object> LoadAssetsFromFolder(string folderPath, Type assetType)
{
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 assets = new List<Object>();
foreach (var guid in assetIds)
assets.Add(AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(guid), assetType));
return assets;
}
}
}

11
com.unity.perception/Editor/Randomization/Utilities/AssetLoadingUtilities.cs.meta


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

8
com.unity.perception/Editor/Randomization/Uxml/AssetSource.meta


fileFormatVersion: 2
guid: 7e7eabbe9ff71e64291989566ea6ec83
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

8
com.unity.perception/Editor/Randomization/VisualElements/AssetSource.meta


fileFormatVersion: 2
guid: 29370b0293eb9a046b454ffdd7b1c372
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

8
com.unity.perception/Runtime/Randomization/Randomizers/AssetSources.meta


fileFormatVersion: 2
guid: c3b723ce8e6a50141834747972131766
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

8
com.unity.perception/Tests/Runtime/Randomization/AssetSourceTests.meta


fileFormatVersion: 2
guid: ea8713402c0e1a946ac6af555b908641
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

8
com.unity.perception/Editor/Pyrception/pyrception-utils.meta


fileFormatVersion: 2
guid: 6c8dccf3511434d2aadb672239c0c571
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

10
com.unity.perception/Editor/Randomization/Uxml/AssetSource/AssetListElement.uxml


<UXML xmlns="UnityEngine.UIElements" xmlns:editor="UnityEditor.UIElements">
<VisualElement class="parameter__categorical-options-list">
<ListView name="assets"/>
</VisualElement>
<VisualElement style="flex-direction: row; justify-content: flex-end;">
<Button name="add-asset" text="Add Asset" class="parameter__categorical-options-list-button"/>
<Button name="add-folder" text="Add Folder" class="parameter__categorical-options-list-button"/>
<Button name="clear-assets" text="Clear Assets" class="parameter__categorical-options-list-button"/>
</VisualElement>
</UXML>

10
com.unity.perception/Editor/Randomization/Uxml/AssetSource/AssetListElement.uxml.meta


fileFormatVersion: 2
guid: e4915dfbbc1de39478264a8f5d168ca0
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}

7
com.unity.perception/Editor/Randomization/Uxml/AssetSource/AssetListItemElement.uxml


<UXML xmlns="UnityEngine.UIElements" xmlns:editor="UnityEditor.UIElements">
<VisualElement class="parameter__categorical-option">
<Button name="remove" class="randomization__remove-item-button"/>
<Label name="index-label" text="[0]" style="min-width: 50px;"/>
<editor:ObjectField name="item" class="parameter__categorical-option-property-field"/>
</VisualElement>
</UXML>

10
com.unity.perception/Editor/Randomization/Uxml/AssetSource/AssetListItemElement.uxml.meta


fileFormatVersion: 2
guid: d710875a5224e1b4186c4334f791ca19
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}

10
com.unity.perception/Editor/Randomization/Uxml/AssetSource/AssetSourceElement.uxml.meta


fileFormatVersion: 2
guid: e6fba9b826939224fac37b7ead85df2a
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}

26
com.unity.perception/Editor/Randomization/Uxml/AssetSource/AssetSourceElement.uxml


<UXML xmlns="UnityEngine.UIElements" xmlns:editor="UnityEditor.UIElements">
<VisualElement style="margin-bottom: 4px;">
<Style src="../../Uss/Styles.uss"/>
<Label name="name" text="Field Name" class="unity-base-field__label"/>
<VisualElement style="margin-left: 18px;">
<VisualElement style="flex-direction: row; align-items: center;">
<Label
text="Location"
class="unity-base-field__label"
tooltip="The asset source location to load assets from"/>
<editor:ToolbarMenu name="location-dropdown" text="Type" class="sampler__type-menu"/>
</VisualElement>
<VisualElement style="margin-left: 18px;">
<VisualElement name="fields-container" style="flex-grow: 1;"/>
<TextElement name="location-notes" class="scenario__info-box"/>
</VisualElement>
<VisualElement style="flex-direction: row; align-items: center;">
<Label
text="Asset Role"
class="unity-base-field__label"
tooltip="Asset Roles preprocess assets loaded from the selected asset source location"/>
<editor:ToolbarMenu name="asset-role-dropdown" text="Type" class="sampler__type-menu"/>
</VisualElement>
</VisualElement>
</VisualElement>
</UXML>

11
com.unity.perception/Editor/Randomization/VisualElements/AssetSource/AssetListElement.cs.meta


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

39
com.unity.perception/Editor/Randomization/VisualElements/AssetSource/AssetListItemElement.cs


using System;
using UnityEditor;
using UnityEditor.Perception.Randomization;
using UnityEditor.UIElements;
using UnityEngine.UIElements;
namespace Editor.Randomization.VisualElements.AssetSource
{
class AssetListItemElement : VisualElement
{
int m_Index;
Type m_ItemType;
SerializedProperty m_Property;
public AssetListItemElement(SerializedProperty property, Type itemType)
{
m_Property = property;
m_ItemType = itemType;
}
public void BindProperties(int i)
{
Clear();
var template = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(
$"{StaticData.uxmlDir}/AssetSource/{nameof(AssetListItemElement)}.uxml");
template.CloneTree(this);
m_Index = i;
var indexLabel = this.Q<Label>("index-label");
indexLabel.text = $"[{m_Index}]";
var optionProperty = m_Property.GetArrayElementAtIndex(i);
var option = this.Q<ObjectField>("item");
option.BindProperty(optionProperty);
option.objectType = m_ItemType;
option.allowSceneObjects = false;
}
}
}

11
com.unity.perception/Editor/Randomization/VisualElements/AssetSource/AssetListItemElement.cs.meta


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

11
com.unity.perception/Editor/Randomization/VisualElements/AssetSource/AssetSourceElement.cs.meta


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

93
com.unity.perception/Editor/Randomization/VisualElements/AssetSource/AssetListElement.cs


using System;
using System.Collections;
using UnityEditor;
using UnityEditor.Perception.Randomization;
using UnityEngine;
using UnityEngine.UIElements;
namespace Editor.Randomization.VisualElements.AssetSource
{
class AssetListElement : VisualElement
{
SerializedProperty m_Property;
IList list => (IList)StaticData.GetManagedReferenceValue(m_Property);
public AssetListElement(SerializedProperty property, Type itemType)
{
m_Property = property;
var template = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(
$"{StaticData.uxmlDir}/AssetSource/AssetListElement.uxml");
template.CloneTree(this);
var listView = this.Q<ListView>("assets");
listView.itemsSource = list;
listView.itemHeight = 22;
listView.selectionType = SelectionType.None;
listView.style.flexGrow = 1.0f;
listView.style.height = new StyleLength(listView.itemHeight * 4);
listView.makeItem = () =>
{
return new AssetListItemElement(m_Property, itemType);
};
listView.bindItem = (element, i) =>
{
var optionElement = (AssetListItemElement)element;
optionElement.BindProperties(i);
var removeButton = optionElement.Q<Button>("remove");
removeButton.clicked += () =>
{
// First delete sets option to null, second delete removes option
var numOptions = m_Property.arraySize;
m_Property.DeleteArrayElementAtIndex(i);
if (numOptions == m_Property.arraySize)
m_Property.DeleteArrayElementAtIndex(i);
m_Property.serializedObject.ApplyModifiedProperties();
listView.itemsSource = list;
listView.Refresh();
};
};
var addOptionButton = this.Q<Button>("add-asset");
addOptionButton.clicked += () =>
{
m_Property.arraySize++;
m_Property.serializedObject.ApplyModifiedProperties();
listView.itemsSource = list;
listView.Refresh();
listView.ScrollToItem(m_Property.arraySize);
};
var addFolderButton = this.Q<Button>("add-folder");
addFolderButton.clicked += () =>
{
var folderPath = EditorUtility.OpenFolderPanel(
"Add Assets From Folder", Application.dataPath, string.Empty);
if (folderPath == string.Empty)
return;
var assets = AssetLoadingUtilities.LoadAssetsFromFolder(folderPath, itemType);
var optionsIndex = m_Property.arraySize;
m_Property.arraySize += assets.Count;
for (var i = 0; i < assets.Count; i++)
{
var optionProperty = m_Property.GetArrayElementAtIndex(optionsIndex + i);
optionProperty.objectReferenceValue = assets[i];
}
m_Property.serializedObject.ApplyModifiedProperties();
listView.itemsSource = list;
listView.Refresh();
};
var clearOptionsButton = this.Q<Button>("clear-assets");
clearOptionsButton.clicked += () =>
{
m_Property.arraySize = 0;
m_Property.serializedObject.ApplyModifiedProperties();
listView.itemsSource = list;
listView.Refresh();
};
}
}
}

153
com.unity.perception/Editor/Randomization/VisualElements/AssetSource/AssetSourceElement.cs


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
using UnityEditor;
using UnityEditor.Perception.Randomization;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.Perception.Randomization;
using UnityEngine.UIElements;
namespace Editor.Randomization.VisualElements.AssetSource
{
class AssetSourceElement : VisualElement
{
SerializedProperty m_AssetRoleProperty;
SerializedProperty m_LocationProperty;
ToolbarMenu m_AssetRoleToolbarMenu;
ToolbarMenu m_LocationToolbarMenu;
VisualElement m_FieldsContainer;
TextElement m_LocationNotes;
Type m_AssetType;
Dictionary<string, Type> m_AssetRoleLabelsToTypes = new Dictionary<string, Type>();
IAssetRoleBase assetRole =>
(IAssetRoleBase)StaticData.GetManagedReferenceValue(m_AssetRoleProperty);
AssetSourceLocation assetSourceLocation =>
(AssetSourceLocation)StaticData.GetManagedReferenceValue(m_LocationProperty);
public AssetSourceElement(SerializedProperty property, FieldInfo fieldInfo)
{
m_AssetType = fieldInfo.FieldType.GetGenericArguments()[0];
m_AssetRoleProperty = property.FindPropertyRelative("m_AssetRoleBase");
m_LocationProperty = property.FindPropertyRelative(nameof(AssetSource<GameObject>.assetSourceLocation));
var template = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(
$"{StaticData.uxmlDir}/AssetSource/AssetSourceElement.uxml");
template.CloneTree(this);
var nameLabel = this.Q<Label>("name");
nameLabel.text = property.displayName;
m_FieldsContainer = this.Q<VisualElement>("fields-container");
m_AssetRoleToolbarMenu = this.Q<ToolbarMenu>("asset-role-dropdown");
var storedAssetRole = assetRole;
m_AssetRoleToolbarMenu.text = storedAssetRole != null
? GetAssetRoleDisplayName(assetRole.GetType()) : "None";
// ReSharper disable once PossibleNullReferenceException
var baseType = fieldInfo.FieldType.GetProperty("assetRole").PropertyType;
m_AssetRoleToolbarMenu.menu.AppendAction(
"None",
a => ReplaceAssetRole(null),
a => DropdownMenuAction.Status.Normal);
m_AssetRoleLabelsToTypes.Clear();
foreach (var type in StaticData.assetRoleTypes)
{
if (!type.IsSubclassOf(baseType))
continue;
var label = GetAssetRoleDisplayName(type);
if (m_AssetRoleLabelsToTypes.ContainsKey(label))
Debug.LogError($"The asset role classes {type.Name} && {m_AssetRoleLabelsToTypes[label].Name} have an identical label: \"{label}\". Asset role labels should be unique.");
else
m_AssetRoleLabelsToTypes.Add(label, type);
m_AssetRoleToolbarMenu.menu.AppendAction(
label,
a => ReplaceAssetRole(type),
a => DropdownMenuAction.Status.Normal);
}
m_LocationNotes = this.Q<TextElement>("location-notes");
m_LocationToolbarMenu = this.Q<ToolbarMenu>("location-dropdown");
foreach (var type in StaticData.assetSourceLocationTypes)
{
m_LocationToolbarMenu.menu.AppendAction(
GetDisplayName(type),
a => ReplaceLocation(type),
a => DropdownMenuAction.Status.Normal);
}
if (assetSourceLocation == null)
CreateAssetSourceLocation(typeof(LocalAssetSourceLocation));
UpdateLocationUI(assetSourceLocation.GetType());
}
void ReplaceAssetRole(Type type)
{
if (type == null)
{
m_AssetRoleToolbarMenu.text = "None";
m_AssetRoleProperty.managedReferenceValue = null;
}
else
{
m_AssetRoleToolbarMenu.text = GetAssetRoleDisplayName(type);
var newAssetRole = (IAssetRoleBase)Activator.CreateInstance(type);
m_AssetRoleProperty.managedReferenceValue = newAssetRole;
}
m_AssetRoleProperty.serializedObject.ApplyModifiedProperties();
}
void CreateAssetSourceLocation(Type type)
{
var newLocation = (AssetSourceLocation)Activator.CreateInstance(type);
m_LocationProperty.managedReferenceValue = newLocation;
m_LocationProperty.serializedObject.ApplyModifiedProperties();
}
void ReplaceLocation(Type type)
{
CreateAssetSourceLocation(type);
UpdateLocationUI(type);
}
void UpdateLocationUI(Type type)
{
m_LocationToolbarMenu.text = GetDisplayName(type);
var notesAttribute = (AssetSourceEditorDescriptionAttribute)Attribute.GetCustomAttribute(type, typeof(AssetSourceEditorDescriptionAttribute));
if (notesAttribute != null)
{
m_LocationNotes.text = notesAttribute.notes;
m_LocationNotes.style.display = new StyleEnum<DisplayStyle>(DisplayStyle.Flex);
}
else
{
m_LocationNotes.style.display = new StyleEnum<DisplayStyle>(DisplayStyle.None);
}
CreatePropertyFields();
}
void CreatePropertyFields()
{
m_FieldsContainer.Clear();
if (m_LocationProperty.type == $"managedReference<{nameof(LocalAssetSourceLocation)}>")
m_FieldsContainer.Add(
new AssetListElement(m_LocationProperty.FindPropertyRelative("assets"), m_AssetType));
else
UIElementsEditorUtilities.CreatePropertyFields(m_LocationProperty, m_FieldsContainer);
}
static string GetDisplayName(Type type)
{
var attribute = (DisplayNameAttribute)Attribute.GetCustomAttribute(type, typeof(DisplayNameAttribute));
return attribute != null ? attribute.DisplayName : type.Name;
}
static string GetAssetRoleDisplayName(Type type)
{
return $"{((IAssetRoleBase)Activator.CreateInstance(type)).label} ({type.Name})";
}
}
}

3
com.unity.perception/Runtime/Randomization/Randomizers/AssetSources/AssetSource.cs.meta


fileFormatVersion: 2
guid: 27aa08b82cf94015adc22309c8f3bc48
timeCreated: 1618977151

35
com.unity.perception/Runtime/Randomization/Randomizers/AssetSources/AssetSourceLocation.cs


using UnityEngine;
namespace UnityEngine.Perception.Randomization
{
/// <summary>
/// Derive this class to load Unity assets from a specific location
/// </summary>
public abstract class AssetSourceLocation
{
/// <summary>
/// The number of assets available at this location
/// </summary>
public abstract int count { get; }
/// <summary>
/// Execute setup steps before accessing assets at this location
/// </summary>
/// <param name="assetRole">The asset role that will be used to preprocess assets from this location</param>
/// <typeparam name="T">The type of assets that will be loaded from this location</typeparam>
public abstract void Initialize<T>(AssetRole<T> assetRole) where T : Object;
/// <summary>
/// Unload all assets loaded from this location
/// </summary>
public abstract void ReleaseAssets();
/// <summary>
/// Retrieves an asset from this location using the provided index
/// </summary>
/// <param name="index">The index to load the asset from</param>
/// <typeparam name="T">The type of asset to load</typeparam>
/// <returns>The loaded asset</returns>
public abstract T LoadAsset<T>(int index) where T : Object;
}
}

3
com.unity.perception/Runtime/Randomization/Randomizers/AssetSources/AssetSourceLocation.cs.meta


fileFormatVersion: 2
guid: 9f2e99decdb94c7c898d7702e10cbce5
timeCreated: 1619732135

3
com.unity.perception/Runtime/Randomization/Randomizers/AssetSources/LocalAssetSourceLocation.cs.meta


fileFormatVersion: 2
guid: 20f161f5e56247c280fc1b56b567f49a
timeCreated: 1618983500

22
com.unity.perception/Runtime/Randomization/Randomizers/AssetSources/AssetRole.cs


namespace UnityEngine.Perception.Randomization
{
/// <summary>
/// Derive this class to create a typed asset role.
/// Typed asset roles are used to apply preprocessing steps to assets loaded from an <see cref="AssetSource{T}"/>.
/// </summary>
/// <typeparam name="T">The type of asset to preprocess</typeparam>
public abstract class AssetRole<T> : IAssetRoleBase where T : Object
{
/// <inheritdoc/>
public abstract string label { get; }
/// <inheritdoc/>
public abstract string description { get; }
/// <summary>
/// Perform preprocessing operations on an asset loaded from an <see cref="AssetSource{T}"/>.
/// </summary>
/// <param name="asset">The asset to preprocess</param>
public abstract void Preprocess(T asset);
}
}

11
com.unity.perception/Runtime/Randomization/Randomizers/AssetSources/AssetRole.cs.meta


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

152
com.unity.perception/Runtime/Randomization/Randomizers/AssetSources/AssetSource.cs


using System;
using UnityEngine.Perception.Randomization.Samplers;
namespace UnityEngine.Perception.Randomization
{
/// <summary>
/// AssetSources are used to load assets from a generically within a <see cref="Randomizers.Randomizer"/>
/// </summary>
/// <typeparam name="T">The type of asset to load</typeparam>
[Serializable]
public sealed class AssetSource<T> where T : Object
{
[SerializeReference] IAssetRoleBase m_AssetRoleBase;
/// <summary>
/// The location to load assets from
/// </summary>
[SerializeReference] public AssetSourceLocation assetSourceLocation = new LocalAssetSourceLocation();
bool m_Initialized;
UniformSampler m_Sampler = new UniformSampler();
/// <summary>
/// The asset role used to preprocess assets from this source
/// </summary>
public AssetRole<T> assetRole
{
get => (AssetRole<T>)m_AssetRoleBase;
set => m_AssetRoleBase = value;
}
/// <summary>
/// The number of assets available within this asset source
/// </summary>
public int count
{
get
{
CheckIfInitialized();
return assetSourceLocation.count;
}
}
/// <summary>
/// Execute setup steps for this AssetSource. It is often unnecessary to call this API directly since all other
/// relevant APIs in this class will Initialize() this AssetSource if it hasn't been already.
/// </summary>
public void Initialize()
{
if (!m_Initialized)
{
assetSourceLocation.Initialize(assetRole);
m_Initialized = true;
}
}
/// <summary>
/// Returns the unprocessed asset loaded from the provided index
/// </summary>
/// <param name="index">The index of the asset to load</param>
/// <returns>The asset loaded at the provided index</returns>
public T LoadRawAsset(int index)
{
CheckIfInitialized();
return assetSourceLocation.LoadAsset<T>(index);
}
/// <summary>
/// Returns all unprocessed assets that can be loaded from this AssetSource
/// </summary>
/// <returns>All assets that can be loaded from this AssetSource</returns>
public T[] LoadAllRawAssets()
{
CheckIfInitialized();
var array = new T[count];
for (var i = 0; i < count; i++)
array[i] = LoadRawAsset(i);
return array;
}
/// <summary>
/// Creates an instance of the asset loaded from the provided index and preprocesses it using the asset role
/// assigned to this asset source
/// </summary>
/// <param name="index">The index of the asset to load</param>
/// <returns>The instantiated instance</returns>
public T CreateProcessedInstance(int index)
{
CheckIfInitialized();
return CreateProcessedInstance(LoadRawAsset(index));
}
/// <summary>
/// Instantiates, preprocesses, and returns all assets that can be loaded from this asset source
/// </summary>
/// <returns>Instantiated instances from every loadable asset</returns>
public T[] CreateProcessedInstances()
{
CheckIfInitialized();
var array = new T[count];
for (var i = 0; i < count; i++)
array[i] = CreateProcessedInstance(i);
return array;
}
/// <summary>
/// Returns a uniformly random sampled asset from this AssetSource
/// </summary>
/// <returns>The randomly sampled asset</returns>
public T SampleAsset()
{
CheckIfInitialized();
return count == 0 ? null : assetSourceLocation.LoadAsset<T>((int)(m_Sampler.Sample() * count));
}
/// <summary>
/// Instantiates and preprocesses a uniformly random sampled asset from this AssetSource
/// </summary>
/// <returns>The generated random instance</returns>
public T SampleInstance()
{
CheckIfInitialized();
return CreateProcessedInstance(SampleAsset());
}
/// <summary>
/// Unloads all assets that have been loaded from this AssetSource
/// </summary>
public void ReleaseAssets()
{
CheckIfInitialized();
assetSourceLocation.ReleaseAssets();
}
void CheckIfInitialized()
{
if (!m_Initialized)
Initialize();
}
T CreateProcessedInstance(T asset)
{
if (asset == null)
return null;
var instance = Object.Instantiate(asset);
if (assetRole != null)
assetRole.Preprocess(instance);
return instance;
}
}
}

34
com.unity.perception/Runtime/Randomization/Randomizers/AssetSources/LocalAssetSourceLocation.cs


using System;
using System.Collections.Generic;
using System.ComponentModel;
namespace UnityEngine.Perception.Randomization
{
/// <summary>
/// A basic <see cref="AssetSourceLocation"/> for loading local project assets
/// </summary>
[Serializable]
[DisplayName("Assets In Project")]
public class LocalAssetSourceLocation : AssetSourceLocation
{
/// <summary>
/// The list of local assets available from this source
/// </summary>
public List<Object> assets = new List<Object>();
/// <inheritdoc/>
public override int count => assets.Count;
/// <inheritdoc/>
public override void Initialize<T>(AssetRole<T> assetRole) { }
/// <inheritdoc/>
public override void ReleaseAssets() { }
/// <inheritdoc/>
public override T LoadAsset<T>(int index)
{
return (T)assets[index];
}
}
}

24
com.unity.perception/Runtime/Randomization/Randomizers/AssetSources/AssetSourceEditorDescriptionAttribute.cs


using System;
namespace UnityEngine.Perception.Randomization
{
/// <summary>
/// Used to annotate an AssetSourceLocation with description notes within the inspector UI
/// </summary>
public class AssetSourceEditorDescriptionAttribute : Attribute
{
/// <summary>
/// The text notes to display in the AssetSourceLocation's UI.
/// </summary>
public string notes;
/// <summary>
/// Constructs a new AssetSourceLocationNotes attribute
/// </summary>
/// <param name="notes">The text notes to display in the inspector</param>
public AssetSourceEditorDescriptionAttribute(string notes)
{
this.notes = notes;
}
}
}

11
com.unity.perception/Runtime/Randomization/Randomizers/AssetSources/AssetSourceEditorDescriptionAttribute.cs.meta


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

11
com.unity.perception/Runtime/Randomization/Randomizers/AssetSources/IAssetRoleBase.cs.meta


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

20
com.unity.perception/Runtime/Randomization/Randomizers/AssetSources/IAssetRoleBase.cs


using UnityEngine;
namespace UnityEngine.Perception.Randomization
{
/// <summary>
/// The base asset role class. Derive from <see cref="AssetRole{T}"/> instead to create a new asset role.
/// </summary>
interface IAssetRoleBase
{
/// <summary>
/// The string label uniquely associated with this asset role
/// </summary>
string label { get; }
/// <summary>
/// A description for this asset role
/// </summary>
string description { get; }
}
}

11
com.unity.perception/Tests/Runtime/Randomization/AssetSourceTests/LocalAssetSourceTests.cs.meta


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

63
com.unity.perception/Tests/Runtime/Randomization/AssetSourceTests/LocalAssetSourceTests.cs


using NUnit.Framework;
using UnityEngine;
using UnityEngine.Perception.Randomization;
using UnityEngine.Perception.Randomization.Randomizers.SampleRandomizers.Tags;
namespace RandomizationTests.AssetSourceTests
{
[TestFixture]
public class LocalAssetSourceTests
{
GameObject m_TestObject;
TestBehaviour m_Behaviour;
class TestAssetRole : AssetRole<GameObject>
{
public override string label => "test";
public override string description => "";
public override void Preprocess(GameObject asset)
{
asset.AddComponent<RotationRandomizerTag>();
}
}
class TestBehaviour : MonoBehaviour
{
public AssetSource<GameObject> gameObjectSource = new AssetSource<GameObject>
{
assetRole = new TestAssetRole(),
assetSourceLocation = new LocalAssetSourceLocation()
};
}
[SetUp]
public void Setup()
{
m_TestObject = new GameObject();
m_Behaviour = m_TestObject.AddComponent<TestBehaviour>();
}
[TearDown]
public void TearDown()
{
Object.DestroyImmediate(m_TestObject);
}
[Test]
public void GetZeroCountWithoutThrowingException()
{
Assert.DoesNotThrow(() =>
{
var count = m_Behaviour.gameObjectSource.count;
});
}
[Test]
public void SampleFromEmptySourceReturnsNull()
{
Assert.IsNull(m_Behaviour.gameObjectSource.SampleAsset());
Assert.IsNull(m_Behaviour.gameObjectSource.SampleInstance());
}
}
}
正在加载...
取消
保存