浏览代码

Merge pull request #241 from Unity-Technologies/fix_wrong_label

Fix wrong labels on 2d bounding boxes
/main
GitHub 3 年前
当前提交
98685db4
共有 26 个文件被更改,包括 343 次插入347 次删除
  1. 99
      TestProjects/PerceptionHDRP/Packages/packages-lock.json
  2. 99
      TestProjects/PerceptionURP/Packages/packages-lock.json
  3. 4
      com.unity.perception/CHANGELOG.md
  4. 2
      com.unity.perception/Editor/GroundTruth/KeypointTemplateEditor.cs
  5. 2
      com.unity.perception/Runtime/GroundTruth/DatasetCapture.cs
  6. 3
      com.unity.perception/Runtime/GroundTruth/Labelers/BoundingBox3DLabeler.cs
  7. 49
      com.unity.perception/Runtime/GroundTruth/Labelers/BoundingBoxLabeler.cs
  8. 13
      com.unity.perception/Runtime/GroundTruth/Labelers/CameraLabeler.cs
  9. 3
      com.unity.perception/Runtime/GroundTruth/Labelers/InstanceSegmentationLabeler.cs
  10. 4
      com.unity.perception/Runtime/GroundTruth/Labelers/KeypointLabeler.cs
  11. 5
      com.unity.perception/Runtime/GroundTruth/Labelers/ObjectCountLabeler.cs
  12. 3
      com.unity.perception/Runtime/GroundTruth/Labelers/RenderedObjectInfoLabeler.cs
  13. 10
      com.unity.perception/Runtime/GroundTruth/Labelers/SemanticSegmentationLabeler.cs
  14. 26
      com.unity.perception/Runtime/GroundTruth/Labeling/IdLabelConfig.cs
  15. 40
      com.unity.perception/Runtime/GroundTruth/Labeling/LabelEntryMatchCache.cs
  16. 29
      com.unity.perception/Runtime/GroundTruth/PerceptionCamera.cs
  17. 32
      com.unity.perception/Runtime/GroundTruth/PerceptionCamera_InstanceSegmentation.cs
  18. 45
      com.unity.perception/Runtime/GroundTruth/RenderTextureReader.cs
  19. 4
      com.unity.perception/Runtime/GroundTruth/SimulationState.cs
  20. 18
      com.unity.perception/Tests/Editor/PerceptionCameraEditorTests.cs
  21. 19
      com.unity.perception/Tests/Runtime/GroundTruthTests/GroundTruthTestBase.cs
  22. 11
      com.unity.perception/Tests/Runtime/GroundTruthTests/LabelEntryMatchCacheTests.cs
  23. 18
      com.unity.perception/Tests/Runtime/GroundTruthTests/PerceptionCameraIntegrationTests.cs
  24. 92
      com.unity.perception/Tests/Runtime/GroundTruthTests/RenderedObjectInfoTests.cs
  25. 5
      com.unity.perception/Tests/Runtime/GroundTruthTests/SegmentationGroundTruthTests.cs
  26. 55
      com.unity.perception/Tests/Runtime/TestAssets/AnimatedCubeScene.unity

99
TestProjects/PerceptionHDRP/Packages/packages-lock.json


