浏览代码

Merge remote-tracking branch 'origin/master' into keypoint_self_occlusion

/keypoint_self_occlusion
Jon Hogins 3 年前
当前提交
0ec551af
共有 122 个文件被更改,包括 11521 次插入2170 次删除
  1. 2
      .yamato/environments.yml
  2. 2
      .yamato/upm-ci-performance.yml
  3. 6
      .yamato/upm-ci-testprojects.yml
  4. 21
      README.md
  5. 14
      TestProjects/PerceptionURP/Packages/packages-lock.json
  6. 45
      com.unity.perception/CHANGELOG.md
  7. 35
      com.unity.perception/Documentation~/GroundTruthLabeling.md
  8. 9
      com.unity.perception/Documentation~/HPTutorial/TUTORIAL.md
  9. 7
      com.unity.perception/Documentation~/Randomization/Index.md
  10. 1
      com.unity.perception/Documentation~/Schema/Synthetic_Dataset_Schema.md
  11. 999
      com.unity.perception/Documentation~/Schema/image_0.png
  12. 999
      com.unity.perception/Documentation~/Tutorial/Images/di_usim_2.png
  13. 589
      com.unity.perception/Documentation~/Tutorial/Images/build_uploaded.png
  14. 597
      com.unity.perception/Documentation~/Tutorial/Images/runinusim.png
  15. 13
      com.unity.perception/Documentation~/Tutorial/Phase3.md
  16. 2
      com.unity.perception/Documentation~/Tutorial/TUTORIAL.md
  17. 5
      com.unity.perception/Documentation~/Tutorial/Phase1.md
  18. 34
      com.unity.perception/Documentation~/Tutorial/Phase2.md
  19. 12
      com.unity.perception/Editor/GroundTruth/IdLabelConfigEditor.cs
  20. 70
      com.unity.perception/Editor/GroundTruth/PerceptionCameraEditor.cs
  21. 13
      com.unity.perception/Editor/Randomization/Utilities/UIElementsEditorUtilities.cs
  22. 5
      com.unity.perception/Editor/Randomization/Utilities/StaticData.cs
  23. 2
      com.unity.perception/Editor/Randomization/Uxml/Sampler/SamplerInterfaceElement.uxml
  24. 7
      com.unity.perception/Editor/Randomization/Uxml/ScenarioBaseElement.uxml
  25. 16
      com.unity.perception/Editor/Randomization/Uxml/RunInUnitySimulationWindow.uxml
  26. 16
      com.unity.perception/Editor/Randomization/VisualElements/Parameter/ParameterElement.cs
  27. 15
      com.unity.perception/Editor/Randomization/VisualElements/Sampler/SamplerInterfaceElement.cs
  28. 221
      com.unity.perception/Editor/Randomization/Editors/RunInUnitySimulationWindow.cs
  29. 15
      com.unity.perception/Editor/Randomization/Editors/ScenarioBaseEditor.cs
  30. 2
      com.unity.perception/Runtime/GroundTruth/DatasetJsonUtility.cs
  31. 2
      com.unity.perception/Runtime/GroundTruth/Labelers/BoundingBox3DLabeler.cs
  32. 51
      com.unity.perception/Runtime/GroundTruth/Labelers/CameraLabeler.cs
  33. 2
      com.unity.perception/Runtime/GroundTruth/Labelers/KeypointLabeler.cs
  34. 6
      com.unity.perception/Runtime/GroundTruth/Labelers/ObjectCountLabeler.cs
  35. 4
      com.unity.perception/Runtime/GroundTruth/PerceptionCamera.cs
  36. 22
      com.unity.perception/Runtime/GroundTruth/SimulationState.cs
  37. 10
      com.unity.perception/Runtime/Randomization/Parameters/CategoricalParameter.cs
  38. 109
      com.unity.perception/Runtime/Randomization/Randomizers/RandomizerExamples/Utilities/GameObjectOneWayCache.cs
  39. 3
      com.unity.perception/Runtime/Randomization/Scenarios/Serialization/SerializationStructures.cs
  40. 5
      com.unity.perception/Runtime/Randomization/Scenarios/Serialization/ScenarioSerializer.cs
  41. 18
      com.unity.perception/Runtime/Randomization/Scenarios/UnitySimulationScenario.cs
  42. 145
      com.unity.perception/Runtime/Randomization/Scenarios/ScenarioBase.cs
  43. 4
      com.unity.perception/Tests/Editor/PerceptionCameraEditorTests.cs
  44. 2
      com.unity.perception/Tests/Runtime/GroundTruthTests/DatasetJsonUtilityTests.cs
  45. 2
      com.unity.perception/Tests/Runtime/GroundTruthTests/VisualizationTests.cs
  46. 15
      com.unity.perception/Tests/Runtime/Randomization/ScenarioTests/Resources/SampleScenarioConfiguration.json
  47. 55
      com.unity.perception/Tests/Runtime/Randomization/ScenarioTests/ScenarioTests.cs
  48. 4
      com.unity.perception/package.json
  49. 15
      TestProjects/PerceptionURP/ProjectSettings/BurstAotSettings_StandaloneOSX.json
  50. 994
      com.unity.perception/Documentation~/Randomization/Images/randomization_uml.png
  51. 250
      com.unity.perception/Documentation~/images/labeling_uml.png
  52. 140
      com.unity.perception/Documentation~/images/unity-wide-whiteback.png
  53. 8
      com.unity.perception/Editor/Pyrception.meta
  54. 51
      com.unity.perception/Editor/Randomization/PropertyDrawers/UIntDrawer.cs
  55. 11
      com.unity.perception/Editor/Randomization/PropertyDrawers/UIntDrawer.cs.meta
  56. 11
      com.unity.perception/Editor/Randomization/PropertyDrawers/AssetSourceDrawer.cs.meta
  57. 26
      com.unity.perception/Editor/Randomization/PropertyDrawers/AssetSourceDrawer.cs
  58. 22
      com.unity.perception/Editor/Randomization/Utilities/AssetLoadingUtilities.cs
  59. 11
      com.unity.perception/Editor/Randomization/Utilities/AssetLoadingUtilities.cs.meta
  60. 8
      com.unity.perception/Editor/Randomization/Uxml/AssetSource.meta
  61. 8
      com.unity.perception/Editor/Randomization/VisualElements/Basic.meta
  62. 8
      com.unity.perception/Editor/Randomization/VisualElements/AssetSource.meta
  63. 8
      com.unity.perception/Editor/Visualizer.meta
  64. 8
      com.unity.perception/Runtime/Randomization/Randomizers/AssetSources.meta
  65. 8
      com.unity.perception/Tests/Runtime/Randomization/AssetSourceTests.meta
  66. 43
      com.unity.perception/Tests/Runtime/Randomization/ScenarioTests/ExampleDelayRandomizer.cs
  67. 11
      com.unity.perception/Tests/Runtime/Randomization/ScenarioTests/ExampleDelayRandomizer.cs.meta
  68. 1001
      com.unity.perception/Documentation~/FAQ/images/inner_objects.png
  69. 1001
      com.unity.perception/Documentation~/FAQ/images/inner_labels.gif
  70. 229
      com.unity.perception/Documentation~/FAQ/images/cluster_randomizer.png
  71. 199
      com.unity.perception/Documentation~/FAQ/images/prefab_cluster.png
  72. 1001
      com.unity.perception/Documentation~/FAQ/images/hdrp.png
  73. 1001
      com.unity.perception/Documentation~/FAQ/images/hdrp_pt_128_samples.png
  74. 1001
      com.unity.perception/Documentation~/FAQ/images/hdrp_pt_4096_samples.png
  75. 1001
      com.unity.perception/Documentation~/FAQ/images/hdrp_rt_gi.png
  76. 419
      com.unity.perception/Documentation~/FAQ/images/volume.png
  77. 609
      com.unity.perception/Documentation~/FAQ/FAQ.md
  78. 10
      com.unity.perception/Editor/Randomization/Uxml/AssetSource/AssetListElement.uxml
  79. 10
      com.unity.perception/Editor/Randomization/Uxml/AssetSource/AssetListElement.uxml.meta
  80. 7
      com.unity.perception/Editor/Randomization/Uxml/AssetSource/AssetListItemElement.uxml
  81. 10
      com.unity.perception/Editor/Randomization/Uxml/AssetSource/AssetListItemElement.uxml.meta
  82. 10
      com.unity.perception/Editor/Randomization/Uxml/AssetSource/AssetSourceElement.uxml.meta
  83. 26
      com.unity.perception/Editor/Randomization/Uxml/AssetSource/AssetSourceElement.uxml
  84. 11
      com.unity.perception/Editor/Randomization/VisualElements/Basic/UIntField.cs.meta
  85. 11
      com.unity.perception/Editor/Randomization/VisualElements/Basic/UxmlUIntAttributeDescription.cs.meta
  86. 136
      com.unity.perception/Editor/Randomization/VisualElements/Basic/UIntField.cs
  87. 52
      com.unity.perception/Editor/Randomization/VisualElements/Basic/UxmlUIntAttributeDescription.cs
  88. 11
      com.unity.perception/Editor/Randomization/VisualElements/AssetSource/AssetListElement.cs.meta
  89. 39
      com.unity.perception/Editor/Randomization/VisualElements/AssetSource/AssetListItemElement.cs
  90. 11
      com.unity.perception/Editor/Randomization/VisualElements/AssetSource/AssetListItemElement.cs.meta
  91. 11
      com.unity.perception/Editor/Randomization/VisualElements/AssetSource/AssetSourceElement.cs.meta

2
.yamato/environments.yml


- name: standalone
display_name: standalone
args: --suite=playmode --platform=
suites:
- name: standalone
display_name: standalone

2
.yamato/upm-ci-performance.yml


agent:
type: Unity::VM::GPU
model: rtx2080
image: cds-ops/ubuntu-18.04-base:latest
image: cds-ops/ubuntu-18.04-base:stable
flavor: b1.large
variables:
PATH: /root/.local/bin:/home/bokken/bin:/home/bokken/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/sbin:/home/bokken/.npm-global/bin

6
.yamato/upm-ci-testprojects.yml


commands:
- git submodule update --init --recursive
- unity-downloader-cli -u {{ editor.version }} -c editor -c StandaloneSupport-IL2CPP -c Linux --wait --published
- .\.Editor\Unity.exe -projectPath ./TestProjects/PerceptionHDRP -testPlatform editmode -runTests -automated -testResults test-results -debugCodeOptimization -enableCodeCoverage -coverageResultsPath test-results --category=!Performance -coverageOptions enableCyclomaticComplexity;generateHtmlReport;generateBadgeReport; assemblyFilters:Unity.Perception.Editor;Unity.Perception.Runtime;Unity.Perception.Sensors;
- .\.Editor\Unity.exe -projectPath ./TestProjects/PerceptionHDRP -testPlatform playmode -runTests -automated -testResults test-results -debugCodeOptimization -enableCodeCoverage -coverageResultsPath test-results --category=!Performance -coverageOptions enableCyclomaticComplexity;generateHtmlReport;generateBadgeReport; assemblyFilters:Unity.Perception.Editor;Unity.Perception.Runtime;Unity.Perception.Sensors;
- .\.Editor\Unity.exe -projectPath ./TestProjects/PerceptionHDRP -testPlatform editmode -runTests -automated -testResults test-results -debugCodeOptimization -enableCodeCoverage -coverageResultsPath test-results --category=!Performance -coverageOptions enableCyclomaticComplexity;generateHtmlReport;generateBadgeReport;assemblyFilters:+Unity.Perception.Runtime
- .\.Editor\Unity.exe -projectPath ./TestProjects/PerceptionHDRP -testPlatform playmode -runTests -automated -testResults test-results -debugCodeOptimization -enableCodeCoverage -coverageResultsPath test-results --category=!Performance -coverageOptions enableCyclomaticComplexity;generateHtmlReport;generateBadgeReport;assemblyFilters:+Unity.Perception.Runtime
# - .\.Editor\Unity.exe -projectPath ./TestProjects/PerceptionHDRP -debugCodeOptimization -enableCodeCoverage -coverageResultsPath test-results -coverageOptions enableCyclomaticComplexity;generateHtmlReport;generateBadgeReport;
artifacts:
logs:

