浏览代码

Merge pull request #150 from Unity-Technologies/animation_curve_sampling

Added animation curve sampling + sampler deserialization bugfix + native sampling removal
/main
GitHub 4 年前
当前提交
d98bf0d6
共有 30 个文件被更改,包括 350 次插入608 次删除
  1. 11
      com.unity.perception/CHANGELOG.md
  2. 8
      com.unity.perception/Documentation~/Randomization/Index.md
  3. 34
      com.unity.perception/Documentation~/Randomization/Parameters.md
  4. 30
      com.unity.perception/Editor/Randomization/VisualElements/Sampler/SamplerElement.cs
  5. 2
      com.unity.perception/Runtime/GroundTruth/Labelers/Visualization/Materials/OutlineMaterial.mat
  6. 11
      com.unity.perception/Runtime/Randomization/Parameters/NumericParameter.cs
  7. 33
      com.unity.perception/Runtime/Randomization/Parameters/ParameterTypes/NumericParameters/BooleanParameter.cs
  8. 111
      com.unity.perception/Runtime/Randomization/Parameters/ParameterTypes/NumericParameters/ColorParameters/ColorHsvaParameter.cs
  9. 52
      com.unity.perception/Runtime/Randomization/Parameters/ParameterTypes/NumericParameters/ColorParameters/ColorRgbParameter.cs
  10. 11
      com.unity.perception/Runtime/Randomization/Parameters/ParameterTypes/NumericParameters/FloatParameter.cs
  11. 31
      com.unity.perception/Runtime/Randomization/Parameters/ParameterTypes/NumericParameters/IntegerParameter.cs
  12. 35
      com.unity.perception/Runtime/Randomization/Parameters/ParameterTypes/NumericParameters/Vector2Parameter.cs
  13. 38
      com.unity.perception/Runtime/Randomization/Parameters/ParameterTypes/NumericParameters/Vector3Parameter.cs
  14. 51
      com.unity.perception/Runtime/Randomization/Parameters/ParameterTypes/NumericParameters/Vector4Parameter.cs
  15. 12
      com.unity.perception/Runtime/Randomization/Samplers/ISampler.cs
  16. 39
      com.unity.perception/Runtime/Randomization/Samplers/SamplerTypes/ConstantSampler.cs
  17. 46
      com.unity.perception/Runtime/Randomization/Samplers/SamplerTypes/NormalSampler.cs
  18. 39
      com.unity.perception/Runtime/Randomization/Samplers/SamplerTypes/UniformSampler.cs
  19. 66
      com.unity.perception/Runtime/Randomization/Samplers/SamplerUtility.cs
  20. 15
      com.unity.perception/Runtime/Randomization/Scenarios/Scenario.cs
  21. 19
      com.unity.perception/Tests/Runtime/Randomization/ParameterTests/StructParameterTests.cs
  22. 21
      com.unity.perception/Tests/Runtime/Randomization/SamplerTests/NormalSamplerTests.cs
  23. 54
      com.unity.perception/Tests/Runtime/Randomization/SamplerTests/SamplerTestsBase.cs
  24. 21
      com.unity.perception/Tests/Runtime/Randomization/SamplerTests/UniformSamplerTests.cs
  25. 99
      com.unity.perception/Runtime/Randomization/Samplers/SamplerTypes/AnimationCurveSampler.cs
  26. 11
      com.unity.perception/Runtime/Randomization/Samplers/SamplerTypes/AnimationCurveSampler.cs.meta
  27. 10
      com.unity.perception/Runtime/Randomization/Samplers/SamplerValidationException.cs
  28. 3
      com.unity.perception/Runtime/Randomization/Samplers/SamplerValidationException.cs.meta
  29. 34
      com.unity.perception/Tests/Runtime/Randomization/SamplerTests/AnimationCurveSamplerTests.cs
  30. 11
      com.unity.perception/Tests/Runtime/Randomization/SamplerTests/AnimationCurveSamplerTests.cs.meta

11
com.unity.perception/CHANGELOG.md


## Unreleased
### Upgrade Notes
Before upgrading a project to this version of the Perception package, make sure to keep a record of **all sampler ranges** in your added Randomizers. Due to a change in how sampler ranges are serialized, **after upgrading to this version, ranges for all stock Perception samplers (Uniform and Normal Samplers) will be reset**, and will need to be manually reverted by the user.
### Added
Added ScenarioConstants base class for all scenario constants objects

Randomizer tags now support inheritance
Added AnimationCurveSampler, which returns random values according to a range and probability distribution denoted by a user provided AnimationCurve.
### Changed

### Removed
Removed ScenarioBase.GenerateRandomSeedFromIndex()
Removed native sampling (through jobs) capability from all samplers and parameters as it introduced additional complexity to the code and was not a common usage pattern
Removed `range` as a required ISampler interface property.
### Fixed

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


Randomizers encapsulate specific randomization activities to perform during the lifecycle of a randomized simulation. For example, randomizers exist for spawning objects, repositioning lights, varying the color of objects, etc. Randomizers expose random parameters to their inspector interface to further customize these variations.
To read more about how to create custom parameter types, navigate over to the [randomizers doc](Randomizers.md).
To read more about how to create custom parameter types, navigate over to the **[Randomizers doc](Randomizers.md)**.
## Randomizer Tags

To read more about how to use RandomizerTags, navigate over to the [RandomizerTags doc](RandomizerTags.md).
To read more about how to use RandomizerTags, navigate over to the **[RandomizerTags doc](RandomizerTags.md)**.
## Parameters

To read more about how to create custom parameter types, navigate over to the [parameters doc](Parameters.md).
To read more about how to create custom parameter types, navigate over to the **[Parameters doc](Parameters.md)**.
## Samplers