{
"dependencies": {
"com.unity.burst": {
"version": "1.3.9",
"version": "1.4.6",
"depth": 1,
"source": "registry",
"dependencies": {

"url": "https://packages.unity.com"
},
"com.unity.collections": {
"version": "0.7.0-preview.2",
"depth": 3,
"source": "registry",
"dependencies": {
"com.unity.test-framework.performance": "1.3.3-preview",
"com.unity.burst": "1.3.0-preview.5"
},
"url": "https://packages.unity.com"
},
"com.unity.entities": {
"version": "0.8.0-preview.8",
"version": "0.9.0-preview.6",
"com.unity.burst": "1.3.0-preview.5",
"com.unity.properties": "0.10.4-preview",
"com.unity.mathematics": "1.1.0",
"com.unity.serialization": "0.6.4-preview",
"com.unity.test-framework.performance": "1.3.3-preview",
"nuget.mono-cecil": "0.1.5-preview",
"com.unity.jobs": "0.2.7-preview.11",
"com.unity.scriptablebuildpipeline": "1.6.4-preview",
"com.unity.platforms": "0.2.1-preview.4"
"com.unity.test-framework.performance": "2.0.8-preview",
"com.unity.burst": "1.3.0-preview.12"
},
"url": "https://packages.unity.com"
},

"dependencies": {},
"url": "https://packages.unity.com"
},
"com.unity.jobs": {
"version": "0.2.7-preview.11",
"depth": 2,
"source": "registry",
"dependencies": {
"com.unity.collections": "0.7.0-preview.2",
"com.unity.mathematics": "1.1.0"
},
"url": "https://packages.unity.com"
},
"com.unity.mathematics": {
"version": "1.2.1",
"depth": 2,

},
"com.unity.nuget.newtonsoft-json": {
"version": "1.1.2",
"depth": 1,
"version": "2.0.0-preview",
"depth": 3,
"source": "registry",
"dependencies": {},
"url": "https://packages.unity.com"

"depth": 0,
"source": "local",
"dependencies": {
"com.unity.burst": "1.4.6",
"com.unity.collections": "0.9.0-preview.6",
"com.unity.burst": "1.3.9",
"com.unity.entities": "0.8.0-preview.8",
"com.unity.simulation.capture": "0.0.10-preview.19",
"com.unity.simulation.capture": "0.0.10-preview.19",
"com.unity.platforms": {
"version": "0.2.1-preview.4",
"depth": 2,
"source": "registry",
"dependencies": {
"com.unity.nuget.newtonsoft-json": "1.1.2",
"com.unity.properties": "0.10.4-preview",
"com.unity.searcher": "4.0.9",
"com.unity.serialization": "0.6.4-preview"
},
"url": "https://packages.unity.com"
},
"com.unity.properties": {
"version": "0.10.4-preview",
"depth": 2,
"source": "registry",
"dependencies": {
"com.unity.collections": "0.1.1-preview",
"com.unity.test-framework.performance": "1.0.9-preview"
},
"url": "https://packages.unity.com"
},
"com.unity.render-pipelines.core": {
"version": "7.3.1",
"depth": 0,

},
"url": "https://packages.unity.com"
},
"com.unity.scriptablebuildpipeline": {
"version": "1.6.4-preview",
"depth": 2,
"source": "registry",
"dependencies": {},
"url": "https://packages.unity.com"
},
"com.unity.searcher": {
"version": "4.0.9",
"depth": 3,
"source": "registry",
"dependencies": {},
"url": "https://packages.unity.com"
},
"com.unity.serialization": {
"version": "0.6.4-preview",
"depth": 2,
"source": "registry",
"dependencies": {
"com.unity.burst": "1.1.2",
"com.unity.collections": "0.1.1-preview",
"com.unity.jobs": "0.1.1-preview",
"com.unity.mathematics": "1.1.0",
"com.unity.properties": "0.10.4-preview",
"com.unity.test-framework.performance": "1.0.9-preview"
},
"url": "https://packages.unity.com"
},
"com.unity.shadergraph": {
"version": "7.3.1",
"depth": 1,

"url": "https://packages.unity.com"
},
"com.unity.test-framework.performance": {
"version": "1.3.3-preview",
"version": "2.0.8-preview",
"com.unity.modules.jsonserialize": "1.0.0"
"com.unity.nuget.newtonsoft-json": "2.0.0-preview"
},
"url": "https://packages.unity.com"
},

99
TestProjects/PerceptionURP/Packages/packages-lock.json


{
"dependencies": {
"com.unity.burst": {
"version": "1.3.9",
"version": "1.4.6",
"depth": 1,
"source": "registry",
"dependencies": {

"url": "https://packages.unity.com"
},
"com.unity.collections": {
"version": "0.7.0-preview.2",
"depth": 3,
"source": "registry",
"dependencies": {
"com.unity.test-framework.performance": "1.3.3-preview",
"com.unity.burst": "1.3.0-preview.5"
},
"url": "https://packages.unity.com"
},
"com.unity.entities": {
"version": "0.8.0-preview.8",
"version": "0.9.0-preview.6",
"com.unity.burst": "1.3.0-preview.5",
"com.unity.properties": "0.10.4-preview",
"com.unity.mathematics": "1.1.0",
"com.unity.serialization": "0.6.4-preview",
"com.unity.test-framework.performance": "1.3.3-preview",
"nuget.mono-cecil": "0.1.5-preview",
"com.unity.jobs": "0.2.7-preview.11",
"com.unity.scriptablebuildpipeline": "1.6.4-preview",
"com.unity.platforms": "0.2.1-preview.4"
"com.unity.test-framework.performance": "2.0.8-preview",
"com.unity.burst": "1.3.0-preview.12"
},
"url": "https://packages.unity.com"
},

"dependencies": {},
"url": "https://packages.unity.com"
},
"com.unity.jobs": {
"version": "0.2.7-preview.11",
"depth": 2,
"source": "registry",
"dependencies": {
"com.unity.collections": "0.7.0-preview.2",
"com.unity.mathematics": "1.1.0"
},
"url": "https://packages.unity.com"
},
"com.unity.mathematics": {
"version": "1.2.1",
"depth": 2,

},
"com.unity.nuget.newtonsoft-json": {
"version": "1.1.2",
"depth": 1,
"version": "2.0.0-preview",
"depth": 3,
"source": "registry",
"dependencies": {},
"url": "https://packages.unity.com"

"depth": 0,
"source": "local",
"dependencies": {
"com.unity.burst": "1.4.6",
"com.unity.collections": "0.9.0-preview.6",
"com.unity.burst": "1.3.9",
"com.unity.entities": "0.8.0-preview.8",
"com.unity.simulation.capture": "0.0.10-preview.19",
"com.unity.simulation.capture": "0.0.10-preview.19",
"com.unity.platforms": {
"version": "0.2.1-preview.4",
"depth": 2,
"source": "registry",
"dependencies": {
"com.unity.nuget.newtonsoft-json": "1.1.2",
"com.unity.properties": "0.10.4-preview",
"com.unity.searcher": "4.0.9",
"com.unity.serialization": "0.6.4-preview"
},
"url": "https://packages.unity.com"
},
"com.unity.properties": {
"version": "0.10.4-preview",
"depth": 2,
"source": "registry",
"dependencies": {
"com.unity.collections": "0.1.1-preview",
"com.unity.test-framework.performance": "1.0.9-preview"
},
"url": "https://packages.unity.com"
},
"com.unity.render-pipelines.core": {
"version": "7.3.1",
"depth": 1,

},
"url": "https://packages.unity.com"
},
"com.unity.scriptablebuildpipeline": {
"version": "1.6.4-preview",
"depth": 2,
"source": "registry",
"dependencies": {},
"url": "https://packages.unity.com"
},
"com.unity.searcher": {
"version": "4.0.9",
"depth": 3,
"source": "registry",
"dependencies": {},
"url": "https://packages.unity.com"
},
"com.unity.serialization": {
"version": "0.6.4-preview",
"depth": 2,
"source": "registry",
"dependencies": {
"com.unity.burst": "1.1.2",
"com.unity.collections": "0.1.1-preview",
"com.unity.jobs": "0.1.1-preview",
"com.unity.mathematics": "1.1.0",
"com.unity.properties": "0.10.4-preview",
"com.unity.test-framework.performance": "1.0.9-preview"
},
"url": "https://packages.unity.com"
},
"com.unity.shadergraph": {
"version": "7.3.1",
"depth": 1,

"url": "https://packages.unity.com"
},
"com.unity.test-framework.performance": {
"version": "1.3.3-preview",
"version": "2.0.8-preview",
"com.unity.modules.jsonserialize": "1.0.0"
"com.unity.nuget.newtonsoft-json": "2.0.0-preview"
},
"url": "https://packages.unity.com"
},

4
com.unity.perception/CHANGELOG.md


The randomizer methods OnCreate(), OnStartRunning(), and OnStopRunning() are now deprecated and have been replaced with OnAwake(), OnEnable() and OnDisable() respectively to better reflect the existing MonoBehaviour lifecycle methods.
CameraLabeler methods OnBeginRendering() and OnEndRendering() have an added ScriptableRenderContext parameter.
Upgraded com.unity.simulation.capture package dependency to integrate new changes that prevent the API updater from looping infinitely when opening the project settings window on new URP projects.
### Deprecated

Fixed keypoints being reported in wrong locations on the first frame an object is visible.
Fixed an out of range error if a keypoint template skeleton relies on a joint that is not available.
Fixed wrong labels on 2d bounding boxes when all labeled objects are deleted in a frame.
## [0.7.0-preview.2] - 2021-02-08

2
com.unity.perception/Editor/GroundTruth/KeypointTemplateEditor.cs


namespace UnityEditor.Perception.GroundTruth
{
[CustomEditor(typeof(KeypointTemplate))]
public class KeypointTemplateEditor: Editor
class KeypointTemplateEditor: Editor
{
ReorderableList m_KeypointsList;
ReorderableList m_SkeletonList;

2
com.unity.perception/Runtime/GroundTruth/DatasetCapture.cs


/// <param name="egoHandle">The ego container for the sensor. Sensor orientation will be reported in the context of the given ego.</param>
/// <param name="modality">The kind of the sensor (ex. "camera", "lidar")</param>
/// <param name="description">A human-readable description of the sensor (ex. "front-left rgb camera")</param>
/// <param name="firstCaptureFrame">The time, in seconds, from the start of the sequence on which this sensor should first be scheduled.</param>
/// <param name="firstCaptureFrame">The offset from the current frame on which this sensor should first be scheduled.</param>
/// <param name="captureTriggerMode">The method of triggering captures for this sensor.</param>
/// <param name="simulationDeltaTime">The simulation frame time (seconds) requested by this sensor.</param>
/// <param name="framesBetweenCaptures">The number of frames to simulate and render between the camera's scheduled captures. Setting this to 0 makes the camera capture every frame.</param>

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


using System.Diagnostics.CodeAnalysis;
using Unity.Collections;
using Unity.Profiling;
using UnityEngine.Rendering;
namespace UnityEngine.Perception.GroundTruth
{

}
/// <inheritdoc/>
protected override void OnBeginRendering()
protected override void OnBeginRendering(ScriptableRenderContext scriptableRenderContext)
{
m_CurrentFrame = Time.frameCount;

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


using Unity.Profiling;
using UnityEngine.Serialization;
using Unity.Simulation;
using UnityEngine.Rendering;
using UnityEngine.UI;
namespace UnityEngine.Perception.GroundTruth

[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "NotAccessedField.Local")]
struct BoundingBoxValue
internal struct BoundingBoxValue
{
public int label_id;
public string label_name;

[FormerlySerializedAs("labelingConfiguration")]
public IdLabelConfig idLabelConfig;
Dictionary<int, AsyncAnnotation> m_AsyncAnnotations;
Dictionary<int, (AsyncAnnotation annotation, LabelEntryMatchCache labelEntryMatchCache)> m_AsyncData;
AnnotationDefinition m_BoundingBoxAnnotationDefinition;
List<BoundingBoxValue> m_BoundingBoxValues;

/// <inheritdoc/>
protected override bool supportsVisualization => true;
/// <summary>
/// Event information for <see cref="BoundingBox2DLabeler.BoundingBoxesCalculated"/>
/// </summary>
internal struct BoundingBoxesCalculatedEventArgs
{
/// <summary>
/// The <see cref="Time.frameCount"/> on which the data was derived. This may be multiple frames in the past.
/// </summary>
public int frameCount;
/// <summary>
/// Bounding boxes.
/// </summary>
public IEnumerable<BoundingBoxValue> data;
}
/// <summary>
/// Event which is called each frame a semantic segmentation image is read back from the GPU.
/// </summary>
internal event Action<BoundingBoxesCalculatedEventArgs> boundingBoxesCalculated;
/// <inheritdoc/>
protected override void Setup()
{

m_AsyncAnnotations = new Dictionary<int, AsyncAnnotation>();
m_AsyncData = new Dictionary<int, (AsyncAnnotation annotation, LabelEntryMatchCache labelEntryMatchCache)>();
m_BoundingBoxValues = new List<BoundingBoxValue>();
m_BoundingBoxAnnotationDefinition = DatasetCapture.RegisterAnnotationDefinition("bounding box", idLabelConfig.GetAnnotationSpecification(),

}
/// <inheritdoc/>
protected override void OnBeginRendering()
protected override void OnBeginRendering(ScriptableRenderContext scriptableRenderContext)
m_AsyncAnnotations[Time.frameCount] = perceptionCamera.SensorHandle.ReportAnnotationAsync(m_BoundingBoxAnnotationDefinition);
m_AsyncData[Time.frameCount] =
(perceptionCamera.SensorHandle.ReportAnnotationAsync(m_BoundingBoxAnnotationDefinition),
idLabelConfig.CreateLabelEntryMatchCache(Allocator.TempJob));
if (!m_AsyncAnnotations.TryGetValue(frameCount, out var asyncAnnotation))
if (!m_AsyncData.TryGetValue(frameCount, out var asyncData))
m_AsyncAnnotations.Remove(frameCount);
m_AsyncData.Remove(frameCount);
using (s_BoundingBoxCallback.Auto())
{
m_BoundingBoxValues.Clear();

if (!idLabelConfig.TryGetLabelEntryFromInstanceId(objectInfo.instanceId, out var labelEntry))
if (!asyncData.labelEntryMatchCache.TryGetLabelEntryFromInstanceId(objectInfo.instanceId, out var labelEntry, out _))
continue;
m_BoundingBoxValues.Add(new BoundingBoxValue

if (!CaptureOptions.useAsyncReadbackIfSupported && frameCount != Time.frameCount)
Debug.LogWarning("Not on current frame: " + frameCount + "(" + Time.frameCount + ")");
asyncAnnotation.ReportValues(m_BoundingBoxValues);
boundingBoxesCalculated?.Invoke(new BoundingBoxesCalculatedEventArgs()
{
data = m_BoundingBoxValues,
frameCount = frameCount
});
asyncData.annotation.ReportValues(m_BoundingBoxValues);
asyncData.labelEntryMatchCache.Dispose();
}
}

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


using System;
using Unity.Simulation;
using UnityEngine.EventSystems;
using UnityEngine.Rendering;
using UnityEngine.UI;
using UnityEngine.UIElements;

/// Called during the Update each frame the the labeler is enabled and <see cref="SensorHandle.ShouldCaptureThisFrame"/> is true.
/// </summary>
protected virtual void OnUpdate() {}
protected virtual void OnBeginRendering() {}
/// <param name="scriptableRenderContext">The current context from the Scriptable Render Pipeline.</param>
protected virtual void OnBeginRendering(ScriptableRenderContext scriptableRenderContext) {}
protected virtual void OnEndRendering() {}
/// <param name="scriptableRenderContext">The current context from the Scriptable Render Pipeline.</param>
protected virtual void OnEndRendering(ScriptableRenderContext scriptableRenderContext) {}
/// <summary>
/// Labeling pass to display labeler's visualization components, if applicable. Important note, all labeler's visualizations need
/// to use Unity's Immediate Mode GUI (IMGUI) <see cref="https://docs.unity3d.com/Manual/GUIScriptingGuide.html"/> system.

set => visualizationEnabled = value;
}
internal void InternalOnUpdate() => OnUpdate();
internal void InternalOnBeginRendering() => OnBeginRendering();
internal void InternalOnEndRendering() => OnEndRendering();
internal void InternalOnBeginRendering(ScriptableRenderContext context) => OnBeginRendering(context);
internal void InternalOnEndRendering(ScriptableRenderContext context) => OnEndRendering(context);
internal void InternalCleanup() => Cleanup();
internal void InternalVisualize() => OnVisualize();

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


using UnityEngine;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Profiling;
using UnityEngine.Rendering;
namespace UnityEngine.Perception.GroundTruth
{

}
/// <inheritdoc/>
protected override void OnBeginRendering()
protected override void OnBeginRendering(ScriptableRenderContext scriptableRenderContext)
{
m_AsyncAnnotations[Time.frameCount] = perceptionCamera.SensorHandle.ReportAnnotationAsync(m_AnnotationDefinition);
}

4
com.unity.perception/Runtime/GroundTruth/Labelers/KeypointLabeler.cs


using System.Collections.Generic;
using System.Linq;
using Unity.Collections;
using UnityEngine.Rendering;
namespace UnityEngine.Perception.GroundTruth
{

asyncAnnotation.annotation.ReportValues(m_ToReport);
}
/// <param name="scriptableRenderContext"></param>
protected override void OnEndRendering()
protected override void OnEndRendering(ScriptableRenderContext scriptableRenderContext)
{
m_CurrentFrame = Time.frameCount;

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


using System.Diagnostics.CodeAnalysis;
using Unity.Collections;
using Unity.Profiling;
using UnityEngine.Rendering;
using UnityEngine.UI;
namespace UnityEngine.Perception.GroundTruth

}
/// <inheritdoc/>
protected override void OnBeginRendering()
protected override void OnBeginRendering(ScriptableRenderContext scriptableRenderContext)
{
if (m_ObjectCountMetricDefinition.Equals(default))
{

// Clear out all of the old entries...
hudPanel.RemoveEntries(this);
}
for (var i = 0; i < entries.Count; i++)
{
m_ClassCountValues[i] = new ClassCountValue()

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


using JetBrains.Annotations;
using Unity.Collections;
using Unity.Profiling;
using UnityEngine.Rendering;
using UnityEngine.Serialization;
using UnityEngine.UI;

}
/// <inheritdoc/>
protected override void OnBeginRendering()
protected override void OnBeginRendering(ScriptableRenderContext scriptableRenderContext)
{
if (m_RenderedObjectInfoMetricDefinition.Equals(default))
{

10
com.unity.perception/Runtime/GroundTruth/Labelers/SemanticSegmentationLabeler.cs


using Unity.Simulation;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Profiling;
using UnityEngine.Rendering;
#if HDRP_PRESENT
using UnityEngine.Rendering.HighDefinition;

"PNG",
id: Guid.Parse(annotationId));
m_SemanticSegmentationTextureReader = new RenderTextureReader<Color32>(targetTexture, myCamera,
(frameCount, data, tex) => OnSemanticSegmentationImageRead(frameCount, data));
m_SemanticSegmentationTextureReader = new RenderTextureReader<Color32>(targetTexture);
visualizationEnabled = supportsVisualization;
}

}
/// <inheritdoc/>
protected override void OnBeginRendering()
protected override void OnEndRendering(ScriptableRenderContext scriptableRenderContext)
m_SemanticSegmentationTextureReader.Capture(scriptableRenderContext,
(frameCount, data, renderTexture) => OnSemanticSegmentationImageRead(frameCount, data));
}
/// <inheritdoc/>

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


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

/// <returns>True if a labelId is found for the given instanceId.</returns>
public bool TryGetLabelEntryFromInstanceId(uint instanceId, out IdLabelEntry labelEntry, out int index)
{
if (m_LabelEntryMatchCache == null)
m_LabelEntryMatchCache = new LabelEntryMatchCache(this);
EnsureInitLabelEntryMatchCache();
private void EnsureInitLabelEntryMatchCache()
{
if (m_LabelEntryMatchCache == null)
m_LabelEntryMatchCache = new LabelEntryMatchCache(this, Allocator.Persistent);
}
/// <inheritdoc/>
protected override void OnInit()
{

label_id = l.id,
label_name = l.label,
}).ToArray();
}
/// <summary>
/// Creates a LabelEntryMatchCache from the currently registered labeled objects, which can be used to look up
/// labeling information in future frames, even after the objects have been destroyed. Due to timing of labeled
/// object registration, if this is called during or before LateUpdate, this cache may become invalid.
///
/// It is recommended to only use this method in rendering, as the cache is guaranteed to be in its final state
/// for ground truth generation.
/// </summary>
/// <param name="allocator">The allocator for creating the cache.</param>
/// <returns>The created cache.</returns>
public LabelEntryMatchCache CreateLabelEntryMatchCache(Allocator allocator)
{
EnsureInitLabelEntryMatchCache();
return m_LabelEntryMatchCache.CloneCurrentState(allocator);
}
}
}

40
com.unity.perception/Runtime/GroundTruth/Labeling/LabelEntryMatchCache.cs


{
/// <summary>
/// Cache of instance id -> label entry index for a LabelConfig. This is not well optimized and is the source of
/// a known memory leak for apps that create new instances frequently
/// a known memory leak for apps that create new instances frequently.
class LabelEntryMatchCache : IGroundTruthGenerator, IDisposable
public class LabelEntryMatchCache : IGroundTruthGenerator, IDisposable
private bool m_ReceiveUpdates;
public LabelEntryMatchCache(IdLabelConfig idLabelConfig)
internal LabelEntryMatchCache(IdLabelConfig idLabelConfig, Allocator allocator = Allocator.Persistent, bool receiveUpdates = true)
m_InstanceIdToLabelEntryIndexLookup = new NativeList<ushort>(k_StartingObjectCount, Allocator.Persistent);
LabelManager.singleton.Activate(this);
m_InstanceIdToLabelEntryIndexLookup = new NativeList<ushort>(k_StartingObjectCount, allocator);
m_ReceiveUpdates = receiveUpdates;
if (receiveUpdates)
LabelManager.singleton.Activate(this);
private LabelEntryMatchCache(LabelEntryMatchCache labelEntryMatchCache, Allocator allocator)
{
m_IdLabelConfig = labelEntryMatchCache.m_IdLabelConfig;
m_InstanceIdToLabelEntryIndexLookup = new NativeList<ushort>(labelEntryMatchCache.m_InstanceIdToLabelEntryIndexLookup.Length, allocator);
m_InstanceIdToLabelEntryIndexLookup.AddRange(labelEntryMatchCache.m_InstanceIdToLabelEntryIndexLookup.AsArray());
m_ReceiveUpdates = false;
}
/// <summary>
/// Retrieves the label entry for the given instance id.
/// </summary>
/// <param name="instanceId">The instance id to look up</param>
/// <param name="labelEntry">The <see cref="IdLabelEntry"/> of the match if found. Otherwise returns <code>default(IdlabelEntry)</code>.</param>
/// <param name="index">The index of the matched <see cref="IdLabelEntry"/> in the <see cref="IdLabelConfig"/> if found. Otherwise returns -1.</param>
/// <returns>True if a the instance id was found in the cache. </returns>
public bool TryGetLabelEntryFromInstanceId(uint instanceId, out IdLabelEntry labelEntry, out int index)
{
labelEntry = default;

return true;
}
/// <inheritdoc/>
void IGroundTruthGenerator.SetupMaterialProperties(MaterialPropertyBlock mpb, Renderer renderer, Labeling labeling, uint instanceId)
{
if (m_IdLabelConfig.TryGetMatchingConfigurationEntry(labeling, out _, out var index))

}
}
/// <inheritdoc/>
LabelManager.singleton.Deactivate(this);
if (m_ReceiveUpdates)
LabelManager.singleton.Deactivate(this);
}
internal LabelEntryMatchCache CloneCurrentState(Allocator allocator)
{
var clone = new LabelEntryMatchCache(this, Allocator.Persistent);
return clone;
}
}
}

