浏览代码

Merge branch '0.8.0-preview.1_staging' into packagejson_and_changelog

/main
GitHub 3 年前
当前提交
41561b2f
共有 36 个文件被更改,包括 2555 次插入3270 次删除
  1. 99
      TestProjects/PerceptionHDRP/Packages/packages-lock.json
  2. 99
      TestProjects/PerceptionURP/Packages/packages-lock.json
  3. 16
      com.unity.perception/CHANGELOG.md
  4. 6
      com.unity.perception/Documentation~/HPTutorial/TUTORIAL.md
  5. 4
      com.unity.perception/Documentation~/SetupSteps.md
  6. 723
      com.unity.perception/Documentation~/Tutorial/Images/build_uploaded.png
  7. 999
      com.unity.perception/Documentation~/Tutorial/Images/camera_prep.png
  8. 770
      com.unity.perception/Documentation~/Tutorial/Images/create_proj.png
  9. 999
      com.unity.perception/Documentation~/Tutorial/Images/package_manager.png
  10. 666
      com.unity.perception/Documentation~/Tutorial/Images/runinusim.png
  11. 883
      com.unity.perception/Documentation~/Tutorial/Images/signin.png
  12. 38
      com.unity.perception/Documentation~/Tutorial/Phase1.md
  13. 35
      com.unity.perception/Documentation~/Tutorial/Phase3.md
  14. 2
      com.unity.perception/Editor/GroundTruth/KeypointTemplateEditor.cs
  15. 2
      com.unity.perception/Runtime/GroundTruth/DatasetCapture.cs
  16. 3
      com.unity.perception/Runtime/GroundTruth/Labelers/BoundingBox3DLabeler.cs
  17. 49
      com.unity.perception/Runtime/GroundTruth/Labelers/BoundingBoxLabeler.cs
  18. 13
      com.unity.perception/Runtime/GroundTruth/Labelers/CameraLabeler.cs
  19. 3
      com.unity.perception/Runtime/GroundTruth/Labelers/InstanceSegmentationLabeler.cs
  20. 4
      com.unity.perception/Runtime/GroundTruth/Labelers/KeypointLabeler.cs
  21. 5
      com.unity.perception/Runtime/GroundTruth/Labelers/ObjectCountLabeler.cs
  22. 3
      com.unity.perception/Runtime/GroundTruth/Labelers/RenderedObjectInfoLabeler.cs
  23. 10
      com.unity.perception/Runtime/GroundTruth/Labelers/SemanticSegmentationLabeler.cs
  24. 26
      com.unity.perception/Runtime/GroundTruth/Labeling/IdLabelConfig.cs
  25. 40
      com.unity.perception/Runtime/GroundTruth/Labeling/LabelEntryMatchCache.cs
  26. 29
      com.unity.perception/Runtime/GroundTruth/PerceptionCamera.cs
  27. 32
      com.unity.perception/Runtime/GroundTruth/PerceptionCamera_InstanceSegmentation.cs
  28. 45
      com.unity.perception/Runtime/GroundTruth/RenderTextureReader.cs
  29. 4
      com.unity.perception/Runtime/GroundTruth/SimulationState.cs
  30. 18
      com.unity.perception/Tests/Editor/PerceptionCameraEditorTests.cs
  31. 19
      com.unity.perception/Tests/Runtime/GroundTruthTests/GroundTruthTestBase.cs
  32. 11
      com.unity.perception/Tests/Runtime/GroundTruthTests/LabelEntryMatchCacheTests.cs
  33. 18
      com.unity.perception/Tests/Runtime/GroundTruthTests/PerceptionCameraIntegrationTests.cs
  34. 92
      com.unity.perception/Tests/Runtime/GroundTruthTests/RenderedObjectInfoTests.cs
  35. 5
      com.unity.perception/Tests/Runtime/GroundTruthTests/SegmentationGroundTruthTests.cs
  36. 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"
},

16
com.unity.perception/CHANGELOG.md


All appearances of the term `KeyPoint` have been renamed to `Keypoint`. If you have code that relies on any renamed types or names, make sure to alter your code to reflect the new names.
`ScenarioBase`'s `Awake`, `Start`, and `Update` functions are now private. If you previously used these, replace the usages with `OnAwake`, `OnStart`, and `OnUpdate`.
`ScenarioBase`'s `Awake()`, `Start()`, and `Update()` functions are now private. If you previously used these, replace the usages with `OnAwake()`, `OnStart()`, and `OnUpdate()`.
### Known Issues