Take a look at the [samplers doc](Samplers.md) to learn more about implementing custom probability distributions and samplers that can integrate with the perception package.
Take a look at the **[Samplers doc](Samplers.md)** to learn more about implementing custom probability distributions and samplers that can integrate with the perception package.
## Getting Started

34
com.unity.perception/Documentation~/Randomization/Parameters.md


### Numeric Parameters
Numeric parameters use samplers to generate randomized structs. Take a look at the [ColorHsvaParameter]() class included in the perception package for an example on how to implement a numeric parameter.
## Improving Sampling Performance
For numeric parameters, it is recommended to use the JobHandle overload of the Samples() method when generating a large number of samples. The JobHandle overload will utilize the Unity Burst Compiler and Job System to automatically optimize and multithread parameter sampling jobs. The code block below is an example of how to use this overload to sample two parameters in parallel:
```
// Get a reference to the parameter configuration attached to this GameObject
var parameterConfiguration = GetComponent<ParameterConfiguration>();
// Lookup parameters
var cubeColorParameter = parameterConfiguration.GetParameter<HsvaColorParameter>("CubeColor");
var cubePositionParameter = parameterConfiguration.GetParameter<Vector3Parameter>("CubePosition");
// Schedule sampling jobs
var cubeColors = cubeColorParameter.Samples(constants.cubeCount, out var colorHandle);
var cubePositions = cubePositionParameter.Samples(constants.cubeCount, out var positionHandle);
// Combine job handles
var handles = JobHandle.CombineDependencies(colorHandle, positionHandle);
// Wait for the jobs to complete
handles.Complete();
// Use the created samples
for (var i = 0; i < constants.cubeCount; i++)
{
m_ObjectMaterials[i].SetColor(k_BaseColorProperty, cubeColors[i]);
m_Objects[i].transform.position = cubePositions[i];
}
// Dispose of the generated samples
cubeColors.Dispose();
cubePositions.Dispose();
```
Numeric parameters use samplers to generate randomized structs. Take a look at the [ColorHsvaParameter]() class included in the perception package for an example on how to implement a numeric parameter.

30
com.unity.perception/Editor/Randomization/VisualElements/Sampler/SamplerElement.cs


using System;
using System.Linq;
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine.Experimental.Perception.Randomization.Parameters;

void CreateSampler(Type samplerType)
{
var newSampler = (ISampler)Activator.CreateInstance(samplerType);
CopyFloatRangeToNewSampler(newSampler);
m_Sampler = newSampler;
m_Property.managedReferenceValue = newSampler;
m_Property.serializedObject.ApplyModifiedProperties();
}
if (m_RangeProperty != null)
newSampler.range = new FloatRange(
m_RangeProperty.FindPropertyRelative("minimum").floatValue,
m_RangeProperty.FindPropertyRelative("maximum").floatValue);
void CopyFloatRangeToNewSampler(ISampler newSampler)
{
if (m_RangeProperty == null)
return;
var rangeField = newSampler.GetType().GetField(m_RangeProperty.name);
if (rangeField == null)
return;
m_Sampler = newSampler;
m_Property.managedReferenceValue = newSampler;
m_Property.serializedObject.ApplyModifiedProperties();
var range = new FloatRange(
m_RangeProperty.FindPropertyRelative("minimum").floatValue,
m_RangeProperty.FindPropertyRelative("maximum").floatValue);
rangeField.SetValue(newSampler, range);
}
void CreatePropertyFields()

{
var propertyField = new PropertyField(currentProperty.Copy());
propertyField.Bind(m_Property.serializedObject);
var originalField = m_Sampler.GetType().GetField(currentProperty.name);
var tooltipAttribute = originalField.GetCustomAttributes(true).ToList().Find(att => att.GetType() == typeof(TooltipAttribute));
if (tooltipAttribute != null)
{
propertyField.tooltip = (tooltipAttribute as TooltipAttribute)?.tooltip;
}
m_Properties.Add(propertyField);
}
}

2
com.unity.perception/Runtime/GroundTruth/Labelers/Visualization/Materials/OutlineMaterial.mat


m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3}
m_Name:
m_EditorClassIdentifier:
version: 2
version: 4
--- !u!21 &2100000
Material:
serializedVersion: 6

11
com.unity.perception/Runtime/Randomization/Parameters/NumericParameter.cs


public abstract T Sample();
/// <summary>
/// Schedules a job to generate an array of parameter samples.
/// Call Complete() on the JobHandle returned by this function to wait on the job generating the parameter samples.
/// </summary>
/// <param name="sampleCount">Number of parameter samples to generate</param>
/// <param name="jobHandle">The JobHandle returned from scheduling the sampling job</param>
/// <returns>A NativeArray containing generated samples</returns>
public abstract NativeArray<T> Samples(int sampleCount, out JobHandle jobHandle);
/// <summary>
/// Generates a generic sample
/// </summary>
/// <returns>The generated sample</returns>

{
base.Validate();
foreach (var sampler in samplers)
sampler.range.Validate();
sampler.Validate();
}
}
}

33
com.unity.perception/Runtime/Randomization/Parameters/ParameterTypes/NumericParameters/BooleanParameter.cs