29
com.unity.perception/Runtime/GroundTruth/PerceptionCamera.cs


void OnEnable()
{
RenderPipelineManager.beginCameraRendering += OnBeginCameraRendering;
RenderPipelineManager.endCameraRendering += OnEndCameraRendering;
RenderPipelineManager.endFrameRendering += OnEndFrameRendering;
void Update()
// LateUpdate is called once per frame. It is called after coroutines, ensuring it is called properly after
// creation when running tests, since the test runner uses coroutines to run test code.
void LateUpdate()
{
EnsureSensorRegistered();
if (!SensorHandle.IsValid)

void OnDisable()
{
RenderPipelineManager.beginCameraRendering -= OnBeginCameraRendering;
RenderPipelineManager.endCameraRendering -= OnEndCameraRendering;
RenderPipelineManager.endFrameRendering -= OnEndFrameRendering;
RenderPipelineManager.endCameraRendering -= CheckForRendererFeature;
}

}
}
void OnBeginCameraRendering(ScriptableRenderContext _, Camera cam)
void OnBeginCameraRendering(ScriptableRenderContext scriptableRenderContext, Camera cam)
{
if (!ShouldCallLabelers(cam, m_LastFrameCaptured))
return;

CallOnLabelers(l => l.InternalOnBeginRendering());
CallOnLabelers(l => l.InternalOnBeginRendering(scriptableRenderContext));
void OnEndCameraRendering(ScriptableRenderContext _, Camera cam)
void OnEndFrameRendering(ScriptableRenderContext scriptableRenderContext, Camera[] cameras)
if (!ShouldCallLabelers(cam, m_LastFrameEndRendering))
bool anyCamera = false;
foreach (var cam in cameras)
{
if (ShouldCallLabelers(cam, m_LastFrameEndRendering))
{
anyCamera = true;
break;
}
}
if (!anyCamera)
CallOnLabelers(l => l.InternalOnEndRendering());
CallOnLabelers(l => l.InternalOnEndRendering(scriptableRenderContext));
CaptureInstanceSegmentation(scriptableRenderContext);
}
void CallOnLabelers(Action<CameraLabeler> action)

