浏览代码

RaycastPerceptionComponent custom editor (#3484)

/asymm-envs
GitHub 4 年前
当前提交
ca914546
共有 6 个文件被更改,包括 285 次插入55 次删除
  1. 2
      com.unity.ml-agents/CHANGELOG.md
  2. 8
      com.unity.ml-agents/Runtime/Sensor/RayPerceptionSensor.cs
  3. 22
      com.unity.ml-agents/Runtime/Sensor/RayPerceptionSensorComponent3D.cs
  4. 203
      com.unity.ml-agents/Runtime/Sensor/RayPerceptionSensorComponentBase.cs
  5. 94
      com.unity.ml-agents/Editor/RayPerceptionSensorComponentBaseEditor.cs
  6. 11
      com.unity.ml-agents/Editor/RayPerceptionSensorComponentBaseEditor.cs.meta

2
com.unity.ml-agents/CHANGELOG.md


- `DemonstrationRecorder` now has an optional path for the demonstrations. This will default to `Application.dataPath` if not set.
- `DemonstrationStore` was changed to accept a `Stream` for its constructor, and was renamed to `DemonstrationWriter`
- The method `GetStepCount()` on the Agent class has been replaced with the property getter `StepCount`
- `RayPerceptionSensorComponent` and related classes now display the debug gizmos whenever the Agent is selected (not just Play mode).
- Most fields on `RayPerceptionSensorComponent` can now be changed while the editor is in Play mode. The exceptions to this are fields that affect the number of observations.
### Bugfixes
- Fixed an issue which caused self-play training sessions to consume a lot of memory. (#3451)

8
com.unity.ml-agents/Runtime/Sensor/RayPerceptionSensor.cs


}
}
internal void SetRayPerceptionInput(RayPerceptionInput input)
{
// TODO make sure that number of rays and tags don't change
m_RayPerceptionInput = input;
}
public int Write(WriteAdapter adapter)
{
using (TimerStack.Instance.Scoped("RayPerceptionSensor.Perceive"))

/// <param name="rayIndex"></param>
/// <param name="debugRayOut"></param>
/// <returns></returns>
static RayPerceptionOutput.RayOutput PerceiveSingleRay(
internal static RayPerceptionOutput.RayOutput PerceiveSingleRay(
RayPerceptionInput input,
int rayIndex,
out DebugDisplayInfo.RayInfo debugRayOut

22
com.unity.ml-agents/Runtime/Sensor/RayPerceptionSensorComponent3D.cs


using System;
using UnityEngine;
using UnityEngine.Serialization;
namespace MLAgents
{

[Header("3D Properties", order = 100)]
[HideInInspector]
[SerializeField]
[FormerlySerializedAs("startVerticalOffset")]
public float startVerticalOffset;
float m_StartVerticalOffset;
public float startVerticalOffset
{
get => m_StartVerticalOffset;
set { m_StartVerticalOffset = value; UpdateSensor(); }
}
[HideInInspector]
[SerializeField]
[FormerlySerializedAs("endVerticalOffset")]
public float endVerticalOffset;
float m_EndVerticalOffset;
public float endVerticalOffset
{
get => m_EndVerticalOffset;
set { m_EndVerticalOffset = value; UpdateSensor(); }
}
public override RayPerceptionCastType GetCastType()
{

203
com.unity.ml-agents/Runtime/Sensor/RayPerceptionSensorComponentBase.cs


using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Serialization;
public string sensorName = "RayPerceptionSensor";
[HideInInspector]
[SerializeField]
[FormerlySerializedAs("sensorName")]
string m_SensorName = "RayPerceptionSensor";
public string sensorName
{
get => m_SensorName;
// Restrict the access on the name, since changing it a runtime doesn't re-sort the Agent sensors.
internal set => m_SensorName = value;
}
[SerializeField]
[FormerlySerializedAs("detectableTags")]
public List<string> detectableTags;
List<string> m_DetectableTags;
public List<string> detectableTags
{
get => m_DetectableTags;
// Note: can't change at runtime
internal set => m_DetectableTags = value;
}
[HideInInspector]
[SerializeField]
[FormerlySerializedAs("raysPerDirection")]
public int raysPerDirection = 3;
int m_RaysPerDirection = 3;
public int raysPerDirection
{
get => m_RaysPerDirection;
// Note: can't change at runtime
internal set => m_RaysPerDirection = value;
}
[HideInInspector]
[SerializeField]
[FormerlySerializedAs("maxRayDegrees")]
public float maxRayDegrees = 70;
float m_MaxRayDegrees = 70;
public float maxRayDegrees
{
get => m_MaxRayDegrees;
set { m_MaxRayDegrees = value; UpdateSensor(); }
}
[HideInInspector]
[SerializeField]
[FormerlySerializedAs("sphereCastRadius")]
public float sphereCastRadius = 0.5f;
float m_SphereCastRadius = 0.5f;
public float sphereCastRadius
{
get => m_SphereCastRadius;
set { m_SphereCastRadius = value; UpdateSensor(); }
}
[HideInInspector]
[SerializeField]
[FormerlySerializedAs("rayLength")]
public float rayLength = 20f;
float m_RayLength = 20f;
public float rayLength
{
get => m_RayLength;
set { m_RayLength = value; UpdateSensor(); }
}
[HideInInspector]
[SerializeField]
[FormerlySerializedAs("rayLayerMask")]
public LayerMask rayLayerMask = Physics.DefaultRaycastLayers;
LayerMask m_RayLayerMask = Physics.DefaultRaycastLayers;
public LayerMask rayLayerMask
{
get => m_RayLayerMask;
set { m_RayLayerMask = value; UpdateSensor();}
}
[HideInInspector]
[SerializeField]
[FormerlySerializedAs("observationStacks")]
public int observationStacks = 1;
int m_ObservationStacks = 1;
internal int observationStacks
{
get => m_ObservationStacks;
set => m_ObservationStacks = value; // Note: can't change at runtime
}
[HideInInspector]
[SerializeField]
public Color rayHitColor = Color.red;
public Color rayMissColor = Color.white;
internal Color rayHitColor = Color.red;
[HideInInspector]
[SerializeField]
internal Color rayMissColor = Color.white;
[NonSerialized]
RayPerceptionSensor m_RaySensor;

public override ISensor CreateSensor()
{
var rayAngles = GetRayAngles(raysPerDirection, maxRayDegrees);
var rayPerceptionInput = GetRayPerceptionInput();
var rayPerceptionInput = new RayPerceptionInput();
rayPerceptionInput.rayLength = rayLength;
rayPerceptionInput.detectableTags = detectableTags;
rayPerceptionInput.angles = rayAngles;
rayPerceptionInput.startOffset = GetStartVerticalOffset();
rayPerceptionInput.endOffset = GetEndVerticalOffset();
rayPerceptionInput.castRadius = sphereCastRadius;
rayPerceptionInput.transform = transform;
rayPerceptionInput.castType = GetCastType();
rayPerceptionInput.layerMask = rayLayerMask;
m_RaySensor = new RayPerceptionSensor(sensorName, rayPerceptionInput);
m_RaySensor = new RayPerceptionSensor(m_SensorName, rayPerceptionInput);
if (observationStacks != 1)
{

public override int[] GetObservationShape()
{
var numRays = 2 * raysPerDirection + 1;
var numTags = detectableTags?.Count ?? 0;
var numTags = m_DetectableTags?.Count ?? 0;
/// <summary>
/// Draw the debug information from the sensor (if available).
/// </summary>
public void OnDrawGizmos()
RayPerceptionInput GetRayPerceptionInput()
{
var rayAngles = GetRayAngles(raysPerDirection, maxRayDegrees);
var rayPerceptionInput = new RayPerceptionInput();
rayPerceptionInput.rayLength = rayLength;
rayPerceptionInput.detectableTags = detectableTags;
rayPerceptionInput.angles = rayAngles;
rayPerceptionInput.startOffset = GetStartVerticalOffset();
rayPerceptionInput.endOffset = GetEndVerticalOffset();
rayPerceptionInput.castRadius = sphereCastRadius;
rayPerceptionInput.transform = transform;
rayPerceptionInput.castType = GetCastType();
rayPerceptionInput.layerMask = rayLayerMask;
return rayPerceptionInput;
}
internal void UpdateSensor()
if (m_RaySensor?.debugDisplayInfo?.rayInfos == null)
if (m_RaySensor != null)
return;
var rayInput = GetRayPerceptionInput();
m_RaySensor.SetRayPerceptionInput(rayInput);
var debugInfo = m_RaySensor.debugDisplayInfo;
}
// Draw "old" observations in a lighter color.
// Since the agent may not step every frame, this helps de-emphasize "stale" hit information.
var alpha = Mathf.Pow(.5f, debugInfo.age);
void OnDrawGizmosSelected()
{
if (m_RaySensor?.debugDisplayInfo?.rayInfos != null)
{
// If we have cached debug info from the sensor, draw that.
// Draw "old" observations in a lighter color.
// Since the agent may not step every frame, this helps de-emphasize "stale" hit information.
var alpha = Mathf.Pow(.5f, m_RaySensor.debugDisplayInfo.age);
foreach (var rayInfo in debugInfo.rayInfos)
foreach (var rayInfo in m_RaySensor.debugDisplayInfo.rayInfos)
{
DrawRaycastGizmos(rayInfo, alpha);
}
}
else
var startPositionWorld = rayInfo.worldStart;
var endPositionWorld = rayInfo.worldEnd;
var rayDirection = endPositionWorld - startPositionWorld;
rayDirection *= rayInfo.rayOutput.hitFraction;
// hit fraction ^2 will shift "far" hits closer to the hit color
var lerpT = rayInfo.rayOutput.hitFraction * rayInfo.rayOutput.hitFraction;
var color = Color.Lerp(rayHitColor, rayMissColor, lerpT);
color.a *= alpha;
Gizmos.color = color;
Gizmos.DrawRay(startPositionWorld, rayDirection);
// Draw the hit point as a sphere. If using rays to cast (0 radius), use a small sphere.
if (rayInfo.rayOutput.hasHit)
var rayInput = GetRayPerceptionInput();
for (var rayIndex = 0; rayIndex < rayInput.angles.Count; rayIndex++)
var hitRadius = Mathf.Max(rayInfo.castRadius, .05f);
Gizmos.DrawWireSphere(startPositionWorld + rayDirection, hitRadius);
DebugDisplayInfo.RayInfo debugRay;
RayPerceptionSensor.PerceiveSingleRay(rayInput, rayIndex, out debugRay);
DrawRaycastGizmos(debugRay);
}
}
/// <summary>
/// Draw the debug information from the sensor (if available).
/// </summary>
void DrawRaycastGizmos(DebugDisplayInfo.RayInfo rayInfo, float alpha=1.0f)
{
var startPositionWorld = rayInfo.worldStart;
var endPositionWorld = rayInfo.worldEnd;
var rayDirection = endPositionWorld - startPositionWorld;
rayDirection *= rayInfo.rayOutput.hitFraction;
// hit fraction ^2 will shift "far" hits closer to the hit color
var lerpT = rayInfo.rayOutput.hitFraction * rayInfo.rayOutput.hitFraction;
var color = Color.Lerp(rayHitColor, rayMissColor, lerpT);
color.a *= alpha;
Gizmos.color = color;
Gizmos.DrawRay(startPositionWorld, rayDirection);
// Draw the hit point as a sphere. If using rays to cast (0 radius), use a small sphere.
if (rayInfo.rayOutput.hasHit)
{
var hitRadius = Mathf.Max(rayInfo.castRadius, .05f);
Gizmos.DrawWireSphere(startPositionWorld + rayDirection, hitRadius);
}
}
}

94
com.unity.ml-agents/Editor/RayPerceptionSensorComponentBaseEditor.cs


using UnityEngine;
using UnityEditor;
using Barracuda;
namespace MLAgents
{
internal class RayPerceptionSensorComponentBaseEditor : Editor
{
bool m_RequireSensorUpdate;
protected void OnRayPerceptionInspectorGUI(bool is3d)
{
var so = serializedObject;
so.Update();
// Drawing the RayPerceptionSensorComponent
EditorGUI.BeginChangeCheck();
EditorGUI.indentLevel++;
EditorGUILayout.PropertyField(so.FindProperty("m_SensorName"), true);
// Because the number of rays and the tags affect the observation shape,
// they are not editable during play mode.
EditorGUI.BeginDisabledGroup(Application.isPlaying);
{
EditorGUILayout.PropertyField(so.FindProperty("m_DetectableTags"), true);
EditorGUILayout.PropertyField(so.FindProperty("m_RaysPerDirection"), true);
}
EditorGUI.EndDisabledGroup();
EditorGUILayout.PropertyField(so.FindProperty("m_MaxRayDegrees"), true);
EditorGUILayout.PropertyField(so.FindProperty("m_SphereCastRadius"), true);
EditorGUILayout.PropertyField(so.FindProperty("m_RayLength"), true);
EditorGUILayout.PropertyField(so.FindProperty("m_RayLayerMask"), true);
// Because the number of observation stacks affects the observation shape,
// it is not editable during play mode.
EditorGUI.BeginDisabledGroup(Application.isPlaying);
{
EditorGUILayout.PropertyField(so.FindProperty("m_ObservationStacks"), true);
}
EditorGUI.EndDisabledGroup();
if (is3d)
{
EditorGUILayout.PropertyField(so.FindProperty("m_StartVerticalOffset"), true);
EditorGUILayout.PropertyField(so.FindProperty("m_EndVerticalOffset"), true);
}
EditorGUILayout.PropertyField(so.FindProperty("rayHitColor"), true);
EditorGUILayout.PropertyField(so.FindProperty("rayMissColor"), true);
EditorGUI.indentLevel--;
if (EditorGUI.EndChangeCheck())
{
m_RequireSensorUpdate = true;
}
UpdateSensorIfDirty();
so.ApplyModifiedProperties();
}
void UpdateSensorIfDirty()
{
if (m_RequireSensorUpdate)
{
var sensorComponent = serializedObject.targetObject as RayPerceptionSensorComponentBase;
sensorComponent?.UpdateSensor();
m_RequireSensorUpdate = false;
}
}
}
[CustomEditor(typeof(RayPerceptionSensorComponent2D))]
[CanEditMultipleObjects]
internal class RayPerceptionSensorComponent2DEditor : RayPerceptionSensorComponentBaseEditor
{
public override void OnInspectorGUI()
{
OnRayPerceptionInspectorGUI(false);
}
}
[CustomEditor(typeof(RayPerceptionSensorComponent3D))]
[CanEditMultipleObjects]
internal class RayPerceptionSensorComponent3DEditor : RayPerceptionSensorComponentBaseEditor
{
public override void OnInspectorGUI()
{
OnRayPerceptionInspectorGUI(true);
}
}
}

11
com.unity.ml-agents/Editor/RayPerceptionSensorComponentBaseEditor.cs.meta


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