{
return Sample(value.Sample());
}
/// <summary>
/// Schedules a job to generate an array of samples
/// </summary>
/// <param name="sampleCount">The number of samples to generate</param>
/// <param name="jobHandle">The handle of the scheduled job</param>
/// <returns>A NativeArray of samples</returns>
public override NativeArray<bool> Samples(int sampleCount, out JobHandle jobHandle)
{
var samples = new NativeArray<bool>(sampleCount, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
var rngSamples = value.Samples(sampleCount, out jobHandle);
jobHandle = new SamplesJob
{
rngSamples = rngSamples,
samples = samples,
threshold = threshold
}.Schedule(jobHandle);
return samples;
}
[BurstCompile]
struct SamplesJob : IJob
{
[DeallocateOnJobCompletion] public NativeArray<float> rngSamples;
public NativeArray<bool> samples;
public float threshold;
public void Execute()
{
for (var i = 0; i < samples.Length; i++)
samples[i] = rngSamples[i] >= threshold;
}
}
}
}

111
com.unity.perception/Runtime/Randomization/Parameters/ParameterTypes/NumericParameters/ColorParameters/ColorHsvaParameter.cs


{
return new ColorHsva(hue.Sample(), saturation.Sample(), value.Sample(), alpha.Sample());
}
/// <summary>
/// Schedules a job to generate an array of RGBA color samples
/// </summary>
/// <param name="sampleCount">The number of samples to generate</param>
/// <param name="jobHandle">The handle of the scheduled job</param>
/// <returns>A NativeArray of samples</returns>
public override NativeArray<Color> Samples(int sampleCount, out JobHandle jobHandle)
{
var samples = new NativeArray<Color>(sampleCount, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
var hueRng = hue.Samples(sampleCount, out var hueHandle);
var satRng = saturation.Samples(sampleCount, out var satHandle);
var valRng = value.Samples(sampleCount, out var valHandle);
var alphaRng = alpha.Samples(sampleCount, out var alphaHandle);
var handles = new NativeArray<JobHandle>(4, Allocator.TempJob)
{
[0] = hueHandle,
[1] = satHandle,
[2] = valHandle,
[3] = alphaHandle
};
var combinedJobHandles = JobHandle.CombineDependencies(handles);
jobHandle = new SamplesJob
{
hueRng = hueRng,
satRng = satRng,
valRng = valRng,
alphaRng = alphaRng,
samples = samples
}.Schedule(combinedJobHandles);
handles.Dispose(jobHandle);
return samples;
}
[BurstCompile]
struct SamplesJob : IJob
{
[DeallocateOnJobCompletion] public NativeArray<float> hueRng;
[DeallocateOnJobCompletion] public NativeArray<float> satRng;
[DeallocateOnJobCompletion] public NativeArray<float> valRng;
[DeallocateOnJobCompletion] public NativeArray<float> alphaRng;
public NativeArray<Color> samples;
static Color CreateColorHsva(float h, float s, float v, float a)
{
var color = Color.HSVToRGB(h, s, v);
color.a = a;
return color;
}
public void Execute()
{
for (var i = 0; i < samples.Length; i++)
samples[i] = CreateColorHsva(hueRng[i], satRng[i], valRng[i], alphaRng[i]);
}
}
/// <summary>
/// Schedules a job to generate an array of HSVA color samples
/// </summary>
/// <param name="sampleCount">The number of samples to generate</param>
/// <param name="jobHandle">The handle of the scheduled job</param>
/// <returns>A NativeArray of samples</returns>
public NativeArray<ColorHsva> SamplesHsva(int sampleCount, out JobHandle jobHandle)
{
var samples = new NativeArray<ColorHsva>(sampleCount, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
var hueRng = hue.Samples(sampleCount, out var hueHandle);
var satRng = saturation.Samples(sampleCount, out var satHandle);
var valRng = value.Samples(sampleCount, out var valHandle);
var alphaRng = alpha.Samples(sampleCount, out var alphaHandle);
var handles = new NativeArray<JobHandle>(4, Allocator.TempJob)
{
[0] = hueHandle,
[1] = satHandle,
[2] = valHandle,
[3] = alphaHandle
};
var combinedJobHandles = JobHandle.CombineDependencies(handles);
jobHandle = new SamplesHsvaJob
{
hueRng = hueRng,
satRng = satRng,
valRng = valRng,
alphaRng = alphaRng,
samples = samples
}.Schedule(combinedJobHandles);
handles.Dispose(jobHandle);
return samples;
}
[BurstCompile]
struct SamplesHsvaJob : IJob
{
[DeallocateOnJobCompletion] public NativeArray<float> hueRng;
[DeallocateOnJobCompletion] public NativeArray<float> satRng;
[DeallocateOnJobCompletion] public NativeArray<float> valRng;
[DeallocateOnJobCompletion] public NativeArray<float> alphaRng;
public NativeArray<ColorHsva> samples;
public void Execute()
{
for (var i = 0; i < samples.Length; i++)
samples[i] = new ColorHsva(hueRng[i], satRng[i], valRng[i], alphaRng[i]);
}
}
}
}

52
com.unity.perception/Runtime/Randomization/Parameters/ParameterTypes/NumericParameters/ColorParameters/ColorRgbParameter.cs