32
com.unity.perception/Runtime/GroundTruth/PerceptionCamera_InstanceSegmentation.cs


using System;
using Unity.Collections;
using Unity.Simulation;
using UnityEngine.Rendering;
#if HDRP_PRESENT
using UnityEngine.Rendering.HighDefinition;
#elif URP_PRESENT

/// Invoked when instance segmentation images are read back from the graphics system. The first parameter is the
/// Time.frameCount at which the objects were rendered. May be invoked many frames after the objects were rendered.
/// </summary>
public event Action<int, NativeArray<Color32>, RenderTexture> InstanceSegmentationImageReadback;
public event Action<int, NativeArray<Color32>, RenderTexture/*, List<IdLabelEntry>*/> InstanceSegmentationImageReadback;
public event Action<int, NativeArray<RenderedObjectInfo>> RenderedObjectInfosCalculated;
public event Action<int, NativeArray<RenderedObjectInfo>/*, List<IdLabelEntry>*/> RenderedObjectInfosCalculated;
RenderedObjectInfoGenerator m_RenderedObjectInfoGenerator;
RenderTexture m_InstanceSegmentationTexture;

m_LensDistortionIntensityOverride;
#endif
m_InstanceSegmentationReader = new RenderTextureReader<Color32>(m_InstanceSegmentationTexture, myCamera, (frameCount, data, tex) =>
m_InstanceSegmentationReader = new RenderTextureReader<Color32>(m_InstanceSegmentationTexture);
}
void CaptureInstanceSegmentation(ScriptableRenderContext scriptableRenderContext)
{
var width = m_InstanceSegmentationTexture.width;
m_InstanceSegmentationReader.Capture(scriptableRenderContext, (frameCount, data, renderTexture) =>
InstanceSegmentationImageReadback?.Invoke(frameCount, data, tex);
if (RenderedObjectInfosCalculated != null)
InstanceSegmentationImageReadback?.Invoke(frameCount, data, m_InstanceSegmentationTexture);
if(RenderedObjectInfosCalculated != null)
m_RenderedObjectInfoGenerator.Compute(data, tex.width, BoundingBoxOrigin.TopLeft, out var renderedObjectInfos, Allocator.Temp);
m_RenderedObjectInfoGenerator.Compute(data, width,
BoundingBoxOrigin.TopLeft, out var renderedObjectInfos, Allocator.Temp);
RenderedObjectInfosCalculated?.Invoke(frameCount, renderedObjectInfos);
renderedObjectInfos.Dispose();
}

void CleanUpInstanceSegmentation()
{
m_InstanceSegmentationReader?.WaitForAllImages();
m_InstanceSegmentationReader?.Dispose();
m_InstanceSegmentationReader = null;
m_InstanceSegmentationReader?.WaitForAllImages();
m_InstanceSegmentationReader?.Dispose();
m_InstanceSegmentationReader = null;
}
}
}

