浏览代码

Merge branch 'labeling-improvements' into tutorial_updates_nov2020rel

/main
Mohsen Kamalzadeh 4 年前
当前提交
cf9ceb49
共有 56 个文件被更改,包括 3221 次插入221 次删除
  1. 307
      com.unity.perception/Editor/GroundTruth/IdLabelConfigEditor.cs
  2. 2
      com.unity.perception/Editor/GroundTruth/IdLabelConfigEditor.cs.meta
  3. 929
      com.unity.perception/Editor/GroundTruth/LabelingEditor.cs
  4. 2
      com.unity.perception/Editor/GroundTruth/LabelingEditor.cs.meta
  5. 143
      com.unity.perception/Editor/GroundTruth/SemanticSegmentationLabelConfigEditor.cs
  6. 4
      com.unity.perception/Editor/GroundTruth/SemanticSegmentationLabelConfigEditor.cs.meta
  7. 20
      com.unity.perception/Editor/Randomization/Uss/Styles.uss
  8. 3
      com.unity.perception/Runtime/GroundTruth/Labelers/BoundingBoxLabeler.cs
  9. 3
      com.unity.perception/Runtime/GroundTruth/Labeling/IdLabelConfig.cs
  10. 25
      com.unity.perception/Runtime/GroundTruth/Labeling/LabelConfig.cs
  11. 37
      com.unity.perception/Runtime/GroundTruth/Labeling/Labeling.cs
  12. 13
      com.unity.perception/Runtime/GroundTruth/Labeling/SemanticSegmentationLabelConfig.cs
  13. 8
      com.unity.perception/Editor/AssetPreparation.meta
  14. 392
      com.unity.perception/Editor/GroundTruth/AddToConfigWindow.cs
  15. 3
      com.unity.perception/Editor/GroundTruth/AddToConfigWindow.cs.meta
  16. 456
      com.unity.perception/Editor/GroundTruth/LabelConfigEditor.cs
  17. 3
      com.unity.perception/Editor/GroundTruth/LabelConfigEditor.cs.meta
  18. 8
      com.unity.perception/Editor/GroundTruth/Uss.meta
  19. 8
      com.unity.perception/Editor/GroundTruth/Uxml.meta
  20. 11
      com.unity.perception/Editor/AssetPreparation/AssetPreparationTools.cs.meta
  21. 24
      com.unity.perception/Editor/AssetPreparation/AssetPreparationTools.cs
  22. 3
      com.unity.perception/Editor/GroundTruth/Uss/Styles.uss.meta
  23. 228
      com.unity.perception/Editor/GroundTruth/Uss/Styles.uss
  24. 13
      com.unity.perception/Editor/GroundTruth/Uxml/AddToConfigWindow.uxml
  25. 10
      com.unity.perception/Editor/GroundTruth/Uxml/AddToConfigWindow.uxml.meta
  26. 7
      com.unity.perception/Editor/GroundTruth/Uxml/AddedLabelElement.uxml
  27. 3
      com.unity.perception/Editor/GroundTruth/Uxml/AddedLabelElement.uxml.meta
  28. 7
      com.unity.perception/Editor/GroundTruth/Uxml/ConfigElementLabelNotPresent.uxml
  29. 3
      com.unity.perception/Editor/GroundTruth/Uxml/ConfigElementLabelNotPresent.uxml.meta
  30. 8
      com.unity.perception/Editor/GroundTruth/Uxml/ConfigElementLabelPresent.uxml
  31. 3
      com.unity.perception/Editor/GroundTruth/Uxml/ConfigElementLabelPresent.uxml.meta
  32. 38
      com.unity.perception/Editor/GroundTruth/Uxml/Labeling_Main.uxml
  33. 10
      com.unity.perception/Editor/GroundTruth/Uxml/Labeling_Main.uxml.meta
  34. 7
      com.unity.perception/Editor/GroundTruth/Uxml/SuggestedLabelElement.uxml
  35. 3
      com.unity.perception/Editor/GroundTruth/Uxml/SuggestedLabelElement.uxml.meta
  36. 13
      com.unity.perception/Editor/GroundTruth/Uxml/ConfigElementForAddingLabelsFrom.uxml
  37. 3
      com.unity.perception/Editor/GroundTruth/Uxml/ConfigElementForAddingLabelsFrom.uxml.meta
  38. 10
      com.unity.perception/Editor/GroundTruth/Uxml/LabelConfig_Main.uxml.meta
  39. 14
      com.unity.perception/Editor/GroundTruth/Uxml/ColoredLabelElementInLabelConfig.uxml
  40. 3
      com.unity.perception/Editor/GroundTruth/Uxml/ColoredLabelElementInLabelConfig.uxml.meta
  41. 14
      com.unity.perception/Editor/GroundTruth/Uxml/IdLabelElementInLabelConfig.uxml
  42. 3
      com.unity.perception/Editor/GroundTruth/Uxml/IdLabelElementInLabelConfig.uxml.meta
  43. 53
      com.unity.perception/Editor/GroundTruth/Uxml/LabelConfig_Main.uxml
  44. 3
      com.unity.perception/Editor/Icons/ChevronDown.png
  45. 142
      com.unity.perception/Editor/Icons/ChevronDown.png.meta
  46. 6
      com.unity.perception/Editor/Icons/ChevronDownPadded.png
  47. 142
      com.unity.perception/Editor/Icons/ChevronDownPadded.png.meta
  48. 4
      com.unity.perception/Editor/Icons/ChevronUp.png
  49. 142
      com.unity.perception/Editor/Icons/ChevronUp.png.meta
  50. 4
      com.unity.perception/Editor/Icons/ChevronUpPadded.png
  51. 142
      com.unity.perception/Editor/Icons/ChevronUpPadded.png.meta
  52. 0
      /com.unity.perception/Editor/Icons.meta
  53. 0
      /com.unity.perception/Editor/Icons

307
com.unity.perception/Editor/GroundTruth/IdLabelConfigEditor.cs


using System;
using Unity.Mathematics;
using UnityEditorInternal;
using UnityEditor.UIElements;
using UnityEngine.UIElements;
class IdLabelConfigEditor : Editor
class IdLabelConfigEditor : LabelConfigEditor<IdLabelEntry>
ReorderableList m_LabelsList;
const float k_Margin = 5f;
protected override void InitUiExtended()
{
m_StartingIdEnumField.RegisterValueChangedCallback(evt =>
{
var id = (int) ((StartingLabelId) evt.newValue);
serializedObject.FindProperty(nameof(IdLabelConfig.startingLabelId)).enumValueIndex = id;
serializedObject.ApplyModifiedProperties();
AutoAssignIds();
});
public void OnEnable()
{
m_LabelsList = new ReorderableList(this.serializedObject, this.serializedObject.FindProperty(IdLabelConfig.labelEntriesFieldName), true, false, true, true);
m_LabelsList.elementHeight = EditorGUIUtility.singleLineHeight * 2 + k_Margin;
m_LabelsList.drawElementCallback = DrawElement;
m_LabelsList.onAddCallback += OnAdd;
m_LabelsList.onRemoveCallback += OnRemove;
m_LabelsList.onReorderCallbackWithDetails += OnReorder;
}
m_AutoIdToggle.RegisterValueChangedCallback(evt =>
{
serializedObject.FindProperty(nameof(IdLabelConfig.autoAssignIds)).boolValue = evt.newValue;
m_StartingIdEnumField.SetEnabled(evt.newValue);
serializedObject.ApplyModifiedProperties();
if (!evt.newValue)
{
ChangesHappeningInForeground = true;
RefreshListDataAndPresentation();
//if evt.newValue is true, the auto assign function will perform the above refresh, so no need to do this twice
//refresh is needed because the id textfields of the labels need to be enabled or disabled accordingly
}
AutoAssignIdsIfNeeded();
});
void OnReorder(ReorderableList list, int oldIndex, int newIndex)
{
if (!autoAssign)
return;
m_StartingIdEnumField.SetEnabled(AutoAssign);
AutoAssignIds();
AutoAssignIdsIfNeeded();
m_MoveDownButton.clicked += MoveSelectedItemDown;
m_MoveUpButton.clicked += MoveSelectedItemUp;
void OnRemove(ReorderableList list)
public override void PostRemoveOperations()
if (list.index != -1)
list.serializedProperty.DeleteArrayElementAtIndex(list.index);
if (autoAssign)
AutoAssignIds();
this.serializedObject.ApplyModifiedProperties();
EditorUtility.SetDirty(target);
AutoAssignIdsIfNeeded();
void OnAdd(ReorderableList list)
private void MoveSelectedItemUp()
int maxLabel = Int32.MinValue;
if (list.serializedProperty.arraySize == 0)
maxLabel = -1;
for (int i = 0; i < list.serializedProperty.arraySize; i++)
var selectedIndex = m_LabelListView.selectedIndex;
if (selectedIndex > 0)
var item = list.serializedProperty.GetArrayElementAtIndex(i);
maxLabel = math.max(maxLabel, item.FindPropertyRelative(nameof(IdLabelEntry.id)).intValue);
}
var index = list.serializedProperty.arraySize;
list.serializedProperty.InsertArrayElementAtIndex(index);
var element = list.serializedProperty.GetArrayElementAtIndex(index);
var idProperty = element.FindPropertyRelative(nameof(IdLabelEntry.id));
idProperty.intValue = maxLabel + 1;
var labelProperty = element.FindPropertyRelative(nameof(IdLabelEntry.label));
labelProperty.stringValue = "";
var currentProperty =
m_SerializedLabelsArray.GetArrayElementAtIndex(selectedIndex)
.FindPropertyRelative(nameof(ILabelEntry.label));
var topProperty = m_SerializedLabelsArray.GetArrayElementAtIndex(selectedIndex - 1)
.FindPropertyRelative(nameof(ILabelEntry.label));
var tmpString = topProperty.stringValue;
topProperty.stringValue = currentProperty.stringValue;
currentProperty.stringValue = tmpString;
if (!AutoAssign)
{
var currentIdProperty =
m_SerializedLabelsArray.GetArrayElementAtIndex(selectedIndex)
.FindPropertyRelative(nameof(IdLabelEntry.id));
var topIdProperty = m_SerializedLabelsArray.GetArrayElementAtIndex(selectedIndex - 1)
.FindPropertyRelative(nameof(IdLabelEntry.id));
var tmpInt = topIdProperty.intValue;
topIdProperty.intValue = currentIdProperty.intValue;
currentIdProperty.intValue = tmpInt;
}
if (autoAssign)
AutoAssignIds();
m_LabelListView.selectedIndex = selectedIndex - 1;
serializedObject.ApplyModifiedProperties();
EditorUtility.SetDirty(target);
serializedObject.ApplyModifiedProperties();
RefreshAddedLabels();
m_LabelListView.Refresh();
RefreshListViewHeight();
}
void DrawElement(Rect rect, int index, bool isactive, bool isfocused)
private void MoveSelectedItemDown()
var element = m_LabelsList.serializedProperty.GetArrayElementAtIndex(index);
var idProperty = element.FindPropertyRelative(nameof(IdLabelEntry.id));
var labelProperty = element.FindPropertyRelative(nameof(IdLabelEntry.label));
using (var change = new EditorGUI.ChangeCheckScope())
var selectedIndex = m_LabelListView.selectedIndex;
if (selectedIndex > -1 && selectedIndex < m_SerializedLabelsArray.arraySize - 1)
var contentRect = new Rect(rect.position, new Vector2(rect.width, EditorGUIUtility.singleLineHeight));
using (new EditorGUI.DisabledScope(autoAssign))
var currentProperty =
m_SerializedLabelsArray.GetArrayElementAtIndex(selectedIndex)
.FindPropertyRelative(nameof(ILabelEntry.label));
var bottomProperty = m_SerializedLabelsArray.GetArrayElementAtIndex(selectedIndex + 1)
.FindPropertyRelative(nameof(ILabelEntry.label));
var tmpString = bottomProperty.stringValue;
bottomProperty.stringValue = currentProperty.stringValue;
currentProperty.stringValue = tmpString;
if (!AutoAssign)
var newLabel = EditorGUI.IntField(contentRect, nameof(IdLabelEntry.id), idProperty.intValue);
if (change.changed)
{
idProperty.intValue = newLabel;
if (autoAssign)
AutoAssignIds();
}
var currentIdProperty =
m_SerializedLabelsArray.GetArrayElementAtIndex(selectedIndex)
.FindPropertyRelative(nameof(IdLabelEntry.id));
var bottomIdProperty = m_SerializedLabelsArray.GetArrayElementAtIndex(selectedIndex + 1)
.FindPropertyRelative(nameof(IdLabelEntry.id));
var tmpInt = bottomIdProperty.intValue;
bottomIdProperty.intValue = currentIdProperty.intValue;
currentIdProperty.intValue = tmpInt;
m_LabelListView.selectedIndex = selectedIndex + 1;
serializedObject.ApplyModifiedProperties();
RefreshAddedLabels();
m_LabelListView.Refresh();
RefreshListViewHeight();
using (var change = new EditorGUI.ChangeCheckScope())
}
protected override void SetupPresentLabelsListView()
{
base.SetupPresentLabelsListView();
VisualElement MakeItem() =>
new IdLabelElementInLabelConfig(this, m_SerializedLabelsArray);
void BindItem(VisualElement e, int i)
var contentRect = new Rect(rect.position + new Vector2(0, EditorGUIUtility.singleLineHeight), new Vector2(rect.width, EditorGUIUtility.singleLineHeight));
var newLabel = EditorGUI.TextField(contentRect, nameof(IdLabelEntry.label), labelProperty.stringValue);
if (change.changed)
if (e is IdLabelElementInLabelConfig addedLabel)
labelProperty.stringValue = newLabel;
addedLabel.m_IndexInList = i;
addedLabel.m_LabelTextField.BindProperty(m_SerializedLabelsArray.GetArrayElementAtIndex(i)
.FindPropertyRelative(nameof(IdLabelEntry.label)));
addedLabel.m_LabelIdTextField.value = m_SerializedLabelsArray.GetArrayElementAtIndex(i)
.FindPropertyRelative(nameof(IdLabelEntry.id)).intValue.ToString();
m_LabelListView.bindItem = BindItem;
m_LabelListView.makeItem = MakeItem;
bool autoAssign => serializedObject.FindProperty(nameof(IdLabelConfig.autoAssignIds)).boolValue;
protected override IdLabelEntry CreateLabelEntryFromLabelString(SerializedProperty serializedArray,
string labelToAdd)
{
int maxLabel = Int32.MinValue;
if (serializedArray.arraySize == 0)
maxLabel = -1;
public override void OnInspectorGUI()
{
serializedObject.Update();
var autoAssignIdsProperty = serializedObject.FindProperty(nameof(IdLabelConfig.autoAssignIds));
using (var change = new EditorGUI.ChangeCheckScope())
for (int i = 0; i < serializedArray.arraySize; i++)
EditorGUILayout.PropertyField(autoAssignIdsProperty, new GUIContent("Auto Assign IDs"));
if (change.changed && autoAssignIdsProperty.boolValue)
AutoAssignIds();
var item = serializedArray.GetArrayElementAtIndex(i);
maxLabel = math.max(maxLabel, item.FindPropertyRelative(nameof(IdLabelEntry.id)).intValue);
if (autoAssignIdsProperty.boolValue)
return new IdLabelEntry
using (var change = new EditorGUI.ChangeCheckScope())
{
var startingLabelIdProperty = serializedObject.FindProperty(nameof(IdLabelConfig.startingLabelId));
EditorGUILayout.PropertyField(startingLabelIdProperty, new GUIContent("Starting Label ID"));
if (change.changed)
AutoAssignIds();
}
}
id = maxLabel + 1,
label = labelToAdd
};
}
m_LabelsList.DoLayoutList();
this.serializedObject.ApplyModifiedProperties();
protected override void AppendLabelEntryToSerializedArray(SerializedProperty serializedArray,
IdLabelEntry labelEntry)
{
var index = serializedArray.arraySize;
serializedArray.InsertArrayElementAtIndex(index);
var element = serializedArray.GetArrayElementAtIndex(index);
var idProperty = element.FindPropertyRelative(nameof(IdLabelEntry.id));
idProperty.intValue = labelEntry.id;
var labelProperty = element.FindPropertyRelative(nameof(ILabelEntry.label));
labelProperty.stringValue = labelEntry.label;
void AutoAssignIds()
public bool AutoAssign => serializedObject.FindProperty(nameof(IdLabelConfig.autoAssignIds)).boolValue;
private void AutoAssignIds()
{
var serializedProperty = serializedObject.FindProperty(IdLabelConfig.labelEntriesFieldName);
var size = serializedProperty.arraySize;

var startingLabelId = (StartingLabelId)serializedObject.FindProperty(nameof(IdLabelConfig.startingLabelId)).enumValueIndex;
var startingLabelId =
(StartingLabelId) serializedObject.FindProperty(nameof(IdLabelConfig.startingLabelId)).enumValueIndex;
serializedProperty.GetArrayElementAtIndex(i).FindPropertyRelative(nameof(IdLabelEntry.id)).intValue = nextId;
serializedProperty.GetArrayElementAtIndex(i).FindPropertyRelative(nameof(IdLabelEntry.id)).intValue =
nextId;
serializedObject.ApplyModifiedProperties();
ChangesHappeningInForeground = true;
RefreshListDataAndPresentation();
EditorUtility.SetDirty(target);
}
private void AutoAssignIdsIfNeeded()
{
if (AutoAssign)
{
AutoAssignIds();
}
}
public int IndexOfGivenIdInSerializedLabelsArray(int id)
{
for (int i = 0; i < m_SerializedLabelsArray.arraySize; i++)
{
var element = m_SerializedLabelsArray.GetArrayElementAtIndex(i).FindPropertyRelative(nameof(IdLabelEntry.id));
if (element.intValue == id)
{
return i;
}
}
return -1;
}
}
internal class IdLabelElementInLabelConfig : LabelElementInLabelConfig<IdLabelEntry>
{
protected override string UxmlPath => UxmlDir + "IdLabelElementInLabelConfig.uxml";
public TextField m_LabelIdTextField;
public IdLabelElementInLabelConfig(LabelConfigEditor<IdLabelEntry> editor, SerializedProperty labelsArray) :
base(editor, labelsArray)
{
}
protected override void InitExtended()
{
m_LabelIdTextField = this.Q<TextField>("label-id-value");
m_LabelIdTextField.isDelayed = true;
m_LabelIdTextField.SetEnabled(!((IdLabelConfigEditor) m_LabelConfigEditor).AutoAssign);
m_LabelIdTextField.RegisterValueChangedCallback(evt =>
{
if(int.TryParse(evt.newValue, out int parsedId))
{
m_LabelsArray.GetArrayElementAtIndex(m_IndexInList).FindPropertyRelative(nameof(IdLabelEntry.id))
.intValue = parsedId;
if (m_LabelsArray.serializedObject.hasModifiedProperties)
{
m_LabelsArray.serializedObject.ApplyModifiedProperties();
m_LabelConfigEditor.ChangesHappeningInForeground = true;
m_LabelConfigEditor.RefreshListDataAndPresentation();
}
int index = ((IdLabelConfigEditor)m_LabelConfigEditor).IndexOfGivenIdInSerializedLabelsArray(parsedId);
if (index != -1 && index != m_IndexInList)
{
//The listview recycles child visual elements and that causes the RegisterValueChangedCallback event to be called when scrolling.
//Therefore, we need to make sure we are not in this code block just because of scrolling, but because the user is actively changing one of the labels.
//The index check is for this purpose.
Debug.LogWarning("A label with the ID " + evt.newValue + " has already been added to this label configuration.");
}
}
else
{
Debug.LogError("Provided id is not a valid integer. Please provide integer values.");
m_LabelIdTextField.value = evt.previousValue;
}
});
}
}
}