{
return new Color(red.Sample(), green.Sample(), blue.Sample(), alpha.Sample());
}
/// <summary>
/// Schedules a job to generate an array of samples
/// </summary>
/// <param name="sampleCount">The number of samples to generate</param>
/// <param name="jobHandle">The handle of the scheduled job</param>
/// <returns>A NativeArray of samples</returns>
public override NativeArray<Color> Samples(int sampleCount, out JobHandle jobHandle)
{
var samples = new NativeArray<Color>(sampleCount, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
var redRng = red.Samples(sampleCount, out var redHandle);
var greenRng = green.Samples(sampleCount, out var greenHandle);
var blueRng = blue.Samples(sampleCount, out var blueHandle);
var alphaRng = alpha.Samples(sampleCount, out var alphaHandle);
var handles = new NativeArray<JobHandle>(4, Allocator.TempJob)
{
[0] = redHandle,
[1] = greenHandle,
[2] = blueHandle,
[3] = alphaHandle
};
var combinedJobHandles = JobHandle.CombineDependencies(handles);
jobHandle = new SamplesJob
{
redRng = redRng,
greenRng = greenRng,
blueRng = blueRng,
alphaRng = alphaRng,
samples = samples
}.Schedule(combinedJobHandles);
handles.Dispose(jobHandle);
return samples;
}
[BurstCompile]
struct SamplesJob : IJob
{
[DeallocateOnJobCompletion] public NativeArray<float> redRng;
[DeallocateOnJobCompletion] public NativeArray<float> greenRng;
[DeallocateOnJobCompletion] public NativeArray<float> blueRng;
[DeallocateOnJobCompletion] public NativeArray<float> alphaRng;
public NativeArray<Color> samples;
public void Execute()
{
for (var i = 0; i < samples.Length; i++)
samples[i] = new Color(redRng[i], greenRng[i], blueRng[i], alphaRng[i]);
}
}
}
}

11
com.unity.perception/Runtime/Randomization/Parameters/ParameterTypes/NumericParameters/FloatParameter.cs


{
return value.Sample();
}
/// <summary>
/// Schedules a job to generate an array of samples
/// </summary>
/// <param name="sampleCount">The number of samples to generate</param>
/// <param name="jobHandle">The handle of the scheduled job</param>
/// <returns>A NativeArray of samples</returns>
public override NativeArray<float> Samples(int sampleCount, out JobHandle jobHandle)
{
return value.Samples(sampleCount, out jobHandle);
}
}
}

31
com.unity.perception/Runtime/Randomization/Parameters/ParameterTypes/NumericParameters/IntegerParameter.cs


/// </summary>
/// <returns>The generated sample</returns>
public override int Sample() => (int)value.Sample();
/// <summary>
/// Schedules a job to generate an array of samples
/// </summary>
/// <param name="sampleCount">The number of samples to generate</param>
/// <param name="jobHandle">The handle of the scheduled job</param>
/// <returns>A NativeArray of samples</returns>
public override NativeArray<int> Samples(int sampleCount, out JobHandle jobHandle)
{
var samples = new NativeArray<int>(sampleCount, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
var rngSamples = value.Samples(sampleCount, out jobHandle);
jobHandle = new SamplesJob
{
rngSamples = rngSamples,
samples = samples
}.Schedule(jobHandle);
return samples;
}
[BurstCompile]
struct SamplesJob : IJob
{
[DeallocateOnJobCompletion] public NativeArray<float> rngSamples;
public NativeArray<int> samples;
public void Execute()
{
for (var i = 0; i < samples.Length; i++)
samples[i] = (int)rngSamples[i];
}
}
}
}

35
com.unity.perception/Runtime/Randomization/Parameters/ParameterTypes/NumericParameters/Vector2Parameter.cs


{
return new Vector2(x.Sample(), y.Sample());
}
/// <summary>
/// Schedules a job to generate an array of samples
/// </summary>
/// <param name="sampleCount">The number of samples to generate</param>
/// <param name="jobHandle">The handle of the scheduled job</param>
/// <returns>A NativeArray of samples</returns>
public override NativeArray<Vector2> Samples(int sampleCount, out JobHandle jobHandle)
{
var samples = new NativeArray<Vector2>(sampleCount, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
var xRng = x.Samples(sampleCount, out var xHandle);
var yRng = y.Samples(sampleCount, out var yHandle);
var combinedJobHandles = JobHandle.CombineDependencies(xHandle, yHandle);
jobHandle = new SamplesJob
{
xRng = xRng,
yRng = yRng,
samples = samples
}.Schedule(combinedJobHandles);
return samples;
}
[BurstCompile]
struct SamplesJob : IJob
{
[DeallocateOnJobCompletion] public NativeArray<float> xRng;
[DeallocateOnJobCompletion] public NativeArray<float> yRng;
public NativeArray<Vector2> samples;
public void Execute()
{
for (var i = 0; i < samples.Length; i++)
samples[i] = new Vector2(xRng[i], yRng[i]);
}
}
}
}

38
com.unity.perception/Runtime/Randomization/Parameters/ParameterTypes/NumericParameters/Vector3Parameter.cs


{
return new Vector3(x.Sample(), y.Sample(), z.Sample());
}
/// <summary>
/// Schedules a job to generate an array of samples
/// </summary>
/// <param name="sampleCount">The number of samples to generate</param>
/// <param name="jobHandle">The handle of the scheduled job</param>
/// <returns>A NativeArray of samples</returns>
public override NativeArray<Vector3> Samples(int sampleCount, out JobHandle jobHandle)
{
var samples = new NativeArray<Vector3>(sampleCount, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
var xRng = x.Samples(sampleCount, out var xHandle);
var yRng = y.Samples(sampleCount, out var yHandle);
var zRng = z.Samples(sampleCount, out var zHandle);
var combinedJobHandles = JobHandle.CombineDependencies(xHandle, yHandle, zHandle);
jobHandle = new SamplesJob
{
xRng = xRng,
yRng = yRng,
zRng = zRng,
samples = samples
}.Schedule(combinedJobHandles);
return samples;
}
[BurstCompile]
struct SamplesJob : IJob
{
[DeallocateOnJobCompletion] public NativeArray<float> xRng;
[DeallocateOnJobCompletion] public NativeArray<float> yRng;
[DeallocateOnJobCompletion] public NativeArray<float> zRng;
public NativeArray<Vector3> samples;
public void Execute()
{
for (var i = 0; i < samples.Length; i++)
samples[i] = new Vector3(xRng[i], yRng[i], zRng[i]);
}
}
}
}