agent:
type: Unity::VM::GPU
model: rtx2080
image: cds-ops/ubuntu-18.04-base:latest
image: cds-ops/ubuntu-18.04-base:stable
flavor: b1.large
variables:
PATH: /root/.local/bin:/home/bokken/bin:/home/bokken/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/sbin:/home/bokken/.npm-global/bin

21
README.md


<img src="com.unity.perception/Documentation~/images/unity-wide.png" align="middle" width="3000"/>
<img src="com.unity.perception/Documentation~/images/unity-wide-whiteback.png" align="middle" width="3000"/>
<img src="com.unity.perception/Documentation~/images/banner2.PNG" align="middle"/>

<img src="https://img.shields.io/badge/unity-2019.4-green.svg?style=flat-square" alt="unity 2019.4">
<img src="https://img.shields.io/badge/unity-2020.2-green.svg?style=flat-square" alt="unity 2020.2">
<img src="https://img.shields.io/badge/unity-2020.2-green.svg?style=flat-square" alt="unity 2020.3">
> com.unity.perception is in active development. Its features and API are subject to significant change as development progresses.
> `com.unity.perception` is in active development. Its features and API are subject to significant change as development progresses.
# Perception Package ([Unity Computer Vision](https://unity.com/computer-vision))

**[Human Pose Labeling and Randomization Tutorial](com.unity.perception/Documentation~/HPTutorial/TUTORIAL.md)**
Step by step instructions for using the keypoint, pose, and animation randomization tools included in the Perception package. It is recommended that you finish Phase 1 of the Perception Tutorial above before starting this tutorial.
**[FAQ](com.unity.perception/Documentation~/FAQ/FAQ.md)**
Check out our FAQ for a list of common questions, tips, tricks, and some sample code.
## Documentation
In-depth documentation on individual components of the package.

|[Dataset Capture](com.unity.perception/Documentation~/DatasetCapture.md)|Ensures sensors are triggered at proper rates and accepts data for the JSON dataset.|
|[Randomization](com.unity.perception/Documentation~/Randomization/Index.md)|The Randomization tool set lets you integrate domain randomization principles into your simulation.|
## Community and Support
For setup problems or discussions about leveraging the Perception package in your project, please create a new thread on the **[Unity Computer Vision forum](https://forum.unity.com/forums/computer-vision.626/)** and make sure to include as much detail as possible. If you run into any other problems with the Perception package or have a specific feature request, please submit a **[GitHub issue](https://github.com/Unity-Technologies/com.unity.perception/issues)**.
For any other questions or feedback, connect directly with the Computer Vision team at [computer-vision@unity3d.com](mailto:computer-vision@unity3d.com).
## Example Projects
### SynthDet

## License
* [License](com.unity.perception/LICENSE.md)
## Community and Feedback
For setup problems or discussions about leveraging the Perception package in your project, please create a new thread on the [Unity Computer Vision forum](https://forum.unity.com/forums/computer-vision.626/) and make sure to include as much detail as possible. If you run into any other problems with the Perception package or have a specific feature request, please submit a [GitHub issue](https://github.com/Unity-Technologies/com.unity.perception/issues).
For any other questions or feedback, connect directly with the Computer Vision team at [computer-vision@unity3d.com](mailto:computer-vision@unity3d.com).
## Citation
If you find this package useful, consider citing it using:

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


"com.unity.collections": "0.9.0-preview.6",
"com.unity.nuget.newtonsoft-json": "1.1.2",
"com.unity.render-pipelines.core": "7.1.6",
"com.unity.simulation.capture": "0.0.10-preview.20",
"com.unity.simulation.capture": "0.0.10-preview.23",
"com.unity.simulation.client": "0.0.10-preview.10",
"com.unity.simulation.core": "0.0.10-preview.22"
}

"url": "https://packages.unity.com"
},
"com.unity.simulation.capture": {
"version": "0.0.10-preview.20",
"version": "0.0.10-preview.23",
"com.unity.simulation.core": "0.0.10-preview.22"
"com.unity.simulation.core": "0.0.10-preview.25"
},
"url": "https://packages.unity.com"
},

