-
Notifications
You must be signed in to change notification settings - Fork 4.4k
RayPerception sensor #2874
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RayPerception sensor #2874
Changes from 10 commits
11235c6
c2a54f5
550f8d7
1d28a5c
f731516
f6ea849
d69cea9
3d7ab8e
49c4449
494e951
133d2b1
7c70587
3329de8
992856e
52fe27a
3891bad
46d6a7c
b6c2ad5
6963744
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| using NUnit.Framework; | ||
| using UnityEngine; | ||
| using MLAgents.Sensor; | ||
|
|
||
| namespace MLAgents.Tests | ||
| { | ||
| public class RayPerceptionSensorTests | ||
| { | ||
| [Test] | ||
| public void TestGetRayAngles() | ||
| { | ||
| var angles = RayPerceptionSensorComponent.GetRayAngles(3, 90f); | ||
| var expectedAngles = new [] { 90f, 60f, 120f, 30f, 150f, 0f, 180f }; | ||
| Assert.AreEqual(expectedAngles.Length, angles.Length); | ||
| for (var i = 0; i < angles.Length; i++) | ||
| { | ||
| Assert.AreEqual(expectedAngles[i], angles[i], .01); | ||
| } | ||
| } | ||
| } | ||
| } |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,6 @@ | ||
| using UnityEngine; | ||
| using MLAgents; | ||
| using MLAgents.Sensor; | ||
|
|
||
| public class FoodCollectorAgent : Agent | ||
| { | ||
|
|
@@ -150,7 +151,7 @@ public void MoveAgent(float[] act) | |
| { | ||
| var myTransform = transform; | ||
| myLaser.transform.localScale = new Vector3(1f, 1f, m_LaserLength); | ||
| var position = myTransform.TransformDirection(RayPerception3D.PolarToCartesian(25f, 90f)); | ||
| var position = myTransform.TransformDirection(RayPerceptionSensor.PolarToCartesian(25f, 90f)); | ||
|
||
| Debug.DrawRay(myTransform.position, position, Color.red, 0f, true); | ||
| RaycastHit hit; | ||
| if (Physics.SphereCast(transform.position, 2f, position, out hit, 25f)) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,7 @@ | ||
| using System.Collections.Generic; | ||
| using System; | ||
| using System.Collections.Generic; | ||
| using UnityEngine; | ||
| using MLAgents.Sensor; | ||
|
|
||
| namespace MLAgents | ||
| { | ||
|
|
@@ -9,7 +11,6 @@ namespace MLAgents | |
| /// </summary> | ||
| public class RayPerception2D : RayPerception | ||
| { | ||
| Vector2 m_EndPosition; | ||
| RaycastHit2D m_Hit; | ||
|
|
||
| /// <summary> | ||
|
|
@@ -30,55 +31,63 @@ public class RayPerception2D : RayPerception | |
| /// <param name="detectableObjects">List of tags which correspond to object types agent can see</param> | ||
| /// <param name="startOffset">Unused</param> | ||
| /// <param name="endOffset">Unused</param> | ||
| public override List<float> Perceive(float rayDistance, | ||
| public override IList<float> Perceive(float rayDistance, | ||
| float[] rayAngles, string[] detectableObjects, | ||
| float startOffset=0.0f, float endOffset=0.0f) | ||
| { | ||
| m_PerceptionBuffer.Clear(); | ||
|
|
||
| var perceptionSize = (detectableObjects.Length + 2) * rayAngles.Length; | ||
| if (m_PerceptionBuffer == null || m_PerceptionBuffer.Length != perceptionSize) | ||
| { | ||
| m_PerceptionBuffer = new float[perceptionSize]; | ||
| } | ||
| Array.Clear(m_PerceptionBuffer, 0, m_PerceptionBuffer.Length); | ||
|
|
||
| // For each ray sublist stores categorical information on detected object | ||
| // along with object distance. | ||
| var bufferOffset = 0; | ||
| foreach (var angle in rayAngles) | ||
| { | ||
| m_EndPosition = transform.TransformDirection( | ||
| PolarToCartesian(rayDistance, angle)); | ||
| Vector2 rayDirection = transform.TransformDirection(PolarToCartesian(rayDistance, angle)); | ||
| if (Application.isEditor) | ||
| { | ||
| Debug.DrawRay(transform.position, | ||
| m_EndPosition, Color.black, 0.01f, true); | ||
| rayDirection, Color.black, 0.01f, true); | ||
| } | ||
|
|
||
| var subList = new float[detectableObjects.Length + 2]; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Got rid of this, and just wrote to the buffer with an offset instead. |
||
| m_Hit = Physics2D.CircleCast(transform.position, 0.5f, m_EndPosition, rayDistance); | ||
| m_Hit = Physics2D.CircleCast(transform.position, 0.5f, rayDirection, rayDistance); | ||
| if (m_Hit) | ||
| { | ||
| for (var i = 0; i < detectableObjects.Length; i++) | ||
| { | ||
| if (m_Hit.collider.gameObject.CompareTag(detectableObjects[i])) | ||
| { | ||
| subList[i] = 1; | ||
| subList[detectableObjects.Length + 1] = m_Hit.distance / rayDistance; | ||
| m_PerceptionBuffer[bufferOffset + i] = 1; | ||
| m_PerceptionBuffer[bufferOffset + detectableObjects.Length + 1] = m_Hit.distance / rayDistance; | ||
| break; | ||
| } | ||
| } | ||
| } | ||
| else | ||
| { | ||
| subList[detectableObjects.Length] = 1f; | ||
| m_PerceptionBuffer[bufferOffset + detectableObjects.Length] = 1f; | ||
| } | ||
|
|
||
| m_PerceptionBuffer.AddRange(subList); | ||
| bufferOffset += detectableObjects.Length + 2; | ||
| } | ||
|
|
||
| return m_PerceptionBuffer; | ||
| } | ||
|
|
||
|
|
||
|
|
||
| /// <summary> | ||
| /// Converts polar coordinate to cartesian coordinate. | ||
| /// </summary> | ||
| public static Vector2 PolarToCartesian(float radius, float angle) | ||
| { | ||
| var x = radius * Mathf.Cos(DegreeToRadian(angle)); | ||
| var y = radius * Mathf.Sin(DegreeToRadian(angle)); | ||
| var x = radius * Mathf.Cos(RayPerceptionSensor.DegreeToRadian(angle)); | ||
|
||
| var y = radius * Mathf.Sin(RayPerceptionSensor.DegreeToRadian(angle)); | ||
| return new Vector2(x, y); | ||
| } | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,7 @@ | ||
| using System; | ||
| using System.Collections.Generic; | ||
| using UnityEngine; | ||
| using MLAgents.Sensor; | ||
|
|
||
| namespace MLAgents | ||
| { | ||
|
|
@@ -10,9 +11,6 @@ namespace MLAgents | |
| /// </summary> | ||
| public class RayPerception3D : RayPerception | ||
| { | ||
| RaycastHit m_Hit; | ||
| float[] m_SubList; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same comment as above. Also RayCast hit is a struct so we don't need to keep it around (I think, correct me if I'm wrong) |
||
|
|
||
| /// <summary> | ||
| /// Creates perception vector to be used as part of an observation of an agent. | ||
| /// Each ray in the rayAngles array adds a sublist of data to the observation. | ||
|
|
@@ -31,66 +29,26 @@ public class RayPerception3D : RayPerception | |
| /// <param name="detectableObjects">List of tags which correspond to object types agent can see</param> | ||
| /// <param name="startOffset">Starting height offset of ray from center of agent.</param> | ||
| /// <param name="endOffset">Ending height offset of ray from center of agent.</param> | ||
| public override List<float> Perceive(float rayDistance, | ||
| public override IList<float> Perceive(float rayDistance, | ||
| float[] rayAngles, string[] detectableObjects, | ||
| float startOffset=0.0f, float endOffset=0.0f) | ||
| { | ||
| if (m_SubList == null || m_SubList.Length != detectableObjects.Length + 2) | ||
| m_SubList = new float[detectableObjects.Length + 2]; | ||
|
|
||
| m_PerceptionBuffer.Clear(); | ||
| m_PerceptionBuffer.Capacity = m_SubList.Length * rayAngles.Length; | ||
|
|
||
| // For each ray sublist stores categorical information on detected object | ||
| // along with object distance. | ||
| foreach (var angle in rayAngles) | ||
| var perceptionSize = (detectableObjects.Length + 2) * rayAngles.Length; | ||
| if (m_PerceptionBuffer == null || m_PerceptionBuffer.Length != perceptionSize) | ||
| { | ||
| Vector3 startPositionLocal = new Vector3(0, startOffset, 0); | ||
| Vector3 endPositionLocal = PolarToCartesian(rayDistance, angle); | ||
| endPositionLocal.y += endOffset; | ||
|
|
||
| var startPositionWorld = transform.TransformPoint(startPositionLocal); | ||
| var endPositionWorld = transform.TransformPoint(endPositionLocal); | ||
|
|
||
| var rayDirection = endPositionWorld - startPositionWorld; | ||
| if (Application.isEditor) | ||
| { | ||
| Debug.DrawRay(startPositionWorld,rayDirection, Color.black, 0.01f, true); | ||
| } | ||
|
|
||
| Array.Clear(m_SubList, 0, m_SubList.Length); | ||
|
|
||
| if (Physics.SphereCast(startPositionWorld, 0.5f, rayDirection, out m_Hit, rayDistance)) | ||
| { | ||
| for (var i = 0; i < detectableObjects.Length; i++) | ||
| { | ||
| if (m_Hit.collider.gameObject.CompareTag(detectableObjects[i])) | ||
| { | ||
| m_SubList[i] = 1; | ||
| m_SubList[detectableObjects.Length + 1] = m_Hit.distance / rayDistance; | ||
| break; | ||
| } | ||
| } | ||
| } | ||
| else | ||
| { | ||
| m_SubList[detectableObjects.Length] = 1f; | ||
| } | ||
|
|
||
| Utilities.AddRangeNoAlloc(m_PerceptionBuffer, m_SubList); | ||
| m_PerceptionBuffer = new float[perceptionSize]; | ||
| } | ||
|
|
||
| const float castRadius = 0.5f; | ||
| const bool legacyHitFractionBehavior = true; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I feel this adds complexity. It is fair to say, you need to retrain when updating. I don't think we should have legacy code in a beta project. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed it adds complexity. Disagree that we shouldn't support it, at least for one more release. The old code is marked as |
||
| RayPerceptionSensor.PerceiveStatic( | ||
| rayDistance, rayAngles, detectableObjects, startOffset, endOffset, castRadius, | ||
| transform, m_PerceptionBuffer, legacyHitFractionBehavior | ||
| ); | ||
|
|
||
| return m_PerceptionBuffer; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Converts polar coordinate to cartesian coordinate. | ||
| /// </summary> | ||
| public static Vector3 PolarToCartesian(float radius, float angle) | ||
| { | ||
| var x = radius * Mathf.Cos(DegreeToRadian(angle)); | ||
| var z = radius * Mathf.Sin(DegreeToRadian(angle)); | ||
| return new Vector3(x, 0f, z); | ||
| } | ||
|
|
||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cleanup suggested by Rider.