45
com.unity.perception/Runtime/GroundTruth/RenderTextureReader.cs


namespace UnityEngine.Perception.GroundTruth
{
/// <summary>
/// RenderTextureReader reads a RenderTexture from the GPU each frame and passes the data back through a provided callback.
/// RenderTextureReader reads a RenderTexture from the GPU whenever Capture is called and passes the data back through a provided callback.
public class RenderTextureReader<T> : IDisposable where T : struct
class RenderTextureReader<T> : IDisposable where T : struct
Action<int, NativeArray<T>, RenderTexture> m_ImageReadCallback;
int m_NextFrameToCapture;
Camera m_CameraRenderingToSource;
/// <param name="cameraRenderingToSource">The <see cref="Camera"/> which renders to the given renderTexture. This is used to determine when to read from the texture.</param>
/// <param name="imageReadCallback">The callback to call after reading the texture</param>
public RenderTextureReader(RenderTexture source, Camera cameraRenderingToSource, Action<int, NativeArray<T>, RenderTexture> imageReadCallback)
public RenderTextureReader(RenderTexture source)
m_ImageReadCallback = imageReadCallback;
m_CameraRenderingToSource = cameraRenderingToSource;
m_NextFrameToCapture = Time.frameCount;
RenderPipelineManager.endFrameRendering += OnEndFrameRendering;
void OnEndFrameRendering(ScriptableRenderContext context, Camera[] cameras)
public void Capture(ScriptableRenderContext context, Action<int, NativeArray<T>, RenderTexture> imageReadCallback)
#if UNITY_EDITOR
if (UnityEditor.EditorApplication.isPaused)
return;
#endif
if (!cameras.Contains(m_CameraRenderingToSource))
return;
if (m_NextFrameToCapture > Time.frameCount)
return;
m_NextFrameToCapture = Time.frameCount + 1;
if (!GraphicsUtilities.SupportsAsyncReadback())
{
RenderTexture.active = m_Source;

0, 0);
RenderTexture.active = null;
var data = m_CpuTexture.GetRawTextureData<T>();
m_ImageReadCallback(Time.frameCount, data, m_Source);
imageReadCallback(Time.frameCount, data, m_Source);
commandBuffer.RequestAsyncReadback(m_Source, r => OnGpuReadback(r, frameCount));
commandBuffer.RequestAsyncReadback(m_Source, r => OnGpuReadback(r, frameCount, imageReadCallback));
context.ExecuteCommandBuffer(commandBuffer);
context.Submit();
CommandBufferPool.Release(commandBuffer);

void OnGpuReadback(AsyncGPUReadbackRequest request, int frameCount)
void OnGpuReadback(AsyncGPUReadbackRequest request, int frameCount,
Action<int, NativeArray<T>, RenderTexture> imageReadCallback)
else if (request.done && m_ImageReadCallback != null)
else if (request.done && imageReadCallback != null)
m_ImageReadCallback(frameCount, request.GetData<T>(), m_Source);
imageReadCallback(frameCount, request.GetData<T>(), m_Source);
}
}