51
com.unity.perception/Runtime/Randomization/Parameters/ParameterTypes/NumericParameters/Vector4Parameter.cs


{
return new Vector4(x.Sample(), y.Sample(), z.Sample(), w.Sample());
}
/// <summary>
/// Schedules a job to generate an array of samples
/// </summary>
/// <param name="sampleCount">The number of samples to generate</param>
/// <param name="jobHandle">The handle of the scheduled job</param>
/// <returns>A NativeArray of samples</returns>
public override NativeArray<Vector4> Samples(int sampleCount, out JobHandle jobHandle)
{
var samples = new NativeArray<Vector4>(sampleCount, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
var xRng = x.Samples(sampleCount, out var xHandle);
var yRng = y.Samples(sampleCount, out var yHandle);
var zRng = z.Samples(sampleCount, out var zHandle);
var wRng = w.Samples(sampleCount, out var wHandle);
var handles = new NativeArray<JobHandle>(4, Allocator.Temp)
{
[0] = xHandle,
[1] = yHandle,
[2] = zHandle,
[3] = wHandle
};
var combinedJobHandles = JobHandle.CombineDependencies(handles);
handles.Dispose();
jobHandle = new SamplesJob
{
xRng = xRng,
yRng = yRng,
zRng = zRng,
wRng = wRng,
samples = samples
}.Schedule(combinedJobHandles);
return samples;
}
[BurstCompile]
struct SamplesJob : IJob
{
[DeallocateOnJobCompletion] public NativeArray<float> xRng;
[DeallocateOnJobCompletion] public NativeArray<float> yRng;
[DeallocateOnJobCompletion] public NativeArray<float> zRng;
[DeallocateOnJobCompletion] public NativeArray<float> wRng;
public NativeArray<Vector4> samples;
public void Execute()
{
for (var i = 0; i < samples.Length; i++)
samples[i] = new Vector4(xRng[i], yRng[i], zRng[i], wRng[i]);
}
}
}
}

12
com.unity.perception/Runtime/Randomization/Samplers/ISampler.cs


public interface ISampler
{
/// <summary>
/// A range bounding the values generated by this sampler
/// </summary>
FloatRange range { get; set; }
/// <summary>
/// Generates one sample
/// </summary>
/// <returns>The generated sample</returns>

/// Schedules a job to generate an array of samples
/// Validates that the sampler is configured properly
/// <param name="sampleCount">The number of samples to generate</param>
/// <param name="jobHandle">The handle of the scheduled job</param>
/// <returns>A NativeArray of generated samples</returns>
NativeArray<float> Samples(int sampleCount, out JobHandle jobHandle);
void Validate();
}
}

39
com.unity.perception/Runtime/Randomization/Samplers/SamplerTypes/ConstantSampler.cs


public float value;
/// <summary>
/// A range bounding the values generated by this sampler
/// </summary>
public FloatRange range
{
get => new FloatRange(value, value);
set { }
}
/// <summary>
/// Constructs a ConstantSampler
/// </summary>
public ConstantSampler()

}
/// <summary>
/// Schedules a job to generate an array of samples
/// Validates that the sampler is configured properly
/// <param name="sampleCount">The number of samples to generate</param>
/// <param name="jobHandle">The handle of the scheduled job</param>
/// <returns>A NativeArray of generated samples</returns>
public NativeArray<float> Samples(int sampleCount, out JobHandle jobHandle)
{
var samples = new NativeArray<float>(
sampleCount, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
jobHandle = new SampleJob
{
value = value,
samples = samples
}.Schedule();
return samples;
}
[BurstCompile]
struct SampleJob : IJob
{
public float value;
public NativeArray<float> samples;
public void Execute()
{
for (var i = 0; i < samples.Length; i++)
samples[i] = value;
}
}
public void Validate() {}
}
}

46
com.unity.perception/Runtime/Randomization/Samplers/SamplerTypes/NormalSampler.cs


/// <summary>
/// A range bounding the values generated by this sampler
/// </summary>
[field: SerializeField]
public FloatRange range { get; set; }
public FloatRange range;
/// <summary>
/// Constructs a normal distribution sampler

}
/// <summary>
/// Schedules a job to generate an array of samples
/// Validates that the sampler is configured properly
/// <param name="sampleCount">The number of samples to generate</param>
/// <param name="jobHandle">The handle of the scheduled job</param>
/// <returns>A NativeArray of generated samples</returns>
public NativeArray<float> Samples(int sampleCount, out JobHandle jobHandle)
{
var samples = new NativeArray<float>(
sampleCount, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
jobHandle = new SampleJob
{
min = range.minimum,
max = range.maximum,
mean = mean,
standardDeviation = standardDeviation,
seed = ScenarioBase.activeScenario.NextRandomState(),
samples = samples
}.ScheduleBatch(sampleCount, SamplerUtility.samplingBatchSize);
return samples;
}
[BurstCompile]
struct SampleJob : IJobParallelForBatch
public void Validate()
public float min;
public float max;
public float mean;
public float standardDeviation;
public uint seed;
public NativeArray<float> samples;
public void Execute(int startIndex, int count)
{
var endIndex = startIndex + count;
var batchIndex = startIndex / SamplerUtility.samplingBatchSize;
var rng = new Unity.Mathematics.Random(SamplerUtility.IterateSeed((uint)batchIndex, seed));
for (var i = startIndex; i < endIndex; i++)
{
samples[i] = SamplerUtility.TruncatedNormalSample(
rng.NextFloat(), min, max, mean, standardDeviation);
}
}
range.Validate();
}
}
}

