浏览代码

Add folder option added to categorical parameter UI

/usim-randomization
Steven Leal 4 年前
当前提交
6b041d51
共有 19 个文件被更改,包括 140 次插入61 次删除
  1. 8
      com.unity.perception/Editor/Randomization/CategoricalOptionElement.cs
  2. 4
      com.unity.perception/Editor/Randomization/ParameterConfigurationEditor.cs
  3. 40
      com.unity.perception/Editor/Randomization/ParameterElement.cs
  4. 1
      com.unity.perception/Editor/Randomization/Uxml/CategoricalParameterTemplate.uxml
  5. 15
      com.unity.perception/Runtime/Randomization/Configuration/ParameterConfiguration.cs
  6. 2
      com.unity.perception/Runtime/Randomization/Parameters/Attributes/ParameterMetaData.cs
  7. 9
      com.unity.perception/Runtime/Randomization/Parameters/CategoricalParameter.cs
  8. 3
      com.unity.perception/Runtime/Randomization/Parameters/CategoricalParameterBase.cs
  9. 9
      com.unity.perception/Runtime/Randomization/Parameters/NumericParameter.cs
  10. 58
      com.unity.perception/Runtime/Randomization/Parameters/Parameter.cs
  11. 12
      com.unity.perception/Runtime/Randomization/Parameters/ParameterTarget.cs
  12. 2
      com.unity.perception/Runtime/Randomization/Parameters/ParameterValidationException.cs
  13. 10
      com.unity.perception/Runtime/Randomization/Samplers/ISampler.cs
  14. 2
      com.unity.perception/Runtime/Randomization/Samplers/SamplerTypes/ConstantSampler.cs
  15. 5
      com.unity.perception/Runtime/Randomization/Samplers/SamplerTypes/NormalSampler.cs
  16. 5
      com.unity.perception/Runtime/Randomization/Samplers/SamplerTypes/UniformSampler.cs
  17. 4
      com.unity.perception/Tests/Runtime/Randomization/ScenarioTests.cs
  18. 9
      com.unity.perception/Runtime/Randomization/Parameters/ParameterException.cs
  19. 3
      com.unity.perception/Runtime/Randomization/Parameters/ParameterException.cs.meta

8
com.unity.perception/Editor/Randomization/CategoricalOptionElement.cs