public void Dispose()
{
WaitForAllImages();
RenderPipelineManager.endFrameRendering -= OnEndFrameRendering;
if (m_CpuTexture != null)
{
Object.Destroy(m_CpuTexture);

4
com.unity.perception/Runtime/GroundTruth/SimulationState.cs


{
modality = modality,
description = description,
firstCaptureTime = firstCaptureFrame * renderingDeltaTime,
firstCaptureTime = UnscaledSequenceTime + firstCaptureFrame * renderingDeltaTime,
captureTriggerMode = captureTriggerMode,
renderingDeltaTime = renderingDeltaTime,
framesBetweenCaptures = framesBetweenCaptures,

};
sensorData.sequenceTimeOfNextCapture = GetSequenceTimeOfNextCapture(sensorData);
sensorData.sequenceTimeOfNextRender = 0;
sensorData.sequenceTimeOfNextRender = UnscaledSequenceTime;
m_ActiveSensors.Add(sensor);
m_Sensors.Add(sensor, sensorData);
m_Ids.Add(sensor.Id);

18
com.unity.perception/Tests/Editor/PerceptionCameraEditorTests.cs


#if MOQ_PRESENT
using Moq;
using Moq.Protected;
using UnityEngine.Rendering;
#endif
namespace EditorTests

mockLabeler.Protected().Verify("Setup", Times.Once());
mockLabeler.Protected().Verify("OnUpdate", Times.Once());
mockLabeler.Protected().Verify("OnBeginRendering", Times.Once());
mockLabeler.Protected().Verify("OnEndRendering", Times.Once());
mockLabeler.Protected().Verify("OnBeginRendering", Times.Once(), ItExpr.IsAny<ScriptableRenderContext>());
mockLabeler.Protected().Verify("OnEndRendering", Times.Once(), ItExpr.IsAny<ScriptableRenderContext>());
yield return new ExitPlayMode();
}
[UnityTest]

mockLabeler.Protected().Verify("Setup", Times.Once());
mockLabeler.Protected().Verify("OnUpdate", Times.Once());
mockLabeler.Protected().Verify("OnBeginRendering", Times.Once());
mockLabeler.Protected().Verify("OnEndRendering", Times.Once());
mockLabeler.Protected().Verify("OnBeginRendering", Times.Once(), ItExpr.IsAny<ScriptableRenderContext>());
mockLabeler.Protected().Verify("OnEndRendering", Times.Once(), ItExpr.IsAny<ScriptableRenderContext>());
yield return new ExitPlayMode();
}
[UnityTest]