2
com.unity.perception/Editor/GroundTruth/IdLabelConfigEditor.cs.meta


fileFormatVersion: 2
guid: 910dd3186e1c4fad8eb6aca9b9ee0f48
guid: 43cb2a3117353435abe59ca5217974a8
timeCreated: 1585940009

929
com.unity.perception/Editor/GroundTruth/LabelingEditor.cs


using Unity.Entities;
using UnityEditorInternal;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEditor.UIElements;
using UnityEngine.UIElements;
using Button = UnityEngine.UIElements.Button;
using Toggle = UnityEngine.UIElements.Toggle;
namespace UnityEditor.Perception.GroundTruth
{

ReorderableList m_LabelsList;
private VisualElement m_Root;
private VisualElement m_ManualLabelingContainer;
private VisualElement m_AutoLabelingContainer;
private VisualElement m_FromLabelConfigsContainer;
private VisualElement m_SuggestedLabelsContainer;
private VisualElement m_SuggestedOnNamePanel;
private VisualElement m_SuggestedOnPathPanel;
private ListView m_CurrentLabelsListView;
private ListView m_SuggestLabelsListView_FromName;
private ListView m_SuggestLabelsListView_FromPath;
private ScrollView m_LabelConfigsScrollView;
private PopupField<string> m_LabelingSchemesPopup;
private Button m_AddButton;
private Button m_AddAutoLabelToConfButton;
private Toggle m_AutoLabelingToggle;
private Label m_CurrentAutoLabel;
private Label m_CurrentAutoLabelTitle;
private Label m_AddManualLabelsTitle;
private Labeling m_Labeling;
private string m_UxmlDir = "Packages/com.unity.perception/Editor/GroundTruth/Uxml/";
private string m_UxmlPath;
private List<string> m_SuggestedLabelsBasedOnName = new List<string>();
private List<string> m_SuggestedLabelsBasedOnPath = new List<string>();
public List<string> CommonLabels { get; private set; } = new List<string>();
private List<Type> m_LabelConfigTypes;
private readonly List<ScriptableObject> m_AllLabelConfigsInProject = new List<ScriptableObject>();
private readonly List<AssetLabelingScheme> m_LabelingSchemes = new List<AssetLabelingScheme>();
/// <summary>
/// List of separator characters used for parsing asset names for auto labeling or label suggestion purposes
/// </summary>
public static readonly string[] NameSeparators = {".", "-", "_"};
/// <summary>
/// List of separator characters used for parsing asset paths for auto labeling or label suggestion purposes
/// </summary>
public static readonly string[] PathSeparators = {"/"};
private void OnEnable()
{
m_LabelConfigTypes = AddToConfigWindow.FindAllSubTypes(typeof(LabelConfig<>));
var mySerializedObject = new SerializedObject(serializedObject.targetObjects[0]);
m_Labeling = mySerializedObject.targetObject as Labeling;
m_UxmlPath = m_UxmlDir + "Labeling_Main.uxml";
m_Root = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(m_UxmlPath).CloneTree();
m_CurrentLabelsListView = m_Root.Q<ListView>("current-labels-listview");
m_SuggestLabelsListView_FromName = m_Root.Q<ListView>("suggested-labels-name-listview");
m_SuggestLabelsListView_FromPath = m_Root.Q<ListView>("suggested-labels-path-listview");
m_LabelConfigsScrollView = m_Root.Q<ScrollView>("label-configs-scrollview");
m_SuggestedOnNamePanel = m_Root.Q<VisualElement>("suggested-labels-from-name");
m_SuggestedOnPathPanel = m_Root.Q<VisualElement>("suggested-labels-from-path");
m_AddButton = m_Root.Q<Button>("add-label");
m_CurrentAutoLabel = m_Root.Q<Label>("current-auto-label");
m_CurrentAutoLabelTitle = m_Root.Q<Label>("current-auto-label-title");
m_AutoLabelingToggle = m_Root.Q<Toggle>("auto-or-manual-toggle");
m_ManualLabelingContainer = m_Root.Q<VisualElement>("manual-labeling");
m_AutoLabelingContainer = m_Root.Q<VisualElement>("automatic-labeling");
m_FromLabelConfigsContainer = m_Root.Q<VisualElement>("from-label-configs");
m_SuggestedLabelsContainer = m_Root.Q<VisualElement>("suggested-labels");
m_AddAutoLabelToConfButton = m_Root.Q<Button>("add-auto-label-to-config");
m_AddManualLabelsTitle = m_Root.Q<Label>("add-manual-labels-title");
var dropdownParent = m_Root.Q<VisualElement>("drop-down-parent");
m_ItIsPossibleToAddMultipleAutoLabelsToConfig = false;
InitializeLabelingSchemes(dropdownParent);
AssesAutoLabelingStatus();
m_FirstItemLabelsArray = serializedObject.FindProperty(nameof(Labeling.labels));
if (serializedObject.targetObjects.Length > 1)
{
var addedTitle = m_Root.Q<Label>("added-labels-title");
addedTitle.text = "Common Labels of Selected Items";
m_SuggestedOnNamePanel.style.display = DisplayStyle.None;
m_AddAutoLabelToConfButton.text = "Add Automatic Labels of All Selected Assets to Config...";
}
else
{
m_AddAutoLabelToConfButton.text = "Add to Label Config...";
}
m_AddAutoLabelToConfButton.clicked += () =>
{
AddToConfigWindow.ShowWindow(CreateUnionOfAllLabels().ToList());
};
m_AddButton.clicked += () =>
{
var labelsUnion = CreateUnionOfAllLabels();
var newLabel = FindNewLabelValue(labelsUnion);
foreach (var targetObject in targets)
{
if (targetObject is Labeling labeling)
{
var serializedLabelingObject2 = new SerializedObject(labeling);
var serializedLabelArray2 = serializedLabelingObject2.FindProperty(nameof(Labeling.labels));
serializedLabelArray2.InsertArrayElementAtIndex(serializedLabelArray2.arraySize);
serializedLabelArray2.GetArrayElementAtIndex(serializedLabelArray2.arraySize-1).stringValue = newLabel;
serializedLabelingObject2.ApplyModifiedProperties();
serializedLabelingObject2.SetIsDifferentCacheDirty();
serializedObject.SetIsDifferentCacheDirty();
}
}
ChangesHappeningInForeground = true;
RefreshManualLabelingData();
};
m_AutoLabelingToggle.RegisterValueChangedCallback(evt =>
{
AutoLabelToggleChanged();
});
ChangesHappeningInForeground = true;
m_Root.schedule.Execute(CheckForModelChanges).Every(30);
}
private int m_PreviousLabelsArraySize = -1;
/// <summary>
/// This boolean is used to signify when changes in the model are triggered directly from the inspector UI by the user.
/// In these cases, the scheduled model checker does not need to update the UI again.
/// </summary>
public bool ChangesHappeningInForeground { get; set; }
private SerializedProperty m_FirstItemLabelsArray;
private void CheckForModelChanges()
{
if (ChangesHappeningInForeground)
{
ChangesHappeningInForeground = false;
m_PreviousLabelsArraySize = m_FirstItemLabelsArray.arraySize;
return;
}
if (m_FirstItemLabelsArray.arraySize != m_PreviousLabelsArraySize)
{
AssesAutoLabelingStatus();
RefreshManualLabelingData();
m_PreviousLabelsArraySize = m_FirstItemLabelsArray.arraySize;
}
}
private bool SerializedObjectHasValidLabelingScheme(SerializedObject serObj)
{
var schemeName = serObj.FindProperty(nameof(Labeling.autoLabelingSchemeType)).stringValue;
return IsValidLabelingSchemeName(schemeName);
}
private bool IsValidLabelingSchemeName(string schemeName)
{
return schemeName != string.Empty &&
m_LabelingSchemes.FindAll(scheme => scheme.GetType().Name == schemeName).Count > 0;
}
private bool m_ItIsPossibleToAddMultipleAutoLabelsToConfig;
private void UpdateUiAspects()
{
m_ManualLabelingContainer.SetEnabled(!m_AutoLabelingToggle.value);
m_AutoLabelingContainer.SetEnabled(m_AutoLabelingToggle.value);
m_AddManualLabelsTitle.style.display = m_AutoLabelingToggle.value ? DisplayStyle.None : DisplayStyle.Flex;
m_FromLabelConfigsContainer.style.display = m_AutoLabelingToggle.value ? DisplayStyle.None : DisplayStyle.Flex;
m_SuggestedLabelsContainer.style.display = m_AutoLabelingToggle.value ? DisplayStyle.None : DisplayStyle.Flex;
m_CurrentLabelsListView.style.minHeight = m_AutoLabelingToggle.value ? 70 : 120;
if (!m_AutoLabelingToggle.value || serializedObject.targetObjects.Length > 1 ||
!SerializedObjectHasValidLabelingScheme(new SerializedObject(serializedObject.targetObjects[0])))
{
m_CurrentAutoLabel.style.display = DisplayStyle.None;
m_AddAutoLabelToConfButton.SetEnabled(false);
}
else
{
m_CurrentAutoLabel.style.display = DisplayStyle.Flex;
m_AddAutoLabelToConfButton.SetEnabled(true);
}
if(m_AutoLabelingToggle.value && serializedObject.targetObjects.Length > 1 && m_ItIsPossibleToAddMultipleAutoLabelsToConfig)
{
m_AddAutoLabelToConfButton.SetEnabled(true);
}
if (serializedObject.targetObjects.Length == 1)
{
m_AutoLabelingToggle.text = "Use Automatic Labeling";
}
else
{
m_CurrentAutoLabelTitle.text = "Select assets individually to inspect their automatic labels.";
m_AutoLabelingToggle.text = "Use Automatic Labeling for All Selected Items";
}
}
private void UpdateCurrentAutoLabelValue(SerializedObject serObj)
{
var array = serObj.FindProperty(nameof(Labeling.labels));
if (array.arraySize > 0)
{
m_CurrentAutoLabel.text = array.GetArrayElementAtIndex(0).stringValue;
}
}
private bool AreSelectedAssetsCompatibleWithAutoLabelScheme(AssetLabelingScheme scheme)
{
foreach (var asset in serializedObject.targetObjects)
{
string label = scheme.GenerateLabel(asset);
if (label == null)
{
return false;
}
}
return true;
}
public void OnEnable()
private void InitializeLabelingSchemes(VisualElement parent)
m_LabelsList = new ReorderableList(serializedObject, serializedObject.FindProperty(nameof(Labeling.labels)), true, false, true, true);
m_LabelsList.drawElementCallback = DrawElement;
m_LabelsList.onAddCallback += OnAdd;
m_LabelsList.onRemoveCallback += OnRemove;
m_LabelsList.onReorderCallbackWithDetails += OnReordered;
//this function should be called only once during the lifecycle of the editor element
AssetLabelingScheme labelingScheme = new AssetNameLabelingScheme();
if (AreSelectedAssetsCompatibleWithAutoLabelScheme(labelingScheme)) m_LabelingSchemes.Add(labelingScheme);
labelingScheme = new AssetFileNameLabelingScheme();
if (AreSelectedAssetsCompatibleWithAutoLabelScheme(labelingScheme)) m_LabelingSchemes.Add(labelingScheme);
labelingScheme = new CurrentOrParentsFolderNameLabelingScheme();
if (AreSelectedAssetsCompatibleWithAutoLabelScheme(labelingScheme)) m_LabelingSchemes.Add(labelingScheme);
var descriptions = m_LabelingSchemes.Select(scheme => scheme.Description).ToList();
descriptions.Insert(0, "<Select Scheme>");
m_LabelingSchemesPopup = new PopupField<string>(descriptions, 0) {label = "Labeling Scheme"};
m_LabelingSchemesPopup.style.marginLeft = 0;
parent.Add(m_LabelingSchemesPopup);
m_LabelingSchemesPopup.RegisterValueChangedCallback(evt => AssignAutomaticLabelToSelectedAssets());
void OnRemove(ReorderableList list)
private void AutoLabelToggleChanged()
if (list.index != -1)
UpdateUiAspects();
if (!m_AutoLabelingToggle.value)
{
m_ItIsPossibleToAddMultipleAutoLabelsToConfig = false;
foreach (var targetObj in serializedObject.targetObjects)
{
var serObj = new SerializedObject(targetObj);
serObj.FindProperty(nameof(Labeling.useAutoLabeling)).boolValue = false;
if (SerializedObjectHasValidLabelingScheme(serObj))
{
//asset already had a labeling scheme before auto labeling was disabled, which means it has auto label(s) attached. these should be cleared now.
serObj.FindProperty(nameof(Labeling.labels)).ClearArray();
}
serObj.FindProperty(nameof(Labeling.autoLabelingSchemeType)).stringValue = string.Empty;
m_LabelingSchemesPopup.index = 0;
serObj.ApplyModifiedProperties();
serObj.SetIsDifferentCacheDirty();
}
}
ChangesHappeningInForeground = true;
RefreshManualLabelingData();
}
private void AssignAutomaticLabelToSelectedAssets()
{
//the 0th index of this popup is "<Select Scheme>" and should not do anything
if (m_LabelingSchemesPopup.index == 0)
{
return;
}
m_ItIsPossibleToAddMultipleAutoLabelsToConfig = true;
var labelingScheme = m_LabelingSchemes[m_LabelingSchemesPopup.index - 1];
foreach (var targetObj in serializedObject.targetObjects)
{
var serObj = new SerializedObject(targetObj);
serObj.FindProperty(nameof(Labeling.useAutoLabeling)).boolValue = true; //only set this flag once the user has actually chosen a scheme, otherwise, we will not touch the flag
serObj.FindProperty(nameof(Labeling.autoLabelingSchemeType)).stringValue = labelingScheme.GetType().Name;
var serLabelsArray = serObj.FindProperty(nameof(Labeling.labels));
serLabelsArray.ClearArray();
serLabelsArray.InsertArrayElementAtIndex(0);
var label = labelingScheme.GenerateLabel(targetObj);
serLabelsArray.GetArrayElementAtIndex(0).stringValue = label;
if (targetObj == serializedObject.targetObjects[0] && serializedObject.targetObjects.Length == 1)
{
UpdateCurrentAutoLabelValue(serObj);
}
serObj.ApplyModifiedProperties();
serObj.SetIsDifferentCacheDirty();
}
UpdateUiAspects();
ChangesHappeningInForeground = true;
RefreshManualLabelingData();
}
private void AssesAutoLabelingStatus()
{
var enabledOrNot = true;
if (serializedObject.targetObjects.Length == 1)
{
var serObj = new SerializedObject(serializedObject.targetObjects[0]);
var enabled = serObj.FindProperty(nameof(Labeling.useAutoLabeling)).boolValue;
m_AutoLabelingToggle.value = enabled;
var currentLabelingSchemeName = serObj.FindProperty(nameof(Labeling.autoLabelingSchemeType)).stringValue;
if (IsValidLabelingSchemeName(currentLabelingSchemeName))
{
m_LabelingSchemesPopup.index =
m_LabelingSchemes.FindIndex(scheme => scheme.GetType().Name.ToString() == currentLabelingSchemeName) + 1;
}
UpdateCurrentAutoLabelValue(serObj);
}
else
{
string unifiedLabelingScheme = null;
var allAssetsUseSameLabelingScheme = true;
foreach (var targetObj in serializedObject.targetObjects)
{
var serObj = new SerializedObject(targetObj);
var enabled = serObj.FindProperty(nameof(Labeling.useAutoLabeling)).boolValue;
enabledOrNot &= enabled;
var schemeName = serObj.FindProperty(nameof(Labeling.autoLabelingSchemeType)).stringValue;
if (schemeName == string.Empty)
{
//if any of the selected assets does not have a labeling scheme, they can't all have the same valid scheme
allAssetsUseSameLabelingScheme = false;
}
if (allAssetsUseSameLabelingScheme)
{
if (unifiedLabelingScheme == null)
{
unifiedLabelingScheme = schemeName;
}
else if (unifiedLabelingScheme != schemeName)
{
allAssetsUseSameLabelingScheme = false;
}
}
}
m_AutoLabelingToggle.value = enabledOrNot;
if (allAssetsUseSameLabelingScheme)
{
//all selected assets have the same scheme recorded in their serialized objects
m_LabelingSchemesPopup.index =
m_LabelingSchemes.FindIndex(scheme => scheme.GetType().Name.ToString() == unifiedLabelingScheme) + 1;
m_ItIsPossibleToAddMultipleAutoLabelsToConfig = enabledOrNot;
//if all selected assets have the same scheme recorded in their serialized objects, and they all
//have auto labeling enabled, we can now add all auto labels to a config
}
else
{
//the selected DO NOT have the same scheme recorded in their serialized objects
m_LabelingSchemesPopup.index = 0;
}
}
UpdateUiAspects();
}
private HashSet<string> CreateUnionOfAllLabels()
{
HashSet<String> result = new HashSet<string>();
foreach (var obj in targets)
{
if (obj is Labeling labeling)
{
result.UnionWith(labeling.labels);
}
}
return result;
}
private string FindNewLabelValue(HashSet<string> labels)
{
string baseLabel = "New Label";
string label = baseLabel;
int count = 1;
while (labels.Contains(label))
{
label = baseLabel + "_" + count++;
}
return label;
}
public override VisualElement CreateInspectorGUI()
{
serializedObject.Update();
m_Labeling = serializedObject.targetObject as Labeling;
RefreshCommonLabels();
RefreshSuggestedLabelLists();
RefreshLabelConfigsList();
SetupListsAndScrollers();
return m_Root;
}
void RefreshLabelConfigsList()
{
List<string> labelConfigGuids = new List<string>();
foreach (var type in m_LabelConfigTypes)
{
labelConfigGuids.AddRange(AssetDatabase.FindAssets("t:"+type.Name));
}
m_AllLabelConfigsInProject.Clear();
foreach (var configGuid in labelConfigGuids)
{
var asset = AssetDatabase.LoadAssetAtPath<ScriptableObject>(AssetDatabase.GUIDToAssetPath(configGuid));
m_AllLabelConfigsInProject.Add(asset);
}
}
public void RemoveAddedLabelsFromSuggestedLists()
{
m_SuggestedLabelsBasedOnName.RemoveAll(s => CommonLabels.Contains(s));
m_SuggestedLabelsBasedOnPath.RemoveAll(s => CommonLabels.Contains(s));
}
public void RefreshSuggestedLabelLists()
{
m_SuggestedLabelsBasedOnName.Clear();
m_SuggestedLabelsBasedOnPath.Clear();
//based on name
if (serializedObject.targetObjects.Length == 1)
{
string assetName = serializedObject.targetObject.name;
var pieces = assetName.Split(NameSeparators, StringSplitOptions.RemoveEmptyEntries).ToList();
if (pieces.Count > 1)
{
//means the asset name was actually split
m_SuggestedLabelsBasedOnName.Add(assetName);
}
m_SuggestedLabelsBasedOnName.AddRange(pieces);
}
//based on path
string assetPath = GetAssetOrPrefabPath(m_Labeling.gameObject);
//var prefabObject = PrefabUtility.GetCorrespondingObjectFromSource(m_Labeling.gameObject);
if (assetPath != null)
{
var stringList = assetPath.Split(PathSeparators, StringSplitOptions.RemoveEmptyEntries).ToList();
stringList.Reverse();
m_SuggestedLabelsBasedOnPath.AddRange(stringList);
}
foreach (var targetObject in targets)
var value = labeling.labels[list.index];
foreach (var t in targets)
if (targetObject == target)
continue; //we have already taken care of this one above
assetPath = GetAssetOrPrefabPath(((Labeling)targetObject).gameObject);
//prefabObject = PrefabUtility.GetCorrespondingObjectFromSource(((Labeling)targetObject).gameObject);
if (assetPath != null)
((Labeling)t).labels.Remove(value);
var stringList = assetPath.Split(PathSeparators, StringSplitOptions.RemoveEmptyEntries).ToList();
m_SuggestedLabelsBasedOnPath = m_SuggestedLabelsBasedOnPath.Intersect(stringList).ToList();
RemoveAddedLabelsFromSuggestedLists();
//Debug.Log("list update, source list count is:" + m_SuggestedLabelsBasedOnPath.Count);
}
public void RefreshManualLabelingData()
{
serializedObject.SetIsDifferentCacheDirty();
serializedObject.Update();
RefreshCommonLabels();
RefreshSuggestedLabelLists();
SetupSuggestedLabelsListViews();
SetupCurrentLabelsListView();
UpdateSuggestedPanelVisibility();
Labeling labeling => (Labeling)target;
void SetupListsAndScrollers()
{
//Labels that have already been added to the target Labeling component
SetupCurrentLabelsListView();
//Labels suggested by the system, which the user can add
SetupSuggestedLabelsListViews();
//Add labels from Label Configs present in project
SetupLabelConfigsScrollView();
UpdateSuggestedPanelVisibility();
}
void OnAdd(ReorderableList list)
void UpdateSuggestedPanelVisibility()
foreach (var t in targets)
m_SuggestedOnNamePanel.style.display = m_SuggestedLabelsBasedOnName.Count == 0 ? DisplayStyle.None : DisplayStyle.Flex;
m_SuggestedOnPathPanel.style.display = m_SuggestedLabelsBasedOnPath.Count == 0 ? DisplayStyle.None : DisplayStyle.Flex;
if (m_SuggestedLabelsBasedOnPath.Count == 0 && m_SuggestedLabelsBasedOnName.Count == 0)
var castedTarget = ((Labeling)t);
castedTarget.labels.Add("");
EditorUtility.SetDirty(castedTarget);
m_SuggestedLabelsContainer.style.display = DisplayStyle.None;
void OnReordered(ReorderableList list, int oldIndex, int newIndex)
void RefreshCommonLabels()
var label = labeling.labels[newIndex];
CommonLabels.Clear();
CommonLabels.AddRange(((Labeling)serializedObject.targetObjects[0]).labels);
foreach (var t in targets)
foreach (var obj in serializedObject.targetObjects)
var l = (Labeling)t;
if (this.labeling == l) continue;
CommonLabels = CommonLabels.Intersect(((Labeling) obj).labels).ToList();
}
}
ReorderLabels(l, label, newIndex);
void SetupCurrentLabelsListView()
{
m_CurrentLabelsListView.itemsSource = CommonLabels;
VisualElement MakeItem() =>
new AddedLabelEditor(this, m_CurrentLabelsListView);
void BindItem(VisualElement e, int i)
{
if (e is AddedLabelEditor addedLabel)
{
addedLabel.m_IndexInList = i;
addedLabel.m_LabelTextField.value = CommonLabels[i];
}
const int itemHeight = 35;
m_CurrentLabelsListView.bindItem = BindItem;
m_CurrentLabelsListView.makeItem = MakeItem;
m_CurrentLabelsListView.itemHeight = itemHeight;
m_CurrentLabelsListView.itemsSource = CommonLabels;
m_CurrentLabelsListView.selectionType = SelectionType.None;
static void ReorderLabels(Labeling labeling, string label, int newIndex)
void SetupSuggestedLabelsListViews()
if (labeling.labels.Contains(label))
SetupSuggestedLabelsBasedOnFlatList(m_SuggestLabelsListView_FromName, m_SuggestedLabelsBasedOnName);
SetupSuggestedLabelsBasedOnFlatList(m_SuggestLabelsListView_FromPath, m_SuggestedLabelsBasedOnPath);
}
void SetupSuggestedLabelsBasedOnFlatList(ListView labelsListView, List<string> stringList)
{
labelsListView.itemsSource = stringList;
VisualElement MakeItem() => new SuggestedLabelElement(this);
void BindItem(VisualElement e, int i)
labeling.labels.Remove(label);
if (newIndex < labeling.labels.Count)
labeling.labels.Insert(newIndex, label);
else
labeling.labels.Add(label);
if (e is SuggestedLabelElement suggestedLabel)
{
suggestedLabel.m_Label.text = stringList[i];
}
}
const int itemHeight = 32;
labelsListView.bindItem = BindItem;
labelsListView.makeItem = MakeItem;
labelsListView.itemHeight = itemHeight;
labelsListView.selectionType = SelectionType.None;
}
void SetupLabelConfigsScrollView()
{
m_LabelConfigsScrollView.Clear();
foreach (var config in m_AllLabelConfigsInProject)
{
VisualElement configElement = new LabelConfigElement(this, config);
m_LabelConfigsScrollView.Add(configElement);
static void ReplaceLabel(Labeling labeling, string oldLabel, string newLabel)
/// <summary>
/// Get the path of the given asset in the project, or get the path of the given Scene GameObject's source prefab if any
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public static string GetAssetOrPrefabPath(UnityEngine.Object obj)
var idx = labeling.labels.IndexOf(oldLabel);
if (idx == -1) return;
labeling.labels[idx] = newLabel;
string assetPath = AssetDatabase.GetAssetPath(obj);
if (assetPath == string.Empty)
{
//this indicates that gObj is a scene object and not a prefab directly selected from the Project tab
var prefabObject = PrefabUtility.GetCorrespondingObjectFromSource(obj);
if (prefabObject)
{
assetPath = AssetDatabase.GetAssetPath(prefabObject);
}
}
return assetPath;
}
private void ReplaceLabel(int index, string newLabel)
internal class AddedLabelEditor : VisualElement
{
private string m_UxmlDir = "Packages/com.unity.perception/Editor/GroundTruth/Uxml/";
public TextField m_LabelTextField;
public int m_IndexInList;
public AddedLabelEditor(LabelingEditor editor, ListView listView)
labeling.labels[index] = newLabel;
var uxmlPath = m_UxmlDir + "AddedLabelElement.uxml";
AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(uxmlPath).CloneTree(this);
m_LabelTextField = this.Q<TextField>("label-value");
var removeButton = this.Q<Button>("remove-button");
var addToConfigButton = this.Q<Button>("add-to-config-button");
m_LabelTextField.isDelayed = true;
m_LabelTextField.RegisterValueChangedCallback((cEvent) =>
{
//Do not let the user define a duplicate label
if (editor.CommonLabels.Contains(cEvent.newValue) && editor.CommonLabels.IndexOf(cEvent.newValue) != m_IndexInList)
{
//The listview recycles child visual elements and that causes the RegisterValueChangedCallback event to be called when scrolling.
//Therefore, we need to make sure we are not in this code block just because of scrolling, but because the user is actively changing one of the labels.
//The editor.CommonLabels.IndexOf(cEvent.newValue) != m_IndexInList check is for this purpose.
Debug.LogError("A label with the string " + cEvent.newValue + " has already been added to selected objects.");
editor.ChangesHappeningInForeground = true;
editor.RefreshManualLabelingData();
return;
}
bool shouldRefresh = false;
foreach (var targetObject in editor.targets)
{
if (targetObject is Labeling labeling)
{
var indexToModifyInTargetLabelList =
labeling.labels.IndexOf(editor.CommonLabels[m_IndexInList]);
var serializedLabelingObject2 = new SerializedObject(labeling);
var serializedLabelArray2 = serializedLabelingObject2.FindProperty(nameof(Labeling.labels));
serializedLabelArray2.GetArrayElementAtIndex(indexToModifyInTargetLabelList).stringValue = cEvent.newValue;
shouldRefresh = shouldRefresh || serializedLabelArray2.serializedObject.hasModifiedProperties;
serializedLabelingObject2.ApplyModifiedProperties();
serializedLabelingObject2.SetIsDifferentCacheDirty();
}
}
//the value change event is called even when the listview recycles its child elements for re-use during scrolling, therefore, we should check to make sure there are modified properties, otherwise we would be doing the refresh for no reason (reduces scrolling performance)
if (shouldRefresh)
{
editor.ChangesHappeningInForeground = true;
editor.RefreshManualLabelingData();
}
});
addToConfigButton.clicked += () =>
{
AddToConfigWindow.ShowWindow(m_LabelTextField.value);
};
removeButton.clicked += () =>
{
List<string> commonLabels = new List<string>();
commonLabels.Clear();
var firstTarget = editor.targets[0] as Labeling;
if (firstTarget != null)
{
commonLabels.AddRange(firstTarget.labels);
foreach (var obj in editor.targets)
{
commonLabels = commonLabels.Intersect(((Labeling) obj).labels).ToList();
}
foreach (var targetObject in editor.targets)
{
if (targetObject is Labeling labeling)
{
RemoveLabelFromLabelingSerObj(labeling, commonLabels);
}
}
editor.serializedObject.SetIsDifferentCacheDirty();
editor.RefreshManualLabelingData();
}
};
void ReplaceLabelAll(int index, string currentLabel)
void RemoveLabelFromLabelingSerObj(Labeling labeling, List<string> commonLabels)
var oldLabel = labeling.labels[index];
ReplaceLabel(index, currentLabel);
Dictionary<int, int> commonsIndexToLabelsIndex = new Dictionary<int, int>();
foreach (var t in targets)
for (int i = 0; i < labeling.labels.Count; i++)
var l = (Labeling)t;
string label = labeling.labels[i];
if (this.labeling == l) continue;
for (int j = 0; j < commonLabels.Count; j++)
{
string label2 = commonLabels[j];
ReplaceLabel(l, oldLabel, currentLabel);
if (string.Equals(label, label2) && !commonsIndexToLabelsIndex.ContainsKey(j))
{
commonsIndexToLabelsIndex.Add(j, i);
}
}
var serializedLabelingObject2 = new SerializedObject(labeling);
var serializedLabelArray2 = serializedLabelingObject2.FindProperty("labels");
serializedLabelArray2.DeleteArrayElementAtIndex(commonsIndexToLabelsIndex[m_IndexInList]);
serializedLabelingObject2.ApplyModifiedProperties();
serializedLabelingObject2.SetIsDifferentCacheDirty();
}
void DrawElement(Rect rect, int index, bool isactive, bool isfocused)
internal class SuggestedLabelElement : VisualElement
{
private string m_UxmlDir = "Packages/com.unity.perception/Editor/GroundTruth/Uxml/";
public Label m_Label;
public SuggestedLabelElement(LabelingEditor editor)
using (var change = new EditorGUI.ChangeCheckScope())
var uxmlPath = m_UxmlDir + "SuggestedLabelElement.uxml";
AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(uxmlPath).CloneTree(this);
m_Label = this.Q<Label>("label-value");
var addButton = this.Q<Button>("add-button");
addButton.clicked += () =>
var contentRect = new Rect(rect.x, rect.y, rect.width, rect.height);
foreach (var targetObject in editor.serializedObject.targetObjects)
{
if (targetObject is Labeling labeling)
{
if (labeling.labels.Contains(m_Label.text))
continue; //Do not allow duplicate labels in one asset. Duplicate labels have no use and cause other operations (especially mutlt asset editing) to get messed up
var serializedLabelingObject2 = new SerializedObject(targetObject);
var serializedLabelArray2 = serializedLabelingObject2.FindProperty("labels");
serializedLabelArray2.InsertArrayElementAtIndex(serializedLabelArray2.arraySize);
serializedLabelArray2.GetArrayElementAtIndex(serializedLabelArray2.arraySize-1).stringValue = m_Label.text;
serializedLabelingObject2.ApplyModifiedProperties();
serializedLabelingObject2.SetIsDifferentCacheDirty();
editor.serializedObject.SetIsDifferentCacheDirty();
}
}
editor.ChangesHappeningInForeground = true;
editor.RefreshManualLabelingData();
};
}
}
var value = EditorGUI.DelayedTextField(contentRect, labeling.labels[index]);
internal class LabelConfigElement : VisualElement
{
private string m_UxmlDir = "Packages/com.unity.perception/Editor/GroundTruth/Uxml/";
private bool m_Collapsed = true;
private ListView m_LabelsListView;
private VisualElement m_CollapseToggle;
public LabelConfigElement(LabelingEditor editor, ScriptableObject config)
{
var uxmlPath = m_UxmlDir + "ConfigElementForAddingLabelsFrom.uxml";
AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(uxmlPath).CloneTree(this);
m_LabelsListView = this.Q<ListView>("label-config-contents-listview");
var openButton = this.Q<Button>("open-config-button");
var configName = this.Q<Label>("config-name");
configName.text = config.name;
m_CollapseToggle = this.Q<VisualElement>("collapse-toggle");
if (change.changed)
openButton.clicked += () =>
{
Selection.SetActiveObjectWithContext(config, null);
};
var propertyInfo = config.GetType().GetProperty(IdLabelConfig.publicLabelEntriesFieldName);
if (propertyInfo != null)
{
var objectList = (IEnumerable) propertyInfo.GetValue(config);
var labelEntryList = objectList.Cast<ILabelEntry>().ToList();
var labelList = labelEntryList.Select(entry => entry.label).ToList();
m_LabelsListView.itemsSource = labelList;
VisualElement MakeItem()
ReplaceLabelAll(index, value);
var element = new SuggestedLabelElement(editor);
element.AddToClassList("label_add_from_config");
return element;
}
if (PrefabUtility.IsPartOfAnyPrefab(target))
void BindItem(VisualElement e, int i)
{
if (e is SuggestedLabelElement suggestedLabel)
EditorUtility.SetDirty(target);
suggestedLabel.m_Label.text = labelList[i];
const int itemHeight = 27;
m_LabelsListView.bindItem = BindItem;
m_LabelsListView.makeItem = MakeItem;
m_LabelsListView.itemHeight = itemHeight;
m_LabelsListView.selectionType = SelectionType.None;
m_CollapseToggle.RegisterCallback<MouseUpEvent>(evt =>
{
m_Collapsed = !m_Collapsed;
ApplyCollapseState();
});
ApplyCollapseState();
public override void OnInspectorGUI()
void ApplyCollapseState()
m_LabelsList.DoLayoutList();
if (m_Collapsed)
{
m_CollapseToggle.AddToClassList("collapsed-toggle-state");
m_LabelsListView.AddToClassList("collapsed");
}
else
{
m_CollapseToggle.RemoveFromClassList("collapsed-toggle-state");
m_LabelsListView.RemoveFromClassList("collapsed");
}
}
}
/// <summary>
/// A labeling scheme based on which an automatic label can be produced for a given asset. E.g. based on asset name, asset path, etc.
/// </summary>
internal abstract class AssetLabelingScheme
{
/// <summary>
/// The description of how this scheme generates labels. Used in the dropdown menu in the UI.
/// </summary>
public abstract string Description { get; }
/// <summary>
/// Generate a label for the given asset
/// </summary>
/// <param name="asset"></param>
/// <returns></returns>
public abstract string GenerateLabel(UnityEngine.Object asset);
}
/// <summary>
/// Asset labeling scheme that outputs the given asset's name as its automatic label
/// </summary>
internal class AssetNameLabelingScheme : AssetLabelingScheme
{
///<inheritdoc/>
public override string Description => "Use asset name";
///<inheritdoc/>
public override string GenerateLabel(UnityEngine.Object asset)
{
return asset.name;
}
}
/// <summary>
/// Asset labeling scheme that outputs the given asset's file name, including extension, as its automatic label
/// </summary>
internal class AssetFileNameLabelingScheme : AssetLabelingScheme
{
///<inheritdoc/>
public override string Description => "Use file name with extension";
///<inheritdoc/>
public override string GenerateLabel(UnityEngine.Object asset)
{
string assetPath = LabelingEditor.GetAssetOrPrefabPath(asset);
var stringList = assetPath.Split(LabelingEditor.PathSeparators, StringSplitOptions.RemoveEmptyEntries)
.ToList();
return stringList.Count > 0 ? stringList.Last() : null;
}
}
/// <summary>
/// Asset labeling scheme that outputs the given asset's folder name as its automatic label
/// </summary>
internal class CurrentOrParentsFolderNameLabelingScheme : AssetLabelingScheme
{
///<inheritdoc/>
public override string Description => "Use the asset's folder name";
///<inheritdoc/>
public override string GenerateLabel(UnityEngine.Object asset)
{
string assetPath = LabelingEditor.GetAssetOrPrefabPath(asset);
var stringList = assetPath.Split(LabelingEditor.PathSeparators, StringSplitOptions.RemoveEmptyEntries)
.ToList();
return stringList.Count > 1 ? stringList[stringList.Count-2] : null;
}
}
}