class CategoricalOptionElement : VisualElement
{
int m_Index;
SerializedProperty m_OptionsProperty;
SerializedProperty m_CategoryProperty;
SerializedProperty optionsProperty,
SerializedProperty categoryProperty,
m_OptionsProperty = optionsProperty;
m_CategoryProperty = categoryProperty;
m_ProbabilitiesProperty = probabilitiesProperty;
var template = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(

var indexLabel = this.Q<Label>("index-label");
indexLabel.text = $"[{m_Index}]";
var optionProperty = m_OptionsProperty.GetArrayElementAtIndex(i);
var optionProperty = m_CategoryProperty.GetArrayElementAtIndex(i);
var option = this.Q<PropertyField>("option");
option.BindProperty(optionProperty);
var label = option.Q<Label>();

4
com.unity.perception/Editor/Randomization/ParameterConfigurationEditor.cs


void AddParameter(Type parameterType)
{
var parameter = config.AddParameter(parameterType);
foreach (var sampler in parameter.samplers)
if (sampler is IRandomRangedSampler rangedSampler)
rangedSampler.baseSeed = SamplerUtility.GenerateRandomSeed();
parameter.RandomizeSamplers();
serializedObject.Update();
m_ParameterContainer.Add(CreateParameterElement(config.parameters.Count - 1));

40
com.unity.perception/Editor/Randomization/ParameterElement.cs


using System;
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine.Perception.Randomization.Parameters;

var template = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(
$"{StaticData.uxmlDir}/CategoricalParameterTemplate.uxml").CloneTree();
var optionsProperty = m_SerializedProperty.FindPropertyRelative("m_Options");
var optionsProperty = m_SerializedProperty.FindPropertyRelative("m_Categories");
var probabilitiesProperty = m_SerializedProperty.FindPropertyRelative("probabilities");
var probabilities = categoricalParameter.probabilities;

listView.ScrollToItem(probabilitiesProperty.arraySize);
};
var addFolderButton = template.Q<Button>("add-folder");
if (categoricalParameter.sampleType.IsSubclassOf(typeof(Object)))
{
addFolderButton.clicked += () =>
{
var folderPath = EditorUtility.OpenFolderPanel("Add Options From Folder", Application.dataPath, "Goober");
var categories = LoadAssetsFromFolder(folderPath, categoricalParameter.sampleType);
probabilitiesProperty.arraySize += categories.Count;
optionsProperty.arraySize += categories.Count;
var uniformProbability = 1f / categories.Count;
for (var i = 0; i < categories.Count; i++)
{
var optionProperty = optionsProperty.GetArrayElementAtIndex(i);
var probabilityProperty = probabilitiesProperty.GetArrayElementAtIndex(i);
optionProperty.objectReferenceValue = categories[i];
probabilityProperty.floatValue = uniformProbability;
}
m_SerializedProperty.serializedObject.ApplyModifiedProperties();
listView.itemsSource = categoricalParameter.probabilities;
listView.Refresh();
};
}
else
addFolderButton.style.display = new StyleEnum<DisplayStyle>(DisplayStyle.None);
var clearOptionsButton = template.Q<Button>("clear-options");
clearOptionsButton.clicked += () =>
{

seedField.BindProperty(m_SerializedProperty.FindPropertyRelative("m_Sampler.<baseSeed>k__BackingField"));
m_ExtraProperties.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 guids = AssetDatabase.FindAssets($"t:{assetType.Name}", new []{assetsPath});
var assets = new List<Object>();
foreach (var guid in guids)
assets.Add(AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(guid), assetType));
return assets;
}
}
}

1
com.unity.perception/Editor/Randomization/Uxml/CategoricalParameterTemplate.uxml


</VisualElement>
<VisualElement style="flex-direction: row; justify-content: flex-end;">
<Button name="add-option" text="Add Option" class="add-option-button"/>
<Button name="add-folder" text="Add Folder" class="add-option-button"/>
<Button name="clear-options" text="Clear Options" class="add-option-button"/>
</VisualElement>
</UXML>

15
com.unity.perception/Runtime/Randomization/Configuration/ParameterConfiguration.cs