Scenario serialization has been updated to include scalar values on Randomizers and Parameters.
Added new `ScenarioBase` virtual lifecycle hooks: `OnAwake`, `OnStart`, `OnUpdate`, `OnComplete`, and `OnIdle`.
Added new `ScenarioBase` virtual lifecycle hooks: `OnAwake()`, `OnStart()`, `OnUpdate()`, `OnComplete()`, and `OnIdle()`.
Keypoint occlusion has been added. No keypoint information will be recorded for a labeled asset completely out of the camera's frustum.

Renamed all appearances of the term `KeyPoint` within types and names to `Keypoint`.
ScenarioBase's `Awake`, `Start`, and `Update` methods are now private. The newly added virtual lifecycle hooks are to be used as replacements.
ScenarioBase's `Awake()`, `Start()`, and `Update()` methods are now private. The newly added virtual lifecycle hooks are to be used as replacements.
The `GetRandomizer` and `CreateRandomizer` methods of `ScenarioBase` have been augmented or replaced with more generic list index style accessors.
The `GetRandomizer()` and `CreateRandomizer()` methods of `ScenarioBase` have been augmented or replaced with more generic list index style accessors.
RandomizerTags now use `OnEnable` and `OnDisable` to manage their lifecycle. This allows the user to toggle them on and off in the editor.
RandomizerTags now use `OnEnable()` and `OnDisable()` to manage their lifecycle. This allows the user to toggle them on and off in the editor.
`CameraLabeler` methods `OnBeginRendering()` and `OnEndRendering()` now have an added `ScriptableRenderContext` parameter.
The Randomizer methods `OnCreate`, `OnStartRunning`, and `OnStopRunning` are now deprecated and have been replaced with `OnAwake`, `OnEnable` and `OnDisable` respectively, so as to better reflect the existing MonoBehaviour lifecycle methods.
The Randomizer methods `OnCreate()`, `OnStartRunning()`, and `OnStopRunning()` are now deprecated and have been replaced with `OnAwake()`, `OnEnable()` and `OnDisable()` respectively, so as to better reflect the existing MonoBehaviour lifecycle methods.
### Removed

Fixed keypoints being reported in wrong locations on the first frame in which an object is visible.
Fixed an out of range error that occurred when a keypoint template skeleton relied on a joint that was 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

6
com.unity.perception/Documentation~/HPTutorial/TUTORIAL.md


In this tutorial, we will walk through the production of keypoint and pose datasets for computer vision tasks such as human pose estimation and gesture recognition.
We strongly recommend you finish [Phase 1 of the Perception Tutorial](../Tutorial/Phase1.md) before continuing with this one, especially if you do not have prior experience with Unity Editor. This tutorial requires at least version **0.7.0-preview.2** of the Perception package.
We strongly recommend you finish [Phase 1 of the Perception Tutorial](../Tutorial/Phase1.md) before continuing with this one, especially if you do not have prior experience with Unity Editor. This tutorial requires at least version **0.8.0-preview.1** of the Perception package.
In this tutorial, **":green_circle: Action:"** mark all of the actions needed to progress through the tutorial. If you are in a hurry, just follow the actions!

We now need to import the sample files required for this tutorial.
* **:green_circle: Action**: Open _**Package Manager**_ and select the Perception package, which should already be present in the navigation pane to the left side.
* **:green_circle: Action**: From the list of ***Samples*** for the Perception package, click on the ***Import into Project*** button for the sample bundle named _**Human Pose Estimation**_.
* **:green_circle: Action**: From the list of ***Samples*** for the Perception package, click on the ***Import*** button for the sample bundle named _**Human Pose Labeling and Randomization**_.
Once the sample files are imported, they will be placed inside the `Assets/Samples/Perception` folder in your Unity project, as seen in the image below:

* **:green_circle: Action**: Select all of the assets inside the `Assets/Samples/Perception/<perception-package-version>/Human Pose Estimation/Models and Animations`.
* **:green_circle: Action**: Select all of the assets inside the `Assets/Samples/Perception/<perception-package-version>/Human Pose Labeling and Randomization/Models and Animations`.
* **:green_circle: Action**: In the _**Inspector**_ tab, navigate to the _**Rig**_ section.
Note how `Animation Type` is set to `Humanoid` for all selected assets. This is a requirement and makes sure all animations included in the sample `.fbx` files are ready to be used on a rigged humanoid model.

4
com.unity.perception/Documentation~/SetupSteps.md


This page provides brief instructions on installing the Perception package. Head over to the [Perception Tutorial](Tutorial/TUTORIAL.md) for more detailed instructions and steps for building a sample project.
1. Install the latest version of 2019.4.x or 2020.1.x Unity Editor from [here](https://unity3d.com/get-unity/download/archive). (Perception has not been tested on Unity versions newer than 2020.1)
1. Install the latest version of **2020.2.x** Unity Editor from [here](https://unity3d.com/get-unity/download/archive). (The Perception package has not been fully tested on newer Unity versions)
1. Create a new HDRP or URP project, or open an existing project.
1. Open `Window` -> `Package Manager`
1. In the Package Manager window find and click the ***+*** button in the upper lefthand corner of the window

Note that although the Perception package is compatible with both URP and HDRP, Unity Simulation currently only supports URP projects, therefore a URP project is recommended.
If you want a specific version of the package, append the version to the end of the "git URL". Ex. `com.unity.perception@0.1.0-preview.4`
If you want a specific version of the package, append the version to the end of the "git URL". Ex. `com.unity.perception@0.8.0-preview.1`
To install from a local clone of the repository, see [installing a local package](https://docs.unity3d.com/Manual/upm-ui-local.html) in the Unity manual.

723
com.unity.perception/Documentation~/Tutorial/Images/build_uploaded.png

之前 之后
宽度: 1325  |  高度: 791  |  大小: 79 KiB

999
com.unity.perception/Documentation~/Tutorial/Images/camera_prep.png
文件差异内容过多而无法显示
查看文件

770
com.unity.perception/Documentation~/Tutorial/Images/create_proj.png

之前 之后
宽度: 1376  |  高度: 878  |  大小: 139 KiB

999
com.unity.perception/Documentation~/Tutorial/Images/package_manager.png
文件差异内容过多而无法显示
查看文件

666
com.unity.perception/Documentation~/Tutorial/Images/runinusim.png

之前 之后
宽度: 1328  |  高度: 792  |  大小: 81 KiB

883
com.unity.perception/Documentation~/Tutorial/Images/signin.png

之前 之后
宽度: 1363  |  高度: 878  |  大小: 123 KiB

38
com.unity.perception/Documentation~/Tutorial/Phase1.md


# Perception Tutorial
## Phase 1: Setup and Basic Randomizations

* [Step 8: Verify Data Using Dataset Insights](#step-8)
### <a name="step-1">Step 1: Download Unity Editor and Create a New Project</a>
* **:green_circle: Action**: Navigate to [this](https://unity3d.com/get-unity/download/archive) page to download and install the latest version of **Unity Editor 2019.4.x**. (The tutorial has not yet been fully tested on newer versions.)
* **:green_circle: Action**: Navigate to [this](https://unity3d.com/get-unity/download/archive) page to download and install the latest version of **Unity Editor 2020.2.x**. (The tutorial has not yet been fully tested on newer versions.)
An alternative approach is to first install [_**Unity Hub**_](https://unity3d.com/get-unity/download), which will allow you to have multiple versions of Unity on your computer, and make it easier to manage your Unity projects and the versions of Unity they will use.

* **:green_circle: Action**: Click on the _**+**_ sign at the top-left corner of the _**Package Manager**_ window and then choose the option _**Add package from git URL...**_.
* **:green_circle: Action**: Enter the address `com.unity.perception` and click _**Add**_.
> :information_source: If you would like to install a specific version of the package, you can append the version to the end of the url. For example `com.unity.perception@0.1.0-preview.5`. For this tutorial, **we do not need to add a version**. You can also install the package from a local clone of the Perception repository. More information on installing local packages is available [here](https://docs.unity3d.com/Manual/upm-ui-local.html).
> :information_source: If you would like to install a specific version of the package, you can append the version to the end of the url. For example `com.unity.perception@0.8.0-preview.1`. For this tutorial, **we do not need to add a version**. You can also install the package from a local clone of the Perception repository. More information on installing local packages is available [here](https://docs.unity3d.com/Manual/upm-ui-local.html).
It will take some time for the manager to download and import the package. Once the operation finishes, you will see the newly downloaded Perception package automatically selected in the _**Package Manager**_, as depicted below:

Each package can come with a set of samples. As seen in the righthand panel, the Perception package includes a sample named _**Tutorial Files**_, which will be required for completing this tutorial. The sample files consist of example foreground and background objects, Randomizer, shaders, and other useful elements to work with during this tutorial. **Foreground** objects are those that the eventual machine learning model will try to detect, and **background** objects will be placed in the background as distractors for the model.
* **:green_circle: Action**: In the _**Package Manager**_ window, from the list of _**Samples**_ for the Perception package, click on the _**Import into Project**_ button for the sample named _**Tutorial Files**_.
* **:green_circle: Action**: In the _**Package Manager**_ window, from the list of _**Samples**_ for the Perception package, click on the _**Import**_ button for the sample named _**Tutorial Files**_.
Once the sample files are imported, they will be placed inside the `Assets/Samples/Perception` folder in your Unity project. You can view your project's folder structure and access your files from the _**Project**_ tab of the editor, as seen in the image below:
Once the sample files are imported, they will be placed inside the `Assets/Samples/Perception` folder in your Unity project. You can view your project's folder structure and access your files from the _**Project**_ tab of the editor, as seen in the image below (the package version should match the version you downloaded):
<img src="Images/project_folders_samples.png" width="600"/>
<img src="Images/project_folders_samples.png" width="500"/>
</p>
* **:green_circle: Action**: **(For URP projects only)** The _**Project**_ tab contains a search bar; use it to find the file named `ForwardRenderer.asset`, as shown below:

As seen above, the new Scene already contains a camera (`Main Camera`) and a light (`Directional Light`). We will now modify the camera's field of view and position to prepare it for the tutorial.
* **:green_circle: Action**: Click on `Main Camera` and in the _**Inspector**_ tab, modify the camera's `Position`, `Rotation`, `Projection` and `Size` to match the screenshot below. (Note that `Size` only becomes available once you set `Projection` to `Orthographic`)
* **:green_circle: Action**: Click on `Main Camera` and in the _**Inspector**_ tab, make sure the camera's `Position`, `Rotation`, `Projection`, and `Field of View` match the screenshot below.
<img src="Images/camera_prep.png" width = "900"/>
<img src="Images/camera_prep.png" width = "400"/>
For this tutorial, we prefer our light to not cast any shadows, therefore:

Click on this asset to bring up its _**Inspector**_ view. In there, you can specify the labels that this config will keep track of. You can type in labels, add any labels defined in the project (through being added to prefabs), and import/export this label config as a JSON file. A new label config like this one contains an empty list of labels.
In this tutorial, we will generate synthetic data intended for detecting 10 everyday grocery items. These grocery items were imported into your project when you imported the tutorial files from the _**Package Manager**_, and are located in the folder `Assets/Samples/Perception/0.6.0-preview.1/Tutorial Files/Foreground Objects/Phase 1/Prefabs`.
In this tutorial, we will generate synthetic data intended for detecting 10 everyday grocery items. These grocery items were imported into your project when you imported the tutorial files from the _**Package Manager**_, and are located in the folder `Assets/Samples/Perception/0.8.0-preview.1/Tutorial Files/Foreground Objects/Phase 1/Prefabs`.
The label configuration we have created (`TutorialIdLabelConfig`) is of type `IdLabelConfig`, and is compatible with three of the four labelers we have attached to our `Perception Camera`. This type of label configuration carries a unique numerical ID for each label. However, `SemanticSegmentationLabeler` requires a different kind of label configuration which includes unique colors for each label instead of numerical IDs. This is because the output of this labeler is a set of images in which each visible foreground object is painted in a unique color.

<img src="Images/pclabelconfigsadded.png" width="400"/>
</p>
It is now time to assign labels to the objects that are supposed to be detected by an eventual object-detection model, and add those labels to both of the label configurations we have created. As mentioned above, these objects are located at `Assets/Samples/Perception/0.6.0-preview.1/Tutorial Files/Foreground Objects/Phase 1/Prefabs`.
It is now time to assign labels to the objects that are supposed to be detected by an eventual object-detection model, and add those labels to both of the label configurations we have created. As mentioned above, these objects are located at `Assets/Samples/Perception/0.8.0-preview.1/Tutorial Files/Foreground Objects/Phase 1/Prefabs`.
* **:green_circle: Action**: In the _**Project**_ tab, navigate to `Assets/Samples/Perception/0.6.0-preview.1/Tutorial Files/Foreground Objects/Phase 1/Prefabs`
* **:green_circle: Action**: In the _**Project**_ tab, navigate to `Assets/Samples/Perception/0.8.0-preview.1/Tutorial Files/Foreground Objects/Phase 1/Prefabs`
* **:green_circle: Action**: Double click the file named `drink_whippingcream_lucerne.prefab` to open the Prefab asset.
When you open the Prefab asset, you will see the object shown in the Scene tab and its components shown on the right side of the editor, in the _**Inspector**_ tab:

Even though the sample Prefabs already have a label manually added, to learn more about how to use the Labeling component, we will now use automatic labeling to label all our foreground objects. This will overwrite their manually added labels.
* **:green_circle: Action**: Select **all the files** inside the `Assets/Samples/Perception/0.6.0-preview.1/Tutorial Files/Foreground Objects/Phase 1/Prefabs` folder.
* **:green_circle: Action**: Select **all the files** inside the `Assets/Samples/Perception/0.8.0-preview.1/Tutorial Files/Foreground Objects/Phase 1/Prefabs` folder.
* **:green_circle: Action**: From the _**Inspector**_ tab, enable `Use Automatic Labeling for All Selected Items`, and then select `Use asset name` as the labeling scheme.
<p align="center">

Now that we have labelled all our foreground objects and setup our label configurations, let's briefly test things.
* **:green_circle: Action**: In the _**Project**_ tab, navigate to `Assets/Samples/Perception/0.6.0-preview.1/Tutorial Files/Foreground Objects/Phase 1/Prefabs`.
* **:green_circle: Action**: In the _**Project**_ tab, navigate to `Assets/Samples/Perception/0.8.0-preview.1/Tutorial Files/Foreground Objects/Phase 1/Prefabs`.
* **:green_circle: Action**: Drag and drop any of the Prefabs inside this folder into the Scene.
* **:green_circle: Action**: Click on the **▷** (play) button located at the top middle section of the editor to run your simulation.

This Randomizer uses Poisson-Disk sampling to select random positions from a given area, and spawn copies of randomly selected Prefabs (from a given list) at the chosen positions. We will use this component to generate a background that will act as a distraction for our eventual object-detection machine learning model.
* **:green_circle: Action**: Click _**Add Folder**_, and from the file explorer window that opens, choose the folder `Assets/Samples/Perception/0.6.0-preview.1/Tutorial Files/Background Objects/Prefabs`.
* **:green_circle: Action**: Click _**Add Folder**_, and from the file explorer window that opens, choose the folder `Assets/Samples/Perception/0.8.0-preview.1/Tutorial Files/Background Objects/Prefabs`.
The background Prefabs are primitive shapes devoid of color or texture. Later Randomizers will take care of those aspects.

<img src="Images/first_run.png" width = "700"/>
</p>
In this view, you will also see the real-time visualizations we discussed before shown on top of the camera's view. In the top right corner of the window, you can see a visualization control panel, through which you can enable or disable visualizations for individual labelers. That said, we currently have no foreground objects in the Scene yet, so no bounding boxes or semantic segmentations will be displayed.
In this view, you will also see the real-time visualizations we discussed before shown on top of the camera's view. In the top right corner of the window, you can see a visualization control panel, through which you can enable or disable visualizations for individual labelers. That said, we currently have no foreground objects in the Scene yet, so no bounding boxes or semantic segmentation overlays will be displayed.
Note that disabling visualizations for a labeler does not affect your generated data. The annotations from all labelers that are active before running the simulation will continue to be recorded and will appear in the output data.

`TextureRandomizer` will have the task of attaching random textures to our colorless background objects at each Iteration of the Scenario. Similarly, `HueOffsetRandomizer` will alter the color of the objects, and `RotationRandomizer` will give the objects a new random rotation each Iteration.
* **:green_circle: Action**: In the UI snippet for `TextureRandomizer`, click _**Add Folder**_ and choose `Assets/Samples/Perception/0.6.0-preview.1/Tutorial Files/Background Textures`.
* **:green_circle: Action**: In the UI snippet for `TextureRandomizer`, click _**Add Folder**_ and choose `Assets/Samples/Perception/0.8.0-preview.1/Tutorial Files/Background Textures`.
* **:green_circle: Action**: In the UI snippet for `RotationRandomizer`, verify that all the minimum values for the three ranges are `0` and that maximum values are `360`.

To make sure each Randomizer knows which objects it should work with, we will use an object tagging and querying workflow that the bundled Randomizers already use. Each Randomizer can query the Scene for objects that carry certain types of `RandomizerTag` components. For instance, the `TextureRandomizer` queries the Scene for objects that have a `TextureRandomizerTag` component (you can change this in code!). Therefore, in order to make sure our background Prefabs are affected by the `TextureRandomizer` we need to make sure they have `TextureRandomizerTag` attached to them.
* **:green_circle: Action**: In the _**Project**_ tab, navigate to `Assets/Samples/Perception/0.6.0-preview.1/Tutorial Files/Background Objects/Prefabs`.
* **:green_circle: Action**: In the _**Project**_ tab, navigate to `Assets/Samples/Perception/0.8.0-preview.1/Tutorial Files/Background Objects/Prefabs`.
* **:green_circle: Action**: Select all the files inside and from the _**Inspector**_ tab add a `TextureRandomizerTag` to them. This will add the component to all the selected files.
* **:green_circle: Action**: Repeat the above step to add `HueOffsetRandomizerTag` and `RotationRandomizerTag` to all selected Prefabs.

It is now time to spawn and randomize our foreground objects.
* **:green_circle: Action**: Add `ForegroundObjectPlacementRandomizer` to your list of Randomizers. Click _**Add Folder**_ and select `Assets/Samples/Perception/0.6.0-preview.1/Tutorial Files/Foreground Objects/Phase 1/Prefabs`.
* **:green_circle: Action**: Add `ForegroundObjectPlacementRandomizer` to your list of Randomizers. Click _**Add Folder**_ and select `Assets/Samples/Perception/0.8.0-preview.1/Tutorial Files/Foreground Objects/Phase 1/Prefabs`.
* **:green_circle: Action**: Set these values for the above Randomizer: `Depth = -3, Separation Distance = 1.5, Placement Area = (5,5)`.
This Randomizer uses the same algorithm as the one we used for backgrounds; however, it is defined in a separate C# class because you can only have **one of each type of Randomizer added to your Scenario**. Therefore, this is our way of differentiating between how background and foreground objects are treated.

* **:green_circle: Action**: From the _**Project**_ tab select all the foreground Prefabs located in `Assets/Samples/Perception/0.6.0-preview.1/Tutorial Files/Foreground Objects/Phase 1/Prefabs`, and add a `RotationRandomizerTag` component to them.
* **:green_circle: Action**: From the _**Project**_ tab select all the foreground Prefabs located in `Assets/Samples/Perception/0.8.0-preview.1/Tutorial Files/Foreground Objects/Phase 1/Prefabs`, and add a `RotationRandomizerTag` component to them.
Randomizers execute according to their order within the list of Randomizers added to your Scenario. If you look at the list now, you will notice that `ForegroundObjectPlacementRandomizer` is coming after `RotationRandomizer`, therefore, foreground objects will NOT be included in the rotation randomizations, even though they are carrying the proper RandomizerTag. To fix that:

35
com.unity.perception/Documentation~/Tutorial/Phase3.md


<img src="Images/cloud_icon.png" width="400"/>
</p>
If you have not logged in yet, the _**Services**_ tab will display a message noting that you are offline:
* **:green_circle: Action** Click the ***General settings***.
This will open the ***Services*** tab of the ***Project Settings*** window. If you have not logged in yet, you will see a message noting that you are signed out:
<img src="Images/signin.png" width="400"/>
<img src="Images/signin.png" width="600"/>
* **:green_circle: Action**: Click _**Sign in...**_ and follow the steps in the window that opens to sign in or create an account.
* **:green_circle: Action**: Click _**Sign in...**_ and follow the steps in the window that opens to sign in or create a Unity account.
Once you have registered for a free trial, you will be taken to your Unity Simulation dashboard, where you will be able to observe your usage and billing invoices.
Once you have registered for a free trial, you will be taken to your Unity Simulation dashboard, where you will be able to observe your usage and billing information.
* **:green_circle: Action**: Return to Unity Editor. In the _**Services**_ tab click _**Select Organization**_ and choose the only available option (which typically has the same name as your Unity username).
* **:green_circle: Action**: Return to Unity Editor. Click _**Select Organization**_ and choose the only available option (which typically has the same name as your Unity username).
If you have used Unity before, you might have set-up multiple organizations for your account. In that case, choose whichever you would like to associate with this project.
If you have used Unity before, you might have set up multiple organizations for your account. In that case, choose whichever you would like to associate with this project.
<img src="Images/create_proj.png" width="400"/>
<img src="Images/create_proj.png" width="600"/>
* **:green_circle: Action**: Click _**Create**_ to create a new cloud project and connect your local project to it.
* **:green_circle: Action**: Click _**Create Project ID**_ to create a new cloud project and connect your local project to it.
### <a name="step-2">Step 2: Run Project on Unity Simulation</a>

<img src="Images/runinusim.png" width="600"/>
</p>
* **:green_circle: Action**: Choose `TutorialScene` (which is the Scene we have been working in) as your _**Main Scene**_ and the `SimulationScenario` object as your _**Scenario**_.
Here, you can also specify a name for the run, the number of Iterations the Scenario will execute for, and the number of _**Instances**_ (number of nodes the work will be distributed across) for the run.
Here, you can also specify a name for the run, the number of Iterations the Scenario will execute for, and the number of _**Instances**_ (number of nodes the work will be distributed across) for the run. This window automatically picks the currently active Scene and Scenario to run in Unity Simulation.
Your project will now be built and then uploaded to Unity Simulation. This may take a few minutes to complete, during which the editor may become frozen; this is normal behaviour.
> :information_source: You can ignore the ***Optional Configuration*** section for now. This is useful if you plan to specify a configuration for your Scenario (including the Randomizers) that will override the values set in the Scenario UI, in Unity Simulation. To generate a configuration, you can click on the ***Generate JSON Config*** button provided in the ***Inspector*** view of Scenario components.
Your project will now be built and then uploaded to Unity Simulation and run. This may take a few minutes to complete, during which the editor may become frozen; this is normal behaviour.
* **:green_circle: Action**: Once the operation is complete, you can find the **Build ID**, **Run Definition ID**, and **Execution ID** of this Unity Simulation run in the _**Console**_ tab:
* **:green_circle: Action**: Once the operation is complete, you can find the **Execution ID** of this Unity Simulation run in the **Console** tab and the ***Run in Unity Simulation** Window:
<img src="Images/build_uploaded.png"/>
<img src="Images/build_uploaded.png" width="600"/>
### <a name="step-3">Step 3: Keep Track of Your Runs Using the Unity Simulation Command-Line Interface</a>

Follow the rest of the steps inside the notebook to generate a variety of plots and stats. Keep in mind that this notebook is provided just as an example, and you can modify and extend it according to your own needs using the tools provided by the [Dataset Insights framework](https://datasetinsights.readthedocs.io/en/latest/).
This concludes the Perception Tutorial. The next step in this workflow would be to train an object-detection model using a dataset generated on Unity Simulation. It is important to note that the 1000 large dataset we generated here is probably not sufficiently large for training most models. We chose this number here so that the run would complete in a fairly short period of time, allowing us to move on to learning how to analyze the statistics of the dataset. In order to generate data for training, we recommend a dataset of about 400,000 captures.
The next step in this workflow, which is out of the scope of this tutorial, is to train an object-detection model using our synthetic dataset. It is important to note that the 1000 large dataset we generated here is probably not sufficiently large for training most models. We chose this number here so that the Unity Simulation run would finish quickly, allowing us to move on to learning how to analyze the statistics of the dataset. In order to generate data for training, we recommend a minimum dataset size of around 50,000 captures with a large degree of randomization.
This concludes the Perception Tutorial. In case of any issues or questions, please feel free to open a GitHub issue on the `com.unity.perception` repository so that the Unity Computer Vision team can get back to you as soon as possible.

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}
正在加载...
取消
保存