yield return null;
mockLabeler.Protected().Verify("Setup", Times.Never());
mockLabeler.Protected().Verify("OnUpdate", Times.Never());
mockLabeler.Protected().Verify("OnBeginRendering", Times.Never());
mockLabeler.Protected().Verify("OnEndRendering", Times.Never());
mockLabeler.Protected().Verify("OnBeginRendering", Times.Never(), It.IsAny<ScriptableRenderContext>());
mockLabeler.Protected().Verify("OnEndRendering", Times.Never(), It.IsAny<ScriptableRenderContext>());
mockLabeler.Protected().Verify("Cleanup", Times.Never());
yield return new ExitPlayMode();
}

yield return null;
mockLabeler.Protected().Verify("Setup", Times.Once());
mockLabeler.Protected().Verify("OnUpdate", Times.Never());
mockLabeler.Protected().Verify("OnBeginRendering", Times.Never());
mockLabeler.Protected().Verify("OnEndRendering", Times.Never());
mockLabeler.Protected().Verify("OnBeginRendering", Times.Never(), It.IsAny<ScriptableRenderContext>());
mockLabeler.Protected().Verify("OnEndRendering", Times.Never(), It.IsAny<ScriptableRenderContext>());
Assert.IsFalse(labeler.enabled);
yield return new ExitPlayMode();
}

19
com.unity.perception/Tests/Runtime/GroundTruthTests/GroundTruthTestBase.cs


Object.DestroyImmediate(@object);
m_ObjectsToDestroy.Remove(@object);
}
public GameObject SetupCamera(Action<PerceptionCamera> initPerceptionCamera, bool activate = true)
{
var cameraObject = new GameObject();
cameraObject.SetActive(false);
var camera = cameraObject.AddComponent<Camera>();
camera.orthographic = true;
camera.orthographicSize = 1;
var perceptionCamera = cameraObject.AddComponent<PerceptionCamera>();
perceptionCamera.captureRgbImages = false;
initPerceptionCamera?.Invoke(perceptionCamera);
if (activate)
cameraObject.SetActive(true);
AddTestObjectForCleanup(cameraObject);
return cameraObject;
}
}
}

11
com.unity.perception/Tests/Runtime/GroundTruthTests/LabelEntryMatchCacheTests.cs


using System.Collections;
using NUnit.Framework;
using Unity.Collections;
using UnityEngine;
using UnityEngine.Perception.GroundTruth;
using UnityEngine.TestTools;

public void TryGet_ReturnsFalse_ForInvalidInstanceId()
{
var config = ScriptableObject.CreateInstance<IdLabelConfig>();
using (var cache = new LabelEntryMatchCache(config))
using (var cache = new LabelEntryMatchCache(config, Allocator.Persistent))
{
Assert.IsFalse(cache.TryGetLabelEntryFromInstanceId(100, out var labelEntry, out var index));
Assert.AreEqual(-1, index);

label = label
},
});
using (var cache = new LabelEntryMatchCache(config))
using (var cache = new LabelEntryMatchCache(config, Allocator.Persistent))
{
//allow label to be registered
yield return null;

var labeledPlane = TestHelper.CreateLabeledPlane(label: label);
AddTestObjectForCleanup(labeledPlane);
var config = ScriptableObject.CreateInstance<IdLabelConfig>();
using (var cache = new LabelEntryMatchCache(config))
using (var cache = new LabelEntryMatchCache(config, Allocator.Persistent))
{
//allow label to be registered
yield return null;

label = label
},
});
using (var cache = new LabelEntryMatchCache(config))
using (var cache = new LabelEntryMatchCache(config, Allocator.Persistent))
{
//allow label to be registered
yield return null;

},
});
using (var cache = new LabelEntryMatchCache(config))
using (var cache = new LabelEntryMatchCache(config, Allocator.Persistent))
{
//allow label to be registered
yield return null;

18
com.unity.perception/Tests/Runtime/GroundTruthTests/PerceptionCameraIntegrationTests.cs


});
return labelingConfiguration;
}
void SetupCamera(Action<PerceptionCamera> initPerceptionCamera, bool activate = true)
{
var cameraObject = new GameObject();
cameraObject.SetActive(false);
var camera = cameraObject.AddComponent<Camera>();
camera.orthographic = true;
camera.orthographicSize = 1;
var perceptionCamera = cameraObject.AddComponent<PerceptionCamera>();
perceptionCamera.captureRgbImages = false;
initPerceptionCamera?.Invoke(perceptionCamera);
if (activate)
cameraObject.SetActive(true);
AddTestObjectForCleanup(cameraObject);
}
}
}