2
com.unity.perception/Editor/GroundTruth/LabelingEditor.cs.meta


fileFormatVersion: 2
guid: 2e725508a34c40a0938c8d891b371980
guid: 387b8732b87094321af57795df93aec4
timeCreated: 1585933334

143
com.unity.perception/Editor/GroundTruth/SemanticSegmentationLabelConfigEditor.cs


using System;
using System.Collections.Generic;
using System.Collections.Generic;
using UnityEditorInternal;
using UnityEditor.UIElements;
using UnityEngine.UIElements;
class SemanticSegmentationLabelConfigEditor : Editor
class SemanticSegmentationLabelConfigEditor : LabelConfigEditor<SemanticSegmentationLabelEntry>
ReorderableList m_LabelsList;
const float k_Margin = 5f;
static List<Color> s_StandardColors = new List<Color>()
protected override void InitUiExtended()
Color.blue,
Color.green,
Color.red,
Color.white,
Color.yellow,
Color.gray
};
m_MoveButtons.style.display = DisplayStyle.None;
m_IdSpecificUi.style.display = DisplayStyle.None;
}
public override void PostRemoveOperations()
{ }
public void OnEnable()
protected override void SetupPresentLabelsListView()
m_LabelsList = new ReorderableList(this.serializedObject, this.serializedObject.FindProperty(IdLabelConfig.labelEntriesFieldName), true, false, true, true);
m_LabelsList.elementHeight = EditorGUIUtility.singleLineHeight * 2 + k_Margin;
m_LabelsList.drawElementCallback = DrawElement;
m_LabelsList.onAddCallback += OnAdd;
base.SetupPresentLabelsListView();
VisualElement MakeItem() =>
new ColoredLabelElementInLabelConfig(this, m_SerializedLabelsArray);
void BindItem(VisualElement e, int i)
{
if (e is ColoredLabelElementInLabelConfig addedLabel)
{
addedLabel.m_IndexInList = i;
addedLabel.m_LabelTextField.BindProperty(m_SerializedLabelsArray.GetArrayElementAtIndex(i)
.FindPropertyRelative(nameof(SemanticSegmentationLabelEntry.label)));
addedLabel.m_ColorField.BindProperty(m_SerializedLabelsArray.GetArrayElementAtIndex(i)
.FindPropertyRelative(nameof(SemanticSegmentationLabelEntry.color)));
}
}
m_LabelListView.bindItem = BindItem;
m_LabelListView.makeItem = MakeItem;
void OnAdd(ReorderableList list)
protected override SemanticSegmentationLabelEntry CreateLabelEntryFromLabelString(SerializedProperty serializedArray, string labelToAdd)
var standardColorList = new List<Color>(s_StandardColors);
for (int i = 0; i < list.serializedProperty.arraySize; i++)
var standardColorList = new List<Color>(SemanticSegmentationLabelConfig.s_StandardColors);
for (int i = 0; i < serializedArray.arraySize; i++)
var item = list.serializedProperty.GetArrayElementAtIndex(i);
var item = serializedArray.GetArrayElementAtIndex(i);
var index = list.serializedProperty.arraySize;
list.serializedProperty.InsertArrayElementAtIndex(index);
var element = list.serializedProperty.GetArrayElementAtIndex(index);
var labelProperty = element.FindPropertyRelative(nameof(SemanticSegmentationLabelEntry.label));
labelProperty.stringValue = "";
var colorProperty = element.FindPropertyRelative(nameof(SemanticSegmentationLabelEntry.color));
Color foundColor;
colorProperty.colorValue = standardColorList.First();
foundColor = standardColorList.First();
colorProperty.colorValue = Random.ColorHSV(0, 1, .5f, 1, 1, 1);
foundColor = Random.ColorHSV(0, 1, .5f, 1, 1, 1);
serializedObject.ApplyModifiedProperties();
EditorUtility.SetDirty(target);
return new SemanticSegmentationLabelEntry
{
color = foundColor,
label = labelToAdd
};
void DrawElement(Rect rect, int index, bool isactive, bool isfocused)
protected override void AppendLabelEntryToSerializedArray(SerializedProperty serializedArray, SemanticSegmentationLabelEntry semanticSegmentationLabelEntry)
var element = m_LabelsList.serializedProperty.GetArrayElementAtIndex(index);
var index = serializedArray.arraySize;
serializedArray.InsertArrayElementAtIndex(index);
var element = serializedArray.GetArrayElementAtIndex(index);
var labelProperty = element.FindPropertyRelative(nameof(SemanticSegmentationLabelEntry.label));
using (var change = new EditorGUI.ChangeCheckScope())
colorProperty.colorValue = semanticSegmentationLabelEntry.color;
var labelProperty = element.FindPropertyRelative(nameof(ILabelEntry.label));
labelProperty.stringValue = semanticSegmentationLabelEntry.label;
}
public int IndexOfGivenColorInSerializedLabelsArray(Color color)
{
for (int i = 0; i < m_SerializedLabelsArray.arraySize; i++)
var contentRect = new Rect(rect.position, new Vector2(rect.width, EditorGUIUtility.singleLineHeight));
var newLabel = EditorGUI.TextField(contentRect, nameof(SemanticSegmentationLabelEntry.label), labelProperty.stringValue);
if (change.changed)
var element = m_SerializedLabelsArray.GetArrayElementAtIndex(i).FindPropertyRelative(nameof(SemanticSegmentationLabelEntry.color));
if (element.colorValue == color)
labelProperty.stringValue = newLabel;
return i;
using (var change = new EditorGUI.ChangeCheckScope())
return -1;
}
}
internal class ColoredLabelElementInLabelConfig : LabelElementInLabelConfig<SemanticSegmentationLabelEntry>
{
protected override string UxmlPath => UxmlDir + "ColoredLabelElementInLabelConfig.uxml";
public ColorField m_ColorField;
public ColoredLabelElementInLabelConfig(LabelConfigEditor<SemanticSegmentationLabelEntry> editor, SerializedProperty labelsArray) : base(editor, labelsArray)
{ }
private Color previousColor;
protected override void InitExtended()
{
m_ColorField = this.Q<ColorField>("label-color-value");
m_ColorField.RegisterValueChangedCallback((cEvent) =>
var contentRect = new Rect(rect.position + new Vector2(0, EditorGUIUtility.singleLineHeight), new Vector2(rect.width, EditorGUIUtility.singleLineHeight));
var newLabel = EditorGUI.ColorField(contentRect, nameof(SemanticSegmentationLabelEntry.color), colorProperty.colorValue);
if (change.changed)
int index = ((SemanticSegmentationLabelConfigEditor)m_LabelConfigEditor).IndexOfGivenColorInSerializedLabelsArray(cEvent.newValue);
if (index != -1 && index != m_IndexInList)
colorProperty.colorValue = newLabel;
//The listview recycles child visual elements and that causes the RegisterValueChangedCallback event to be called when scrolling.
//Therefore, we need to make sure we are not in this code block just because of scrolling, but because the user is actively changing one of the labels.
//The index check is for this purpose.
Debug.LogWarning("A label with the chosen color " + cEvent.newValue + " has already been added to this label configuration.");
}
}
});
public override void OnInspectorGUI()
{
serializedObject.Update();
m_LabelsList.DoLayoutList();
this.serializedObject.ApplyModifiedProperties();
}
}
}