39
com.unity.perception/Runtime/Randomization/Samplers/SamplerTypes/UniformSampler.cs


/// <summary>
/// A range bounding the values generated by this sampler
/// </summary>
[field: SerializeField]
public FloatRange range { get; set; }
public FloatRange range;
/// <summary>
/// Constructs a UniformSampler

}
/// <summary>
/// Schedules a job to generate an array of samples
/// Validates that the sampler is configured properly
/// <param name="sampleCount">The number of samples to generate</param>
/// <param name="jobHandle">The handle of the scheduled job</param>
/// <returns>A NativeArray of generated samples</returns>
public NativeArray<float> Samples(int sampleCount, out JobHandle jobHandle)
public void Validate()
var samples = new NativeArray<float>(
sampleCount, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
jobHandle = new SampleJob
{
min = range.minimum,
max = range.maximum,
seed = ScenarioBase.activeScenario.NextRandomState(),
samples = samples
}.ScheduleBatch(sampleCount, SamplerUtility.samplingBatchSize);
return samples;
}
[BurstCompile]
struct SampleJob : IJobParallelForBatch
{
public float min;
public float max;
public uint seed;
public NativeArray<float> samples;
public void Execute(int startIndex, int count)
{
var endIndex = startIndex + count;
var batchIndex = startIndex / SamplerUtility.samplingBatchSize;
var rng = new Unity.Mathematics.Random(SamplerUtility.IterateSeed((uint)batchIndex, seed));
for (var i = startIndex; i < endIndex; i++)
samples[i] = rng.NextFloat(min, max);
}
range.Validate();
}
}
}

66
com.unity.perception/Runtime/Randomization/Samplers/SamplerUtility.cs


using System;
using System.Runtime.CompilerServices;
using Unity.Collections;
using Unity.Mathematics;
namespace UnityEngine.Experimental.Perception.Randomization.Samplers

var stdTruncNorm = NormalCdfInverse(c);
return stdTruncNorm * stdDev + mean;
}
/// <summary>
/// Generate samples from probability distribution derived from a given AnimationCurve.
/// </summary>
/// <param name="integratedCurve">Numerical integration representing the AnimationCurve</param>
/// <param name="uniformSample">A sample value between 0 and 1 generated from a uniform distribution</param>
/// <param name="interval">The interval at which the original AnimationCurve was sampled in order to produce integratedCurve</param>
/// <param name="startTime">The time attribute of the first key of the original AnimationCurve</param>
/// <param name="endTime">The time attribute of the last key of the original AnimationCurve</param>
/// <returns>The generated sample</returns>
public static float AnimationCurveSample(float[] integratedCurve, float uniformSample, float interval, float startTime, float endTime)
{
var scaledSample = uniformSample * integratedCurve[integratedCurve.Length - 1];
for (var i = 0; i < integratedCurve.Length - 1; i++)
{
if (scaledSample > integratedCurve[i] && scaledSample < integratedCurve[i + 1])
{
var valueDifference = integratedCurve[i + 1] - integratedCurve[i];
var upperWeight = (scaledSample - integratedCurve[i]) / valueDifference;
var lowerWeight = 1 - upperWeight;
var matchingIndex = i * lowerWeight + (i + 1) * upperWeight;
var matchingTimeStamp = startTime + matchingIndex * interval;
return matchingTimeStamp;
}
}
throw new ArithmeticException("Could not find matching timestamp.");
}
/// <summary>
/// Numerically integrate a given AnimationCurve using the specified number of samples.
/// Based on https://en.wikipedia.org/wiki/Numerical_integration and http://blog.s-schoener.com/2018-05-05-animation-curves/
/// Using the trapezoidal rule for numerical interpolation
/// </summary>
/// <param name="array">The array to fill with integrated values</param>
/// <param name="curve">The animation curve to sample integrate</param>
/// <exception cref="ArgumentException"></exception>
public static void IntegrateCurve(float[] array, AnimationCurve curve)
{
if (curve.length == 0)
{
throw new ArgumentException("The provided Animation Curve includes no keys.");
}
var startTime = curve.keys[0].time;
var endTime = curve.keys[curve.length - 1].time;
var interval = (endTime - startTime) / (array.Length - 1);
array[0] = 0;
var previousValue = curve.Evaluate(startTime);
for (var i = 1; i < array.Length; i++)
{
if (curve.length == 1)
{
array[i] = previousValue;
}
else
{
var currentTime = startTime + i * interval;
var currentValue = curve.Evaluate(currentTime);
array[i] = array[i-1] + (previousValue + currentValue) * interval / 2;
previousValue = currentValue;
}
}
}
}
}

15
com.unity.perception/Runtime/Randomization/Scenarios/Scenario.cs


using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using UnityEngine.Experimental.Perception.Randomization.Parameters;

var samplerObj = new JObject();
var fields = sampler.GetType().GetFields();
foreach (var field in fields)
samplerObj.Add(new JProperty(field.Name, field.GetValue(sampler)));
{
samplerObj.Add(new JProperty(field.Name, JToken.FromObject(field.GetValue(sampler))));
}
if (sampler.GetType() != typeof(ConstantSampler))
{
var rangeProperty = sampler.GetType().GetProperty("range");

if (samplerFieldPair.Key == "range")
{
var rangeObj = (JObject)samplerFieldPair.Value;
sampler.range = new FloatRange(
rangeObj["minimum"].ToObject<float>(), rangeObj["maximum"].ToObject<float>());
var field = sampler.GetType().GetField(samplerFieldPair.Key);
var range = new FloatRange(rangeObj["minimum"].ToObject<float>(), rangeObj["maximum"].ToObject<float>());
field.SetValue(sampler, range);
field.SetValue(sampler, ((JValue)samplerFieldPair.Value).Value);
{
field.SetValue(sampler, JsonConvert.DeserializeObject(samplerFieldPair.Value.ToString(), field.FieldType));
}
}
}
}