"url": "https://packages.unity.com"
},
"com.unity.simulation.core": {
"version": "0.0.10-preview.22",
"depth": 1,
"version": "0.0.10-preview.25",
"depth": 2,
"dependencies": {},
"dependencies": {
"com.unity.nuget.newtonsoft-json": "2.0.0-preview"
},
"url": "https://packages.unity.com"
},
"com.unity.sysroot": {

45
com.unity.perception/CHANGELOG.md


### Known Issues
### Added
The user can now choose the base folder location to store their generated datasets.
Added the AssetSource class for loading assets from generic sources inside randomizers.
Users can now choose the base folder location to store their generated datasets.
Added a `projection` field in the capture.sensor metadata. Values are either "perspective" or "orthographic".
Users can now delay the current iteration for one frame from within randomizers by calling the `DelayIteration` function of the active scenario.
### Changed
Changed the JSON serialization key of Normal Sampler's standard deviation property from "standardDeviation" to "stddev". Scneario JSON configurations that were generated using previous versions will need to be manually updated to reflect this change.
### Deprecated
### Removed
### Fixed
Fixed an indexing issue with the IdLabelConfig editor. When a new label was added to an empty Id Label Config with Auto Assign IDs enabled, the starting id (0 or 1) was ignored and the new label would always have an id of 0.
## [0.8.0-preview.4] - 2021-07-05
### Upgrade Notes
### Known Issues
When using URP in OSX, having MSAA enabled on the camera while the post-processing option is disabled may cause the output RGB images to be blank. As a workaround, you can disable MSAA and use FXAA instead, until the issue is fixed.
### Added
Added random seed field to the Run in Unity Simulation Window.
Added support for keypoint self occlusion.
Added the ability to adjust keypoint self occlusion tolerance per keypoint in keypoint template file.

Added a Keypoint Occlusion Override component which allows a user to universally scale all of the keypoint tolerances for a model.
### Changed
Increased color variety in instance segmentation images
Increased color variety in instance segmentation images.
Upgraded capture package dependency to 0.0.10-preview.23 to fix two issues: (1) Post processing effects were not included when capturing images in URP (2) RGB images were upside-down when post processing effects were enabled and FXAA disabled.
### Deprecated

Fixed an issue where Simulation Delta Time values larger than 100 seconds (in Perception Camera) would cause incorrect capture scheduling behavior.
Fixed an issue where Simulation Delta Time values larger than 100 seconds in Perception Camera would cause incorrect capture scheduling behavior.
Fixed an issue where Categorical Parameters sometimes tried to fetch items at `i = categories.Count`, which caused an exception.
## [0.8.0-preview.3] - 2021-03-24
### Changed

35
com.unity.perception/Documentation~/GroundTruthLabeling.md


# Labeling
Many labelers require mapping the objects in the view to the values recorded in the dataset. As an example, Semantic Segmentation needs to determine the color to draw each object in the segmentation image.
# Ground Truth Generation
The Perception package includes a set of Labelers which capture ground truth information along with each captured frame. The built-in Labelers support a variety of common computer vision tasks, including 2D and 3D bounding boxes, instance and semantic segmentation, and keypoint labeling (labeled points on 3D objects). The package also includes extensible components for building new Labelers to support additional tasks. Labelers derive ground truth data from labels specified on the GameObjects present in the Scene.
<p align="center">
<img src="images/labeling_uml.png" width="800"/>
<br><i>Class diagram for the ground truth generation system of the Perception package</i>
</p>
## Camera Labeler
A set of Camera Labelers are added to the Perception Camera, each tasked with generating a specific type of ground truth. For instance, the Semantic Segmentation Labeler outputs segmentation images in which each labeled object is rendered in a unique user-definable color and non-labeled objects and the background are rendered black.
## Label Config
The Label Config acts as a mapping between string labels and object classes (currently colors or integers), deciding which labels in the Scene (and thus which objects) should be tracked by the Labeler, and what color (or integer id) they should have in the captured frames.
## Labeling Component
The Labeling component associates a list of string-based labels with a GameObject and its descendants. A Labeling component on a descendant overrides its parent's labels.
## Label Resolution
The Labeling component added to the GameObjects in the Scene works in conjunction with each active Labeler's Label Config, in order to map each labeled GameObject to an object class in the output.
## Labeling component
The Labeling component associates a list of string-based labels with a GameObject and its descendants. A Labeling component on a descendant overrides its parent's labels.
### Limitations
## Limitations
## Label Config
Many labelers require a Label Config asset. This asset specifies a list of all labels to be captured in the dataset along with extra information used by the various labelers.
For example, you could label an asset representing a box of Rice Krispies as `food\cereal\kellogs\ricekrispies`
For example, you can assign four different labels to an asset representing a box of Rice Krispies so as to define an inherent hierarchy:
* "food": type
* "cereal": subtype

If the goal of the algorithm is to identify all objects in a Scene that are "food", that label is available and can be used. Conversely if the goal is to identify only Rice Krispies cereal within a Scene that label is also available. Depending on the goal of the algorithm, you can use any mix of labels in the hierarchy.
This way, you can have Label Configs that include labels from different levels of this hierarchy so that you can easily switch an object's label in the output by switching to a different Label Config. If the goal of the algorithm is to identify all objects in a Scene that are "food", that label is available and can be used if the Label Config only contains "food" and not the other labels of the object. Conversely if the goal is to identify only Rice Krispies cereal within a Scene, that label is also available. Depending on the goal of the algorithm, you can use any mix of labels in the hierarchy.

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


* [Step 5: Add Joints to the Character and Customize Keypoint Templates](#step-5)
* [Step 6: Randomize the Humanoid Character's Animations](#step-6)
> :information_source: If you face any problems while following this tutorial, please create a post on the **[Unity Computer Vision forum](https://forum.unity.com/forums/computer-vision.626/)** or the **[GitHub issues](https://github.com/Unity-Technologies/com.unity.perception/issues)** page and include as much detail as possible.
### <a name="step-1">Step 1: Import `.fbx` Models and Animations</a>
This tutorial assumes that you have already created a Unity project, installed the Perception package, and set up a Scene with a `Perception Camera` inside. If this is not the case, please follow **steps 1 to 3** of [Phase 1 of the Perception Tutorial](../Tutorial/Phase1.md).

</p>
* **:green_circle: Action**: Return to `Perception Camera` and assign `HPE_IdLabelConfig` to the `KeyPointLabeler`'s label configuration property.
* **:green_circle: Action**: Search in the _**Project**_ tab for `CocoKeypointTemplate`, with the scope set to _**In Packages**_. Drag and drop the found asset into the `Active Template` field of the `Perception Camera`.
</p>
</p>
Note the `CocoKeypointTemplate` asset that is already assigned as the `Active Template`. This template will tell the labeler how to map default Unity rig joints to human joint labels in the popular COCO dataset so that the output of the labeler can be easily converted to COCO format. Later in this tutorial, we will learn how to add more joints to our character and how to customize joint mapping templates.
The `Active Template` tells the labeler how to map default Unity rig joints to human joint labels in the popular COCO dataset so that the output of the labeler can be easily converted to COCO format. Later in this tutorial, we will learn how to add more joints to our character and how to customize joint mapping templates.
<p align="center">
<img src="Images/take_objects_keypoints.gif" width="600"/>

7
com.unity.perception/Documentation~/Randomization/Index.md


4. Parameters
5. Samplers
<br>
<p align="center">
<img src="Images/randomization_uml.png" width="900"/>
<br><i>Class diagram for the randomization framework included in the Perception package</i>
</p>
## Scenarios

1
com.unity.perception/Documentation~/Schema/Synthetic_Dataset_Schema.md


translation: <float, float, float> -- Position in meters: (x, y, z) with respect to the ego coordinate system. This is typically fixed during the simulation, but we can allow small variation for domain randomization.
rotation: <float, float, float, float> -- Orientation as quaternion: (w, x, y, z) with respect to ego coordinate system. This is typically fixed during the simulation, but we can allow small variation for domain randomization.
camera_intrinsic: <3x3 float matrix> [optional] -- Intrinsic camera calibration. Empty for sensors that are not cameras.
projection: <string> -- holds the type of projection the camera used for that capture: Options: "perspective" or "orthographic"
# add arbitrary optional key-value pairs for sensor attributes
}

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

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

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

之前 之后
宽度: 1382  |  高度: 841  |  大小: 68 KiB

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

之前 之后
宽度: 1212  |  高度: 812  |  大小: 61 KiB

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


Here, you can 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.
* **:green_circle: Action**: Name your run `FirstRun`, set the number of Iterations to `1000`, and Instances to `20`.
* **:green_circle: Action**: Name your run `FirstRun`, set the number of Iterations to `1000`, and Instances to `20`.
* **:green_circle: Action**: If you'd like to use a new random seed for this run of your Scenario, click `Randomize` to generate a new seed.
* **:green_circle: Action**: Click _**Build and Run**_.
> :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.

```
name id creation time
--------------------- ---------------------------------------- ---------------------------
Perception Tutorial acd31956-582b-4138-bec8-6670be150f09 * 2020-09-30T00:33:41+00:00
Perception Tutorial 38baa0d0-a2cd-4ee1-801b-39ca3fc5cbc6 * 2020-09-30T00:33:41+00:00
SynthDet 9ec23417-73cd-becd-9dd6-556183946153 2020-08-12T19:46:20+00:00
```

An example output with 3 runs would look like this:
```
Active Project ID: acd31956-582b-4138-bec8-6670be150f09
Active Project ID: 38baa0d0-a2cd-4ee1-801b-39ca3fc5cbc6
yegz4WN In_Progress 2020-10-01 23:17:54
ojE8Z20 In_Progress 2020-10-01 23:17:54
Run2 klvfxgT 2020-10-01 21:46:39 id status created_at
--------- ------------- ---------------------
kML3i50 In_Progress 2020-10-01 21:46:42

You can also obtain a list of all the builds you have uploaded to Unity Simulation using the `usim get builds` command.
You may notice that the IDs seen above for the run named `FirstRun` match those we saw earlier in Unity Editor's _**Console**_. You can see here that the single execution for our recently uploaded build is `In_Progress` and that the execution ID is `yegz4WN`.
You may notice that the IDs seen above for the run named `FirstRun` match those we saw earlier in Unity Editor's _**Console**_. You can see here that the single execution for our recently uploaded build is `In_Progress` and that the execution ID is `ojE8Z20`.
Unity Simulation utilizes the ability to run simulation Instances in parallel. If you enter a number larger than 1 for the number of Instances in the _**Run in Unity Simulation**_ window, your run will be parallelized, and multiple simulation Instances will simultaneously execute. You can view the status of all simulation Instances using the `usim summarize run-execution <execution-id>` command. This command will tell you how many Instances have succeeded, failed, have not run yet, or are in progress. Make sure to replace `<execution-id>` with the execution ID seen in your run list. In the above example, this ID would be `yegz4WN`.
Unity Simulation utilizes the ability to run simulation Instances in parallel. If you enter a number larger than 1 for the number of Instances in the _**Run in Unity Simulation**_ window, your run will be parallelized, and multiple simulation Instances will simultaneously execute. You can view the status of all simulation Instances using the `usim summarize run-execution <execution-id>` command. This command will tell you how many Instances have succeeded, failed, have not run yet, or are in progress. Make sure to replace `<execution-id>` with the execution ID seen in your run list. In the above example, this ID would be `ojE8Z20`.
* **:green_circle: Action**: Use the `usim summarize run-execution <execution-id>` command to observe the status of your execution nodes:

2
com.unity.perception/Documentation~/Tutorial/TUTORIAL.md


<img src="../images/unity-wide.png" align="middle" width="3000"/>
<img src="../images/unity-wide-whiteback.png" align="middle" width="3000"/>
# Perception Tutorial

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


* [Step 7: Inspect Generated Synthetic Data](#step-7)
* [Step 8: Verify Data Using Dataset Insights](#step-8)
> :information_source: If you face any problems while following this tutorial, please create a post on the **[Unity Computer Vision forum](https://forum.unity.com/forums/computer-vision.626/)** or the **[GitHub issues](https://github.com/Unity-Technologies/com.unity.perception/issues)** page and include as much detail as possible.
### <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 2020.2.x**. (The tutorial has not yet been fully tested on newer versions.)

- Semantic segmentation images (if the `SemanticSegmentationLabeler` is added and active on `Perception Camera`)
The output dataset includes a variety of information about different aspects of the active sensors in the Scene (currently only one), as well as the ground-truth generated by all active Labelers. [This page](https://github.com/Unity-Technologies/com.unity.perception/blob/master/com.unity.perception/Documentation%7E/Schema/Synthetic_Dataset_Schema.md) provides a comprehensive explanation on the schema of this dataset. We strongly recommend having a look at the page once you have completed this tutorial.
> :information_source: Are the RGB images blank? This may be a bug. When using URP in OSX, having MSAA enabled on the camera may cause the output RGB images to be blank. As a workaround, you can disable MSAA and use FXAA instead, until the issue is fixed. To do this, select `Main Camera`, and in the ***Inspector*** view of the Camera component, in the ***Output*** section, set MSAA to `Off`. If you would like to use FXAA, in the ***Rendering*** section, set the Anti-aliasing option to `Fast Approximate Anti-aliasing (FXAA)`.
* **:green_circle: Action**: To get a quick feel of how the data is stored, open the folder whose name starts with `Dataset`, then open the file named `captures_000.json`. This file contains the output from `BoundingBox2DLabeler`. The `captures` array contains the position and rotation of the sensor (camera), the position and rotation of the ego (sensor group, currently only one), and the annotations made by `BoundingBox2DLabeler` for all visible objects defined in its label configuration. For each visible object, the annotations include:
* `label_id`: The numerical id assigned to this object's label in the Labeler's label configuration

34
com.unity.perception/Documentation~/Tutorial/Phase2.md


The purpose of this piece of code is to obtain a random float Parameter and assign it to the light's `Intensity` field on the start of every Iteration. Let's go through the code above and understand each part. The `FloatParameter` field makes it possible for us to define a randomized float Parameter and modify its properties from the editor UI, similar to how we already modified the properties for the previous Randomizers we used.
> :information_source: If you look at the _**Console**_ tab of the editor now, you will see an error regarding `MyLightRandomizerTag` not being found. This is to be expected, since we have not yet created this class; the error will go away once we create the class later.
If you return to your list of Randomizers in the _**Inspector**_ view of `SimulationScenario`, you can now add this new Randomizer.
* **:green_circle: Action**: Add `MyLightRandomizer` to the list of Randomizers in `SimulationScenario`.
You will notice that the Randomizer's UI snippet contains one Parameter named `Light Intensity Parameter`. This is the same Parameter we added in the code block above. Here, you can set the sampling distribution (`Value`) and `Range` for this float Parameter:
<p align="center">
<img src="Images/light_rand_1.png" width="420"/>
</p>
* **:green_circle: Action**: In the UI snippet for `MyLightRandomzier`, set the minimum and maximum for range to **0.5** and **3**.
This range of intensities is arbitrary but will give us a typically nice lighting without excessive darkness or burnt-out highlights.
> :information_source: If you look at the _**Console**_ tab of the editor now, you will see an error regarding `MyLightRandomizerTag` not being found. This is normal, because we have not yet created this class; the error will go away once we create the class later.
The `MyLightRandomizer` class extends `Randomizer`, which is the base class for all Randomizers that can be added to a Scenario. This base class provides a plethora of useful functions and properties that can help catalyze the process of creating new Randomizers.

Yes, a RandomizerTag can be this simple if you just need it for helping Randomizers query for target objects. Later, you will learn how to add code here to encapsulate more data and logic within the randomized objects.
Notice there is a `RequireComponent(typeof(Light))` line at the top. This line makes it so that you can only add the `MyLightRandomizerTag` component to an object that already has a `Light` component attached. This way, the Randomizers that query for this tag can be confident that the found tags are attached to GameObjects that also have a `Light` component, and can thus be Randomized.
If you return to your list of Randomizers in the _**Inspector**_ view of `SimulationScenario`, you can now add the new Randomizer we created here.
* **:green_circle: Action**: Add `MyLightRandomizer` to the list of Randomizers in `SimulationScenario`.
You will notice that the Randomizer's UI snippet contains one Parameter named `Light Intensity Parameter`. This is the same Parameter we added in the code block above. Here, you can set the sampling distribution (`Value`) and `Range` for this float Parameter:
<p align="center">
<img src="Images/light_rand_1.png" width="420"/>
</p>
* **:green_circle: Action**: In the UI snippet for `MyLightRandomzier`, set the minimum and maximum for range to **0.5** and **3**.
This range of intensities is arbitrary but will give us a typically nice lighting without excessive darkness or burnt-out highlights.
It is now time to add the tag we created earlier to the light in our Scene, so that the Randomizer can find it.
* **:green_circle: Action**: Select `Directional Light` in the Scene's _**Hierarchy**_, and in the _**Inspector**_ tab, add a `My Light Randomizer Tag` component.
* **:green_circle: Action**: Run the simulation again and inspect how `Directional Light` now switches between different intensities. You can pause the simulation and then use the step button (to the right of the pause button) to move the simulation one frame forward and clearly see the varying light intensity

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


protected override IdLabelEntry CreateLabelEntryFromLabelString(SerializedProperty serializedArray,
string labelToAdd)
{
int maxLabel = Int32.MinValue;
var maxLabel = int.MinValue;
for (int i = 0; i < serializedArray.arraySize; i++)
for (var i = 0; i < serializedArray.arraySize; i++)
}
if (maxLabel == -1)
{
var startingLabelId =
(StartingLabelId) serializedObject.FindProperty(nameof(IdLabelConfig.startingLabelId)).enumValueIndex;
if (startingLabelId == StartingLabelId.One)
maxLabel = 0;
}
return new IdLabelEntry

70
com.unity.perception/Editor/GroundTruth/PerceptionCameraEditor.cs


using System;
using System;
#if UNITY_EDITOR_WIN || UNITY_EDITOR_OSX
using UnityEditor.Perception.Visualizer;
#endif
namespace UnityEditor.Perception.GroundTruth
{

m_LabelersList.DoLayoutList();
}
var s = new GUIStyle(EditorStyles.textField);
s.wordWrap = true;
var defaultColor = s.normal.textColor;
EditorGUILayout.LabelField("Latest Output Folder");
EditorGUILayout.LabelField("Latest Generated Dataset");
EditorGUILayout.HelpBox(dir, MessageType.None);
s.normal.textColor = Color.green;
EditorGUILayout.LabelField(dir, s);
if (GUILayout.Button("Show Folder"))
{
EditorUtility.RevealInFinder(dir);

GUILayout.EndHorizontal();
GUILayout.EndVertical();
}
GUILayout.Space(10);
var userBaseDir = PlayerPrefs.GetString(SimulationState.userBaseDirectoryKey);
if (userBaseDir == string.Empty)
{
var folder = PlayerPrefs.GetString(SimulationState.defaultOutputBaseDirectory);
userBaseDir = folder != string.Empty ? folder : Application.persistentDataPath;
}
EditorGUILayout.LabelField("Output Base Folder");
GUILayout.BeginVertical("TextArea");
s.normal.textColor = defaultColor;
EditorGUILayout.LabelField(userBaseDir, s);
GUILayout.BeginHorizontal();
if (GUILayout.Button("Change Folder"))
{
var path = EditorUtility.OpenFolderPanel("Choose Output Folder", "", "");
if (path.Length != 0)
{
Debug.Log($"Chose path: {path}");
PlayerPrefs.SetString(SimulationState.userBaseDirectoryKey, path);
}
}
GUILayout.EndHorizontal();
GUILayout.EndVertical();
#if UNITY_EDITOR_WIN || UNITY_EDITOR_OSX
GUILayout.Space(10);
EditorGUILayout.LabelField("Visualizer Tool");
GUILayout.BeginHorizontal("TextArea");
if (GUILayout.Button("Open Visualizer"))
{
var project = Application.dataPath;
_=VisualizerInstaller.RunVisualizer(project);
}
if (GUILayout.Button("Check For Updates"))
{
var project = Application.dataPath;
_=VisualizerInstaller.CheckForUpdates();
}
GUILayout.EndHorizontal();
GUILayout.Space(10);
#endif
if (EditorSettings.asyncShaderCompilation)
{

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


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

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


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

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

2
com.unity.perception/Editor/Randomization/Uxml/Sampler/SamplerInterfaceElement.uxml


<UXML xmlns="UnityEngine.UIElements" xmlns:editor="UnityEditor.UIElements">
<VisualElement name="sampler-template" style="margin-bottom: 4px;">
<VisualElement style="margin-bottom: 4px;">
<Style src="../../Uss/Styles.uss"/>
<VisualElement style="flex-direction: row; align-items: center;">
<Label name="sampler-name" text="Sampler Name" class="unity-base-field__label"/>

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


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

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


tooltip="The number of scenario iterations to execute"/>
<editor:IntegerField name="instance-count" label="Instance Count" max-value="10000"
tooltip="The number of instances to distribute the work load across"/>
<VisualElement style="flex-direction: row;">
<editor:UIntField name="random-seed" label="Random Seed" style="flex-grow: 1;"
tooltip="The initial random seed to use for the simulation"/>
<Button name="randomize-seed" text="Randomize"/>
</VisualElement>
<VisualElement class="unity-base-field"
tooltip="The compute resources configuration to execute the simulation with">
<Label text="Sys-Param" class="unity-base-field__label"/>

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

<Label name="prev-run-name" text="Run Name: " class="sim-window__label-prev-result"/>
<Label name="project-id" text="Project ID: " class="sim-window__label-prev-result"/>
<Label name="execution-id" text="Execution ID: " class="sim-window__label-prev-result"/>
<Label name="prev-random-seed" text="Random Seed: " class="sim-window__label-prev-result"/>
<Button name="copy-prev-random-seed" text="Copy Seed" style="flex-grow: 1; flex-shrink: 0;"/>
</VisualElement>
</VisualElement>
</VisualElement>

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


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

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

});
m_PropertiesContainer.Add(template);
}
static List<Object> LoadAssetsFromFolder(string folderPath, Type assetType)
{
if (!folderPath.StartsWith(Application.dataPath))
throw new ApplicationException("Selected folder is not an asset folder in this project");
var assetsPath = "Assets" + folderPath.Remove(0, Application.dataPath.Length);
var assetIds = AssetDatabase.FindAssets($"t:{assetType.Name}", new[] { assetsPath });
var assets = new List<Object>();
foreach (var guid in assetIds)
assets.Add(AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(guid), assetType));
return assets;
}
}
}

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


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

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

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

m_RangeProperty = null;
m_PropertiesContainer.Clear();
UIElementsEditorUtilities.CreatePropertyFields(m_Property, m_PropertiesContainer);
}
static string UppercaseFirstLetter(string s)
{
return string.IsNullOrEmpty(s) ? string.Empty : char.ToUpper(s[0]) + s.Substring(1);
}
}
}

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


using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json;

using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.Perception.Randomization.Samplers;
using Random = System.Random;
private const string m_SupportedGPUString = "Tesla";
string m_BuildDirectory;
string m_BuildZipPath;
SysParamDefinition[] m_SysParamDefinitions;

UIntField m_RandomSeedField;
ToolbarMenu m_SysParamMenu;
int m_SysParamIndex;
ObjectField m_ScenarioConfigField;

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

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

m_RunNameField = root.Q<TextField>("run-name");
m_TotalIterationsField = root.Q<IntegerField>("total-iterations");
m_InstanceCountField = root.Q<IntegerField>("instance-count");
m_RandomSeedField = root.Q<UIntField>("random-seed");
var randomizeSeedButton = root.Q<Button>("randomize-seed");
randomizeSeedButton.clicked += () =>
{
var bytes = new byte[4];
new Random().NextBytes(bytes);
m_RandomSeedField.value = BitConverter.ToUInt32(bytes, 0);
};
m_SysParamDefinitions = API.GetSysParams();
m_SysParamMenu = root.Q<ToolbarMenu>("sys-param");

m_PrevRunNameLabel = root.Q<Label>("prev-run-name");
m_ProjectIdLabel = root.Q<Label>("project-id");
m_PrevExecutionIdLabel = root.Q<Label>("execution-id");
m_PrevRandomSeedLabel = root.Q<Label>("prev-random-seed");
var copyExecutionIdButton = root.Q<Button>("copy-execution-id");
copyExecutionIdButton.clicked += () =>

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

var prevRandomSeed = PlayerPrefs.GetString("SimWindow/prevRandomSeed");
m_RandomSeedField.value = string.IsNullOrEmpty(prevRandomSeed)
? SamplerUtility.largePrime : uint.Parse(prevRandomSeed);
m_PrevRandomSeedLabel.text = $"Random Seed: {PlayerPrefs.GetString("SimWindow/prevRandomSeed")}";
}
static string IncrementRunName(string runName)

async void RunInUnitySimulation()
{
#if PLATFORM_CLOUD_RENDERING
if (!m_SysParamDefinitions[m_SysParamIndex].description.Contains(m_SupportedGPUString))
if (!m_SysParamDefinitions[m_SysParamIndex].description.Contains(k_SupportedGPUString))
{
EditorUtility.DisplayDialog("Unsupported Sysparam",
"The current selection of the Sysparam " + m_SysParamDefinitions[m_SysParamIndex].description +

runName = m_RunNameField.value,
totalIterations = m_TotalIterationsField.value,
instanceCount = m_InstanceCountField.value,
randomSeed = m_RandomSeedField.value,
sysParamIndex = m_SysParamIndex,
scenarioConfig = (TextAsset)m_ScenarioConfigField.value,
currentOpenScenePath = SceneManager.GetSceneAt(0).path,

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

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

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

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

var constants = configuration["constants"];
constants["totalIterations"] = m_RunParameters.totalIterations;
constants["instanceCount"] = m_RunParameters.instanceCount;
constants["randomSeed"] = m_RunParameters.randomSeed;
var appParamName = $"{m_RunParameters.runName}";
var appParamsString = JsonConvert.SerializeObject(configuration, Formatting.Indented);

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

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

PlayerPrefs.SetInt("SimWindow/instanceCount", m_RunParameters.instanceCount);
PlayerPrefs.SetString("SimWindow/prevRandomSeed", m_RunParameters.randomSeed.ToString());
PlayerPrefs.SetInt("SimWindow/sysParamIndex", m_RunParameters.sysParamIndex);
PlayerPrefs.SetString("SimWindow/scenarioConfig",
m_RunParameters.scenarioConfig != null ? m_RunParameters.scenarioConfigAssetPath : string.Empty);

public string runName;
public int totalIterations;
public int instanceCount;
public uint randomSeed;
public int sysParamIndex;
public TextAsset scenarioConfig;
public string currentOpenScenePath;

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


using System.IO;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.Perception.Randomization.Scenarios;
using UnityEngine.UIElements;

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

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

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

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


case double v:
return new JValue(v);
case string v:
return new JValue($"\"{v}\"");
return new JValue(v);
case uint v:
return new JValue(v);
}

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


protected override void Setup()
{
if (idLabelConfig == null)
throw new InvalidOperationException("BoundingBox2DLabeler's idLabelConfig field must be assigned");
throw new InvalidOperationException("BoundingBox3DLabeler's idLabelConfig field must be assigned");
m_AnnotationDefinition = DatasetCapture.RegisterAnnotationDefinition("bounding box 3D", idLabelConfig.GetAnnotationSpecification(),
"Bounding box for each labeled object visible to the sensor", id: new Guid(annotationId));

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


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

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

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

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

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


return json;
}
}
}
}

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


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

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


// Record the camera's projection matrix
SetPersistentSensorData("camera_intrinsic", ToProjectionMatrix3x3(cam.projectionMatrix));
// Record the camera's projection type (orthographic or perspective)
SetPersistentSensorData("projection", cam.orthographic ? "orthographic" : "perspective");
var captureFilename = $"{Manager.Instance.GetDirectoryFor(rgbDirectory)}/{k_RgbFilePrefix}{Time.frameCount}.png";
var dxRootPath = $"{rgbDirectory}/{k_RgbFilePrefix}{Time.frameCount}.png";
SensorHandle.ReportCapture(dxRootPath, SensorSpatialData.FromGameObjects(

#else
CaptureCamera.Capture(cam, colorFunctor, flipY: flipY);
#endif
Profiler.EndSample();
}

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


float m_LastTimeScale;
readonly string m_OutputDirectoryName;
string m_OutputDirectoryPath;
public const string userBaseDirectoryKey = "userBaseDirectory";
public const string defaultOutputBaseDirectory = "defaultOutputBaseDirectory";
public bool IsRunning { get; private set; }

public SimulationState(string outputDirectory)
{
PlayerPrefs.SetString(defaultOutputBaseDirectory, Configuration.Instance.GetStorageBasePath());
PlayerPrefs.SetString(latestOutputDirectoryKey, Manager.Instance.GetDirectoryFor());
var basePath = PlayerPrefs.GetString(userBaseDirectoryKey, string.Empty);
if (basePath != string.Empty)
{
if (Directory.Exists(basePath))
{
Configuration.localPersistentDataPath = basePath;
}
else
{
Debug.LogWarning($"Passed in directory to store simulation artifacts: {basePath}, does not exist. Using default directory {Configuration.localPersistentDataPath} instead.");
basePath = Configuration.localPersistentDataPath;
}
}
PlayerPrefs.SetString(latestOutputDirectoryKey, Manager.Instance.GetDirectoryFor("", basePath));
IsRunning = true;
}

m_Ids.Add(egoHandle.Id);
}
public bool IsEnabled(SensorHandle sensorHandle) => m_ActiveSensors.Contains(sensorHandle);
public void SetEnabled(SensorHandle sensorHandle, bool value)

Debug.LogError($"Simulation ended with pending metrics: {string.Join(", ", m_PendingMetrics.Select(c => $"id:{c.MetricId} step:{c.Step}"))}");
WriteReferences();
Time.captureDeltaTime = 0;
IsRunning = false;
}

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


public T Sample()
{
var randomValue = m_Sampler.Sample();
return uniform
? m_Categories[(int)(randomValue * m_Categories.Count)]
: m_Categories[BinarySearch(randomValue)];
if (uniform)
{
var index = (int)(randomValue * m_Categories.Count);
index = index == m_Categories.Count ? index - 1 : index;
return m_Categories[index];
}
return m_Categories[BinarySearch(randomValue)];
}
/// <summary>

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


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

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

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

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

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

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

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

3
com.unity.perception/Runtime/Randomization/Scenarios/Serialization/SerializationStructures.cs


{
public string name = string.Empty;
public string description = string.Empty;
public string imageLink = string.Empty;
}
class Group

public double min;
public double max;
public double mean;
public double standardDeviation;
public double stddev;
}
class ConstantSampler : ISamplerOption

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


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

min = normalSampler.range.minimum,
max = normalSampler.range.maximum,
mean = normalSampler.mean,
standardDeviation = normalSampler.standardDeviation
stddev = normalSampler.standardDeviation
};
else
throw new ArgumentException($"Invalid sampler type ({sampler.GetType()})");

maximum = (float)normalSampler.max
},
mean = (float)normalSampler.mean,
standardDeviation = (float)normalSampler.standardDeviation
standardDeviation = (float)normalSampler.stddev
};
throw new ArgumentException($"Cannot deserialize unsupported sampler type {samplerOption.GetType()}");
}

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


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

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


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

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

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

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

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

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

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

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

// Iterate scenario frame count
currentIterationFrame++;
if (!m_ShouldDelayIteration)
currentIterationFrame++;
framesSinceInitialization++;
}

/// The scenario has finished and is idle
/// </summary>
Idle
}
public void RestartIteration()
{
m_ShouldRestartIteration = true;
}
/// <summary>
/// Delays the current iteration by one frame.
/// This results in <see cref="OnIterationStart" /> being called again for the same iteration.
/// </summary>
/// <remarks>
/// Must be called from within the <see cref="OnIterationStart"/> function of a class
/// inheriting from <see cref="Randomizer" />.
/// </remarks>
public void DelayIteration()
{
m_ShouldDelayIteration = true;
}
}
}

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


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

var camera = cameraObject.AddComponent<Camera>();
camera.orthographic = true;
camera.orthographicSize = 1;
#elif URP_PRESENT
cameraObject.AddComponent<UnityEngine.Rendering.Universal.UniversalAdditionalCameraData>();
#endif
var perceptionCamera = cameraObject.AddComponent<PerceptionCamera>();

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


[TestCase(1u, "1")]
[TestCase(1.0, "1")]
[TestCase(1.0f, "1")]
[TestCase("string", "\"string\"")]
[TestCase("string", "string")]
public void Primitive_ReturnsValue(object o, string jsonExpected)
{
var jsonActual = DatasetJsonUtility.ToJToken(o).ToString();

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


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

15
com.unity.perception/Tests/Runtime/Randomization/ScenarioTests/Resources/SampleScenarioConfiguration.json


"RotationRandomizer": {
"metadata": {
"name": "",
"description": ""
"description": "",
"imageLink": ""
},
"items": {
"rotation": {

"description": ""
"description": "",
"imageLink": ""
},
"items": {
"x": {

"description": ""
"description": "",
"imageLink": ""
},
"uniform": {
"min": 0.0,

"samplerOptions": {
"metadata": {
"name": "",
"description": ""
"description": "",
"imageLink": ""
},
"uniform": {
"min": 0.0,

"samplerOptions": {
"metadata": {
"name": "",
"description": ""
"description": "",
"imageLink": ""
},
"uniform": {
"min": 0.0,

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


using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine.Perception.Randomization.Randomizers;
using UnityEngine.Perception.Randomization.Scenarios;
using UnityEngine.TestTools;
using Object = UnityEngine.Object;

}
// TODO: update this function once the perception camera doesn't skip the first frame
IEnumerator CreateNewScenario(int totalIterations, int framesPerIteration)
IEnumerator CreateNewScenario(int totalIterations, int framesPerIteration, Randomizer[] randomizers = null)
if (randomizers != null)
{
foreach (var rnd in randomizers)
{
m_Scenario.AddRandomizer(rnd);
}
}
yield return null; // Skip first frame
yield return null; // Skip first Update() frame
}

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

yield return null;
for (var i = 0; i < 3; i++)
Assert.AreNotEqual(seeds[i], SamplerState.NextRandomState());
}
[UnityTest]
public IEnumerator IterationCorrectlyDelays()
{
yield return CreateNewScenario(5, 1, new Randomizer[]
{
// Delays every other iteration
new ExampleDelayRandomizer(2)
});
// State: currentIteration = 0
Assert.AreEqual(0, m_Scenario.currentIteration);
yield return null;
// State: currentIteration = 1
Assert.AreEqual(1, m_Scenario.currentIteration);
yield return null;
// State: currentIteration = 2
// Action: ExampleDelayRandomizer will delay the iteration
Assert.AreEqual(2, m_Scenario.currentIteration);
yield return null;
// State: currentIteration = 2
Assert.AreEqual(2, m_Scenario.currentIteration);
yield return null;
// State: currentIteration = 3;
Assert.AreEqual(3, m_Scenario.currentIteration);
yield return null;
// State: currentIteration = 4
// Action: ExampleDelayRandomizer will delay the iteration
Assert.AreEqual(4, m_Scenario.currentIteration);
yield return null;
// State: currentIteration = 4
Assert.AreEqual(4, m_Scenario.currentIteration);
yield return null;
// State: currentIteration = 5
Assert.AreEqual(5, m_Scenario.currentIteration);
}
PerceptionCamera SetupPerceptionCamera()

4
com.unity.perception/package.json


"com.unity.collections": "0.9.0-preview.6",
"com.unity.nuget.newtonsoft-json": "1.1.2",
"com.unity.render-pipelines.core": "7.1.6",
"com.unity.simulation.capture": "0.0.10-preview.20",
"com.unity.simulation.capture": "0.0.10-preview.23",
"com.unity.simulation.client": "0.0.10-preview.10",
"com.unity.simulation.core": "0.0.10-preview.22"
},

"unity": "2020.3",
"version": "0.8.0-preview.3",
"version": "0.8.0-preview.4",
"samples": [
{
"displayName": "Tutorial Files",

15
TestProjects/PerceptionURP/ProjectSettings/BurstAotSettings_StandaloneOSX.json


{
"MonoBehaviour": {
"Version": 3,
"EnableBurstCompilation": true,
"EnableOptimisations": true,
"EnableSafetyChecks": false,
"EnableDebugInAllBuilds": false,
"UsePlatformSDKLinker": false,
"CpuMinTargetX32": 0,
"CpuMaxTargetX32": 0,
"CpuMinTargetX64": 0,
"CpuMaxTargetX64": 0,
"CpuTargetsX64": 72
}
}

994
com.unity.perception/Documentation~/Randomization/Images/randomization_uml.png

之前 之后
宽度: 3124  |  高度: 1304  |  大小: 254 KiB

250
com.unity.perception/Documentation~/images/labeling_uml.png
文件差异内容过多而无法显示
查看文件

140
com.unity.perception/Documentation~/images/unity-wide-whiteback.png

之前 之后
宽度: 3000  |  高度: 636  |  大小: 41 KiB

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


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

51
com.unity.perception/Editor/Randomization/PropertyDrawers/UIntDrawer.cs


using System;
using UnityEngine;
using UnityEngine.UIElements;
using UnityEditor.UIElements;
namespace UnityEditor.Perception.Randomization.PropertyDrawers
{
[CustomPropertyDrawer(typeof(uint))]
class UIntDrawer : PropertyDrawer
{
public override VisualElement CreatePropertyGUI(SerializedProperty property)
{
var field = new UIntField
{
label = property.displayName,
value = (uint)property.longValue
};
//Binding does not work on this custom UI Element field that we have created, so we need to use the change event
field.RegisterValueChangedCallback(evt =>
{
field.value = evt.newValue;
property.longValue = evt.newValue;
property.serializedObject.ApplyModifiedProperties();
});
// Create a surrogate integer field to detect and pass along external change events (non UI event) on the underlying serialized property.
var surrogateField = new IntegerField();
field.Add(surrogateField);
surrogateField.style.display = DisplayStyle.None;
surrogateField.bindingPath = property.propertyPath;
surrogateField.RegisterValueChangedCallback(evt =>
{
evt.StopImmediatePropagation();
field.value = UIntField.ClampInput(property.longValue);
});
return field;
}
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.PropertyField(position, property, label, true);
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
return EditorGUI.GetPropertyHeight(property);
}
}
}

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


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

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


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

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


using Editor.Randomization.VisualElements.AssetSource;
using UnityEngine;
using UnityEngine.Perception.Randomization;
using UnityEngine.UIElements;
namespace UnityEditor.Perception.Randomization.PropertyDrawers
{
[CustomPropertyDrawer(typeof(AssetSource<>))]
class AssetSourceDrawer : PropertyDrawer
{
public override VisualElement CreatePropertyGUI(SerializedProperty property)
{
return new AssetSourceElement(property, fieldInfo);
}
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.PropertyField(position, property, label, true);
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
return EditorGUI.GetPropertyHeight(property);
}
}
}

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


using System;
using System.Collections.Generic;
using UnityEngine;
using Object = UnityEngine.Object;
namespace UnityEditor.Perception.Randomization
{
static class AssetLoadingUtilities
{
public static List<Object> LoadAssetsFromFolder(string folderPath, Type assetType)
{
if (!folderPath.StartsWith(Application.dataPath))
throw new ApplicationException("Selected folder is not an asset folder in this project");
var assetsPath = "Assets" + folderPath.Remove(0, Application.dataPath.Length);
var assetIds = AssetDatabase.FindAssets($"t:{assetType.Name}", new[] { assetsPath });
var assets = new List<Object>();
foreach (var guid in assetIds)
assets.Add(AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(guid), assetType));
return assets;
}
}
}

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


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

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


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

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


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

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


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

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


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

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


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

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


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

43
com.unity.perception/Tests/Runtime/Randomization/ScenarioTests/ExampleDelayRandomizer.cs


using System;
using UnityEngine;
using UnityEngine.Perception.Randomization.Randomizers;
namespace RandomizationTests.ScenarioTests
{
/// <summary>
/// Delays the scenario every Nth iteration where N is given by <see cref="m_IterationDelay" />.
/// Does not delay the very first iteration i.e. iteration 0.
/// </summary>
/// <remarks>
/// With <see cref="m_IterationDelay" /> set to 2, the iterations 2, 4, 6, ..., etc. will be delayed once.
/// </remarks>
[Serializable]
[AddRandomizerMenu("Perception Tests/Example Delay Randomizer")]
public class ExampleDelayRandomizer : Randomizer
{
int m_IterationDelay = 2;
bool m_DelayedThisIteration = false;
public ExampleDelayRandomizer(int iterationDelay = 2)
{
m_IterationDelay = Math.Max(2, iterationDelay);
}
protected override void OnIterationStart()
{
if (m_DelayedThisIteration)
{
m_DelayedThisIteration = false;
return;
}
var currentIteration = scenario.currentIteration;
if (currentIteration > 0 && ((currentIteration) % m_IterationDelay) == 0)
{
Debug.Log($"Delaying iteration {currentIteration} once.");
m_DelayedThisIteration = true;
scenario.DelayIteration();
}
}
}
}

11
com.unity.perception/Tests/Runtime/Randomization/ScenarioTests/ExampleDelayRandomizer.cs.meta


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

1001
com.unity.perception/Documentation~/FAQ/images/inner_objects.png
文件差异内容过多而无法显示
查看文件

1001
com.unity.perception/Documentation~/FAQ/images/inner_labels.gif
文件差异内容过多而无法显示
查看文件

229
com.unity.perception/Documentation~/FAQ/images/cluster_randomizer.png

之前 之后
宽度: 850  |  高度: 460  |  大小: 73 KiB

199
com.unity.perception/Documentation~/FAQ/images/prefab_cluster.png

之前 之后
宽度: 802  |  高度: 312  |  大小: 55 KiB

1001
com.unity.perception/Documentation~/FAQ/images/hdrp.png
文件差异内容过多而无法显示
查看文件

1001
com.unity.perception/Documentation~/FAQ/images/hdrp_pt_128_samples.png
文件差异内容过多而无法显示
查看文件

1001
com.unity.perception/Documentation~/FAQ/images/hdrp_pt_4096_samples.png
文件差异内容过多而无法显示
查看文件

1001
com.unity.perception/Documentation~/FAQ/images/hdrp_rt_gi.png
文件差异内容过多而无法显示
查看文件

419
com.unity.perception/Documentation~/FAQ/images/volume.png

之前 之后
宽度: 1234  |  高度: 740  |  大小: 115 KiB

609
com.unity.perception/Documentation~/FAQ/FAQ.md


# FAQ and Code Samples
This page covers a variety of topics, including common questions and issues that may arise while using the Perception package, as well as code samples and recommendations for a number of popular workflows and use-cases.
## <a name="labeling">Labeling</a>
<details>
<summary><strong>Q: How can I disable or enable labeling on an object at runtime?</strong></summary>
<br>
You can turn labeling on and off on a GameObject by switching the enabled state of its `Labeling` component. For example:
```C#
gameObject.GetComponent<Labeling>().enabled = false;
```
---
</details>
<details>
<summary><strong>Q: How can I remove or add new labels to objects at runtime?</strong></summary><br>
This can be achieved through modifying the `labels` list of the `Labeling` component. The key is to call `RefreshLabeling()` on the component after making any changes to the labels. Example:
```C#
var labeling = gameObject.GetComponent<Labeling>();
labeling.labels.Clear();
labeling.labels.Add("new-label");
labeling.RefreshLabeling();
```
Keep in mind that any new label added with this method should already be present in the Label Config attached to the Labeler that is supposed to label this object.
---
</details>
<details>
<summary><strong>Q: Is it possible to label only parts of an object or assign different labels to different parts of objects?</strong></summary><br>
Labeling works on the GameObject level, so to achieve the scenarios described here, you will need to break down your main object into multiple GameObjects parented to the same root object, and add `Labeling` components to each of the inner objects, as shown below.
<p align="center">
<img src="images/inner_objects.png" width="800"/>
</p>
Alternatively, in cases where parts of the surface of the object need to be labeled (e.g. decals on objects), you can add labeled invisible surfaces on top of these sections. These invisible surfaces need to have a fully transparent material. To create an invisible material:
* Create a new material (***Assets -> Create -> Material***) and name it `TransparentMaterial`
* Set the **Surface Type** for the material to **Transparent**, and set the alpha channel of the **Base Map** color to 0.
* For HDRP: In addition to the above, disable **Preserve specular lighting**
An example labeled output for an object with separate labels on inner objects and decals is shown below:
<p align="center">
<img src="images/inner_labels.gif" width="600"/>
</p>
---
</details>
<details>
<summary><strong>Q: When visible surfaces of two objects are fully aligned, the bounding boxes seem to blink in and out of existence from one frame to another. Why is that?</strong></summary><br>
This is due to a common graphics problem called *z-fighting*. This occurs when the shader can't decide which of the two surfaces to draw on top of the other, since they both have the exact same distance from the camera. To fix this, simply move one of the objects slightly so that the two problematic surfaces do not fully align.
---
</details>
## <a name="randomization">Randomization</a>
<details>
<summary><strong>Q: How can I have multiple sets of prefabs in a foreground placement Randomizer, and on every Iteration select one from each set?</strong>
</summary><br>
This question is an example of more complex functionality that can be achieved by applying slight modifications to the provided sample Randomizers, or by creating completely custom ones by extending the `Randomizer` class.
Here, we have a variety of options toward achieving the described outcome. One simple method could be to add several more `GameObjectParameter` fields inside of the provided sample `ForegroundObjectPlacementRandomizer`. Each of these Parameters could hold one of our object lists. Then, on each iteration, we would fetch one prefab from each of the lists using the `Sample()` function of each Parameter.
The above solution can work but it is not modular enough, with the lists of prefabs not being reusable in other Randomizers.
A better approach can be to define each prefab list separately as a scriptable object asset, and then just reference those scriptable objects inside of our foreground Randomizer. To do this, we first define a `PrefabCluster` class to hold a list of prefabs.
```C#
using UnityEngine;
using UnityEngine.Perception.Randomization.Parameters;
[CreateAssetMenu(fileName="NewPrefabCluster", menuName="Test/PrefabCluster")]
public class PrefabCluster : ScriptableObject
{
public GameObjectParameter clusterPrefabs;
}
```
We can now create a cluster asset using the ***Assets -> Create -> Test -> PrefabCluster*** menu option and populate its list of prefabs. Each cluster contains one `GameObjectParameter`, which will hold the list of prefabs and provide us with a `Sample()` function.
To be able to edit these clusters with the same editor UI available for Randomizers, you will also need to add an empty custom editor for the `PrefabCluster` class that extends our bespoke `ParameterUIElementsEditor` class:
```C#
using UnityEditor;
using UnityEditor.Perception.Randomization;
[CustomEditor(typeof(PrefabCluster))]
public class PrefabClusterEditor : ParameterUIElementsEditor { }
```
Note that any editor scripts must be placed inside a folder named "Editor" within your project. "Editor" is a special folder name in Unity that prevents editor code from compiling into a player during the build process. For example, the file path for the `PrefabClusterEditor` script above could be `.../Assets/Scripts/Editor/PrefabClusterEditor`.
The ***Inspector*** view of a prefab cluster asset looks like below:
<p align="center">
<img src="images/prefab_cluster.png" width="400"/>
</p>
Now all that is left is to use our prefab clusters inside a Randomizer. Here is some sample code:
```C#
using System;
using UnityEngine;
[Serializable]
[UnityEngine.Perception.Randomization.Randomizers.AddRandomizerMenu("My Randomizers/Cluster Randomizer")]
public class ClusterRandomizer : UnityEngine.Perception.Randomization.Randomizers.Randomizer
{
public PrefabCluster[] clusters;
protected override void OnIterationStart()
{
//select a random prefab from each cluster
foreach (var cluster in clusters)
{
var prefab = cluster.clusterPrefabs.Sample();
//do things with this prefab, e.g. create instances of it, etc.
}
}
}
```
This Randomizer takes a list of `PrefabCluster` assets, then, on each Iteration, it goes through all the provided clusters and samples one prefab from each. The ***Inspector*** view for this Randomizer looks like this:
<p align="center">
<img src="images/cluster_randomizer.png" width="400"/>
</p>
---
</details>
<details>
<summary><strong>Q: How can I specify an exact number of objects to place using the sample foreground object placement Randomizer?</strong> </summary><br>
The provided `ForegroundObjectPlacementRandomizer` uses Poisson Disk sampling to find randomly positioned points in the space denoted by the provided `Width` and `Height` values. The lower bound on the distance between the sampled points will be `Separation Distance`. The number of sampled points will be the maximum number of points in the given area that match these criteria.
Thus, to limit the number of spawned objects, you can simply introduce a hard limit in the `for` loop that iterates over the Poisson Disk samples, to break out of the loop if the limit is reached. Additionally, we will need to shuffle the list of points retrieved from the Poisson Disk sampling in order to remove any selection bias when building our subset of points. This is because Poisson Disk points are sampled in sequence and relative to the points already sampled, therefore, the initial points in the list are likely to be closer to each other. We will use a `FloatParameter` to perform this shuffle, so that we can guarantee that our simulation is deterministic and reproducible.
```C#
FloatParameter m_IndexShuffleParameter = new FloatParameter { value = new UniformSampler(0, 1) };
protected override void OnIterationStart()
{
var seed = SamplerState.NextRandomState();
var placementSamples = PoissonDiskSampling.GenerateSamples(
placementArea.x, placementArea.y, separationDistance, seed);
var offset = new Vector3(placementArea.x, placementArea.y, 0f) * -0.5f;
//shuffle retrieved points
var indexes = Enumerable.Range(0, placementSamples.Length).ToList();
indexes = indexes.OrderBy(item => m_IndexShuffleParameter.Sample()).ToList();
//maximum number of objects to place
var limit = 50;
var instantiatedCount = 0;
//iterate over all points
foreach (var index in indexes)
{
instantiatedCount ++;
if (instantiatedCount == limit)
break;
var instance = m_GameObjectOneWayCache.GetOrInstantiate(prefabs.Sample());
instance.transform.position = new Vector3(placementSamples[index].x, placementSamples[index].y, depth) + offset;
}
placementSamples.Dispose();
}
```
This will guarantee an upper limit of 50 on the number of objects. To have exactly 50 objects, we need to make sure the `Separation Distance` is small enough for the given area, so that there are always at least 50 point samples found. Experiment with different values for the distance until you find one that produces the minimum number of points required.
---
</details>
<details>
<summary><strong>Q: How can I avoid object overlap with the sample foreground object placement Randomizer?</strong></summary><br>
There are a number of ways for procedurally placing objects while avoiding any overlap between them, and most of these methods can be rather complex and need to place objects in a sequence. All the modifications to the objects (like scale, rotation, etc.) would also need to happen before the next object is placed, so that the state of the world is fully known before each placement.
Here, we are going to introduce a rather simple modification in the sample foreground placement code provided with the package. In each Iteration, a random scale factor is chosen, and then a desirable separation distance is calculated based on this scale factor and the list of given prefabs. We also scale the objects here to introduce additional randomization, due to the fact that once we have placed the objects we can no longer scale them.
Based on the value given for `Non Overlap Guarantee`, this Randomizer can either reduce the amount of overlap or completely remove overlap.
```C#
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.Perception.Randomization.Parameters;
using UnityEngine.Perception.Randomization.Randomizers;
using UnityEngine.Perception.Randomization.Randomizers.Utilities;
using UnityEngine.Perception.Randomization.Samplers;
[Serializable]
[AddRandomizerMenu("Example/No Overlap Foreground Object Placement Randomizer")]
public class NoOverlapForegroundObjectPlacementRandomizer : Randomizer
{
public float depth;
[Tooltip("Range of scales used for objects. All objects in each frame will use the same scale.")]
public FloatParameter scaleParameter = new FloatParameter { value = new UniformSampler(4, 8) };
public Vector2 placementArea;
public GameObjectParameter prefabs;
[Tooltip("Degree to which we can guarantee that no objects will overlap. Use 1 for no overlap and smaller values (down to 0) for more dense placement with a possibility of some overlap.")]
public float nonOverlapGuarantee = 1;
float m_ScaleFactor = 1f;
GameObject m_Container;
GameObjectOneWayCache m_GameObjectOneWayCache;
Dictionary<GameObject, float> m_GameObjectBoundsSizeCache;
List<GameObject> m_SelectedPrefabs;
int m_SelectionPoolSizePerFrame = 1;
FloatParameter m_IndexSelector = new FloatParameter { value = new UniformSampler(0, 1) };
protected override void OnAwake()
{
m_Container = new GameObject("Foreground Objects");
m_Container.transform.parent = scenario.transform;
m_GameObjectOneWayCache = new GameObjectOneWayCache(
m_Container.transform, prefabs.categories.Select(element => element.Item1).ToArray());
m_GameObjectBoundsSizeCache = new Dictionary<GameObject, float>();
m_SelectedPrefabs = new List<GameObject>();
//Calculate the average bounds size for the prefabs included in this categorical parameter
var averageBoundsSize = CalculateAverageBoundsSize();
//Calculate average scale based on the scale range given
var averageScale = 1f;
var sampler = (UniformSampler)scaleParameter.value;
if (sampler != null)
{
averageScale = (sampler.range.minimum + sampler.range.maximum) / 2;
}
//Use average bounds size and average scale to guess the maximum number of objects that can be placed without having them overlap.
//This is a heuristic to help us start the placement process. The actual number of items placed will usually be much smaller.
m_SelectionPoolSizePerFrame = (int)(placementArea.x * placementArea.y / (averageBoundsSize * averageScale));
}
protected override void OnIterationStart()
{
m_ScaleFactor = scaleParameter.Sample();
m_SelectedPrefabs.Clear();
//Select a random number of prefabs for this frame. Placement calculations will be done based on this subset.
for (var i = 0; i < m_SelectionPoolSizePerFrame; i++)
{
var randIndex = (int)Mathf.Round((m_IndexSelector.Sample() * prefabs.categories.Count) - 0.5f);
m_SelectedPrefabs.Add(prefabs.categories[randIndex].Item1);
}
//Calculate the minimum separation distance needed for the selected prefabs to not overlap.
var separationDistance = CalculateMaxSeparationDistance(m_SelectedPrefabs);
var seed = SamplerState.NextRandomState();
var placementSamples = PoissonDiskSampling.GenerateSamples(
placementArea.x, placementArea.y, separationDistance, seed);
var offset = new Vector3(placementArea.x, placementArea.y, 0f) * -0.5f;
foreach (var sample in placementSamples)
{
//Pick a random prefab from the selected subset and instantiate it.
var randIndex = (int)Mathf.Round((m_IndexSelector.Sample() * m_SelectedPrefabs.Count) - 0.5f);
var instance = m_GameObjectOneWayCache.GetOrInstantiate(m_SelectedPrefabs[randIndex]);
instance.transform.position = new Vector3(sample.x, sample.y, depth) + offset;
instance.transform.localScale = Vector3.one * m_ScaleFactor;
}
placementSamples.Dispose();
}
protected override void OnIterationEnd()
{
m_GameObjectOneWayCache.ResetAllObjects();
}
/// <summary>
/// Calculates the separation distance needed between placed objects to be sure that no two objects will overlap
/// </summary><br>
/// <returns>The max separation distance</returns>
float CalculateMaxSeparationDistance(ICollection<GameObject> categories)
{
var maxBoundsSize = m_GameObjectBoundsSizeCache.Where(item => categories.Contains(item.Key)).Max(pair => pair.Value);
return maxBoundsSize * m_ScaleFactor * nonOverlapGuarantee;
}
float CalculateAverageBoundsSize()
{
foreach (var category in prefabs.categories)
{
var prefab = category.Item1;
prefab.transform.localScale = Vector3.one;
var renderers = prefab.GetComponentsInChildren<Renderer>();
var totalBounds = new Bounds();
foreach (var renderer in renderers)
{
totalBounds.Encapsulate(renderer.bounds);
}
var boundsSize = totalBounds.size.magnitude;
m_GameObjectBoundsSizeCache.Add(prefab, boundsSize);
}
return m_GameObjectBoundsSizeCache.Values.Average();
}
}
```
---
</details>
<details>
<summary><strong>Q: What if I don't want randomized object placement? Can I move my objects in a non-randomized deterministic manner on each frame?</strong> </summary><br>
Even though we call them Randomizers, you can use a Randomizer to perform any task through-out the execution lifecycle of your Scenario. The power of the Randomizers comes from the lifecycle hooks that they have into the Iteration and the Scenario, making it easy to know and guarantee when and in which order in the life of your simulation each piece of code runs. These functions include:
* `OnEnable`
* `OnAwake`
* `OnUpdate`
* `OnIterationStart`
* `OnIterationEnd`
* `OnScenarioStart`
* `OnScenarioComplete`
* `OnDisable`
So, in order to have deliberate non-random object movement, you will just need to put your object movement code inside of one of the recurrent lifecycle functions. `OnUpdate()` runs on every frame of the simulation, and `OnIterationStart()` runs every Iteration (which can be the same as each frame if you have only 1 frame per Iteration of your Scenario). For example, the code below moves all objects tagged with the component `ForwardMoverTag` along their forward axis by 1 unit, on every Iteration.
```C#
protected override void OnIterationStart()
{
var tags = tagManager.Query<ForwardMoverTag>();
foreach (var tag in tags)
{
tag.transform.Translate(Vector3.forward);
}
}
```
Additionally, keep in mind that you can use Perception Samplers (and therefore Parameters) to generate constant values, not just random ones. The `ConstantSampler` class provides this functionality.
---
</details>
<details>
<summary><strong>Q: The objects instantiated using the sample foreground placement Randomizer are floating in the air. How can I use this Randomizer to place objects on a horizontal surface instead?</strong> </summary><br>
The objects instantiated by the sample foreground Randomizer are all parented to an object named `Foreground Objects` at the root of the Scene Hierarchy. To modify the orientation of the objects, you can simply rotate this parent object at the beginning of the Scenario.
Alternatively, you could also place `Foreground Objects` inside another GameObject in the Scene using the `Transform.SetParent()` method, and then modify the local position and rotation of `Foreground Objects` in such a way that makes the objects appear on the surface of the parent GameObject.
In addition, if you'd like to have horizontal placement without touching the parent object, you can modify the Randomizer's code to place objects horizontally instead of vertically. The lines responsible for placement are:
```C#
var offset = new Vector3(placementArea.x, placementArea.y, 0) * -0.5f;
```
```C#
instance.transform.position = new Vector3(sample.x, sample.y, depth) + offset;
```
The first line builds an offset vector that is later used to center the points retrieved from Poisson Disk sampling around the center of the coordinate system. The second line is executed in a loop, and each time, places one object at one of the sampled points at the depth (along Z axis) provided by the user.
To make this placement horizontal, you would just need to change these two lines to swap Y for Z. The resulting lines would be:
```C#
var offset = new Vector3(placementArea.x, 0, placementArea.y) * -0.5f;
```
```C#
instance.transform.position = new Vector3(sample.x, depth, sample.y) + offset;
```
Note that the variable `depth` is in fact playing the role of a height variable now.
Finally, to achieve more natural placement, you could also use Unity's physics engine to drop the objects on a surface, let them settle, and then capture an image. To achieve this, you would just need to have sufficient frames in each Iteration of the Scenario (instead of the default 1 frame per iteration), and set your Perception Camera's capture interval to a large enough number that would make it capture each Iteration once after the objects have settled. This example is explained in more detail in the [Perception Camera](#perception-camera) section of this FAQ.
---
</details>
<details>
<summary><strong>Q: Does using the same Random Seed value in two runs of the same Scenario guarantee that the generated datasets are identical?</strong></summary><br>
If you only use the Samplers (and Parameters, which internally use Samplers) provided in the Perception package to generate random values throughout the Scenario's lifecycle and keep the `Random Seed` value unchanged, an identical sequence of random numbers will be generated every time the Scenario is run. This is because the Samplers obtain their seeds through continually mutating the provided global `Random Seed` in the Scenario.
Keep in mind that any change in the order of sampling or the number of samples obtained can lead to different outcomes. For example, if you change the order of Randomizers in the Scenario, the Samplers inside of these Randomizers will now execute in the new order, and thus, they will operate based on different seeds than before and generate different numbers. The same can happen if you add additional calls to a Sampler inside a Randomizer, causing the Samplers in later Randomizers to now use different seeds, since the global seed has been mutated more times than before.
One more thing to keep in mind is that certain systems and components of Unity are not deterministic and can produce different outcomes in consecutive runs. Examples of this are the physics engine and the film grain post processing. Hence, if you need to guarantee that your simulation always produces the exact same dataset, make sure to research the various systems that you use to make sure they behave deterministically.
---
</details>
## <a name="perception-camera">Perception Camera</a>
<details>
<summary><strong>Q: What is the relationship between the Scenario's lifecycle properties (Iterations and Frames per Iteration) and the Perception Camera's timing properties (Simulation Delta Time, Start at Frame, and Frames Between Captures)?</strong> </summary><br>
Each Iteration of the Scenario resets the Perception Camera's timing variables. Thus, you can think of each Iteration of the Scenario as one separate Perception Camera sequence, in which the camera's internal timing properties come into play. For instance, if you have 10 `Frames Per Iteration` on your Scenario, and your Perception Camera's `Start at Frame` value is set to 8, you will get two captures from the camera at the 9th and 10th frames of each Iteration (note that `Start at Frame` starts from 0). Similarly, you can use the `Frames Between Captures` to introduce intervals between captures. A value of 0 leads to all frames being captured.
---
</details>
<details>
<summary><strong>Q: I want to simulate physics (or other accumulative behaviors such as auto-exposure) for a number of frames and let things settle before capturing the Scene. Is this possible with the Perception package?</strong></summary><br>
Yes. The Perception Camera can be set to capture at specific frame intervals, rather than every frame. The `Frames Between Captures` value is set to 0 by default, which causes the camera to capture all frames; however, you can change this to 1 to capture every other frame, or larger numbers to allow more time between captures. You can also have the camera start capturing at a certain frame rather than the first frame, by setting the `Start at Frame` value to a value other than 0. All of this timing happens within each Iteration of the Scenario, and gets reset when you advance to the next Iteration. Therefore, the combination of these properties and the Scenario's `Frames Per Iteration` property allows you to randomize the state of your Scene at the start of each Iteration, let things run for a number of frames, and then capture the Scene at the end of the Iteration.
Suppose we need to drop a few objects into the Scene, let them interact physically and settle after a number of frames, and then capture their final state once. Afterwards, we want to repeat this cycle by randomizing the initial positions of the objects, dropping them, and capturing the final state again. We will set the Scenario's `Frames Per Iteration` to 300, which should be sufficient for the objects to get close to a settled position (this depends on the value you use for `Simulation Delta Time` in Perception Camera and the physical properties of the engine and objects, and can be found through experimentation). We also set the `Start at Frame` value of the Perception Camera to 290, and the `Frames Between Captures` to a sufficiently large number (like 100), so that we only get one capture per Iteration of the Scenario. The results look like below. Note how the bounding boxes only appear after the objects are fairly settled. These are the timestamps at which captures are happening.
<p align="center">
<img src="images/object_drop.gif" width="700"/>
</p>
---
</details>
<details>
<summary><strong>Q: I do not want the Perception Camera to control the delta time of my simulation or capture on a scheduled basis. Can I have a Perception Camera in my Scene that does not affect timings and trigger captures manually from other scripts?</strong></summary><br>
Yes. The Perception Camera offers two trigger modes, `Scheduled` and `Manual`, and these can be chosen in the editor UI for the Perception Camera component. If you select the `Manual` mode, you will be able to trigger captures by calling the `RequestCapture()` method of `PerceptionCamera`. In this mode, you have the option to not have this camera dictate your simulation delta time. This is controlled using the `Affect Simulation Timing` checkbox.
---
</details>
<details>
<summary><strong>Q: Can I have multiple Perception Cameras active in my Scene simultaneously?</strong></summary><br>
No, at this time the Perception package only supports one active Perception Camera. This is something that is on our roadmap and we hope to support soon.
However, the package does support having more than one Perception Camera in the Scene, as long as only one is active when the simulation starts. Therefore, one possible workaround, if your simulation is fully deterministic from one run to the next, would be to run the simulation more than once, each time with one of the cameras active. While not ideal, this will at least let you generate matching datasets.
---
</details>
<details>
<summary><strong>Q: My RGB images look darker than what I see in Unity Editor, when I render the Perception Camera to a texture. How can I fix this?</strong>
</summary><br>
This issue is caused by the color format of the texture. In the ***Inspector*** view of the render texture, set color format to `R8G8B8A8_SRGB`.
---
</details>
<details>
<summary><strong>Q: How do I report additional custom information in my output dataset for each frame or the whole simulation (e.g. 3D position of objects at the start of each Iteration, intensity of lights, etc.)?</strong>
</summary><br>
This can be done by adding custom annotations to your dataset. Have a look at [this](https://github.com/Unity-Technologies/com.unity.perception/blob/master/com.unity.perception/Documentation%7E/DatasetCapture.md) page for an explanation, as well as an example for how to do this.
---
</details>
## <a name="miscellaneous">Miscellaneous</a>
<details>
<summary><strong>Q: Objects in my captured images have jagged edges, how can I fix this?</strong>
</summary><br>
This is a common issue with rendering graphics into raster images (digital images), when the resolution of the raster is not high enough to perfectly display slanting lines. The common solution to this issue is the use of anti-aliasing methods, and Unity offers a number of these in both URP and HDRP. To experiment with anti-aliasing, go to the ***Inspector*** view of your Perception Camera object and in the Camera component, change `Anti-aliasing` from `None` to another option.
---
</details>
<details>
<summary><strong>Q: I am using an HDRP Unity project with Perception and my images have significant blurring around most objects. How can I remove this blur?</strong>
</summary><br>
The effect you are observing here is motion blur, which happens because the placement Randomizers used in the Perception tutorial cache their instantiated objects from one Iteration to the next, and move them to new locations on each Iteration instead of destroying them and creating new ones. This "motion" of the objects causes the motion blur effect to kick in.
HDRP projects have motion blur and a number of other post processing effects enabled by default. To disable motion blur or any other effect, follow these steps:
1. Create an empty GameObject in your Scene and add a Volume component to it.
2. Set the Volume's profile to the **Volume Global** asset.
3. Uncheck the **Motion Blur** option.
<p align="center">
<img src="images/volume.png" width="500"/>
</p>
---
</details>
<details>
<summary><strong>Q: Are all post processing effects provided by Unity safe to use in synthetic datasets?</strong>
</summary><br>
No. When using post processing effects, you need to be careful about issues regarding randomness and determinism:
* There are certain post processing effects that need randomization internally, e.g. film grain. The film grain effect provided by Unity is not sufficiently randomized for model training and can thus mislead your CV model to look for a specific noise pattern during prediction.
* Even if such an effect is properly randomized, using a randomized effect would make your overall randomization strategy non-deterministic, meaning you would not be able to reproduce your datasets. This is because the effect would internally use random number generators outside of the Samplers provided by the Perception package. If you have access to the source code for a randomized effect, you can modify it to only use Perception Samplers for random number generation, which would make its behavior deterministic and thus appropriate for use in synthetic datasets that need to be reproducible.
To make sure you do not run into insufficient randomization or non-determinism, it would be best to implement effects such as film grain yourself or modify existing code to make sure no random number generators are used except for the Samplers provided in the Perception package.
---
</details>
<details>
<summary><strong>Q: What post processing effects can help improve model performance?</strong>
</summary><br>
Based on our experiments, randomizing contrast, saturation, lens blur, and lens distortion can help significantly improve the performance of your CV model. We recommend experimenting with these as well as other effects to determine those that work best for your use-case.
---
</details>
<details>
<summary><strong>Q: Can I debug my C# code?</strong>
</summary><br>
Unity projects can be debugged using external editors such as Visual Studio or JetBrains Rider. For local development and debugging, you will first need to clone the Perception repository to disk and add the Perception package from this cloned repository to your Unity project. Then, in Unity Editor, go to ***Edit (or "Unity" on OSX) -> Preferences -> External Tools***. Select your preferred editor as the External Script Editor, and enable
**General .csproj files** for at least **Embedded packages** and **Local packages**. This will allow you to quickly navigate through the code-base for the Perception package and internal Unity Editor packages.
All you need to do now is to double click any of the Perception package's C# script files from inside Unity Editor's **Project** window. The files are located in `Assets/Perception`. Double clicking will open them in your external editor of choice, and you will be able to attach the debugger to Unity.
---
</details>
<details>
<summary><strong>Q: What kind of synthetic environment will be best for my use-case?</strong>
</summary><br>
It is difficult to say what type of synthetic environment would lead to the best model performance. It is best to carry out small and quick experiments with both random unstructured environments (such as the [SynthDet](https://github.com/Unity-Technologies/SynthDet) project) and more structured ones that may resemble real environments in which prediction will need to happen. This will help identify the types of environments and randomizations that work best for each specific use-case. The beauty of synthetic data is that you can try these experiments fairly quickly.
Here are a few blog posts to give you some ideas: [1](https://blog.unity.com/technology/synthetic-data-simulating-myriad-possibilities-to-train-robust-machine-learning-models), [2](https://blog.unity.com/technology/use-unitys-perception-tools-to-generate-and-analyze-synthetic-data-at-scale-to-train), [3](https://blog.unity.com/technology/training-a-performant-object-detection-ml-model-on-synthetic-data-using-unity-perception), [4](https://blog.unity.com/technology/supercharge-your-computer-vision-models-with-synthetic-datasets-built-by-unity), [5](https://blog.unity.com/technology/boosting-computer-vision-performance-with-synthetic-data).
---
</details>
<details>
<summary><strong>Q: Can I have more realistic rendering in my Scene?</strong>
</summary><br>
A project's lighting configuration typically has the greatest influence over the final rendered output over any other simulation property. Unity has many lighting options, each of which is designed as a different trade-off between performance and realism/capability. The 3 most pertinent options that you will likely be interested in are:
* URP baked lighting: The Universal Render Pipeline offers the most performant lighting configurations by using an offline baking process to generate realistic bounce lighting within a static scene and then using simple shadow mapped dynamic lights in conjunctions with light probes to make dynamic (or randomized) objects "fit" into the baked scene. This option provides high performance, but lacks the visual fidelity needed for interior environments and is geared toward more outdoor-like settings. Also, depending on scene randomization complexity, light baking might not be the best option. Randomly generated scenes will often place objects and adjust lighting in ways that make the new scene incompatible with the original baked lighting configuration.
* HDRP lighting: A default HDRP scene offers a step toward more realistic environments with a much larger array of lighting settings (soft shadows, multiple dynamic lights, etc.) and a host of additional real-time effects like camera exposure and screen space ambient occlusion. A warning though: real time screen space effects may make your scene "look better", but the way these effects are calculated is not based on how light works in the real world, so realism may vary. Another huge advantage of HDRP is the potential to have moderately realistic lighting without baking your lighting configuration (though you can integrate light baking if you want to). However, there is no real-time global illumination option in default HDRP, meaning that your scene will not simulate complex real world light behavior such as light bouncing, light bleeding, or realistic shadows for dynamic scenes. This can result in unrealistically dark scenes when only using directional lights and windows (without extra interior lights to brighten things up). Overall though, HDRP offers a good compromise between performance and realism for some use cases.
* HDRP DXR (DirectX Raytracing): Unity offers some preview ray tracing features in its latest editor versions that can be used to drastically improve the realism of your scene. Here are the pros and cons of DXR:
* Pros:
* Can simulate more realistic light behaviors (light bouncing, light color bleeding, and realistic shadows)
* No light baking required
* Cons:
* Requires special hardware to run (Nvidia RTX graphics cards)
* Time consuming to render (relative to default HDRP). Some lighting options (Global Illumination) are less expensive than others (Path Tracing).
* More complicated to configure
* These features are still in preview and subject to change
A visual comparison of the different lighting configurations in HDRP is shown below. The Scene includes one directional light and one dim point light on the ceiling.
Default HDRP:
<p align="center">
<img src="images/hdrp.png" width="700"/>
</p>
HDRP with Global Illumination (notice how much brighter the scene is with ray traced light bouncing):
<p align="center">
<img src="images/hdrp_rt_gi.png" width="700"/>
</p>
HDRP with Path Tracing (128 samples) (notice the red light bleeding from the cube onto the floor and the increased shadow quality):
<p align="center">
<img src="images/hdrp_pt_128_samples.png" width="700"/>
</p>
HDRP with Path Tracing (4096 samples) (more samples leads to less ray tracing noise but also a longer time to render):
<p align="center">
<img src="images/hdrp_pt_4096_samples.png" width="700"/>
</p>
---
</details>
<details>
<summary><strong>Q: I am randomizing my Scene every frame and using ray casting to detect the position of objects, but my ray casts are returning incorrect results. What is the issue here?</strong>
</summary><br>
The physics engine needs to catch up with the position and rotation of your objects and is typically a frame behind. When you randomize things every frame, the physics engine can never catch up. To fix this, call `Physics.SyncTransforms` just before calling any ray casting methods.
---
</details>
<details>
<summary><strong>Q: Where can I get humanoid models and animations?</strong>
</summary><br>
One useful resource for humanoid characters and animations is [Mixamo](https://www.mixamo.com/#/?page=1&type=Motion%2CMotionPack).
---
</details>

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


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

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


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

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


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

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


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

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


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

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


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

11
com.unity.perception/Editor/Randomization/VisualElements/Basic/UIntField.cs.meta


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

11
com.unity.perception/Editor/Randomization/VisualElements/Basic/UxmlUIntAttributeDescription.cs.meta


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

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


using System;
using System.Globalization;
using UnityEngine;
using UnityEngine.UIElements;
namespace UnityEditor.UIElements
{
/// <summary>
/// <para>Makes a text field for entering an unsigned integer.</para>
/// </summary>
class UIntField : TextValueField<uint>
{
/// <summary>
/// <para>USS class name of elements of this type.</para>
/// </summary>
public new static readonly string ussClassName = "unity-uint-field";
/// <summary>
/// <para>USS class name of labels in elements of this type.</para>
/// </summary>
public new static readonly string labelUssClassName = ussClassName + "__label";
/// <summary>
/// <para>USS class name of input elements in elements of this type.</para>
/// </summary>
public new static readonly string inputUssClassName = ussClassName + "__input";
/// <summary>
/// <para>Constructor.</para>
/// </summary>
public UIntField()
: this(null) { }
/// <summary>
/// <para>Constructor.</para>
/// </summary>
/// <param name="maxLength">Maximum number of characters the field can take.</param>
public UIntField(int maxLength)
: this(null, maxLength) { }
public UIntField(string label, int maxLength = -1)
: base(label, maxLength, new UIntInput())
{
AddToClassList(ussClassName);
labelElement.AddToClassList(labelUssClassName);
labelElement.AddToClassList("unity-property-field__label");
AddLabelDragger<uint>();
}
UIntInput uIntInput => (UIntInput)textInputBase;
/// <summary>
/// <para>Converts the given uint to a string.</para>
/// </summary>
/// <param name="v">The uint to be converted to string.</param>
/// <returns>
/// <para>The uint as string.</para>
/// </returns>
protected override string ValueToString(uint v)
{
return v.ToString(formatString, CultureInfo.InvariantCulture.NumberFormat);
}
/// <summary>
/// <para>Converts a string to an uint.</para>
/// </summary>
/// <param name="str">The string to convert.</param>
/// <returns>
/// <para>The uint parsed from the string.</para>
/// </returns>
protected override uint StringToValue(string str)
{
long.TryParse(str, out var result);
return ClampInput(result);
}
/// <summary>
/// <para>Modify the value using a 3D delta and a speed, typically coming from an input device.</para>
/// </summary>
/// <param name="delta">A vector used to compute the value change.</param>
/// <param name="speed">A multiplier for the value change.</param>
/// <param name="startValue">The start value.</param>
public override void ApplyInputDeviceDelta(Vector3 delta, DeltaSpeed speed, uint startValue)
{
uIntInput.ApplyInputDeviceDelta(delta, speed, startValue);
}
/// <summary>
/// <para>Instantiates an UIntField using the data read from a UXML file.</para>
/// </summary>
public new class UxmlFactory : UxmlFactory<UIntField, UxmlTraits> { }
/// <summary>
/// <para>Defines UxmlTraits for the UIntField.</para>
/// </summary>
public new class UxmlTraits : TextValueFieldTraits<uint, UxmlUIntAttributeDescription> { }
public static uint ClampInput(long input)
{
input = input > uint.MaxValue ? uint.MaxValue : input;
input = input < uint.MinValue ? uint.MinValue : input;
return (uint)input;
}
class UIntInput : TextValueInput
{
internal UIntInput()
{
formatString = "#######0";
}
UIntField parentUIntField => (UIntField)parent;
protected override string allowedCharacters => "0123456789";
public override void ApplyInputDeviceDelta(Vector3 delta, DeltaSpeed speed, uint startValue)
{
var num = StringToValue(text) + (long)Math.Round(delta.x);
var value = ClampInput(num);
if (parentUIntField.isDelayed)
text = ValueToString(value);
else
parentUIntField.value = value;
}
protected override string ValueToString(uint v)
{
return v.ToString(formatString);
}
protected override uint StringToValue(string str)
{
long.TryParse(str, out var result);
return ClampInput(result);
}
}
}
}

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


using System;
using System.Globalization;
namespace UnityEngine.UIElements
{
/// <summary>
/// <para>Describes a XML int attribute.</para>
/// </summary>
class UxmlUIntAttributeDescription : TypedUxmlAttributeDescription<uint>
{
/// <summary>
/// <para>Constructor.</para>
/// </summary>
public UxmlUIntAttributeDescription()
{
type = "int";
typeNamespace = "http://www.w3.org/2001/XMLSchema";
defaultValue = 0;
}
/// <summary>
/// <para>The default value for the attribute, as a string.</para>
/// </summary>
public override string defaultValueAsString => defaultValue.ToString(CultureInfo.InvariantCulture.NumberFormat);
/// <summary>
/// <para>
/// Retrieves the value of this attribute from the attribute bag. Returns it if it is found, otherwise return
/// defaultValue.
/// </para>
/// </summary>
/// <param name="bag">The bag of attributes.</param>
/// <param name="cc">The context in which the values are retrieved.</param>
/// <returns>
/// <para>The value of the attribute.</para>
/// </returns>
public override uint GetValueFromBag(IUxmlAttributes bag, CreationContext cc)
{
return GetValueFromBag(bag, cc, (s, i) => ConvertValueToUInt(s, i), defaultValue);
}
public bool TryGetValueFromBag(IUxmlAttributes bag, CreationContext cc, ref uint value)
{
return TryGetValueFromBag(bag, cc, (s, i) => ConvertValueToUInt(s, i), defaultValue, ref value);
}
static uint ConvertValueToUInt(string v, uint defaultValue)
{
return v == null || !uint.TryParse(v, out uint result) ? defaultValue : result;
}
}
}

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


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

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


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

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


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

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


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

部分文件因为文件数量过多而无法显示

正在加载...
取消
保存