4
com.unity.perception/Editor/GroundTruth/SemanticSegmentationLabelConfigEditor.cs.meta


fileFormatVersion: 2
guid: e8cb4fead5b34d41884c1c9a77308c72
timeCreated: 1593454492
guid: c8e809a6323844c71aa3cb751a6ae9a1
timeCreated: 1585940009

20
com.unity.perception/Editor/Randomization/Uss/Styles.uss


.randomization__remove-item-button {
width: 12px;
height: 14px;
background-image: resource("Packages/com.unity.perception/Editor/Randomization/Icons/X.png");
background-image: resource("Packages/com.unity.perception/Editor/Icons/X.png");
}
.randomization__collapse-toggle {

width: 10px;
height: 10px;
background-image: resource("Packages/com.unity.perception/Editor/Randomization/Icons/FoldoutOpen.png");
background-image: resource("Packages/com.unity.perception/Editor/Icons/FoldoutOpen.png");
background-image: resource("Packages/com.unity.perception/Editor/Randomization/Icons/FoldoutClosed.png");
background-image: resource("Packages/com.unity.perception/Editor/Icons/FoldoutClosed.png");
}
.randomization__collapse-toggle:hover {

.randomization__chevron-left {
height: 12px;
width: 12px;
background-image: resource("Packages/com.unity.perception/Editor/Randomization/Icons/ChevronLeft.png");
background-image: resource("Packages/com.unity.perception/Editor/Icons/ChevronLeft.png");
background-image: resource("Packages/com.unity.perception/Editor/Randomization/Icons/ChevronRight.png");
background-image: resource("Packages/com.unity.perception/Editor/Icons/ChevronRight.png");
}

border-color: #191919;
padding: 2px 4px 2px 4px;
border-color: #808080;
padding: 7px;
border-radius: 4px;
white-space: normal;
margin-top: 4px;
margin-bottom: 4px;

padding: 2px;
}
/* Randomizer classes */
.randomizer__drag-bar {
width: 100px;

width: 16px;
height: 100%;
min-height: 20px;
background-image: resource("Packages/com.unity.perception/Editor/Randomization/Icons/DragHandle.png");
background-image: resource("Packages/com.unity.perception/Editor/Icons/DragHandle.png");
}
.randomizer__drag-handle:hover {

top: 9px;
width: 10px;
height: 10px;
background-image: resource("Packages/com.unity.perception/Editor/Randomization/Icons/Search.png");
background-image: resource("Packages/com.unity.perception/Editor/Icons/Search.png");
}
.randomizer__menu-search-bar .unity-base-text-field__input {

3
com.unity.perception/Runtime/GroundTruth/Labelers/BoundingBoxLabeler.cs


m_AsyncAnnotations[Time.frameCount] = perceptionCamera.SensorHandle.ReportAnnotationAsync(m_BoundingBoxAnnotationDefinition);
}
private int count = 0;
void OnRenderedObjectInfosCalculated(int frameCount, NativeArray<RenderedObjectInfo> renderedObjectInfos)
{
if (!m_AsyncAnnotations.TryGetValue(frameCount, out var asyncAnnotation))

count++;
using (s_BoundingBoxCallback.Auto())
{
m_BoundingBoxValues.Clear();

3
com.unity.perception/Runtime/GroundTruth/Labeling/IdLabelConfig.cs


using System.Diagnostics.CodeAnalysis;
using System.Linq;
using JetBrains.Annotations;
using Newtonsoft.Json;
namespace UnityEngine.Perception.GroundTruth {
/// <summary>

public class IdLabelConfig : LabelConfig<IdLabelEntry>
{
/// <summary>
/// Whether the inspector will auto-assign ids based on the id of the first element.
/// </summary>

25
com.unity.perception/Runtime/GroundTruth/Labeling/LabelConfig.cs


using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine.Serialization;
namespace UnityEngine.Perception.GroundTruth

/// </summary>
public const string labelEntriesFieldName = nameof(m_LabelEntries);
/// <summary>
/// List of LabelEntry items added to this label configuration
/// </summary>
List<T> m_LabelEntries = new List<T>();
protected List<T> m_LabelEntries = new List<T>();
/// Name of the public accessor for the list of label entries, used for reflection purposes.
/// </summary>
public const string publicLabelEntriesFieldName = nameof(labelEntries);
/// <summary>
/// A sequence of <see cref="ILabelEntry"/> which defines the labels relevant for this configuration and their values.
/// </summary>
public IReadOnlyList<T> labelEntries => m_LabelEntries;

public bool TryGetMatchingConfigurationEntry(Labeling labeling, out T labelEntry)
{
return TryGetMatchingConfigurationEntry(labeling, out labelEntry, out int _);
}
/// <summary>
/// Name of the function that checks whether a given string matches any of the label entries in this label configuration, used for reflection purposes.
/// </summary>
public const string DoesLabelMatchAnEntryName = nameof(DoesLabelMatchAnEntry);
/// <summary>
/// Does the given string match any of the label entries added to this label configuration.
/// </summary>
/// <param name="label"></param>
/// <returns></returns>
public bool DoesLabelMatchAnEntry(string label)
{
return m_LabelEntries.Any(entry => string.Equals(entry.label, label));
}
/// <summary>

37
com.unity.perception/Runtime/GroundTruth/Labeling/Labeling.cs


using System;
using UnityEngine;
using UnityEditor;
using UnityEngine.Serialization;
namespace UnityEngine.Perception.GroundTruth

/// The label names to associate with the GameObject. Modifications to this list after the Update() step of the frame the object is created in are
/// not guaranteed to be reflected by labelers.
/// </summary>
[FormerlySerializedAs("classes")]
public List<string> labels = new List<string>();
[FormerlySerializedAs("classes")] public List<string> labels = new List<string>();
// /// <summary>
// /// A list for backing up the asset's manually added labels, so that if the user switches to auto labeling and back, the previously added labels can be revived
// /// </summary>
// public List<string> manualLabelsBackup = new List<string>();
/// <summary>
/// Whether this labeling component is currently using an automatic labeling scheme. When this is enabled, the asset can have only one label (the automatic one) and the user cannot add more labels.
/// </summary>
public bool useAutoLabeling;
/// <summary>
/// The specific subtype of AssetLabelingScheme that this component is using, if useAutoLabeling is enabled.
/// </summary>
public string autoLabelingSchemeType = string.Empty;
/// <summary>
/// The unique id of this labeling component instance

{
this.instanceId = instanceId;
}
void Awake()
{
m_Entity = World.DefaultGameObjectInjectionWorld.EntityManager.CreateEntity();

World.DefaultGameObjectInjectionWorld.EntityManager.DestroyEntity(m_Entity);
}
void Reset()
{
labels.Clear();
useAutoLabeling = false;
autoLabelingSchemeType = string.Empty;
#if UNITY_EDITOR
EditorUtility.SetDirty(gameObject);
#endif
}
/// <summary>
/// Refresh ground truth generation for the labeling of the attached GameObject. This is necessary when the
/// list of labels changes or when renderers or materials change on objects in the hierarchy.

World.DefaultGameObjectInjectionWorld.GetOrCreateSystem<GroundTruthLabelSetupSystem>().RefreshLabeling(m_Entity);
World.DefaultGameObjectInjectionWorld.GetOrCreateSystem<GroundTruthLabelSetupSystem>()
.RefreshLabeling(m_Entity);
}
}
}

13
com.unity.perception/Runtime/GroundTruth/Labeling/SemanticSegmentationLabelConfig.cs


using System;
using System.Collections.Generic;
namespace UnityEngine.Perception.GroundTruth {
/// <summary>

public class SemanticSegmentationLabelConfig : LabelConfig<SemanticSegmentationLabelEntry>
{
/// <summary>
/// List of standard color based on which this type of label configuration assigns new colors to added labels.
/// </summary>
public static readonly List<Color> s_StandardColors = new List<Color>()
{
Color.blue,
Color.green,
Color.red,
Color.white,
Color.yellow,
Color.gray
};
}
/// <summary>

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


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

392
com.unity.perception/Editor/GroundTruth/AddToConfigWindow.cs


using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.Perception.GroundTruth;
using UnityEngine.UIElements;
using Object = UnityEngine.Object;
using Random = UnityEngine.Random;
namespace UnityEditor.Perception.GroundTruth
{
class AddToConfigWindow : EditorWindow
{
private VisualElement m_Root;
private string m_UxmlDir = "Packages/com.unity.perception/Editor/GroundTruth/Uxml/";
private string m_UxmlPath;
private static List<string> m_LabelValues = new List<string>();
private static Label m_TitleLabel;
private static Label m_Status;
public void SetStatus(string status)
{
m_Status.text = status;
m_Status.style.display = DisplayStyle.Flex;
}
private List<string> m_AllLabelConfigGuids = new List<string>();
private List<ScriptableObject> m_ConfigsContainingLabel = new List<ScriptableObject>();
private List<ScriptableObject> m_ConfigsNotContainingLabel = new List<ScriptableObject>();
private static ListView m_PresentConfigsListview;
private static ListView m_NonPresentConfigsListview;
private static ListView m_SelectedLabelsListview;
private static Label m_CurrentlyPresentTitle;
private static Label m_OtherConfigsTitle;
private List<Type> m_LabelConfigTypes = new List<Type>();
public static void ShowWindow(string labelValue)
{
m_LabelValues.Clear();
m_LabelValues.Add(labelValue);
ShowWindow(m_LabelValues);
}
public static void ShowWindow(List<string> labelValues)
{
m_LabelValues = new List<string>(labelValues);
var window = GetWindow<AddToConfigWindow>();
if (labelValues.Count == 1)
{
if(m_TitleLabel != null)
m_TitleLabel.text = "Label: \"" + m_LabelValues.First() + "\"";
if (m_PresentConfigsListview != null)
{
m_PresentConfigsListview.style.display = DisplayStyle.Flex;
}
if (m_CurrentlyPresentTitle != null)
{
m_CurrentlyPresentTitle.style.display = DisplayStyle.Flex;
}
if (m_OtherConfigsTitle != null)
{
m_OtherConfigsTitle.text = "Other Label Configs in Project";
}
if (m_NonPresentConfigsListview != null)
{
m_NonPresentConfigsListview.style.height = 150;
}
if (m_SelectedLabelsListview != null)
{
m_SelectedLabelsListview.style.display = DisplayStyle.None;
}
window.titleContent = new GUIContent("Manage Label");
window.minSize = new Vector2(400, 390);
window.maxSize = new Vector2(400, 390);
}
else
{
if(m_TitleLabel != null)
m_TitleLabel.text = "Labels to Add";
if (m_PresentConfigsListview != null)
{
m_PresentConfigsListview.style.display = DisplayStyle.None;
}
if (m_CurrentlyPresentTitle != null)
{
m_CurrentlyPresentTitle.style.display = DisplayStyle.None;
}
if (m_OtherConfigsTitle != null)
{
m_OtherConfigsTitle.text = "All Label Configurations in Project";
}
if (m_NonPresentConfigsListview != null)
{
m_NonPresentConfigsListview.style.height = 250;
}
if (m_SelectedLabelsListview != null)
{
m_SelectedLabelsListview.style.display = DisplayStyle.Flex;
}
window.titleContent = new GUIContent("Manage Labels");
window.minSize = new Vector2(400, 370);
window.maxSize = new Vector2(400, 1000);
}
window.Init();
}
void Init()
{
Show();
m_ConfigsContainingLabel.Clear();
m_LabelConfigTypes = FindAllSubTypes(typeof(LabelConfig<>));
RefreshConfigAssets();
CheckInclusionInConfigs(m_AllLabelConfigGuids, m_LabelValues.Count == 1? m_LabelValues.First() : null);
SetupListViews();
}
void RefreshConfigAssets()
{
AssetDatabase.Refresh();
m_AllLabelConfigGuids.Clear();
foreach (var type in m_LabelConfigTypes)
{
m_AllLabelConfigGuids.AddRange(AssetDatabase.FindAssets("t:"+type.Name));
}
}
void SetupListViews()
{
//configs containing label
if (m_LabelValues.Count == 1)
{
//we are dealing with only one label
m_PresentConfigsListview.itemsSource = m_ConfigsContainingLabel;
VisualElement MakeItem1() => new ConfigElementLabelPresent(this, m_LabelValues.First());
void BindItem1(VisualElement e, int i)
{
if (e is ConfigElementLabelPresent element)
{
element.m_Label.text = m_ConfigsContainingLabel[i].name;
element.m_LabelConfig = m_ConfigsContainingLabel[i];
}
}
m_PresentConfigsListview.itemHeight = 30;
m_PresentConfigsListview.bindItem = BindItem1;
m_PresentConfigsListview.makeItem = MakeItem1;
m_PresentConfigsListview.selectionType = SelectionType.None;
}
//Configs not containing label
m_NonPresentConfigsListview.itemsSource = m_ConfigsNotContainingLabel;
VisualElement MakeItem2() => new ConfigElementLabelNotPresent(this, m_LabelValues);
void BindItem2(VisualElement e, int i)
{
if (e is ConfigElementLabelNotPresent element)
{
element.m_Label.text = m_ConfigsNotContainingLabel[i].name;
element.m_LabelConfig = m_ConfigsNotContainingLabel[i];
}
}
m_NonPresentConfigsListview.itemHeight = 30;
m_NonPresentConfigsListview.bindItem = BindItem2;
m_NonPresentConfigsListview.makeItem = MakeItem2;
m_NonPresentConfigsListview.selectionType = SelectionType.None;
//Selected labels
m_SelectedLabelsListview.itemsSource = m_LabelValues;
VisualElement MakeItem3() => new Label();
void BindItem3(VisualElement e, int i)
{
if (e is Label label)
{
label.text = m_LabelValues[i];
label.style.marginLeft = 2;
label.style.marginRight = 2;
}
}
m_SelectedLabelsListview.itemHeight = 20;
m_SelectedLabelsListview.bindItem = BindItem3;
m_SelectedLabelsListview.makeItem = MakeItem3;
m_SelectedLabelsListview.selectionType = SelectionType.None;
}
public void RefreshLists()
{
CheckInclusionInConfigs(m_AllLabelConfigGuids, m_LabelValues.Count == 1? m_LabelValues.First() : null);
m_PresentConfigsListview.Refresh();
m_NonPresentConfigsListview.Refresh();
}
void OnEnable()
{
m_UxmlPath = m_UxmlDir + "AddToConfigWindow.uxml";
m_Root = rootVisualElement;
AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(m_UxmlPath).CloneTree(m_Root);
m_TitleLabel = m_Root.Q<Label>("title");
m_CurrentlyPresentTitle = m_Root.Q<Label>("currently-present-label");
m_OtherConfigsTitle = m_Root.Q<Label>("other-configs-label");
m_PresentConfigsListview = m_Root.Q<ListView>("current-configs-listview");
m_NonPresentConfigsListview = m_Root.Q<ListView>("other-configs-listview");
m_SelectedLabelsListview = m_Root.Q<ListView>("selected-labels-list");
m_Status = m_Root.Q<Label>("status");
m_Status.style.display = DisplayStyle.None;
}
void CheckInclusionInConfigs(List<string> configGuids, string label = null)
{
m_ConfigsContainingLabel.Clear();
m_ConfigsNotContainingLabel.Clear();
foreach (var configGuid in configGuids)
{
var asset = AssetDatabase.LoadAssetAtPath<ScriptableObject>(AssetDatabase.GUIDToAssetPath(configGuid));
if (label != null)
{
//means we are dealing with only one label not a set
var methodInfo = asset.GetType().GetMethod(IdLabelConfig.DoesLabelMatchAnEntryName);
if (methodInfo == null)
continue;
object[] parametersArray = new object[1];
parametersArray[0] = label;
var labelExistsInConfig = (bool) methodInfo.Invoke(asset, parametersArray);
if (labelExistsInConfig)
{
m_ConfigsContainingLabel.Add(asset);
}
else
{
m_ConfigsNotContainingLabel.Add(asset);
}
}
else
{
m_ConfigsNotContainingLabel.Add(asset);
}
}
}
public static List<Type> FindAllSubTypes(Type superType)
{
Assembly assembly = Assembly.GetAssembly(superType);
Type[] types = assembly.GetTypes();
List<Type> subclasses = types.Where(t => IsSubclassOfRawGeneric(superType, t)).ToList();
return subclasses;
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;
}
}
}
class ConfigElementLabelPresent : VisualElement
{
private string m_UxmlDir = "Packages/com.unity.perception/Editor/GroundTruth/Uxml/";
private VisualElement m_Root;
private ObjectField m_ConfigObjectField;
public Label m_Label;
public ScriptableObject m_LabelConfig;
public ConfigElementLabelPresent(AddToConfigWindow window, string targetLabel)
{
var uxmlPath = m_UxmlDir + "ConfigElementLabelPresent.uxml";
AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(uxmlPath).CloneTree(this);
m_Label = this.Q<Label>("config-name");
var removeButton = this.Q<Button>("remove-from-config-button");
removeButton.text = "Remove Label";
var openButton = this.Q<Button>("open-config-button");
openButton.clicked += () =>
{
Selection.SetActiveObjectWithContext(m_LabelConfig, null);
};
removeButton.clicked += () =>
{
var editor = Editor.CreateEditor(m_LabelConfig);
if (editor is SemanticSegmentationLabelConfigEditor semanticEditor)
{
semanticEditor.RemoveLabel(targetLabel);
}
else if (editor is IdLabelConfigEditor idEditor)
{
idEditor.RemoveLabel(targetLabel);
}
window.RefreshLists();
//AssetDatabase.SaveAssets();
Object.DestroyImmediate(editor);
};
}
}
class ConfigElementLabelNotPresent : VisualElement
{
private string m_UxmlDir = "Packages/com.unity.perception/Editor/GroundTruth/Uxml/";
private VisualElement m_Root;
private ObjectField m_ConfigObjectField;
public Label m_Label;
public ScriptableObject m_LabelConfig;
public ConfigElementLabelNotPresent(AddToConfigWindow window, List<string> targetLabels)
{
var uxmlPath = m_UxmlDir + "ConfigElementLabelPresent.uxml";
AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(uxmlPath).CloneTree(this);
m_Label = this.Q<Label>("config-name");
var addButton = this.Q<Button>("remove-from-config-button");
addButton.text = targetLabels.Count ==1 ? "Add Label" : "Add All Labels";
var openButton = this.Q<Button>("open-config-button");
openButton.clicked += () =>
{
Selection.SetActiveObjectWithContext(m_LabelConfig, null);
};
addButton.clicked += () =>
{
var editor = Editor.CreateEditor(m_LabelConfig);
if (editor is SemanticSegmentationLabelConfigEditor semanticEditor)
{
foreach (var label in targetLabels)
{
semanticEditor.AddLabel(label);
}
}
else if (editor is IdLabelConfigEditor idEditor)
{
foreach (var label in targetLabels)
{
idEditor.AddLabel(label);
}
}
if (targetLabels.Count > 1)
{
window.SetStatus("All Labels Added to " + m_LabelConfig.name);
}
window.RefreshLists();
//AssetDatabase.SaveAssets();
Object.DestroyImmediate(editor);
};
}
}
}

3
com.unity.perception/Editor/GroundTruth/AddToConfigWindow.cs.meta


fileFormatVersion: 2
guid: 2485979b726fe4f3b829a3a4173a72c6
timeCreated: 1585933334

456
com.unity.perception/Editor/GroundTruth/LabelConfigEditor.cs


using System.Collections.Generic;
using System.IO;
using System.Linq;
using Newtonsoft.Json.Linq;
using UnityEngine;
using UnityEngine.Perception.GroundTruth;
using UnityEngine.UIElements;
using UnityEditor.UIElements;
namespace UnityEditor.Perception.GroundTruth
{
abstract class LabelConfigEditor<T> : Editor where T : ILabelEntry
{
private string m_UxmlDir = "Packages/com.unity.perception/Editor/GroundTruth/Uxml/";
private string m_UxmlPath;
private int m_AddedLabelsItemHeight = 37;
private int m_OtherLabelsItemHeight = 27;
private List<string> m_AddedLabels = new List<string>();
protected SerializedProperty m_SerializedLabelsArray;
private static HashSet<string> allLabelsInProject = new HashSet<string>();
private List<string> m_LabelsNotPresentInConfig = new List<string>();
private bool m_UiInitialized;
private bool m_EditorHasUi;
private VisualElement m_Root;
private Button m_SaveButton;
private Button m_AddNewLabelButton;
private Button m_RemoveAllButton;
private Button m_AddAllButton;
private Button m_ImportFromFileButton;
private Button m_ExportToFileButton;
private ListView m_NonPresentLabelsListView;
protected ListView m_LabelListView;
protected Button m_MoveUpButton;
protected Button m_MoveDownButton;
protected VisualElement m_MoveButtons;
protected VisualElement m_IdSpecificUi;
protected EnumField m_StartingIdEnumField;
protected Toggle m_AutoIdToggle;
public void OnEnable()
{
m_SerializedLabelsArray = serializedObject.FindProperty(IdLabelConfig.labelEntriesFieldName);
m_UiInitialized = false;
ChangesHappeningInForeground = true;
RefreshListDataAndPresentation();
}
private int m_PreviousLabelsArraySize = -1;
/// <summary>
/// This boolean is used to signify when changes in the model are triggered directly from the inspector UI by the user.
/// In these cases, the scheduled model checker does not need to update the UI again.
/// </summary>
public bool ChangesHappeningInForeground { get; set; }
private void CheckForModelChanges()
{
if (ChangesHappeningInForeground)
{
ChangesHappeningInForeground = false;
m_PreviousLabelsArraySize = m_SerializedLabelsArray.arraySize;
return;
}
if (m_SerializedLabelsArray.arraySize != m_PreviousLabelsArraySize)
{
RefreshListDataAndPresentation();
m_PreviousLabelsArraySize = m_SerializedLabelsArray.arraySize;
}
}
protected abstract void InitUiExtended();
public abstract void PostRemoveOperations();
public override VisualElement CreateInspectorGUI()
{
if (!m_UiInitialized)
{
InitUi();
m_UiInitialized = true;
}
serializedObject.Update();
RefreshListDataAndPresentation();
return m_Root;
}
private void InitUi()
{
m_EditorHasUi = true;
m_UxmlPath = m_UxmlDir + "LabelConfig_Main.uxml";
m_Root = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(m_UxmlPath).CloneTree();
m_LabelListView = m_Root.Q<ListView>("labels-listview");
m_NonPresentLabelsListView = m_Root.Q<ListView>("labels-in-project-listview");
m_SaveButton = m_Root.Q<Button>("save-button");
m_AddNewLabelButton = m_Root.Q<Button>("add-label");
m_RemoveAllButton = m_Root.Q<Button>("remove-all-labels");
m_MoveUpButton = m_Root.Q<Button>("move-up-button");
m_MoveDownButton = m_Root.Q<Button>("move-down-button");
m_MoveButtons = m_Root.Q<VisualElement>("move-buttons");
m_ImportFromFileButton = m_Root.Q<Button>("import-file-button");
m_ExportToFileButton = m_Root.Q<Button>("export-file-button");
m_AddAllButton = m_Root.Q<Button>("add-all-labels-in-project");
m_StartingIdEnumField = m_Root.Q<EnumField>("starting-id-dropdown");
m_AutoIdToggle = m_Root.Q<Toggle>("auto-id-toggle");
m_IdSpecificUi = m_Root.Q<VisualElement>("id-specific-ui");
m_SaveButton.SetEnabled(false);
SetupPresentLabelsListView();
RefreshLabelsMasterList();
RefreshNonPresentLabels();
SetupNonPresentLabelsListView();
InitUiExtended();
UpdateMoveButtonState(null);
m_AddNewLabelButton.clicked += () => { AddNewLabel(m_AddedLabels); };
m_LabelListView.onSelectionChanged += UpdateMoveButtonState;
m_RemoveAllButton.clicked += () =>
{
m_SerializedLabelsArray.ClearArray();
serializedObject.ApplyModifiedProperties();
ChangesHappeningInForeground = true;
RefreshListDataAndPresentation();
};
m_AddAllButton.clicked += () =>
{
foreach (var label in m_LabelsNotPresentInConfig)
{
AppendLabelEntryToSerializedArray(m_SerializedLabelsArray, CreateLabelEntryFromLabelString(m_SerializedLabelsArray, label));
}
serializedObject.ApplyModifiedProperties();
ChangesHappeningInForeground = true;
RefreshListDataAndPresentation();
};
m_ImportFromFileButton.clicked += () =>
{
var path = EditorUtility.OpenFilePanel("Import label configuration from file", "", "json");
if (path.Length != 0)
{
var fileContent = File.ReadAllText(path);
var jsonObj = JObject.Parse(fileContent);
ImportFromJson(jsonObj);
}
};
m_ExportToFileButton.clicked += () =>
{
var path = EditorUtility.SaveFilePanel("Export label configuration to file", "", this.name, "json");
if (path.Length != 0)
{
string fileContents = ExportToJson();
var writer = File.CreateText(path);
writer.Write(fileContents);
writer.Flush();
writer.Close();
}
};
m_Root.schedule.Execute(CheckForModelChanges).Every(30);
}
static void RefreshLabelsMasterList()
{
allLabelsInProject.Clear();
var allPrefabPaths = GetAllPrefabsInProject();
foreach (var path in allPrefabPaths)
{
var asset = AssetDatabase.LoadAssetAtPath<GameObject>(path);
var labeling = asset.GetComponent<Labeling>();
if (labeling)
{
allLabelsInProject.UnionWith(labeling.labels);
}
}
}
private void RefreshNonPresentLabels()
{
m_LabelsNotPresentInConfig.Clear();
m_LabelsNotPresentInConfig.AddRange(allLabelsInProject);
m_LabelsNotPresentInConfig.RemoveAll(label => m_AddedLabels.Contains(label));
}
private static IEnumerable<string> GetAllPrefabsInProject()
{
var allPaths = AssetDatabase.GetAllAssetPaths();
return allPaths.Where(path => path.EndsWith(".prefab")).ToList();
}
private void UpdateMoveButtonState(IEnumerable<object> objectList)
{
var selectedIndex = m_LabelListView.selectedIndex;
m_MoveDownButton.SetEnabled(selectedIndex < m_LabelListView.itemsSource.Count - 1);
m_MoveUpButton.SetEnabled(selectedIndex > 0);
}
public void RefreshListDataAndPresentation()
{
serializedObject.Update();
RefreshAddedLabels();
if (m_EditorHasUi && m_UiInitialized)
{
RefreshNonPresentLabels();
m_NonPresentLabelsListView.Refresh();
RefreshListViewHeight();
m_LabelListView.Refresh();
}
}
private void ScrollToBottomAndSelectLastItem()
{
m_LabelListView.selectedIndex = m_LabelListView.itemsSource.Count - 1;
UpdateMoveButtonState(null);
m_Root.schedule.Execute(() => { m_LabelListView.ScrollToItem(-1); })
.StartingIn(
10); //to circumvent the delay in listview's internal scrollview updating its geometry (when new items are added).
}
protected void RefreshAddedLabels()
{
m_AddedLabels.Clear();
m_SerializedLabelsArray = serializedObject.FindProperty(IdLabelConfig.labelEntriesFieldName);
for (int i = 0; i < m_SerializedLabelsArray.arraySize; i++)
{
m_AddedLabels.Add(m_SerializedLabelsArray.GetArrayElementAtIndex(i).FindPropertyRelative(nameof(ILabelEntry.label)).stringValue);
}
}
protected virtual void SetupPresentLabelsListView()
{
m_LabelListView.itemsSource = m_AddedLabels;
m_LabelListView.itemHeight = m_AddedLabelsItemHeight;
m_LabelListView.selectionType = SelectionType.Single;
m_LabelListView.RegisterCallback<AttachToPanelEvent>(evt => { RefreshListViewHeight(); });
}
private void SetupNonPresentLabelsListView()
{
m_NonPresentLabelsListView.itemsSource = m_LabelsNotPresentInConfig;
VisualElement MakeItem()
{
var element = new NonPresentLabelElement<T>(this);
return element;
}
void BindItem(VisualElement e, int i)
{
if (e is NonPresentLabelElement<T> nonPresentLabel)
{
nonPresentLabel.m_Label.text = m_LabelsNotPresentInConfig[i];
}
}
m_NonPresentLabelsListView.bindItem = BindItem;
m_NonPresentLabelsListView.makeItem = MakeItem;
m_NonPresentLabelsListView.itemHeight = m_OtherLabelsItemHeight;
m_NonPresentLabelsListView.selectionType = SelectionType.None;
}
protected void RefreshListViewHeight()
{
m_LabelListView.style.minHeight =
Mathf.Clamp(m_LabelListView.itemsSource.Count * m_LabelListView.itemHeight, 300, 600);
}
string FindNewLabelString(List<string> labels)
{
string baseLabel = "New Label";
string label = baseLabel;
int count = 1;
while (labels.Contains(label))
{
label = baseLabel + "_" + count++;
}
return label;
}
private void AddNewLabel(List<string> presentLabels)
{
AddLabel(FindNewLabelString(presentLabels));
}
public void AddLabel(string labelToAdd)
{
if (m_AddedLabels.Contains(labelToAdd)) //label has already been added, cannot add again
return;
AppendLabelEntryToSerializedArray(m_SerializedLabelsArray, CreateLabelEntryFromLabelString(m_SerializedLabelsArray, labelToAdd));
serializedObject.ApplyModifiedProperties();
RefreshListDataAndPresentation();
if (m_EditorHasUi)
ScrollToBottomAndSelectLastItem();
}
public void RemoveLabel(string labelToRemove)
{
var index = IndexOfStringLabelInSerializedLabelsArray(labelToRemove);
if (index >= 0)
{
m_SerializedLabelsArray.DeleteArrayElementAtIndex(index);
}
serializedObject.ApplyModifiedProperties();
RefreshListDataAndPresentation();
if (m_EditorHasUi)
ScrollToBottomAndSelectLastItem();
}
protected abstract T CreateLabelEntryFromLabelString(SerializedProperty serializedArray, string labelToAdd);
protected abstract void AppendLabelEntryToSerializedArray(SerializedProperty serializedArray, T labelEntry);
void ImportFromJson(JObject jsonObj)
{
Undo.RegisterCompleteObjectUndo(serializedObject.targetObject, "Import new label config");
JsonUtility.FromJsonOverwrite(jsonObj.ToString(), serializedObject.targetObject);
ChangesHappeningInForeground = true;
RefreshListDataAndPresentation();
}
private string ExportToJson()
{
return JsonUtility.ToJson(serializedObject.targetObject);
}
public int IndexOfStringLabelInSerializedLabelsArray(string label)
{
for (int i = 0; i < m_SerializedLabelsArray.arraySize; i++)
{
var element = m_SerializedLabelsArray.GetArrayElementAtIndex(i).FindPropertyRelative(nameof(ILabelEntry.label));
if (element.stringValue == label)
{
return i;
}
}
return -1;
}
}
internal abstract class LabelElementInLabelConfig<T> : VisualElement where T : ILabelEntry
{
protected const string UxmlDir = "Packages/com.unity.perception/Editor/GroundTruth/Uxml/";
protected abstract string UxmlPath { get; }
private Button m_RemoveButton;
public TextField m_LabelTextField;
public int m_IndexInList;
protected SerializedProperty m_LabelsArray;
protected LabelConfigEditor<T> m_LabelConfigEditor;
protected LabelElementInLabelConfig(LabelConfigEditor<T> editor, SerializedProperty labelsArray)
{
m_LabelConfigEditor = editor;
m_LabelsArray = labelsArray;
Init();
}
private void Init()
{
AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(UxmlPath).CloneTree(this);
m_LabelTextField = this.Q<TextField>("label-value");
m_RemoveButton = this.Q<Button>("remove-button");
m_LabelTextField.isDelayed = true;
InitExtended();
m_LabelTextField.RegisterValueChangedCallback((cEvent) =>
{
int index = m_LabelConfigEditor.IndexOfStringLabelInSerializedLabelsArray(cEvent.newValue);
if (index != -1 && index != m_IndexInList)
{
//The listview recycles child visual elements and that causes the RegisterValueChangedCallback event to be called when scrolling.
//Therefore, we need to make sure we are not in this code block just because of scrolling, but because the user is actively changing one of the labels.
//The index check is for this purpose.
Debug.LogError("A label with the string " + cEvent.newValue + " has already been added to this label configuration.");
m_LabelsArray.GetArrayElementAtIndex(m_IndexInList).FindPropertyRelative(nameof(ILabelEntry.label))
.stringValue = cEvent.previousValue; //since the textfield is bound to this property, it has already changed the property, so we need to revert the proprty.
m_LabelsArray.serializedObject.ApplyModifiedProperties();
m_LabelConfigEditor.ChangesHappeningInForeground = true;
m_LabelConfigEditor.RefreshListDataAndPresentation();
return;
}
//even though the textfield is already bound to the relevant property, we need to explicitly set the
//property here too in order to make "hasModifiedProperties" return the right value in the next line. Otherwise it will always be false.
m_LabelsArray.GetArrayElementAtIndex(m_IndexInList).FindPropertyRelative(nameof(ILabelEntry.label))
.stringValue = cEvent.newValue;
if (m_LabelsArray.serializedObject.hasModifiedProperties)
{
//the value change event is called even when the listview recycles its child elements for re-use during scrolling, therefore, we should check to make sure there are modified properties, otherwise we would be doing the refresh for no reason (reduces scrolling performance)
m_LabelsArray.serializedObject.ApplyModifiedProperties();
m_LabelConfigEditor.ChangesHappeningInForeground = true;
m_LabelConfigEditor.RefreshListDataAndPresentation();
}
});
m_RemoveButton.clicked += () =>
{
m_LabelsArray.DeleteArrayElementAtIndex(m_IndexInList);
m_LabelConfigEditor.PostRemoveOperations();
m_LabelConfigEditor.serializedObject.ApplyModifiedProperties();
m_LabelConfigEditor.ChangesHappeningInForeground = true;
m_LabelConfigEditor.RefreshListDataAndPresentation();
};
}
protected abstract void InitExtended();
}
class NonPresentLabelElement<T> : VisualElement where T : ILabelEntry
{
private string m_UxmlDir = "Packages/com.unity.perception/Editor/GroundTruth/Uxml/";
public Label m_Label;
public NonPresentLabelElement(LabelConfigEditor<T> editor)
{
var uxmlPath = m_UxmlDir + "SuggestedLabelElement.uxml";
AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(uxmlPath).CloneTree(this);
m_Label = this.Q<Label>("label-value");
var addButton = this.Q<Button>("add-button");
addButton.clicked += () => { editor.AddLabel(m_Label.text); };
}
}
}

3
com.unity.perception/Editor/GroundTruth/LabelConfigEditor.cs.meta


fileFormatVersion: 2
guid: ffb8bb7ed73a343f3ae88c68aaf8a84f
timeCreated: 1585940009

8
com.unity.perception/Editor/GroundTruth/Uss.meta


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

8
com.unity.perception/Editor/GroundTruth/Uxml.meta


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

11
com.unity.perception/Editor/AssetPreparation/AssetPreparationTools.cs.meta


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

24
com.unity.perception/Editor/AssetPreparation/AssetPreparationTools.cs


using System.IO;
using UnityEngine;
namespace UnityEditor.Perception.AssetPreparation
{
public class CreatePrefabFromSelectedAssets : MonoBehaviour
{
/// <summary>
/// Function for creating prefabs from multiple models with one click. Created prefabs will be placed in the same folder as their corresponding model.
/// </summary>
[MenuItem("Assets/Perception/Create Prefabs from Selected Models")]
static void CreatePrefabsFromSelectedModels()
{
foreach (var selection in Selection.gameObjects)
{
var path = AssetDatabase.GetAssetPath(selection);
var tmpGameObject = Instantiate(selection);
var destinationPath = Path.GetDirectoryName(path) + "/" + selection.name + ".prefab";
PrefabUtility.SaveAsPrefabAsset(tmpGameObject, destinationPath);
DestroyImmediate(tmpGameObject);
}
}
}
}

3
com.unity.perception/Editor/GroundTruth/Uss/Styles.uss.meta


fileFormatVersion: 2
guid: dbe9e8ec4b8ef4ff384a22001ff72674
timeCreated: 1601665266

228
com.unity.perception/Editor/GroundTruth/Uss/Styles.uss


.labeling__remove-item-button {
width: 16px;
height: 16px;
background-image: resource('Packages/com.unity.perception/Editor/Icons/X.png');
background-color: #505050;
align-self: center;
}
.labeling__remove-item-button:hover {
background-color: #808080;
}
.added-label {
margin: 3px 4px 3px 4px;
flex-direction: row;
align-content: center;
}
.labeling__added-label-value {
width: 40%;
flex-grow: 1;
color: black;
}
.labeling__added-label-value > .unity-text-field__input {
color: rgb(195, 195, 195);
background-color: #313131;
border-width: 0;
}
.suggested-label {
flex-direction: row;
align-content: center;
margin: 4px 6px 0 6px;
padding: 2px;
padding-left: 5px;
border-radius: 4px;
background-color: #313131;
}
.labeling__suggested-label-value {
width: auto;
flex-grow: 1;
align-self: center;
color: rgb(180, 180, 180);
}
.labeling__label-listview {
flex-grow: 1;
min-height: 120px;
border-radius: 4px;
margin-right: 2px;
margin-top: 2px;
padding: 6px;
padding-top: 6px;
border-bottom-right-radius: 0;
background-color: #272727;
}
.labeling__configs-listview {
flex-grow: 1;
min-height: 150px;
background-color: rgb(32, 32, 32);
border-radius: 4px;
margin: 6px;
padding: 6px;
border-bottom-right-radius: 0;
}
.labeling__add-label-button {
align-self: flex-end;
border-top-right-radius: 0;
border-top-left-radius: 0;
background-color: #222222;
border-color: #707070;
border-width: 0;
margin-right: 2px;
margin-top: 2px;
border-radius: 2px;
color: #CACACA;
}
.labeling__add-label-button:hover{
background-color: #606060;
}
.labeling__add-label-button:active{
background-color: #303030;
}
.outer-container {
padding-top: 5px;
flex-grow: 1;
}
.outer-container-in-window{
padding: 7px;
}
.inner-container {
margin-top: 5px;
border-radius: 4px;
border-width: 1px;
padding: 5px;
background-color: #454545;
align-content: flex-start;
}
.inner-container .depth2{
background-color: rgb(60, 60, 60);
}
.labeling__add-to-list-button {
align-self: flex-end;
background-color: #505050;
border-width: 0;
color: #EEEEEE;
}
.labeling__add-to-config-button {
padding: 6px;
flex-shrink: 1;
-unity-text-align: middle-left;
background-color: #505050;
border-width: 0;
color: #EEEEEE;
}
.title-label {
-unity-font-style: bold;
margin-bottom: 5px;
color: #CACACA;
}
.subtitle-label {
color: #CACACA;
}
.collapse-toggle {
flex-shrink: 0;
margin-right: 3px;
margin-left: 3px;
width: 10px;
height: 10px;
align-self: center;
background-image: resource("Packages/com.unity.perception/Editor/Icons/FoldoutOpen.png");
}
.collapsed-toggle-state{
background-image: resource("Packages/com.unity.perception/Editor/Icons/FoldoutClosed.png");
}
.collapse-toggle:hover {
-unity-background-image-tint-color: cornflowerblue;
}
.label-config-header{
background-color: #272727;
flex-direction: row;
}
.suggested-label.label_add_from_config{
margin: 3px 3px 3px 3px;
}
.label-config-add-from{
border-radius: 4px;
margin: 2px 0 2px 0;
background-color: #272727;
padding: 3px 1px 3px 1px;
}
.labeling__config-name-label {
color: rgb(220, 220, 220);
width: auto;
flex-grow: 1;
align-self: center;
padding: 4px;
}
.collapsed {
display: none;
}
.config-label-present{
flex-direction: row;
align-content: center;
border-radius: 4px;
margin: 3px;
background-color: #272727;
}
.move-label-in-config-button{
background-color: #505050;
width: 30px;
height: 16px;
align-self: center;
-unity-background-scale-mode: scale-to-fit;
}
.move-up{
background-image: resource('Packages/com.unity.perception/Editor/Icons/ChevronUpPadded.png');
}
.move-down{
background-image: resource('Packages/com.unity.perception/Editor/Icons/ChevronDownPadded.png');
}
.move-label-in-config-button:hover{
background-color: #808080;
}
.move-label-in-config-button:active{
background-color: #303030;
}
.generic-hover:hover{
background-color: #555555;
}
.helpbox{
border-width: 1px;
border-color: #808080;
border-radius: 4px;
padding: 7px;
white-space: normal;
margin-top: 4px;
margin-bottom: 4px;
}

13
com.unity.perception/Editor/GroundTruth/Uxml/AddToConfigWindow.uxml


<UXML xmlns="UnityEngine.UIElements">
<VisualElement class="outer-container-in-window" name="outer-container">
<Style src="../Uss/Styles.uss"/>
<Label name="title" class="title-label"/>
<ListView name="selected-labels-list" class="labeling__label-listview" style="height:800px; margin: 0;"/>
<Label name="currently-present-label" text="Currently Present In:" style="margin: 10px 0 4px 0"/>
<ListView name="current-configs-listview" class="labeling__configs-listview" style="height:150px; margin: 0; max-height:150px"/>
<Label name="other-configs-label" style="margin: 10px 0 4px 0"/>
<ListView name="other-configs-listview" class="labeling__configs-listview" style="height:150px; margin: 0; max-height:150px"/>
<Label name="status" style="display:none; margin-top: 7px; -unity-font-style: bold; color:yellow"/>
</VisualElement>
</UXML>

10
com.unity.perception/Editor/GroundTruth/Uxml/AddToConfigWindow.uxml.meta


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

7
com.unity.perception/Editor/GroundTruth/Uxml/AddedLabelElement.uxml


<UXML xmlns="UnityEngine.UIElements">
<VisualElement class="added-label">
<Button name="remove-button" class="labeling__remove-item-button" />
<TextField name="label-value" class="labeling__added-label-value" />
<Button name="add-to-config-button" text="Add to Label Config..." class="labeling__add-to-config-button" />
</VisualElement>
</UXML>

3
com.unity.perception/Editor/GroundTruth/Uxml/AddedLabelElement.uxml.meta


fileFormatVersion: 2
guid: ab7eae2a6fad4a95ac73aa5d46704ef6
timeCreated: 1603311500

7
com.unity.perception/Editor/GroundTruth/Uxml/ConfigElementLabelNotPresent.uxml


<UXML xmlns="UnityEngine.UIElements">
<VisualElement>
<Style src="../Uss/Styles.uss"/>
<Label name="config-name" class="labeling__config-name-label"/>
<Button name="add-to-config-button" class="labeling__addremove-config-button"/>
</VisualElement>
</UXML>

3
com.unity.perception/Editor/GroundTruth/Uxml/ConfigElementLabelNotPresent.uxml.meta


fileFormatVersion: 2
guid: 5335f0007841a4aae96d6ec9e95d1b39
timeCreated: 1603311500

8
com.unity.perception/Editor/GroundTruth/Uxml/ConfigElementLabelPresent.uxml


<UXML xmlns="UnityEngine.UIElements" xmlns:editor="UnityEditor.UIElements">
<VisualElement class="config-label-present">
<Style src="../Uss/Styles.uss"/>
<Label name="config-name" class="labeling__config-name-label"/>
<Button name="remove-from-config-button" class="labeling__addremove-config-button"/>
<Button name="open-config-button" class="labeling__addremove-config-button" text="Open"/>
</VisualElement>
</UXML>

3
com.unity.perception/Editor/GroundTruth/Uxml/ConfigElementLabelPresent.uxml.meta


fileFormatVersion: 2
guid: f65364e03181f4f24acd20305f6c34bb
timeCreated: 1603311500

38
com.unity.perception/Editor/GroundTruth/Uxml/Labeling_Main.uxml


<UXML xmlns="UnityEngine.UIElements" xmlns:editor="UnityEditor.UIElements">
<VisualElement class="outer-container" name="outer-container">
<Style src="../Uss/Styles.uss"/>
<Toggle name = "auto-or-manual-toggle" text="Use Automatic Labeling" style="margin-top: 5px"/>
<VisualElement name="automatic-labeling" class="inner-container">
<VisualElement name = "drop-down-parent"/>
<VisualElement style="flex-direction:row; flex-shrink:1; width:auto">
<Label name ="current-auto-label-title" text="Automatic Label:"/>
<Label name ="current-auto-label" style="-unity-font-style: bold; margin-left: 54px;"/>
</VisualElement>
<Button name ="add-auto-label-to-config" text="Add to Label Config..." style="margin-top: 5px; align-self: flex-end;"/>
</VisualElement>
<VisualElement name="manual-labeling" class="inner-container" style="margin-top:5px">
<Label text="Added Labels" name="added-labels-title" class="title-label"/>
<ListView name="current-labels-listview" class="labeling__label-listview" style="margin-top: 2px"/>
<Button name="add-label" text="Add New Label" class="labeling__add-label-button"/>
<Label name = "add-manual-labels-title" text="Add Labels" class="title-label" style = "margin-top:0px"/>
<VisualElement name="from-label-configs" class="inner-container depth2" style="margin-top:0">
<Label text="From Existing Label Configs" class="title-label"/>
<VisualElement name="add-from-label-configs" style="padding-top: 0px;">
<ScrollView name="label-configs-scrollview" class="labeling__label-configs-scrollview" style="min-height: 100px;"/>
</VisualElement>
</VisualElement>
<VisualElement name="suggested-labels" class="inner-container depth2">
<Label text="Other Suggested Labels" class="title-label"/>
<VisualElement name="suggested-labels-from-name" style="padding-top: 5px;">
<Label text="Based on asset name" class="subtitle-label"/>
<ListView name="suggested-labels-name-listview" class="labeling__label-listview" style="min-height: 100px;"/>
</VisualElement>
<VisualElement name="suggested-labels-from-path" style="padding-top: 5px;">
<Label text="Based on asset path" class="subtitle-label"/>
<ListView name="suggested-labels-path-listview" class="labeling__label-listview" style="min-height: 100px;"/>
</VisualElement>
</VisualElement>
</VisualElement>
</VisualElement>
</UXML>

10
com.unity.perception/Editor/GroundTruth/Uxml/Labeling_Main.uxml.meta


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

7
com.unity.perception/Editor/GroundTruth/Uxml/SuggestedLabelElement.uxml


<UXML xmlns="UnityEngine.UIElements">
<VisualElement class="suggested-label">
<Style src="../Uss/Styles.uss"/>
<Label name="label-value" class="labeling__suggested-label-value"/>
<Button name="add-button" class="labeling__add-to-list-button" text="Add to Labels"/>
</VisualElement>
</UXML>

3
com.unity.perception/Editor/GroundTruth/Uxml/SuggestedLabelElement.uxml.meta


fileFormatVersion: 2
guid: 194f2c0998a924e0eb89baba7fa4141a
timeCreated: 1603311500

13
com.unity.perception/Editor/GroundTruth/Uxml/ConfigElementForAddingLabelsFrom.uxml


<UXML xmlns="UnityEngine.UIElements">
<Toggle name="collapsed-state" style="display:none"/>
<VisualElement class="label-config-add-from">
<Style src="../Uss/Styles.uss"/>
<VisualElement class="label-config-header">
<VisualElement name="collapse-toggle" class="collapse-toggle"/>
<Label name="config-name" class="labeling__config-name-label"/>
<VisualElement style="flex-grow:1"/>
<Button name="open-config-button" text="Open"/>
</VisualElement>
<ListView name="label-config-contents-listview" class="labeling__label-listview" style="height: 300px"/>
</VisualElement>
</UXML>

3
com.unity.perception/Editor/GroundTruth/Uxml/ConfigElementForAddingLabelsFrom.uxml.meta


fileFormatVersion: 2
guid: 0b6d5a00362234d9488a43570dfd15ae
timeCreated: 1603311500

10
com.unity.perception/Editor/GroundTruth/Uxml/LabelConfig_Main.uxml.meta


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

14
com.unity.perception/Editor/GroundTruth/Uxml/ColoredLabelElementInLabelConfig.uxml


<UXML xmlns="UnityEngine.UIElements" xmlns:editor="UnityEditor.UIElements">
<VisualElement class="added-label" style="padding-top: 3px;">
<Button name="remove-button" class="labeling__remove-item-button"/>
<VisualElement class="generic-hover"
style="flex-direction: row; padding: 3px 0 3px 6px; margin-left: 3px; margin-right: 3px; border-width: 1px; border-color: #555555; border-radius: 4px;">
<editor:ColorField name="label-color-value" style="min-width : 60px; max-width: 60px; align-self:center;"/>
</VisualElement>
<TextField name="label-value" class="labeling__added-label-value"/>
<VisualElement style="min-width:20px; flex-direction: row; display:none">
<Button name="move-up-button" class="move-label-in-config-button move-up" style="margin-right:-2px"/>
<Button name="move-down-button" class="move-label-in-config-button move-down"/>
</VisualElement>
</VisualElement>
</UXML>

3
com.unity.perception/Editor/GroundTruth/Uxml/ColoredLabelElementInLabelConfig.uxml.meta


fileFormatVersion: 2
guid: 092a4ceabfda6410dbc745780dd88616
timeCreated: 1603311500

14
com.unity.perception/Editor/GroundTruth/Uxml/IdLabelElementInLabelConfig.uxml


<UXML xmlns="UnityEngine.UIElements">
<VisualElement class="added-label" style="padding-top: 3px;">
<Button name="remove-button" class="labeling__remove-item-button" />
<VisualElement class="generic-hover" style = "flex-direction: row; padding: 3px; margin-left: 3px; margin-right: 3px; border-width: 1px; border-color: #555555; border-radius: 4px;">
<Label name="label-id-title" text = "ID = " style="align-self:center; color: #888888;"/>
<TextField name="label-id-value" style="-unity-font-style: bold; color: #888888; min-width : 30px; align-self:center;"/>
</VisualElement>
<TextField name="label-value" class="labeling__added-label-value"/>
<VisualElement style="min-width:20px; flex-direction: row; display:none">
<Button name="move-up-button" class="move-label-in-config-button move-up" style="margin-right:-2px"/>
<Button name="move-down-button" class="move-label-in-config-button move-down"/>
</VisualElement>
</VisualElement>
</UXML>

3
com.unity.perception/Editor/GroundTruth/Uxml/IdLabelElementInLabelConfig.uxml.meta


fileFormatVersion: 2
guid: 2961168094add41168cf3b38ba7009dd
timeCreated: 1603311500

53
com.unity.perception/Editor/GroundTruth/Uxml/LabelConfig_Main.uxml


<UXML xmlns="UnityEngine.UIElements" xmlns:editor="UnityEditor.UIElements">
<VisualElement class="outer-container" name="outer-container">
<Style src="../Uss/Styles.uss"/>
<VisualElement class="inner-container" name="id-specific-ui">
<Toggle name="auto-id-toggle" text="Auto Assign IDs" style="margin:0" binding-path="autoAssignIds"/>
<VisualElement style="flex-direction: row; flex-grow: 1;">
<editor:EnumField label="Starting ID" name="starting-id-dropdown" binding-path="startingLabelId"
style="flex-grow:1; margin:0"/>
</VisualElement>
</VisualElement>
<VisualElement name="added-labels" class="inner-container" style="margin-top:5px">
<Label text="Added Labels" name="added-labels-title" class="title-label"/>
<ListView name="labels-listview" class="labeling__label-listview" style="margin-top: 5px;"/>
<Button name="save-button" text="Save" style="display:none"/>
<VisualElement name="button-bar" style="min-width:20px; flex-direction: row; margin-top: 5px">
<VisualElement name="move-buttons" style="flex-direction: row; min-width:100px">
<Label text="Move Selected Label:" style="align-self:center; margin-left: 2px; flex-shrink:1"/>
<Button name="move-up-button" class="move-label-in-config-button move-up"
style="margin-right:-2px"/>
<Button name="move-down-button" class="move-label-in-config-button move-down"/>
</VisualElement>
<VisualElement style="flex-grow:1"/>
<Button name="remove-all-labels" text="Remove All" class="labeling__add-label-button"
style="color:red"/>
<Button name="add-label" text="Add New Label" class="labeling__add-label-button"/>
</VisualElement>
</VisualElement>
<VisualElement name="other-labels" class="inner-container depth2">
<Label text="Other Labels in Project" class="title-label"/>
<ListView name="labels-in-project-listview" class="labeling__label-listview"
style="margin-top: 5px; min-height: 200px"/>
<Button name="add-all-labels-in-project" text="Add All Labels to Config" class="labeling__add-label-button"
style="margin-top: 5px"/>
</VisualElement>
<VisualElement name="other-labels" class="inner-container depth2">
<Label text="Import or Export Label Config" name="added-labels-title" class="title-label"/>
<VisualElement style="flex-direction: row; flex-grow: 1; padding: 0; margin: 8 0 3 0">
<Button name="import-file-button" text="Import from File" class="title-label"
style="align-self: center; padding: 10px; flex-grow:1; height: 40px; margin: 0 3 0 0"/>
<Button name="export-file-button" text="Export to File" class="title-label"
style="align-self: center; padding: 10px; flex-grow:1; height: 40px; margin: 0 0 0 3"/>
</VisualElement>
<VisualElement class="helpbox" style="margin: 7px 0 7px 0 ">
<TextElement
text="Importing a label config file will overwrite all existing contents of this label config."/>
</VisualElement>
</VisualElement>
</VisualElement>
</UXML>

3
com.unity.perception/Editor/Icons/ChevronDown.png

之前 之后
宽度: 32  |  高度: 32  |  大小: 2.1 KiB

142
com.unity.perception/Editor/Icons/ChevronDown.png.meta


fileFormatVersion: 2
guid: fa47b84af1c764637bf825673d76949a
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 11
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: 2
mipBias: -100
wrapU: 0
wrapV: 0
wrapW: 0
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 8192
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 8192
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: iPhone
maxTextureSize: 8192
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Android
maxTextureSize: 8192
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Windows Store Apps
maxTextureSize: 8192
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

6
com.unity.perception/Editor/Icons/ChevronDownPadded.png

之前 之后
宽度: 32  |  高度: 32  |  大小: 2.1 KiB

142
com.unity.perception/Editor/Icons/ChevronDownPadded.png.meta


fileFormatVersion: 2
guid: 7d8b0ddb7696e48a6a9e037ba7d08e73
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 11
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: 2
mipBias: -100
wrapU: 0
wrapV: 0
wrapW: 0
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 8192
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 8192
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: iPhone
maxTextureSize: 8192
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Android
maxTextureSize: 8192
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Windows Store Apps
maxTextureSize: 8192
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

4
com.unity.perception/Editor/Icons/ChevronUp.png

之前 之后
宽度: 32  |  高度: 32  |  大小: 2.1 KiB

142
com.unity.perception/Editor/Icons/ChevronUp.png.meta


fileFormatVersion: 2
guid: 7c5db57ceb3164158b79c2eceb75cdbc
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 11
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: 2
mipBias: -100
wrapU: 0
wrapV: 0
wrapW: 0
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 8192
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 8192
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: iPhone
maxTextureSize: 8192
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Android
maxTextureSize: 8192
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Windows Store Apps
maxTextureSize: 8192
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

4
com.unity.perception/Editor/Icons/ChevronUpPadded.png

之前 之后
宽度: 32  |  高度: 32  |  大小: 2.1 KiB

142
com.unity.perception/Editor/Icons/ChevronUpPadded.png.meta


fileFormatVersion: 2
guid: 110dd95b59b974fd28227e7a929eec75
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 11
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: 2
mipBias: -100
wrapU: 0
wrapV: 0
wrapW: 0
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 8192
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 8192
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: iPhone
maxTextureSize: 8192
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Android
maxTextureSize: 8192
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Windows Store Apps
maxTextureSize: 8192
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

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

/com.unity.perception/Editor/Randomization/Icons → /com.unity.perception/Editor/Icons

正在加载...
取消
保存