19
com.unity.perception/Tests/Runtime/Randomization/ParameterTests/StructParameterTests.cs


}
[Test]
public void CorrectNumberOfNativeSamplesAreGenerated()
public void CorrectNumberOfSamplesAreGenerated()
test.GeneratesNativeSamples();
test.GeneratesSamples();
public abstract void GeneratesNativeSamples();
public abstract void GeneratesSamples();
}
public class NumericParameterTest<T> : BaseStructParameterTest where T : struct

m_Parameter = parameter;
}
public override void GeneratesNativeSamples()
public override void GeneratesSamples()
var nativeSamples = m_Parameter.Samples(TestValues.TestSampleCount, out var handle);
handle.Complete();
Assert.AreEqual(nativeSamples.Length, TestValues.TestSampleCount);
nativeSamples.Dispose();
var samples = new T[TestValues.TestSampleCount];
for (var i = 0; i < samples.Length; i++)
{
samples[i] = m_Parameter.Sample();
}
Assert.AreEqual(samples.Length, TestValues.TestSampleCount);
}
}
}

21
com.unity.perception/Tests/Runtime/Randomization/SamplerTests/NormalSamplerTests.cs


namespace RandomizationTests.SamplerTests
{
[TestFixture]
public class NormalSamplerTests : RangedSamplerTests<NormalSampler>
public class NormalSamplerTestsBase : SamplerTestsBase<NormalSampler>
public NormalSamplerTests()
public NormalSamplerTestsBase()
}
[Test]
public void SamplesInRange()
{
var samples = new float[k_TestSampleCount];
for (var i = 0; i < samples.Length; i++)
{
samples[i] = m_Sampler.Sample();
}
Assert.AreEqual(samples.Length, k_TestSampleCount);
for (var i = 0; i < samples.Length; i++)
{
Assert.GreaterOrEqual(samples[i], m_Sampler.range.minimum);
Assert.LessOrEqual(samples[i], m_Sampler.range.maximum);
}
}
}
}

54
com.unity.perception/Tests/Runtime/Randomization/SamplerTests/SamplerTestsBase.cs


namespace RandomizationTests.SamplerTests
{
public abstract class RangedSamplerTests<T> where T : ISampler
public abstract class SamplerTestsBase<T> where T : ISampler
const int k_TestSampleCount = 30;
protected const int k_TestSampleCount = 30;
T m_Sampler;
protected T m_Sampler;
GameObject m_ScenarioObj;
static ScenarioBase activeScenario => ScenarioBase.activeScenario;

}
[Test]
public void SamplesInRange()
{
var samples = m_Sampler.Samples(k_TestSampleCount, out var handle);
handle.Complete();
Assert.AreEqual(samples.Length, k_TestSampleCount);
foreach (var sample in samples)
{
Assert.GreaterOrEqual(sample, m_Sampler.range.minimum);
Assert.LessOrEqual(sample, m_Sampler.range.maximum);
}
samples.Dispose();
}
[Test]
public void NativeSamplesInRange()
{
var samples = m_Sampler.Samples(k_TestSampleCount, out var handle);
handle.Complete();
Assert.AreEqual(samples.Length, k_TestSampleCount);
foreach (var sample in samples)
{
Assert.GreaterOrEqual(sample, m_Sampler.range.minimum);
Assert.LessOrEqual(sample, m_Sampler.range.maximum);
}
samples.Dispose();
}
[Test]
public void ConsecutiveSamplesChangesState()
{
var state0 = activeScenario.randomState;

Assert.AreNotEqual(state0, state1);
Assert.AreNotEqual(state1, state2);
}
[Test]
public void ConsecutiveSampleBatchesChangesState()
{
var state0 = activeScenario.randomState;
var samples1 = m_Sampler.Samples(k_TestSampleCount, out var handle1);
var state1 = activeScenario.randomState;
var samples2 = m_Sampler.Samples(k_TestSampleCount, out var handle2);
var state2 = activeScenario.randomState;
JobHandle.CombineDependencies(handle1, handle2).Complete();
Assert.AreEqual(samples1.Length, samples2.Length);
Assert.AreNotEqual(state0, state1);
Assert.AreNotEqual(state1, state2);
Assert.AreNotEqual(samples1[0], samples2[0]);
samples1.Dispose();
samples2.Dispose();
}
}
}

21
com.unity.perception/Tests/Runtime/Randomization/SamplerTests/UniformSamplerTests.cs


namespace RandomizationTests.SamplerTests
{
[TestFixture]
public class UniformSamplerTests : RangedSamplerTests<UniformSampler>
public class UniformSamplerTestsBase : SamplerTestsBase<UniformSampler>
public UniformSamplerTests()
public UniformSamplerTestsBase()
}
[Test]
public void SamplesInRange()
{
var samples = new float[k_TestSampleCount];
for (var i = 0; i < samples.Length; i++)
{
samples[i] = m_Sampler.Sample();
}
Assert.AreEqual(samples.Length, k_TestSampleCount);
for (var i = 0; i < samples.Length; i++)
{
Assert.GreaterOrEqual(samples[i], m_Sampler.range.minimum);
Assert.LessOrEqual(samples[i], m_Sampler.range.maximum);
}
}
}
}

99
com.unity.perception/Runtime/Randomization/Samplers/SamplerTypes/AnimationCurveSampler.cs