92
com.unity.perception/Tests/Runtime/GroundTruthTests/RenderedObjectInfoTests.cs


using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Object = UnityEngine.Object;
namespace GroundTruthTests
{

var dataNativeArray = new NativeArray<Color32>(producesCorrectObjectInfoData.data, Allocator.Persistent);
var cache = labelingConfiguration.CreateLabelEntryMatchCache(Allocator.Persistent);
renderedObjectInfoGenerator.Compute(dataNativeArray, producesCorrectObjectInfoData.stride, producesCorrectObjectInfoData.boundingBoxOrigin, out var boundingBoxes, Allocator.Temp);
CollectionAssert.AreEqual(producesCorrectObjectInfoData.renderedObjectInfosExpected, boundingBoxes.ToArray());

cache.Dispose();
}
[UnityTest]
public IEnumerator LabelsCorrectWhenIdsReset()
{
int timesInfoReceived = 0;
Dictionary<int, int> expectedLabelIdAtFrame = null;
//TestHelper.LoadAndStartRenderDocCapture(out var gameView);
void OnBoundingBoxesReceived(BoundingBox2DLabeler.BoundingBoxesCalculatedEventArgs eventArgs)
{
if (expectedLabelIdAtFrame == null || !expectedLabelIdAtFrame.ContainsKey(eventArgs.frameCount)) return;
timesInfoReceived++;
Debug.Log($"Bounding boxes received. FrameCount: {eventArgs.frameCount}");
Assert.AreEqual(1, eventArgs.data.Count());
Assert.AreEqual(expectedLabelIdAtFrame[eventArgs.frameCount], eventArgs.data.First().label_id);
}
var idLabelConfig = ScriptableObject.CreateInstance<IdLabelConfig>();
idLabelConfig.Init(new []
{
new IdLabelEntry()
{
id = 1,
label = "label1"
},
new IdLabelEntry()
{
id = 2,
label = "label2"
},
new IdLabelEntry()
{
id = 3,
label = "label3"
},
});
AddTestObjectForCleanup(idLabelConfig);
var cameraObject = SetupCameraBoundingBox2D(OnBoundingBoxesReceived, idLabelConfig);
expectedLabelIdAtFrame = new Dictionary<int, int>
{
{Time.frameCount , 1},
{Time.frameCount + 1, 2},
{Time.frameCount + 2, 3}
};
GameObject planeObject;
//Put a plane in front of the camera
planeObject = TestHelper.CreateLabeledPlane(label: "label1");
yield return null;
//UnityEditorInternal.RenderDoc.EndCaptureRenderDoc(gameView);
Object.DestroyImmediate(planeObject);
planeObject = TestHelper.CreateLabeledPlane(label: "label2");
//TestHelper.LoadAndStartRenderDocCapture(out gameView);
yield return null;
//UnityEditorInternal.RenderDoc.EndCaptureRenderDoc(gameView);
Object.DestroyImmediate(planeObject);
planeObject = TestHelper.CreateLabeledPlane(label: "label3");
yield return null;
Object.DestroyImmediate(planeObject);
yield return null;
//destroy the object to force all pending segmented image readbacks to finish and events to be fired.
DestroyTestObject(cameraObject);
Assert.AreEqual(3, timesInfoReceived);
}
private GameObject SetupCameraBoundingBox2D(Action<BoundingBox2DLabeler.BoundingBoxesCalculatedEventArgs> onBoundingBoxesCalculated, IdLabelConfig idLabelConfig)
{
var cameraObject = SetupCamera(camera =>
{
camera.showVisualizations = false;
var boundingBox2DLabeler = new BoundingBox2DLabeler(idLabelConfig);
boundingBox2DLabeler.boundingBoxesCalculated += onBoundingBoxesCalculated;
camera.AddLabeler(boundingBox2DLabeler);
});
return cameraObject;
}
}
}

5
com.unity.perception/Tests/Runtime/GroundTruthTests/SegmentationGroundTruthTests.cs


void Awake()
{
m_Reader = new RenderTextureReader<Color32>(source, cameraSource, ImageReadCallback);
m_Reader = new RenderTextureReader<Color32>(source);
RenderPipelineManager.endCameraRendering += (context, camera) =>
m_Reader.Capture(context,
(frameCount, data, renderTexture) => ImageReadCallback(frameCount, data, renderTexture));
}
void ImageReadCallback(int frameCount, NativeArray<Color32> data, RenderTexture renderTexture)

55
com.unity.perception/Tests/Runtime/TestAssets/AnimatedCubeScene.unity


m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
m_AmbientIntensity: 1
m_AmbientMode: 0
m_AmbientMode: 3
m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
m_SkyboxMaterial: {fileID: 0}
m_HaloStrength: 0.5

LightmapSettings:
m_ObjectHideFlags: 0
serializedVersion: 11
m_GIWorkflowMode: 1
m_GIWorkflowMode: 0
m_GISettings:
serializedVersion: 2
m_BounceScale: 1

m_TrainingDataDestination: TrainingData
m_LightProbeSampleCountMultiplier: 4
m_LightingDataAsset: {fileID: 0}
m_UseShadowmask: 1
m_UseShadowmask: 0
--- !u!196 &4
NavMeshSettings:
serializedVersion: 2

value: AnimatedCube
objectReference: {fileID: 0}
m_RemovedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 19412e53743b3814da68e59d98ab6794, type: 3}
--- !u!1 &2024690174
GameObject:
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 2024690176}
- component: {fileID: 2024690175}
m_Layer: 0
m_Name: StaticLightingSky
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &2024690175
MonoBehaviour:
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2024690174}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 441482e8936e35048a1dffac814e3ef8, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Profile: {fileID: 0}
m_StaticLightingSkyUniqueID: 0
m_SkySettings: {fileID: 0}
m_SkySettingsFromProfile: {fileID: 0}
--- !u!4 &2024690176
Transform:
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2024690174}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: []
m_Father: {fileID: 0}
m_RootOrder: 1
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_SourcePrefab: {fileID: 100100000, guid: 19412e53743b3814da68e59d98ab6794, type: 3}
正在加载...
取消
保存