string PlaceholderParameterName() => $"Parameter{parameters.Count}";
/// <summary>
/// Adds a new typed parameter to this configuration
/// </summary>
/// <typeparam name="T">The type of parameter to add</typeparam>
/// <returns>The newly added parameter</returns>
public T AddParameter<T>() where T : Parameter, new()
internal T AddParameter<T>() where T : Parameter, new()
{
var parameter = new T();
parameter.name = PlaceholderParameterName();

/// <summary>
/// Adds a new parameter to this configuration
/// </summary>
/// <param name="parameterType">The type of parameter to add</param>
/// <returns>The newly added parameter</returns>
/// <exception cref="ParameterConfigurationException"></exception>
public Parameter AddParameter(Type parameterType)
internal Parameter AddParameter(Type parameterType)
{
if (!parameterType.IsSubclassOf(typeof(Parameter)))
throw new ParameterConfigurationException($"Cannot add non-parameter types ({parameterType})");

2
com.unity.perception/Runtime/Randomization/Parameters/Attributes/ParameterMetaData.cs


namespace UnityEngine.Perception.Randomization.Parameters.Attributes
{
[AttributeUsage(AttributeTargets.Class)]
public class ParameterMetaData : Attribute
class ParameterMetaData : Attribute
{
public static ParameterMetaData GetMetaData(Type type) =>
(ParameterMetaData)GetCustomAttribute(type, typeof(ParameterMetaData));

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


/// <returns>The probability value stored at the specified index</returns>
public float GetProbability(int index) => probabilities[index];
internal CategoricalParameter() { }
protected CategoricalParameter() { }
/// <summary>
/// Create a new categorical parameter from a list of categories with uniform probabilities

public CategoricalParameter(IEnumerable<T> categoricalOptions)
protected CategoricalParameter(IEnumerable<T> categoricalOptions)
{
if (categories.Count == 0)
throw new ArgumentException("List of options is empty");

/// </summary>
/// <param name="categoricalOptions">List of categories and their associated probabilities</param>
/// <exception cref="ArgumentException"></exception>
public CategoricalParameter(IEnumerable<(T, float)> categoricalOptions)
protected CategoricalParameter(IEnumerable<(T, float)> categoricalOptions)
{
if (categories.Count == 0)
throw new ArgumentException("List of options is empty");

if (!uniform)
{
if (probabilities.Count != m_Categories.Count)
throw new ParameterValidationException(
"Number of options must be equal to the number of probabilities");
throw new ParameterValidationException("Number of options must be equal to the number of probabilities");
NormalizeProbabilities();
}
}

3
com.unity.perception/Runtime/Randomization/Parameters/CategoricalParameterBase.cs


namespace UnityEngine.Perception.Randomization.Parameters
{
/// <summary>
/// The base class of CategoricalParameters.
/// </summary>
[Serializable]
public abstract class CategoricalParameterBase : Parameter
{

9
com.unity.perception/Runtime/Randomization/Parameters/NumericParameter.cs


namespace UnityEngine.Perception.Randomization.Parameters
{
/// <summary>
/// Numeric parameters use samplers to generate randomized structs
/// </summary>
/// <typeparam name="T">The sample type of the parameter</typeparam>
/// <summary>
/// The sample type of parameter
/// </summary>
/// <returns>The generated sample</returns>
public abstract T Sample();
/// <summary>

/// <param name="sampleCount">Number of parameter samples to generate</param>
/// <param name="jobHandle">The JobHandle returned from scheduling the sampling job</param>
/// <returns>A NativeArray containing generated samples</returns>
public abstract NativeArray<T> Samples(int sampleCount, out JobHandle jobHandle);
internal sealed override void ApplyToTarget(int seedOffset)

58
com.unity.perception/Runtime/Randomization/Parameters/Parameter.cs


[Serializable]
public abstract class Parameter
{
[SerializeField] internal bool collapsed;
/// <summary>
/// The name of the parameter
/// </summary>
[SerializeField] internal bool collapsed;
[HideInInspector] public ParameterTarget target = new ParameterTarget();
/// <summary>
/// The target this parameter apply a sample to
/// </summary>
[SerializeField] internal ParameterTarget target = new ParameterTarget();
/// <summary>
/// Indicates whether this parameter has a target GameObject
/// </summary>
public ParameterMetaData MetaData =>
internal ParameterMetaData MetaData =>
/// <summary>
/// The sample type generated by this parameter
/// </summary>
public abstract Type sampleType { get; }
/// <summary>
/// An array containing a reference to each sampler field in this parameter

protected Parameter()
{
InitializeSamplers();
}
/// <summary>
/// Deterministically ensures that no sampler shares the same seed when a parameter is initialized
/// </summary>
void InitializeSamplers()
{
var i = 0;
foreach (var sampler in samplers)
{
sampler.Rebase(SamplerUtility.IterateSeed((uint)i++, SamplerUtility.largePrime));
sampler.ResetState();
}
}
internal void RandomizeSamplers()
{
foreach (var sampler in samplers)
{
sampler.Rebase(SamplerUtility.GenerateRandomSeed());
sampler.ResetState();
}
}
/// <summary>
/// Resets sampler states and then offsets those states using the current scenario iteration
/// </summary>

}
/// <summary>
/// The sample type generated by this parameter
/// </summary>
public abstract Type sampleType { get; }
/// <summary>
/// Applies one sampled value to this parameters assigned target gameobject
/// </summary>
internal abstract void ApplyToTarget(int seedOffset);

if (hasTarget)
{
if (target.component == null)
throw new ParameterException($"Null component target on parameter \"{name}\"");
throw new ParameterValidationException($"Null component target on parameter \"{name}\"");
throw new ParameterException($"Invalid property target on parameter \"{name}\"");
throw new ParameterValidationException($"Invalid property target on parameter \"{name}\"");
}
}
}

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


/// Typically managed by a parameter configuration.
/// </summary>
[Serializable]
public class ParameterTarget
class ParameterTarget
{
public GameObject gameObject;
public Component component;

public void Set(
public void AssignNewTarget(
GameObject obj, Component comp, string fieldOrPropertyName, ParameterApplicationFrequency frequency)
{
gameObject = obj;

{
var field = componentType.GetField(propertyName);
if (field == null)
throw new ParameterException(
throw new ParameterValidationException(
$"Component type {componentType.Name} does not have a field named {propertyName}");
field.SetValue(component, value);
}

if (property == null)
throw new ParameterException(
throw new ParameterValidationException(
$"Component type {componentType.Name} does not have a property named {propertyName}");
property.SetValue(component, value);
}

public enum ParameterApplicationFrequency
enum ParameterApplicationFrequency
public enum FieldOrProperty
enum FieldOrProperty
{
Field, Property
}

2
com.unity.perception/Runtime/Randomization/Parameters/ParameterValidationException.cs


namespace UnityEngine.Perception.Randomization.Parameters
{
public class ParameterValidationException : Exception
class ParameterValidationException : Exception
{
public ParameterValidationException(string msg) : base(msg) {}
}

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


/// <summary>
/// Resets a sampler's state to its base random seed and then offsets said seed using an index value
/// </summary>
/// <param name="index">
/// Often a the active scenario's currentIteration
/// </param>
/// <param name="index">Often a the active scenario's currentIteration</param>
/// <summary>
/// Set the base seed value of this sampler
/// </summary>
/// <param name="seed"></param>
void Rebase(uint seed);
/// <summary>
/// Deterministically offsets a sampler's state when generating values within a batched job

2
com.unity.perception/Runtime/Randomization/Samplers/SamplerTypes/ConstantSampler.cs


public void ResetState(int index) { }
public void Rebase(uint seed) { }
public void IterateState(int batchIndex) { }
public float Sample()

5
com.unity.perception/Runtime/Randomization/Samplers/SamplerTypes/NormalSampler.cs


IterateState(index);
}
public void Rebase(uint seed)
{
baseSeed = seed;
}
public void IterateState(int batchIndex)
{
state = SamplerUtility.IterateSeed((uint)batchIndex, state);

5
com.unity.perception/Runtime/Randomization/Samplers/SamplerTypes/UniformSampler.cs


IterateState(index);
}
public void Rebase(uint seed)
{
baseSeed = seed;
}
public void IterateState(int batchIndex)
{
state = SamplerUtility.IterateSeed((uint)batchIndex, state);

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


parameter.x = new UniformSampler(1, 2);
parameter.y = new UniformSampler(1, 2);
parameter.z = new UniformSampler(1, 2);
parameter.target.Set(
parameter.target.AssignNewTarget(
m_TestObject, m_TestObject.transform, "position", ParameterApplicationFrequency.EveryFrame);
var initialPosition = new Vector3();

parameter.z = new UniformSampler(1, 2);
var transform = m_Scenario.transform;
parameter.target.Set(
parameter.target.AssignNewTarget(
m_TestObject, transform, "position", ParameterApplicationFrequency.OnIterationSetup);
var initialPosition = new Vector3();

9
com.unity.perception/Runtime/Randomization/Parameters/ParameterException.cs


using System;
namespace UnityEngine.Perception.Randomization.Parameters
{
public class ParameterException : Exception
{
public ParameterException(string msg) : base(msg) {}
}
}

3
com.unity.perception/Runtime/Randomization/Parameters/ParameterException.cs.meta


fileFormatVersion: 2
guid: 725c4ff9c2e14a0689be1710e53f48d7
timeCreated: 1594668730
正在加载...
取消
保存