using System;
using System.Runtime.CompilerServices;
using Unity.Burst;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Jobs;
using UnityEngine.Experimental.Perception.Randomization.Scenarios;
namespace UnityEngine.Experimental.Perception.Randomization.Samplers
{
/// <summary>
/// Returns random values according to a range and probability distribution denoted by a user provided AnimationCurve.
/// The X axis of the AnimationCurve corresponds to the values this sampler will pick from,
/// and the Y axis corresponds to the relative probability of the values.
/// The relative probabilities (Y axis) do not need to max out at 1, as only the shape of the curve matters.
/// The Y values cannot however be negative.
/// </summary>
[Serializable]
public class AnimationCurveSampler : ISampler
{
/// <summary>
/// The Animation Curve associated with this sampler
/// </summary>
[Tooltip("Probability distribution curve used for this sampler. The X axis corresponds to the values this sampler will pick from, and the Y axis corresponds to the relative probability of the values. The relative probabilities (Y axis) do not need to max out at 1 as only the shape of the curve matters. The Y values cannot however be negative.")]
public AnimationCurve distributionCurve;
/// <summary>
/// Number of samples used for integrating over the provided AnimationCurve.
/// The larger the number of samples, the more accurate the resulting probability distribution will be.
/// </summary>
[Tooltip("Number of internal samples used for integrating over the provided AnimationCurve. The larger the number of samples, the more accurately the resulting probability distribution will follow the provided AnimationCurve. Increase this if the default value proves insufficient.")]
public int numOfSamplesForIntegration = 500;
float[] m_IntegratedCurve;
bool m_Initialized;
float m_StartTime;
float m_EndTime;
float m_Interval;
/// <summary>
/// Constructs a default AnimationCurveSampler
/// </summary>
public AnimationCurveSampler()
{
distributionCurve = new AnimationCurve(
new Keyframe(0, 0), new Keyframe(0.5f, 1), new Keyframe(1, 0));
}
/// <summary>
/// Constructs an AnimationCurveSampler with a given animation curve
/// </summary>
/// <param name="curve">The animation curve to sample from</param>
/// <param name="numberOfSamples">Number of samples used for integrating over the provided AnimationCurve</param>
public AnimationCurveSampler(AnimationCurve curve, int numberOfSamples=500)
{
distributionCurve = curve;
numOfSamplesForIntegration = numberOfSamples;
}
/// <summary>
/// Generates one sample
/// </summary>
/// <returns>The generated sample</returns>
public float Sample()
{
Initialize();
var rng = new Unity.Mathematics.Random(ScenarioBase.activeScenario.NextRandomState());
return SamplerUtility.AnimationCurveSample(
m_IntegratedCurve, rng.NextFloat(), m_Interval, m_StartTime, m_EndTime);
}
/// <summary>
/// Validates that the sampler is configured properly
/// </summary>
/// <exception cref="SamplerValidationException"></exception>
public void Validate()
{
if (distributionCurve.length == 0)
throw new SamplerValidationException("The distribution curve provided is empty");
if (numOfSamplesForIntegration < 2)
throw new SamplerValidationException("Insufficient number of integration samples");
}
void Initialize()
{
if (m_Initialized)
return;
Validate();
m_IntegratedCurve = new float[numOfSamplesForIntegration];
SamplerUtility.IntegrateCurve(m_IntegratedCurve, distributionCurve);
m_StartTime = distributionCurve.keys[0].time;
m_EndTime = distributionCurve.keys[distributionCurve.length - 1].time;
m_Interval = (m_EndTime - m_StartTime) / (numOfSamplesForIntegration - 1);
m_Initialized = true;
}
}
}

11
com.unity.perception/Runtime/Randomization/Samplers/SamplerTypes/AnimationCurveSampler.cs.meta


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

10
com.unity.perception/Runtime/Randomization/Samplers/SamplerValidationException.cs


using System;
namespace UnityEngine.Experimental.Perception.Randomization.Samplers
{
class SamplerValidationException : Exception
{
public SamplerValidationException(string msg) : base(msg) {}
public SamplerValidationException(string msg, Exception innerException) : base(msg, innerException) {}
}
}

3
com.unity.perception/Runtime/Randomization/Samplers/SamplerValidationException.cs.meta


fileFormatVersion: 2
guid: 232e97ede3ab4d769096833ee3e8d0e4
timeCreated: 1610570590

34
com.unity.perception/Tests/Runtime/Randomization/SamplerTests/AnimationCurveSamplerTests.cs


using NUnit.Framework;
using UnityEngine.Experimental.Perception.Randomization.Samplers;
namespace RandomizationTests.SamplerTests
{
[TestFixture]
public class AnimationCurveSamplerTestsBase : SamplerTestsBase<AnimationCurveSampler>
{
public AnimationCurveSamplerTestsBase()
{
m_BaseSampler = new AnimationCurveSampler();
}
[Test]
public void SamplesInRange()
{
var min = m_Sampler.distributionCurve.keys[0].time;
var max = m_Sampler.distributionCurve.keys[m_Sampler.distributionCurve.length - 1].time;
var samples = new float[k_TestSampleCount];
for (var i = 0; i < samples.Length; i++)
{
samples[i] = m_Sampler.Sample();
}
Assert.AreEqual(samples.Length, k_TestSampleCount);
for (var i = 0; i < samples.Length; i++)
{
Assert.GreaterOrEqual(samples[i], min);
Assert.LessOrEqual(samples[i], max);
}
}
}
}

11
com.unity.perception/Tests/Runtime/Randomization/SamplerTests/AnimationCurveSamplerTests.cs.meta


fileFormatVersion: 2
guid: 15fca3a26ddcf4459be02aea956806bc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
正在加载...
取消
保存