updated randomizer default values
This commit is contained in:
Родитель
c4d2ffa004
Коммит
a1f5427b96
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:0db75a046c8dcdae5b0e6e6b3c24c129d782240930b075e2a37f219726544899
|
||||
size 100683
|
||||
oid sha256:26424c3a508656ea81a61ba91b040412eda4b7e1249e51b8ce1ae3b2467150b3
|
||||
size 100812
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 36bd4a49b03b4494839cf95a2cee495c
|
||||
timeCreated: 1615929356
|
|
@ -0,0 +1,10 @@
|
|||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Perception.Randomization.Randomizers;
|
||||
|
||||
namespace SynthDet.RandomizerTags
|
||||
{
|
||||
[AddComponentMenu("SynthDet/RandomizerTags/My Camera Post-processing Metric Reporter Tag")]
|
||||
public class CameraPostProcessingMetricReporterTag : RandomizerTag { }
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Perception.Randomization.Randomizers;
|
||||
|
||||
namespace SynthDet.RandomizerTags
|
||||
{
|
||||
[RequireComponent(typeof(Camera))]
|
||||
[AddComponentMenu("Perception/RandomizerTags/My Camera Randomizer Tag")]
|
||||
public class CameraRandomizerTag : RandomizerTag { }
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Perception.Randomization.Randomizers;
|
||||
|
||||
namespace SynthDet.RandomizerTags
|
||||
{
|
||||
[AddComponentMenu("SynthDet/RandomizerTags/My Foreground Object Metric Reporter Tag")]
|
||||
public class ForegroundObjectMetricReporterTag : RandomizerTag { }
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Perception.Randomization.Randomizers;
|
||||
|
||||
namespace SynthDet.RandomizerTags
|
||||
{
|
||||
[AddComponentMenu("SynthDet/RandomizerTags/MyForegroundOccluderScaleRandomizerTag")]
|
||||
public class ForegroundOccluderScaleRandomizerTag : RandomizerTag { }
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Perception.Randomization.Randomizers;
|
||||
|
||||
namespace SynthDet.RandomizerTags
|
||||
{
|
||||
[AddComponentMenu("SynthDet/RandomizerTags/MyForegroundScaleRandomizerTag")]
|
||||
public class ForegroundScaleRandomizerTag : RandomizerTag { }
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Perception.Randomization.Randomizers;
|
||||
|
||||
namespace SynthDet.RandomizerTags
|
||||
{
|
||||
[RequireComponent(typeof(Light))]
|
||||
[AddComponentMenu("SynthDet/RandomizerTags/MyLightRandomizerTag")]
|
||||
public class LightRandomizerTag : RandomizerTag
|
||||
{
|
||||
public float minIntensity;
|
||||
public float maxIntensity;
|
||||
|
||||
public void SetIntensity(float rawIntensity)
|
||||
{
|
||||
var light = gameObject.GetComponent<Light>();
|
||||
var scaledIntensity = rawIntensity * (maxIntensity - minIntensity) + minIntensity;
|
||||
light.intensity = scaledIntensity;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Perception.Randomization.Randomizers;
|
||||
|
||||
namespace SynthDet.RandomizerTags
|
||||
{
|
||||
[RequireComponent(typeof(Light))]
|
||||
[AddComponentMenu("SynthDet/RandomizerTags/MyLightSwitcherTag")]
|
||||
public class LightSwitcherTag : RandomizerTag
|
||||
{
|
||||
public float enabledProbability;
|
||||
public void Act(float rawInput)
|
||||
{
|
||||
var light = gameObject.GetComponent<Light>();
|
||||
light.enabled = rawInput < enabledProbability;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Perception.Randomization.Randomizers;
|
||||
|
||||
namespace SynthDet.RandomizerTags
|
||||
{
|
||||
[AddComponentMenu("SynthDet/RandomizerTags/My Lighting Info Metric Reporter Tag")]
|
||||
public class LightingInfoMetricReporterTag : RandomizerTag { }
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Perception.Randomization.Randomizers;
|
||||
|
||||
namespace SynthDet.RandomizerTags
|
||||
{
|
||||
/// <summary>
|
||||
/// Used in conjunction with a RotationRandomizer to vary the rotation of GameObjects
|
||||
/// </summary>
|
||||
[AddComponentMenu("SynthDet/RandomizerTags/My Unified Rotation Randomizer Tag")]
|
||||
public class UnifiedRotationRandomizerTag : RandomizerTag { }
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 4fd818e10d6b425184aaf98ac2cb7fb7
|
||||
timeCreated: 1615928826
|
|
@ -0,0 +1,83 @@
|
|||
using System;
|
||||
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;
|
||||
|
||||
namespace SynthDet.Randomizers
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates multiple layers of evenly distributed but randomly placed objects
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[AddRandomizerMenu("SynthDet/My Background Object Placement Randomizer")]
|
||||
public class BackgroundObjectPlacementRandomizer : Randomizer
|
||||
{
|
||||
/// <summary>
|
||||
/// The Z offset component applied to all generated background layers
|
||||
/// </summary>
|
||||
public float depth;
|
||||
|
||||
/// <summary>
|
||||
/// The number of background layers to generate
|
||||
/// </summary>
|
||||
public int layerCount = 2;
|
||||
|
||||
/// <summary>
|
||||
/// The minimum distance between placed background objects
|
||||
/// </summary>
|
||||
public float separationDistance = 0.5f;
|
||||
|
||||
/// <summary>
|
||||
/// The 2D size of the generated background layers
|
||||
/// </summary>
|
||||
public Vector2 placementArea = new Vector2(6f, 6f);
|
||||
|
||||
/// <summary>
|
||||
/// A categorical parameter for sampling random prefabs to place
|
||||
/// </summary>
|
||||
public GameObjectParameter prefabs;
|
||||
|
||||
GameObject m_Container;
|
||||
GameObjectOneWayCache m_GameObjectOneWayCache;
|
||||
|
||||
protected override void OnAwake()
|
||||
{
|
||||
m_Container = new GameObject("Background Distractors");
|
||||
m_Container.transform.parent = scenario.transform;
|
||||
m_GameObjectOneWayCache = new GameObjectOneWayCache(m_Container.transform,
|
||||
prefabs.categories.Select((element) => element.Item1).ToArray());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates background layers of objects at the start of each scenario iteration
|
||||
/// </summary>
|
||||
protected override void OnIterationStart()
|
||||
{
|
||||
for (var i = 0; i < layerCount; i++)
|
||||
{
|
||||
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)
|
||||
{
|
||||
var instance = m_GameObjectOneWayCache.GetOrInstantiate(prefabs.Sample());
|
||||
instance.transform.position = new Vector3(sample.x, sample.y, separationDistance * i + depth) + offset;
|
||||
}
|
||||
|
||||
placementSamples.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes generated background objects after each scenario iteration is complete
|
||||
/// </summary>
|
||||
protected override void OnIterationEnd()
|
||||
{
|
||||
m_GameObjectOneWayCache.ResetAllObjects();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using SynthDet.RandomizerTags;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Perception.GroundTruth;
|
||||
using UnityEngine.Perception.Randomization.Randomizers;
|
||||
using UnityEngine.Rendering;
|
||||
using UnityEngine.Rendering.Universal;
|
||||
|
||||
namespace SynthDet.Randomizers
|
||||
{
|
||||
/// <summary>
|
||||
/// Reports post processing metrics for object that contain a post-processing volume component and are tagged with <see cref="CameraPostProcessingMetricReporter"/>.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[AddRandomizerMenu("SynthDet/My Camera Post-processing Metric Reporter")]
|
||||
public class CameraPostProcessingMetricReporter : Randomizer
|
||||
{
|
||||
const string k_CameraPostProcessingMetricGuid = "a4b2253c-0eb2-4a90-9b20-6e77f1d13286";
|
||||
MetricDefinition m_CameraPostProcessingMetricDefinition;
|
||||
Dictionary<GameObject, Volume> m_PostProcessingVolumeCache;
|
||||
|
||||
protected override void OnAwake()
|
||||
{
|
||||
m_CameraPostProcessingMetricDefinition = DatasetCapture.RegisterMetricDefinition("Per Frame Camera Post Processing Info", $"Reports post-processing effects of cameras (or other objects with a Volume) carrying a {nameof(CameraPostProcessingMetricReporter)} component.", new Guid(k_CameraPostProcessingMetricGuid));
|
||||
m_PostProcessingVolumeCache = new Dictionary<GameObject, Volume>();
|
||||
}
|
||||
|
||||
protected override void OnUpdate()
|
||||
{
|
||||
var tags = tagManager.Query<CameraPostProcessingMetricReporterTag >();
|
||||
ReportMetrics(tags);
|
||||
}
|
||||
|
||||
void ReportMetrics(IEnumerable<RandomizerTag> tags)
|
||||
{
|
||||
var infos = new List<MyVolumeInfo>();
|
||||
foreach (var tag in tags)
|
||||
{
|
||||
var taggedObject = tag.gameObject;
|
||||
if (!m_PostProcessingVolumeCache.TryGetValue(taggedObject, out var volume))
|
||||
{
|
||||
volume = taggedObject.GetComponentInChildren<Volume>();
|
||||
m_PostProcessingVolumeCache.Add(taggedObject, volume);
|
||||
}
|
||||
|
||||
var vignette = (Vignette)volume.profile.components.Find(comp => comp is Vignette);
|
||||
var colorAdjustments = (ColorAdjustments)volume.profile.components.Find(comp => comp is ColorAdjustments);
|
||||
var depthOfField = (DepthOfField)volume.profile.components.Find(comp => comp is DepthOfField);
|
||||
infos.Add(new MyVolumeInfo()
|
||||
{
|
||||
vignetteIntensity = vignette.intensity.value,
|
||||
saturation = colorAdjustments.saturation.value,
|
||||
contrast = colorAdjustments.contrast.value,
|
||||
gaussianDofStart = depthOfField.gaussianStart.value,
|
||||
gaussianDofEnd = depthOfField.gaussianEnd.value,
|
||||
gaussianDofRadius = depthOfField.gaussianMaxRadius.value
|
||||
});
|
||||
}
|
||||
|
||||
DatasetCapture.ReportMetric(m_CameraPostProcessingMetricDefinition, infos.ToArray());
|
||||
}
|
||||
|
||||
struct MyVolumeInfo
|
||||
{
|
||||
public float vignetteIntensity;
|
||||
public float saturation;
|
||||
public float contrast;
|
||||
public float gaussianDofStart;
|
||||
public float gaussianDofEnd;
|
||||
public float gaussianDofRadius;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
using System;
|
||||
using SynthDet.RandomizerTags;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Perception.Randomization.Randomizers;
|
||||
using UnityEngine.Perception.Randomization.Samplers;
|
||||
using UnityEngine.Rendering;
|
||||
using UnityEngine.Rendering.Universal;
|
||||
using FloatParameter = UnityEngine.Perception.Randomization.Parameters.FloatParameter;
|
||||
|
||||
namespace SynthDet.Randomizers
|
||||
{
|
||||
/// <summary>
|
||||
/// Randomizes the blur, contract, saturation, and grain properties of the scene's volume profile
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[AddRandomizerMenu("Perception/My Camera Randomizer")]
|
||||
public class CameraRandomizer : Randomizer
|
||||
{
|
||||
public FloatParameter blurParameter = new FloatParameter { value = new UniformSampler(0f, 4f) };
|
||||
public FloatParameter contrastParameter = new FloatParameter { value = new UniformSampler(-10f, 10f) };
|
||||
public FloatParameter saturationParameter = new FloatParameter { value = new UniformSampler(-10f, 10f) };
|
||||
public FloatParameter grainAmountParameter = new FloatParameter { value = new ConstantSampler(0f) };
|
||||
|
||||
protected override void OnIterationStart()
|
||||
{
|
||||
var tags = tagManager.Query<CameraRandomizerTag>();
|
||||
foreach (var tag in tags)
|
||||
{
|
||||
var volume = tag.gameObject.GetComponent<Volume>();
|
||||
if (volume && volume.profile)
|
||||
{
|
||||
var dof = (DepthOfField) volume.profile.components.Find(comp => comp is DepthOfField);
|
||||
if (dof)
|
||||
{
|
||||
var val = blurParameter.Sample();
|
||||
dof.gaussianStart.value = val;
|
||||
}
|
||||
|
||||
var colorAdjust = (ColorAdjustments) volume.profile.components.Find(comp => comp is ColorAdjustments);
|
||||
if (colorAdjust)
|
||||
{
|
||||
var val = contrastParameter.Sample();
|
||||
colorAdjust.contrast.value = val;
|
||||
|
||||
val = saturationParameter.Sample();
|
||||
colorAdjust.saturation.value = val;
|
||||
}
|
||||
|
||||
var grain = (FilmGrain) volume.profile.components.Find(comp => comp is FilmGrain);
|
||||
if (grain)
|
||||
{
|
||||
var val = grainAmountParameter.Sample();
|
||||
grain.intensity.value = Mathf.Clamp(val, 0,1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
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;
|
||||
|
||||
namespace SynthDet.Randomizers
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a 2D layer of of evenly spaced GameObjects from a given list of prefabs
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[AddRandomizerMenu("Perception/My Dual Layer Foreground Object Placement Randomizer")]
|
||||
public class DualLayerForegroundObjectPlacementRandomizer : Randomizer
|
||||
{
|
||||
List<GameObject> m_SpawnedObjects;
|
||||
public int maxObjectCount = 100;
|
||||
|
||||
public GameObjectParameter prefabs;
|
||||
|
||||
public bool dualLayer;
|
||||
|
||||
public float layerOneDepth = 3f;
|
||||
public FloatParameter layerOneSeparationDistance = new FloatParameter { value = new UniformSampler(0.7f, 1.2f) };
|
||||
public Vector2 layerOnePlacementArea = new Vector2(5f, 5f);
|
||||
|
||||
public float layerTwoDepth = 6f;
|
||||
public FloatParameter layerTwoSeparationDistance = new FloatParameter { value = new UniformSampler(0f, 1f) };
|
||||
public Vector2 layerTwoPlacementArea = new Vector2(5f, 5f);
|
||||
|
||||
GameObject m_Container;
|
||||
GameObjectOneWayCache m_GameObjectOneWayCache;
|
||||
|
||||
protected override void OnAwake()
|
||||
{
|
||||
m_SpawnedObjects = new List<GameObject>();
|
||||
m_Container = new GameObject("Foreground Objects");
|
||||
var transform = scenario.transform;
|
||||
m_Container.transform.parent = transform;
|
||||
m_GameObjectOneWayCache = new GameObjectOneWayCache(m_Container.transform, prefabs.categories.Select(element => element.Item1).ToArray());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates a foreground layer of objects at the start of each scenario iteration
|
||||
/// </summary>
|
||||
protected override void OnIterationStart()
|
||||
{
|
||||
m_SpawnedObjects.Clear();
|
||||
|
||||
PlaceLayerOneObjects();
|
||||
|
||||
if (dualLayer)
|
||||
PlaceLayerTwoObjects();
|
||||
|
||||
TrimObjects();
|
||||
}
|
||||
|
||||
|
||||
void PlaceLayerOneObjects()
|
||||
{
|
||||
var seed = SamplerState.NextRandomState();
|
||||
var placementSamples = PoissonDiskSampling.GenerateSamples(
|
||||
layerOnePlacementArea.x, layerOnePlacementArea.y, layerOneSeparationDistance.Sample(), seed);
|
||||
var offset = new Vector3(layerOnePlacementArea.x, layerOnePlacementArea.y, 0) * -0.5f;
|
||||
|
||||
foreach (var sample in placementSamples)
|
||||
{
|
||||
var instance = m_GameObjectOneWayCache.GetOrInstantiate(prefabs.Sample());
|
||||
instance.transform.position = new Vector3(sample.x, sample.y, layerOneDepth) + offset;
|
||||
m_SpawnedObjects.Add(instance);
|
||||
}
|
||||
placementSamples.Dispose();
|
||||
}
|
||||
|
||||
|
||||
void PlaceLayerTwoObjects()
|
||||
{
|
||||
var seed = SamplerState.NextRandomState();
|
||||
var placementSamples = PoissonDiskSampling.GenerateSamples(
|
||||
layerTwoPlacementArea.x, layerTwoPlacementArea.y, layerTwoSeparationDistance.Sample(), seed);
|
||||
var offset = new Vector3(layerTwoPlacementArea.x, layerTwoPlacementArea.y, 0) * -0.5f;
|
||||
|
||||
foreach (var sample in placementSamples)
|
||||
{
|
||||
var instance = m_GameObjectOneWayCache.GetOrInstantiate(prefabs.Sample());
|
||||
instance.transform.position = new Vector3(sample.x, sample.y, layerTwoDepth) + offset;
|
||||
m_SpawnedObjects.Add(instance);
|
||||
}
|
||||
placementSamples.Dispose();
|
||||
}
|
||||
|
||||
void TrimObjects()
|
||||
{
|
||||
var r = new System.Random();
|
||||
while (m_SpawnedObjects.Count > maxObjectCount)
|
||||
{
|
||||
var obj = m_SpawnedObjects.ElementAt(r.Next(0, m_SpawnedObjects.Count));
|
||||
m_SpawnedObjects.Remove(obj);
|
||||
obj.transform.localPosition = new Vector3(10000, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes generated foreground objects after each scenario iteration is complete
|
||||
/// </summary>
|
||||
protected override void OnIterationEnd()
|
||||
{
|
||||
m_GameObjectOneWayCache.ResetAllObjects();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using SynthDet.RandomizerTags;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Perception.GroundTruth;
|
||||
using UnityEngine.Perception.Randomization.Randomizers;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace SynthDet.Randomizers
|
||||
{
|
||||
/// <summary>
|
||||
/// Reports metrics for rotation, world position, scale, and label id of objects that are tagged with <see cref="ForegroundObjectMetricReporterTag"/>.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[AddRandomizerMenu("Perception/My Foreground Object Metric Reporter")]
|
||||
public class ForegroundObjectMetricReporter : Randomizer
|
||||
{
|
||||
const string k_LayerOneForegroundObjectPlacementInfoMetricGuid = "061E08CC-4428-4926-9933-A6732524B52B";
|
||||
MetricDefinition m_ForegroundObjectPlacementMetricDefinition;
|
||||
public IdLabelConfig labelConfigForObjectPlacementMetrics;
|
||||
Dictionary<GameObject, Labeling> m_LabelingComponentsCache;
|
||||
|
||||
protected override void OnAwake()
|
||||
{
|
||||
m_ForegroundObjectPlacementMetricDefinition = DatasetCapture.RegisterMetricDefinition("Per Frame Foreground Object Placement Info", $"Reports the world position, scale, rotation, and label id of objects carrying a {nameof(ForegroundObjectMetricReporterTag)} component.", new Guid(k_LayerOneForegroundObjectPlacementInfoMetricGuid));
|
||||
m_LabelingComponentsCache = new Dictionary<GameObject, Labeling>();
|
||||
if (labelConfigForObjectPlacementMetrics == null)
|
||||
{
|
||||
var perceptionCamera = Object.FindObjectOfType<PerceptionCamera>();
|
||||
if (perceptionCamera && perceptionCamera.labelers.Count > 0 && perceptionCamera.labelers[0] is BoundingBox2DLabeler boundingBox2DLabeler)
|
||||
{
|
||||
labelConfigForObjectPlacementMetrics = boundingBox2DLabeler.idLabelConfig;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnUpdate()
|
||||
{
|
||||
var tags = tagManager.Query<ForegroundObjectMetricReporterTag>();
|
||||
ReportMetrics(tags);
|
||||
}
|
||||
|
||||
void ReportMetrics(IEnumerable<RandomizerTag> tags)
|
||||
{
|
||||
var objectStates = new JArray();
|
||||
foreach (var tag in tags)
|
||||
{
|
||||
var taggedObject = tag.gameObject;
|
||||
if (!m_LabelingComponentsCache.TryGetValue(taggedObject, out var labeling))
|
||||
{
|
||||
labeling = taggedObject.GetComponentInChildren<Labeling>();
|
||||
m_LabelingComponentsCache.Add(taggedObject, labeling);
|
||||
}
|
||||
|
||||
int labelId = -1;
|
||||
if (labelConfigForObjectPlacementMetrics.TryGetMatchingConfigurationEntry(labeling, out IdLabelEntry labelEntry))
|
||||
{
|
||||
labelId = labelEntry.id;
|
||||
}
|
||||
|
||||
var jObject = new JObject();
|
||||
jObject["label_id"] = labelId;
|
||||
var rotationEulerAngles = (float3)taggedObject.transform.rotation.eulerAngles;
|
||||
jObject["rotation"] = new JRaw($"[{rotationEulerAngles.x}, {rotationEulerAngles.y}, {rotationEulerAngles.z}]");
|
||||
var position = (float3)taggedObject.transform.position;
|
||||
jObject["position"] = new JRaw($"[{position.x}, {position.y}, {position.z}]");
|
||||
var scale = (float3)taggedObject.transform.localScale;
|
||||
jObject["scale"] = new JRaw($"[{scale.x}, {scale.y}, {scale.z}]");
|
||||
objectStates.Add(jObject);
|
||||
}
|
||||
|
||||
DatasetCapture.ReportMetric(m_ForegroundObjectPlacementMetricDefinition, objectStates.ToString(Formatting.Indented));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
using System;
|
||||
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;
|
||||
|
||||
namespace SynthDet.Randomizers
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a 2D layer of of evenly spaced GameObjects from a given list of prefabs
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[AddRandomizerMenu("Perception/MyForeground Occluder Placement Randomizer")]
|
||||
public class ForegroundOccluderPlacementRandomizer : Randomizer
|
||||
{
|
||||
/// <summary>
|
||||
/// The Z offset component applied to the generated layer of GameObjects
|
||||
/// </summary>
|
||||
public float depth = 5;
|
||||
|
||||
/// <summary>
|
||||
/// The minimum distance between all placed objects
|
||||
/// </summary>
|
||||
public FloatParameter occluderSeparationDistance = new FloatParameter { value = new UniformSampler(2f, 2f) };
|
||||
|
||||
/// <summary>
|
||||
/// The size of the 2D area designated for object placement
|
||||
/// </summary>
|
||||
public Vector2 placementArea = new Vector2(6f, 6f);
|
||||
|
||||
/// <summary>
|
||||
/// The list of prefabs sample and randomly place
|
||||
/// </summary>
|
||||
public GameObjectParameter prefabs;
|
||||
|
||||
GameObject m_Container;
|
||||
GameObjectOneWayCache m_GameObjectOneWayCache;
|
||||
|
||||
protected override void OnAwake()
|
||||
{
|
||||
m_Container = new GameObject("Foreground Occluders");
|
||||
var transform = scenario.transform;
|
||||
m_Container.transform.parent = transform;
|
||||
m_GameObjectOneWayCache = new GameObjectOneWayCache(m_Container.transform, prefabs.categories.Select(element => element.Item1).ToArray());
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Generates a foreground layer of objects at the start of each scenario iteration
|
||||
/// </summary>
|
||||
protected override void OnIterationStart()
|
||||
{
|
||||
var seed = SamplerState.NextRandomState();
|
||||
var placementSamples = PoissonDiskSampling.GenerateSamples(
|
||||
placementArea.x, placementArea.y, occluderSeparationDistance.Sample(), seed);
|
||||
var offset = new Vector3(placementArea.x, placementArea.y, 0f) * -0.5f;
|
||||
|
||||
foreach (var sample in placementSamples)
|
||||
{
|
||||
var instance = m_GameObjectOneWayCache.GetOrInstantiate(prefabs.Sample());
|
||||
instance.transform.position = new Vector3(sample.x, sample.y, depth) + offset;
|
||||
}
|
||||
placementSamples.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes generated foreground objects after each scenario iteration is complete
|
||||
/// </summary>
|
||||
protected override void OnIterationEnd()
|
||||
{
|
||||
m_GameObjectOneWayCache.ResetAllObjects();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
using System;
|
||||
using SynthDet.RandomizerTags;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Perception.Randomization.Parameters;
|
||||
using UnityEngine.Perception.Randomization.Randomizers;
|
||||
using UnityEngine.Perception.Randomization.Samplers;
|
||||
|
||||
namespace SynthDet.Randomizers
|
||||
{
|
||||
[Serializable]
|
||||
[AddRandomizerMenu("Perception/My Foreground Occluder Scale Randomizer")]
|
||||
public class ForegroundOccluderScaleRandomizer : Randomizer
|
||||
{
|
||||
public FloatParameter scale = new FloatParameter { value = new UniformSampler(0.5f, 6f) };
|
||||
|
||||
protected override void OnIterationStart()
|
||||
{
|
||||
var tags = tagManager.Query<ForegroundOccluderScaleRandomizerTag>();
|
||||
foreach (var tag in tags)
|
||||
{
|
||||
tag.transform.localScale = Vector3.one * scale.Sample();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
using System;
|
||||
using SynthDet.RandomizerTags;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Perception.Randomization.Parameters;
|
||||
using UnityEngine.Perception.Randomization.Randomizers;
|
||||
using UnityEngine.Perception.Randomization.Samplers;
|
||||
|
||||
namespace SynthDet.Randomizers
|
||||
{
|
||||
[Serializable]
|
||||
[AddRandomizerMenu("Perception/My Foreground Scale Randomizer")]
|
||||
public class ForegroundScaleRandomizer : Randomizer
|
||||
{
|
||||
public FloatParameter scale = new FloatParameter { value = new UniformSampler(4f, 8f) };
|
||||
|
||||
protected override void OnIterationStart()
|
||||
{
|
||||
var tags = tagManager.Query<ForegroundScaleRandomizerTag>();
|
||||
foreach (var tag in tags)
|
||||
{
|
||||
tag.transform.localScale = Vector3.one * scale.Sample();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
using System;
|
||||
using SynthDet.RandomizerTags;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Perception.Randomization.Parameters;
|
||||
using UnityEngine.Perception.Randomization.Randomizers;
|
||||
using UnityEngine.Perception.Randomization.Samplers;
|
||||
|
||||
namespace SynthDet.Randomizers
|
||||
{
|
||||
[Serializable]
|
||||
[AddRandomizerMenu("Perception/My Light Randomizer")]
|
||||
public class LightRandomizer : Randomizer
|
||||
{
|
||||
public FloatParameter lightIntensityParameter = new FloatParameter { value = new UniformSampler(0f, 1f) };
|
||||
public ColorRgbParameter lightColorParameter = new ColorRgbParameter
|
||||
{
|
||||
red = new UniformSampler(0.4f, 1f),
|
||||
green = new UniformSampler(0.4f, 1f),
|
||||
blue = new UniformSampler(0.4f, 1f),
|
||||
alpha = new ConstantSampler(1f),
|
||||
};
|
||||
public FloatParameter auxParameter = new FloatParameter { value = new UniformSampler(0f, 1f) };
|
||||
|
||||
protected override void OnIterationStart()
|
||||
{
|
||||
var randomizerTags = tagManager.Query<LightRandomizerTag>();
|
||||
foreach (var tag in randomizerTags)
|
||||
{
|
||||
var light = tag.GetComponent<Light>();
|
||||
light.color = lightColorParameter.Sample();
|
||||
tag.SetIntensity(lightIntensityParameter.Sample());
|
||||
}
|
||||
|
||||
var switcherTags = tagManager.Query<LightSwitcherTag>();
|
||||
foreach (var tag in switcherTags)
|
||||
{
|
||||
tag.Act(auxParameter.Sample());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using SynthDet.RandomizerTags;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Perception.GroundTruth;
|
||||
using UnityEngine.Perception.Randomization.Randomizers;
|
||||
|
||||
namespace SynthDet.Randomizers
|
||||
{
|
||||
/// <summary>
|
||||
/// Reports metrics for light intensity, light colour, and rotation for objects that contain a light component and are tagged with <see cref="LightingInfoMetricReporterTag"/>.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[AddRandomizerMenu("Perception/My Lighting Info Metric Reporter")]
|
||||
public class LightingInfoMetricReporter : Randomizer
|
||||
{
|
||||
const string k_LightingInfoMetricGuid = "939248EE-668A-4E98-8E79-E7909F034A47";
|
||||
MetricDefinition m_LightingInfoMetricDefinition;
|
||||
|
||||
protected override void OnAwake()
|
||||
{
|
||||
m_LightingInfoMetricDefinition = DatasetCapture.RegisterMetricDefinition("Per Frame Lighting Info", $"Reports the enabled state, intensity, colour, and rotation of lights carrying a {nameof(LightingInfoMetricReporterTag)} component.", new Guid(k_LightingInfoMetricGuid));
|
||||
}
|
||||
|
||||
protected override void OnUpdate()
|
||||
{
|
||||
var tags = tagManager.Query<LightingInfoMetricReporterTag>();
|
||||
ReportMetrics(tags);
|
||||
}
|
||||
|
||||
void ReportMetrics(IEnumerable<RandomizerTag> tags)
|
||||
{
|
||||
var infos = new List<MyLightInfo>();
|
||||
foreach (var tag in tags)
|
||||
{
|
||||
var light = tag.gameObject.GetComponent<Light>();
|
||||
var rotation = tag.transform.rotation;
|
||||
infos.Add(new MyLightInfo()
|
||||
{
|
||||
lightName = tag.name,
|
||||
intensity = light.intensity,
|
||||
color = light.color,
|
||||
x_rotation = rotation.eulerAngles.x,
|
||||
y_rotation = rotation.eulerAngles.y,
|
||||
z_rotation = rotation.eulerAngles.z,
|
||||
enabled = light.enabled
|
||||
});
|
||||
}
|
||||
|
||||
DatasetCapture.ReportMetric(m_LightingInfoMetricDefinition, infos.ToArray());
|
||||
}
|
||||
|
||||
struct MyLightInfo
|
||||
{
|
||||
public string lightName;
|
||||
public bool enabled;
|
||||
public float intensity;
|
||||
public Color color;
|
||||
// ReSharper disable InconsistentNaming
|
||||
public float x_rotation;
|
||||
// ReSharper disable InconsistentNaming
|
||||
public float y_rotation;
|
||||
// ReSharper disable InconsistentNaming
|
||||
public float z_rotation;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
using System;
|
||||
using SynthDet.RandomizerTags;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Perception.Randomization.Parameters;
|
||||
using UnityEngine.Perception.Randomization.Randomizers;
|
||||
using UnityEngine.Perception.Randomization.Samplers;
|
||||
|
||||
namespace SynthDet.Randomizers
|
||||
{
|
||||
/// <summary>
|
||||
/// Randomizes the rotation of objects tagged with a RotationRandomizerTag
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[AddRandomizerMenu("Perception/My Unified Rotation Randomizer")]
|
||||
public class UnifiedRotationRandomizer : Randomizer
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the range of random rotations that can be assigned to tagged objects
|
||||
/// </summary>
|
||||
public Vector3Parameter rotation = new Vector3Parameter
|
||||
{
|
||||
x = new UniformSampler(0, 360),
|
||||
y = new UniformSampler(0, 360),
|
||||
z = new UniformSampler(0, 360)
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Randomizes the rotation of tagged objects at the start of each scenario iteration
|
||||
/// </summary>
|
||||
protected override void OnIterationStart()
|
||||
{
|
||||
var tags = tagManager.Query<UnifiedRotationRandomizerTag>();
|
||||
var rotationSample = Quaternion.Euler(rotation.Sample());
|
||||
foreach (var tag in tags)
|
||||
tag.transform.rotation = rotationSample;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,80 +0,0 @@
|
|||
using System;
|
||||
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;
|
||||
|
||||
/// <summary>
|
||||
/// Creates multiple layers of evenly distributed but randomly placed objects
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[AddRandomizerMenu("Perception/My Background Object Placement Randomizer")]
|
||||
public class MyBackgroundObjectPlacementRandomizer : Randomizer
|
||||
{
|
||||
/// <summary>
|
||||
/// The Z offset component applied to all generated background layers
|
||||
/// </summary>
|
||||
public float depth;
|
||||
|
||||
/// <summary>
|
||||
/// The number of background layers to generate
|
||||
/// </summary>
|
||||
public int layerCount = 2;
|
||||
|
||||
/// <summary>
|
||||
/// The minimum distance between placed background objects
|
||||
/// </summary>
|
||||
public float separationDistance = 2f;
|
||||
|
||||
/// <summary>
|
||||
/// The 2D size of the generated background layers
|
||||
/// </summary>
|
||||
public Vector2 placementArea;
|
||||
|
||||
/// <summary>
|
||||
/// A categorical parameter for sampling random prefabs to place
|
||||
/// </summary>
|
||||
public GameObjectParameter prefabs;
|
||||
|
||||
GameObject m_Container;
|
||||
GameObjectOneWayCache m_GameObjectOneWayCache;
|
||||
|
||||
protected override void OnAwake()
|
||||
{
|
||||
m_Container = new GameObject("Background Distractors");
|
||||
m_Container.transform.parent = scenario.transform;
|
||||
m_GameObjectOneWayCache = new GameObjectOneWayCache(m_Container.transform,
|
||||
prefabs.categories.Select((element) => element.Item1).ToArray());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates background layers of objects at the start of each scenario iteration
|
||||
/// </summary>
|
||||
protected override void OnIterationStart()
|
||||
{
|
||||
for (var i = 0; i < layerCount; i++)
|
||||
{
|
||||
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)
|
||||
{
|
||||
var instance = m_GameObjectOneWayCache.GetOrInstantiate(prefabs.Sample());
|
||||
instance.transform.position = new Vector3(sample.x, sample.y, separationDistance * i + depth) + offset;
|
||||
}
|
||||
|
||||
placementSamples.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes generated background objects after each scenario iteration is complete
|
||||
/// </summary>
|
||||
protected override void OnIterationEnd()
|
||||
{
|
||||
m_GameObjectOneWayCache.ResetAllObjects();
|
||||
}
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Perception.GroundTruth;
|
||||
using UnityEngine.Perception.Randomization.Randomizers;
|
||||
using UnityEngine.Rendering;
|
||||
using UnityEngine.Rendering.Universal;
|
||||
|
||||
/// <summary>
|
||||
/// Reports post processing metrics for object that contain a post-processing volume component and are tagged with <see cref="MyCameraPostProcessingMetricReporter"/>.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[AddRandomizerMenu("Perception/My Camera Post-processing Metric Reporter")]
|
||||
public class MyCameraPostProcessingMetricReporter : Randomizer
|
||||
{
|
||||
|
||||
const string k_CameraPostProcessingMetricGuid = "a4b2253c-0eb2-4a90-9b20-6e77f1d13286";
|
||||
MetricDefinition m_CameraPostProcessingMetricDefinition;
|
||||
Dictionary<GameObject, Volume> m_PostProcessingVolumeCache;
|
||||
|
||||
protected override void OnAwake()
|
||||
{
|
||||
m_CameraPostProcessingMetricDefinition = DatasetCapture.RegisterMetricDefinition("Per Frame Camera Post Processing Info", $"Reports post-processing effects of cameras (or other objects with a Volume) carrying a {nameof(MyCameraPostProcessingMetricReporter)} component.", new Guid(k_CameraPostProcessingMetricGuid));
|
||||
m_PostProcessingVolumeCache = new Dictionary<GameObject, Volume>();
|
||||
}
|
||||
|
||||
protected override void OnUpdate()
|
||||
{
|
||||
var tags = tagManager.Query<MyCameraPostProcessingMetricReporterTag >();
|
||||
ReportMetrics(tags);
|
||||
}
|
||||
|
||||
void ReportMetrics(IEnumerable<RandomizerTag> tags)
|
||||
{
|
||||
var infos = new List<MyVolumeInfo>();
|
||||
foreach (var tag in tags)
|
||||
{
|
||||
var taggedObject = tag.gameObject;
|
||||
if (!m_PostProcessingVolumeCache.TryGetValue(taggedObject, out var volume))
|
||||
{
|
||||
volume = taggedObject.GetComponentInChildren<Volume>();
|
||||
m_PostProcessingVolumeCache.Add(taggedObject, volume);
|
||||
}
|
||||
|
||||
var vignette = (Vignette)volume.profile.components.Find(comp => comp is Vignette);
|
||||
var colorAdjustments = (ColorAdjustments)volume.profile.components.Find(comp => comp is ColorAdjustments);
|
||||
var depthOfField = (DepthOfField)volume.profile.components.Find(comp => comp is DepthOfField);
|
||||
infos.Add(new MyVolumeInfo()
|
||||
{
|
||||
vignetteIntensity = vignette.intensity.value,
|
||||
saturation = colorAdjustments.saturation.value,
|
||||
contrast = colorAdjustments.contrast.value,
|
||||
gaussianDofStart = depthOfField.gaussianStart.value,
|
||||
gaussianDofEnd = depthOfField.gaussianEnd.value,
|
||||
gaussianDofRadius = depthOfField.gaussianMaxRadius.value
|
||||
});
|
||||
}
|
||||
|
||||
DatasetCapture.ReportMetric(m_CameraPostProcessingMetricDefinition, infos.ToArray());
|
||||
}
|
||||
|
||||
struct MyVolumeInfo
|
||||
{
|
||||
public float vignetteIntensity;
|
||||
public float saturation;
|
||||
public float contrast;
|
||||
public float gaussianDofStart;
|
||||
public float gaussianDofEnd;
|
||||
public float gaussianDofRadius;
|
||||
}
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
using UnityEngine;
|
||||
using UnityEngine.Perception.Randomization.Randomizers;
|
||||
|
||||
[AddComponentMenu("Perception/RandomizerTags/My Camera Post-processing Metric Reporter Tag")]
|
||||
public class MyCameraPostProcessingMetricReporterTag : RandomizerTag { }
|
||||
|
|
@ -1,52 +0,0 @@
|
|||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Perception.Randomization.Randomizers;
|
||||
using UnityEngine.Rendering;
|
||||
using UnityEngine.Rendering.Universal;
|
||||
using FloatParameter = UnityEngine.Perception.Randomization.Parameters.FloatParameter;
|
||||
|
||||
[Serializable]
|
||||
|
||||
[AddRandomizerMenu("Perception/My Camera Randomizer")]
|
||||
public class MyCameraRandomizer : Randomizer
|
||||
{
|
||||
public FloatParameter blurParameter;
|
||||
public FloatParameter contrastParameter;
|
||||
public FloatParameter saturationParameter;
|
||||
public FloatParameter grainAmountParameter;
|
||||
|
||||
protected override void OnIterationStart()
|
||||
{
|
||||
var tags = tagManager.Query<MyCameraRandomizerTag>();
|
||||
foreach (var tag in tags)
|
||||
{
|
||||
var volume = tag.gameObject.GetComponent<Volume>();
|
||||
if (volume && volume.profile)
|
||||
{
|
||||
var dof = (DepthOfField) volume.profile.components.Find(comp => comp is DepthOfField);
|
||||
if (dof)
|
||||
{
|
||||
var val = blurParameter.Sample();
|
||||
dof.gaussianStart.value = val;
|
||||
}
|
||||
|
||||
var colorAdjust = (ColorAdjustments) volume.profile.components.Find(comp => comp is ColorAdjustments);
|
||||
if (colorAdjust)
|
||||
{
|
||||
var val = contrastParameter.Sample();
|
||||
colorAdjust.contrast.value = val;
|
||||
|
||||
val = saturationParameter.Sample();
|
||||
colorAdjust.saturation.value = val;
|
||||
}
|
||||
|
||||
var grain = (FilmGrain) volume.profile.components.Find(comp => comp is FilmGrain);
|
||||
if (grain)
|
||||
{
|
||||
var val = grainAmountParameter.Sample();
|
||||
grain.intensity.value = Mathf.Clamp(val, 0,1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
using UnityEngine;
|
||||
using UnityEngine.Perception.Randomization.Randomizers;
|
||||
|
||||
[RequireComponent(typeof(Camera))]
|
||||
[AddComponentMenu("Perception/RandomizerTags/My Camera Randomizer Tag")]
|
||||
public class MyCameraRandomizerTag : RandomizerTag { }
|
|
@ -1,113 +0,0 @@
|
|||
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;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Creates a 2D layer of of evenly spaced GameObjects from a given list of prefabs
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[AddRandomizerMenu("Perception/My Dual Layer Foreground Object Placement Randomizer")]
|
||||
public class MyDualLayerForegroundObjectPlacementRandomizer : Randomizer
|
||||
{
|
||||
List<GameObject> m_SpawnedObjects;
|
||||
public int maxObjectCount;
|
||||
|
||||
public GameObjectParameter prefabs;
|
||||
|
||||
public bool dualLayer;
|
||||
|
||||
public float layerOneDepth;
|
||||
public FloatParameter layerOneSeparationDistance;
|
||||
public Vector2 layerOnePlacementArea;
|
||||
|
||||
public float layerTwoDepth;
|
||||
public FloatParameter layerTwoSeparationDistance;
|
||||
public Vector2 layerTwoPlacementArea;
|
||||
|
||||
GameObject m_Container;
|
||||
GameObjectOneWayCache m_GameObjectOneWayCache;
|
||||
|
||||
protected override void OnAwake()
|
||||
{
|
||||
m_SpawnedObjects = new List<GameObject>();
|
||||
m_Container = new GameObject("Foreground Objects");
|
||||
var transform = scenario.transform;
|
||||
m_Container.transform.parent = transform;
|
||||
m_GameObjectOneWayCache = new GameObjectOneWayCache(m_Container.transform, prefabs.categories.Select(element => element.Item1).ToArray());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates a foreground layer of objects at the start of each scenario iteration
|
||||
/// </summary>
|
||||
protected override void OnIterationStart()
|
||||
{
|
||||
m_SpawnedObjects.Clear();
|
||||
|
||||
PlaceLayerOneObjects();
|
||||
|
||||
if (dualLayer)
|
||||
PlaceLayerTwoObjects();
|
||||
|
||||
TrimObjects();
|
||||
}
|
||||
|
||||
|
||||
void PlaceLayerOneObjects()
|
||||
{
|
||||
var seed = SamplerState.NextRandomState();
|
||||
var placementSamples = PoissonDiskSampling.GenerateSamples(
|
||||
layerOnePlacementArea.x, layerOnePlacementArea.y, layerOneSeparationDistance.Sample(), seed);
|
||||
var offset = new Vector3(layerOnePlacementArea.x, layerOnePlacementArea.y, 0) * -0.5f;
|
||||
|
||||
foreach (var sample in placementSamples)
|
||||
{
|
||||
var instance = m_GameObjectOneWayCache.GetOrInstantiate(prefabs.Sample());
|
||||
instance.transform.position = new Vector3(sample.x, sample.y, layerOneDepth) + offset;
|
||||
m_SpawnedObjects.Add(instance);
|
||||
}
|
||||
placementSamples.Dispose();
|
||||
}
|
||||
|
||||
|
||||
void PlaceLayerTwoObjects()
|
||||
{
|
||||
var seed = SamplerState.NextRandomState();
|
||||
var placementSamples = PoissonDiskSampling.GenerateSamples(
|
||||
layerTwoPlacementArea.x, layerTwoPlacementArea.y, layerTwoSeparationDistance.Sample(), seed);
|
||||
var offset = new Vector3(layerTwoPlacementArea.x, layerTwoPlacementArea.y, 0) * -0.5f;
|
||||
|
||||
foreach (var sample in placementSamples)
|
||||
{
|
||||
var instance = m_GameObjectOneWayCache.GetOrInstantiate(prefabs.Sample());
|
||||
instance.transform.position = new Vector3(sample.x, sample.y, layerTwoDepth) + offset;
|
||||
m_SpawnedObjects.Add(instance);
|
||||
}
|
||||
placementSamples.Dispose();
|
||||
}
|
||||
|
||||
void TrimObjects()
|
||||
{
|
||||
var r = new System.Random();
|
||||
while (m_SpawnedObjects.Count > maxObjectCount)
|
||||
{
|
||||
var obj = m_SpawnedObjects.ElementAt(r.Next(0, m_SpawnedObjects.Count));
|
||||
m_SpawnedObjects.Remove(obj);
|
||||
obj.transform.localPosition = new Vector3(10000, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes generated foreground objects after each scenario iteration is complete
|
||||
/// </summary>
|
||||
protected override void OnIterationEnd()
|
||||
{
|
||||
m_GameObjectOneWayCache.ResetAllObjects();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,75 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Perception.GroundTruth;
|
||||
using UnityEngine.Perception.Randomization.Randomizers;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
/// <summary>
|
||||
/// Reports metrics for rotation, world position, scale, and label id of objects that are tagged with <see cref="MyForegroundObjectMetricReporterTag"/>.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[AddRandomizerMenu("Perception/My Foreground Object Metric Reporter")]
|
||||
public class MyForegroundObjectMetricReporter : Randomizer
|
||||
{
|
||||
|
||||
const string k_LayerOneForegroundObjectPlacementInfoMetricGuid = "061E08CC-4428-4926-9933-A6732524B52B";
|
||||
MetricDefinition m_ForegroundObjectPlacementMetricDefinition;
|
||||
public IdLabelConfig labelConfigForObjectPlacementMetrics;
|
||||
Dictionary<GameObject, Labeling> m_LabelingComponentsCache;
|
||||
|
||||
protected override void OnAwake()
|
||||
{
|
||||
m_ForegroundObjectPlacementMetricDefinition = DatasetCapture.RegisterMetricDefinition("Per Frame Foreground Object Placement Info", $"Reports the world position, scale, rotation, and label id of objects carrying a {nameof(MyForegroundObjectMetricReporterTag)} component.", new Guid(k_LayerOneForegroundObjectPlacementInfoMetricGuid));
|
||||
m_LabelingComponentsCache = new Dictionary<GameObject, Labeling>();
|
||||
if (labelConfigForObjectPlacementMetrics == null)
|
||||
{
|
||||
var perceptionCamera = Object.FindObjectOfType<PerceptionCamera>();
|
||||
if (perceptionCamera && perceptionCamera.labelers.Count > 0 && perceptionCamera.labelers[0] is BoundingBox2DLabeler boundingBox2DLabeler)
|
||||
{
|
||||
labelConfigForObjectPlacementMetrics = boundingBox2DLabeler.idLabelConfig;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnUpdate()
|
||||
{
|
||||
var tags = tagManager.Query<MyForegroundObjectMetricReporterTag>();
|
||||
ReportMetrics(tags);
|
||||
}
|
||||
|
||||
void ReportMetrics(IEnumerable<RandomizerTag> tags)
|
||||
{
|
||||
var objectStates = new JArray();
|
||||
foreach (var tag in tags)
|
||||
{
|
||||
var taggedObject = tag.gameObject;
|
||||
if (!m_LabelingComponentsCache.TryGetValue(taggedObject, out var labeling))
|
||||
{
|
||||
labeling = taggedObject.GetComponentInChildren<Labeling>();
|
||||
m_LabelingComponentsCache.Add(taggedObject, labeling);
|
||||
}
|
||||
|
||||
int labelId = -1;
|
||||
if (labelConfigForObjectPlacementMetrics.TryGetMatchingConfigurationEntry(labeling, out IdLabelEntry labelEntry))
|
||||
{
|
||||
labelId = labelEntry.id;
|
||||
}
|
||||
|
||||
var jObject = new JObject();
|
||||
jObject["label_id"] = labelId;
|
||||
var rotationEulerAngles = (float3)taggedObject.transform.rotation.eulerAngles;
|
||||
jObject["rotation"] = new JRaw($"[{rotationEulerAngles.x}, {rotationEulerAngles.y}, {rotationEulerAngles.z}]");
|
||||
var position = (float3)taggedObject.transform.position;
|
||||
jObject["position"] = new JRaw($"[{position.x}, {position.y}, {position.z}]");
|
||||
var scale = (float3)taggedObject.transform.localScale;
|
||||
jObject["scale"] = new JRaw($"[{scale.x}, {scale.y}, {scale.z}]");
|
||||
objectStates.Add(jObject);
|
||||
}
|
||||
|
||||
DatasetCapture.ReportMetric(m_ForegroundObjectPlacementMetricDefinition, objectStates.ToString(Formatting.Indented));
|
||||
}
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
using UnityEngine;
|
||||
using UnityEngine.Perception.Randomization.Randomizers;
|
||||
|
||||
[AddComponentMenu("Perception/RandomizerTags/My Foreground Object Metric Reporter Tag")]
|
||||
public class MyForegroundObjectMetricReporterTag : RandomizerTag { }
|
||||
|
|
@ -1,74 +0,0 @@
|
|||
using System;
|
||||
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;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a 2D layer of of evenly spaced GameObjects from a given list of prefabs
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[AddRandomizerMenu("Perception/MyForeground Occluder Placement Randomizer")]
|
||||
public class MyForegroundOccluderPlacementRandomizer : Randomizer
|
||||
{
|
||||
/// <summary>
|
||||
/// The Z offset component applied to the generated layer of GameObjects
|
||||
/// </summary>
|
||||
public float depth;
|
||||
|
||||
/// <summary>
|
||||
/// The minimum distance between all placed objects
|
||||
/// </summary>
|
||||
public FloatParameter occluderSeparationDistance;
|
||||
|
||||
/// <summary>
|
||||
/// The size of the 2D area designated for object placement
|
||||
/// </summary>
|
||||
public Vector2 placementArea;
|
||||
|
||||
/// <summary>
|
||||
/// The list of prefabs sample and randomly place
|
||||
/// </summary>
|
||||
public GameObjectParameter prefabs;
|
||||
|
||||
GameObject m_Container;
|
||||
GameObjectOneWayCache m_GameObjectOneWayCache;
|
||||
|
||||
protected override void OnAwake()
|
||||
{
|
||||
m_Container = new GameObject("Foreground Occluders");
|
||||
var transform = scenario.transform;
|
||||
m_Container.transform.parent = transform;
|
||||
m_GameObjectOneWayCache = new GameObjectOneWayCache(m_Container.transform, prefabs.categories.Select(element => element.Item1).ToArray());
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Generates a foreground layer of objects at the start of each scenario iteration
|
||||
/// </summary>
|
||||
protected override void OnIterationStart()
|
||||
{
|
||||
var seed = SamplerState.NextRandomState();
|
||||
var placementSamples = PoissonDiskSampling.GenerateSamples(
|
||||
placementArea.x, placementArea.y, occluderSeparationDistance.Sample(), seed);
|
||||
var offset = new Vector3(placementArea.x, placementArea.y, 0f) * -0.5f;
|
||||
|
||||
foreach (var sample in placementSamples)
|
||||
{
|
||||
var instance = m_GameObjectOneWayCache.GetOrInstantiate(prefabs.Sample());
|
||||
instance.transform.position = new Vector3(sample.x, sample.y, depth) + offset;
|
||||
}
|
||||
placementSamples.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes generated foreground objects after each scenario iteration is complete
|
||||
/// </summary>
|
||||
protected override void OnIterationEnd()
|
||||
{
|
||||
m_GameObjectOneWayCache.ResetAllObjects();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Perception.Randomization.Parameters;
|
||||
using UnityEngine.Perception.Randomization.Randomizers;
|
||||
|
||||
[Serializable]
|
||||
[AddRandomizerMenu("Perception/My Foreground Occluder Scale Randomizer")]
|
||||
public class MyForegroundOccluderScaleRandomizer : Randomizer
|
||||
{
|
||||
public FloatParameter scale;
|
||||
|
||||
protected override void OnIterationStart()
|
||||
{
|
||||
var tags = tagManager.Query<MyForegroundOccluderScaleRandomizerTag>();
|
||||
foreach (var tag in tags)
|
||||
{
|
||||
tag.transform.localScale = Vector3.one * scale.Sample();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
using UnityEngine;
|
||||
using UnityEngine.Perception.Randomization.Randomizers;
|
||||
|
||||
[AddComponentMenu("Perception/RandomizerTags/MyForegroundOccluderScaleRandomizerTag")]
|
||||
public class MyForegroundOccluderScaleRandomizerTag : RandomizerTag { }
|
|
@ -1,20 +0,0 @@
|
|||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Perception.Randomization.Parameters;
|
||||
using UnityEngine.Perception.Randomization.Randomizers;
|
||||
|
||||
[Serializable]
|
||||
[AddRandomizerMenu("Perception/My Foreground Scale Randomizer")]
|
||||
public class MyForegroundScaleRandomizer : Randomizer
|
||||
{
|
||||
public FloatParameter scale;
|
||||
|
||||
protected override void OnIterationStart()
|
||||
{
|
||||
var tags = tagManager.Query<MyForegroundScaleRandomizerTag>();
|
||||
foreach (var tag in tags)
|
||||
{
|
||||
tag.transform.localScale = Vector3.one * scale.Sample();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
using UnityEngine;
|
||||
using UnityEngine.Perception.Randomization.Randomizers;
|
||||
|
||||
[AddComponentMenu("Perception/RandomizerTags/MyForegroundScaleRandomizerTag")]
|
||||
public class MyForegroundScaleRandomizerTag : RandomizerTag { }
|
|
@ -1,31 +0,0 @@
|
|||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Perception.Randomization.Parameters;
|
||||
using UnityEngine.Perception.Randomization.Randomizers;
|
||||
|
||||
[Serializable]
|
||||
|
||||
[AddRandomizerMenu("Perception/My Light Randomizer")]
|
||||
public class MyLightRandomizer : Randomizer
|
||||
{
|
||||
public FloatParameter lightIntensityParameter;
|
||||
public ColorRgbParameter lightColorParameter;
|
||||
public FloatParameter auxParameter;
|
||||
|
||||
protected override void OnIterationStart()
|
||||
{
|
||||
var randomizerTags = tagManager.Query<MyLightRandomizerTag>();
|
||||
foreach (var tag in randomizerTags)
|
||||
{
|
||||
var light = tag.GetComponent<Light>();
|
||||
light.color = lightColorParameter.Sample();
|
||||
tag.SetIntensity(lightIntensityParameter.Sample());
|
||||
}
|
||||
|
||||
var switcherTags = tagManager.Query<MyLightSwitcherTag>();
|
||||
foreach (var tag in switcherTags)
|
||||
{
|
||||
tag.Act(auxParameter.Sample());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
using UnityEngine;
|
||||
using UnityEngine.Perception.Randomization.Randomizers;
|
||||
|
||||
[RequireComponent(typeof(Light))]
|
||||
[AddComponentMenu("Perception/RandomizerTags/MyLightRandomizerTag")]
|
||||
public class MyLightRandomizerTag : RandomizerTag
|
||||
{
|
||||
public float minIntensity;
|
||||
public float maxIntensity;
|
||||
|
||||
public void SetIntensity(float rawIntensity)
|
||||
{
|
||||
var light = gameObject.GetComponent<Light>();
|
||||
var scaledIntensity = rawIntensity * (maxIntensity - minIntensity) + minIntensity;
|
||||
light.intensity = scaledIntensity;
|
||||
}
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
using UnityEngine;
|
||||
using UnityEngine.Perception.Randomization.Randomizers;
|
||||
|
||||
[RequireComponent(typeof(Light))]
|
||||
[AddComponentMenu("Perception/RandomizerTags/MyLightSwitcherTag")]
|
||||
public class MyLightSwitcherTag : RandomizerTag
|
||||
{
|
||||
public float enabledProbability;
|
||||
public void Act(float rawInput)
|
||||
{
|
||||
var light = gameObject.GetComponent<Light>();
|
||||
light.enabled = rawInput < enabledProbability;
|
||||
}
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Perception.GroundTruth;
|
||||
using UnityEngine.Perception.Randomization.Randomizers;
|
||||
|
||||
/// <summary>
|
||||
/// Reports metrics for light intensity, light colour, and rotation for objects that contain a light component and are tagged with <see cref="MyLightingInfoMetricReporterTag"/>.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[AddRandomizerMenu("Perception/My Lighting Info Metric Reporter")]
|
||||
public class MyLightingInfoMetricReporter : Randomizer
|
||||
{
|
||||
const string k_LightingInfoMetricGuid = "939248EE-668A-4E98-8E79-E7909F034A47";
|
||||
MetricDefinition m_LightingInfoMetricDefinition;
|
||||
|
||||
protected override void OnAwake()
|
||||
{
|
||||
m_LightingInfoMetricDefinition = DatasetCapture.RegisterMetricDefinition("Per Frame Lighting Info", $"Reports the enabled state, intensity, colour, and rotation of lights carrying a {nameof(MyLightingInfoMetricReporterTag)} component.", new Guid(k_LightingInfoMetricGuid));
|
||||
}
|
||||
|
||||
protected override void OnUpdate()
|
||||
{
|
||||
var tags = tagManager.Query<MyLightingInfoMetricReporterTag>();
|
||||
ReportMetrics(tags);
|
||||
}
|
||||
|
||||
void ReportMetrics(IEnumerable<RandomizerTag> tags)
|
||||
{
|
||||
var infos = new List<MyLightInfo>();
|
||||
foreach (var tag in tags)
|
||||
{
|
||||
var light = tag.gameObject.GetComponent<Light>();
|
||||
var rotation = tag.transform.rotation;
|
||||
infos.Add(new MyLightInfo()
|
||||
{
|
||||
lightName = tag.name,
|
||||
intensity = light.intensity,
|
||||
color = light.color,
|
||||
x_rotation = rotation.eulerAngles.x,
|
||||
y_rotation = rotation.eulerAngles.y,
|
||||
z_rotation = rotation.eulerAngles.z,
|
||||
enabled = light.enabled
|
||||
});
|
||||
}
|
||||
|
||||
DatasetCapture.ReportMetric(m_LightingInfoMetricDefinition, infos.ToArray());
|
||||
}
|
||||
|
||||
struct MyLightInfo
|
||||
{
|
||||
public string lightName;
|
||||
public bool enabled;
|
||||
public float intensity;
|
||||
public Color color;
|
||||
// ReSharper disable InconsistentNaming
|
||||
public float x_rotation;
|
||||
// ReSharper disable InconsistentNaming
|
||||
public float y_rotation;
|
||||
// ReSharper disable InconsistentNaming
|
||||
public float z_rotation;
|
||||
}
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
using UnityEngine;
|
||||
using UnityEngine.Perception.Randomization.Randomizers;
|
||||
|
||||
[AddComponentMenu("Perception/RandomizerTags/My Lighting Info Metric Reporter Tag")]
|
||||
public class MyLightingInfoMetricReporterTag : RandomizerTag { }
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Perception.Randomization.Parameters;
|
||||
using UnityEngine.Perception.Randomization.Randomizers;
|
||||
using UnityEngine.Perception.Randomization.Samplers;
|
||||
|
||||
/// <summary>
|
||||
/// Randomizes the rotation of objects tagged with a RotationRandomizerTag
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[AddRandomizerMenu("Perception/My Unified Rotation Randomizer")]
|
||||
public class MyUnifiedRotationRandomizer : Randomizer
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the range of random rotations that can be assigned to tagged objects
|
||||
/// </summary>
|
||||
public Vector3Parameter rotation = new Vector3Parameter
|
||||
{
|
||||
x = new UniformSampler(0, 360),
|
||||
y = new UniformSampler(0, 360),
|
||||
z = new UniformSampler(0, 360)
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Randomizes the rotation of tagged objects at the start of each scenario iteration
|
||||
/// </summary>
|
||||
protected override void OnIterationStart()
|
||||
{
|
||||
var tags = tagManager.Query<MyUnifiedRotationRandomizerTag>();
|
||||
var rotationSample = Quaternion.Euler(rotation.Sample());
|
||||
foreach (var tag in tags)
|
||||
tag.transform.rotation = rotationSample;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
using UnityEngine;
|
||||
using UnityEngine.Perception.Randomization.Randomizers;
|
||||
|
||||
/// <summary>
|
||||
/// Used in conjunction with a RotationRandomizer to vary the rotation of GameObjects
|
||||
/// </summary>
|
||||
[AddComponentMenu("Perception/RandomizerTags/My Unified Rotation Randomizer Tag")]
|
||||
public class MyUnifiedRotationRandomizerTag : RandomizerTag { }
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
using SynthDet.Randomizers;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Perception.Randomization.Randomizers.SampleRandomizers;
|
||||
using UnityEngine.Perception.Randomization.Scenarios;
|
||||
using BackgroundObjectPlacementRandomizer = SynthDet.Randomizers.BackgroundObjectPlacementRandomizer;
|
||||
|
||||
namespace SynthDet.MenuItems
|
||||
{
|
||||
public static class SynthDetCreateScenarioMenuItem
|
||||
{
|
||||
[MenuItem("SynthDet/Create Scenario")]
|
||||
static void CreateScenario()
|
||||
{
|
||||
var scenarioObj = new GameObject("Scenario");
|
||||
|
||||
var scenario = scenarioObj.AddComponent<FixedLengthScenario>();
|
||||
scenario.constants.totalIterations = 1000;
|
||||
|
||||
scenario.AddRandomizer(new BackgroundObjectPlacementRandomizer());
|
||||
scenario.AddRandomizer(new ForegroundOccluderPlacementRandomizer());
|
||||
scenario.AddRandomizer(new ForegroundOccluderScaleRandomizer());
|
||||
scenario.AddRandomizer(new TextureRandomizer());
|
||||
scenario.AddRandomizer(new HueOffsetRandomizer());
|
||||
scenario.AddRandomizer(new DualLayerForegroundObjectPlacementRandomizer());
|
||||
scenario.AddRandomizer(new RotationRandomizer());
|
||||
scenario.AddRandomizer(new LightRandomizer());
|
||||
scenario.AddRandomizer(new ForegroundScaleRandomizer());
|
||||
scenario.AddRandomizer(new CameraRandomizer());
|
||||
scenario.AddRandomizer(new UnifiedRotationRandomizer());
|
||||
scenario.AddRandomizer(new ForegroundObjectMetricReporter());
|
||||
scenario.AddRandomizer(new LightingInfoMetricReporter());
|
||||
scenario.AddRandomizer(new CameraPostProcessingMetricReporter());
|
||||
|
||||
Selection.activeGameObject = scenarioObj;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c4ed0e3512ad499184e92f4c444c4f9d
|
||||
timeCreated: 1615930149
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:f7854524bd32ea8e3ac36dd3a15a5c45df1a52856257a7cb52a1f3047b1b1596
|
||||
size 420
|
||||
oid sha256:0481362f1f0938e7e1288ff92e39b64931a29d823a7ca7f8a18b67d310aa9645
|
||||
size 599
|
||||
|
|
Загрузка…
Ссылка в новой задаче