浏览代码

Separate boxoverlap out of GridSensor (#5238)

/check-for-ModelOverriders
GitHub 4 年前
当前提交
ca2f0b78
共有 37 个文件被更改,包括 2560 次插入1315 次删除
  1. 50
      Project/Assets/ML-Agents/Examples/FoodCollector/Prefabs/FoodCollectorArea.prefab
  2. 276
      Project/Assets/ML-Agents/Examples/PushBlock/Prefabs/PushBlockCollabAreaGrid.prefab
  3. 172
      Project/Assets/ML-Agents/Examples/PushBlock/Scenes/PushBlockCollab.unity
  4. 995
      Project/Assets/ML-Agents/Examples/PushBlock/TFModels/PushBlockCollab.onnx
  5. 8
      Project/Assets/ML-Agents/Examples/PushBlock/TFModels/PushBlockCollab.onnx.meta
  6. 50
      com.unity.ml-agents.extensions/Editor/GridSensorComponentEditor.cs
  7. 158
      com.unity.ml-agents.extensions/Runtime/Sensors/GridSensorComponent.cs
  8. 2
      com.unity.ml-agents.extensions/Runtime/Sensors/BoxOverlapChecker.cs.meta
  9. 2
      com.unity.ml-agents.extensions/Tests/Editor/GridSensors/BoxOverlapCheckerTests.cs.meta
  10. 2
      com.unity.ml-agents.extensions/Tests/Editor/GridSensors/GridSensorTests.cs.meta
  11. 2
      com.unity.ml-agents.extensions/Runtime/Sensors/CountingGridSensor.cs.meta
  12. 2
      com.unity.ml-agents.extensions/Runtime/Sensors/GridSensorBase.cs.meta
  13. 2
      com.unity.ml-agents.extensions/Runtime/Sensors/OneHotGridSensor.cs.meta
  14. 2
      com.unity.ml-agents.extensions/Tests/Editor/GridSensors/SimpleTestGridSensor.cs.meta
  15. 254
      com.unity.ml-agents.extensions/Runtime/Sensors/BoxOverlapChecker.cs
  16. 61
      com.unity.ml-agents.extensions/Runtime/Sensors/CountingGridSensor.cs
  17. 366
      com.unity.ml-agents.extensions/Runtime/Sensors/GridSensorBase.cs
  18. 60
      com.unity.ml-agents.extensions/Runtime/Sensors/OneHotGridSensor.cs
  19. 8
      com.unity.ml-agents.extensions/Tests/Editor/GridSensors.meta
  20. 297
      com.unity.ml-agents.extensions/Tests/Editor/GridSensors/BoxOverlapCheckerTests.cs
  21. 88
      com.unity.ml-agents.extensions/Tests/Editor/GridSensors/GridSensorTestUtils.cs
  22. 210
      com.unity.ml-agents.extensions/Tests/Editor/GridSensors/GridSensorTests.cs
  23. 131
      com.unity.ml-agents.extensions/Tests/Editor/GridSensors/SimpleTestGridSensor.cs
  24. 661
      com.unity.ml-agents.extensions/Runtime/Sensors/GridSensor.cs
  25. 8
      com.unity.ml-agents.extensions/Tests/Editor/Sensors.meta
  26. 8
      com.unity.ml-agents.extensions/Tests/Utils.meta
  27. 0
      /com.unity.ml-agents.extensions/Runtime/Sensors/BoxOverlapChecker.cs.meta
  28. 0
      /com.unity.ml-agents.extensions/Tests/Editor/GridSensors/BoxOverlapCheckerTests.cs.meta
  29. 0
      /com.unity.ml-agents.extensions/Tests/Editor/GridSensors/GridSensorTests.cs.meta
  30. 0
      /com.unity.ml-agents.extensions/Runtime/Sensors/CountingGridSensor.cs.meta
  31. 0
      /com.unity.ml-agents.extensions/Runtime/Sensors/GridSensorBase.cs.meta
  32. 0
      /com.unity.ml-agents.extensions/Runtime/Sensors/OneHotGridSensor.cs.meta
  33. 0
      /com.unity.ml-agents.extensions/Tests/Editor/GridSensors/GridSensorTestUtils.cs.meta
  34. 0
      /com.unity.ml-agents.extensions/Tests/Editor/GridSensors/SimpleTestGridSensor.cs.meta

50
Project/Assets/ML-Agents/Examples/FoodCollector/Prefabs/FoodCollectorArea.prefab


- component: {fileID: 114176228333253036}
- component: {fileID: 8297075921230369060}
- component: {fileID: 1222199865870203693}
- component: {fileID: 2010492400}
- component: {fileID: 2106566910232743969}
m_Layer: 0
m_Name: Agent
m_TagString: agent

m_Name:
m_EditorClassIdentifier:
debugCommandLineOverride:
--- !u!114 &2010492400
--- !u!114 &2106566910232743969
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}

m_CellScale: {x: 1, y: 0.01, z: 1}
m_GridSize: {x: 40, y: 1, z: 40}
m_RotateWithAgent: 1
m_ChannelDepths: 05000000
m_DetectableObjects:
m_DetectableTags:
- food
- agent
- wall

serializedVersion: 2
m_Bits: 307
m_DepthType: 1
m_MaxColliderBufferSize: 500
m_InitialColliderBufferSize: 4
m_DebugColors:

m_ShowGizmos: 0
m_CompressionType: 1
m_ObservationStacks: 1
m_UseOneHotTag: 1
m_CountColliders: 0
--- !u!1 &1482701732800114
GameObject:
m_ObjectHideFlags: 0

- component: {fileID: 114522573150607728}
- component: {fileID: 114711827726849508}
- component: {fileID: 259154752087955944}
- component: {fileID: 7409303125559953495}
- component: {fileID: 556732721703992837}
m_Layer: 0
m_Name: Agent (1)
m_TagString: agent

m_EditorClassIdentifier:
DecisionPeriod: 5
TakeActionsBetweenDecisions: 1
--- !u!114 &7409303125559953495
--- !u!114 &556732721703992837
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}

m_CellScale: {x: 1, y: 0.01, z: 1}
m_GridSize: {x: 40, y: 1, z: 40}
m_RotateWithAgent: 1
m_ChannelDepths: 05000000
m_DetectableObjects:
m_DetectableTags:
- food
- agent
- wall

serializedVersion: 2
m_Bits: 307
m_DepthType: 1
m_MaxColliderBufferSize: 500
m_InitialColliderBufferSize: 4
m_DebugColors:

m_ShowGizmos: 0
m_CompressionType: 1
m_ObservationStacks: 1
m_UseOneHotTag: 1
m_CountColliders: 0
--- !u!1 &1528397385587768
GameObject:
m_ObjectHideFlags: 0

- component: {fileID: 114980787530065684}
- component: {fileID: 114542632553128056}
- component: {fileID: 5519119940433428255}
- component: {fileID: 1115669858669834387}
- component: {fileID: 1408842157152425307}
m_Layer: 0
m_Name: Agent (2)
m_TagString: agent

m_EditorClassIdentifier:
DecisionPeriod: 5
TakeActionsBetweenDecisions: 1
--- !u!114 &1115669858669834387
--- !u!114 &1408842157152425307
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}

m_CellScale: {x: 1, y: 0.01, z: 1}
m_GridSize: {x: 40, y: 1, z: 40}
m_RotateWithAgent: 1
m_ChannelDepths: 05000000
m_DetectableObjects:
m_DetectableTags:
- food
- agent
- wall

serializedVersion: 2
m_Bits: 307
m_DepthType: 1
m_MaxColliderBufferSize: 500
m_InitialColliderBufferSize: 4
m_DebugColors:

m_ShowGizmos: 0
m_CompressionType: 1
m_ObservationStacks: 1
m_UseOneHotTag: 1
m_CountColliders: 0
--- !u!1 &1617924810425504
GameObject:
m_ObjectHideFlags: 0

- component: {fileID: 114878550018296316}
- component: {fileID: 114189751434580810}
- component: {fileID: 5884750436653390196}
- component: {fileID: 3147256093106034163}
- component: {fileID: 455231854019269609}
m_Layer: 0
m_Name: Agent (4)
m_TagString: agent

m_EditorClassIdentifier:
DecisionPeriod: 5
TakeActionsBetweenDecisions: 1
--- !u!114 &3147256093106034163
--- !u!114 &455231854019269609
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}

m_CellScale: {x: 1, y: 0.01, z: 1}
m_GridSize: {x: 40, y: 1, z: 40}
m_RotateWithAgent: 1
m_ChannelDepths: 05000000
m_DetectableObjects:
m_DetectableTags:
- food
- agent
- wall

serializedVersion: 2
m_Bits: 307
m_DepthType: 1
m_MaxColliderBufferSize: 500
m_InitialColliderBufferSize: 4
m_DebugColors:

m_ShowGizmos: 0
m_CompressionType: 1
m_ObservationStacks: 1
m_UseOneHotTag: 1
m_CountColliders: 0
--- !u!1 &1688105343773098
GameObject:
m_ObjectHideFlags: 0

- component: {fileID: 114035338027591536}
- component: {fileID: 114235147148547996}
- component: {fileID: 4768752321433982785}
- component: {fileID: 3712017990468381030}
- component: {fileID: 653284020512459243}
m_Layer: 0
m_Name: Agent (3)
m_TagString: agent

m_EditorClassIdentifier:
DecisionPeriod: 5
TakeActionsBetweenDecisions: 1
--- !u!114 &3712017990468381030
--- !u!114 &653284020512459243
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}

m_CellScale: {x: 1, y: 0.01, z: 1}
m_GridSize: {x: 40, y: 1, z: 40}
m_RotateWithAgent: 1
m_ChannelDepths: 05000000
m_DetectableObjects:
m_DetectableTags:
- food
- agent
- wall

serializedVersion: 2
m_Bits: 307
m_DepthType: 1
m_MaxColliderBufferSize: 500
m_InitialColliderBufferSize: 4
m_DebugColors:

m_ShowGizmos: 0
m_CompressionType: 1
m_ObservationStacks: 1
m_UseOneHotTag: 1
m_CountColliders: 0
--- !u!1 &1729825611722018
GameObject:
m_ObjectHideFlags: 0

276
Project/Assets/ML-Agents/Examples/PushBlock/Prefabs/PushBlockCollabAreaGrid.prefab


m_GameObject: {fileID: 1679953550419902237}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 1980459831, guid: f70555f144d8491a825f0804e09c671c, type: 3}
m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3}
m_Name:
m_EditorClassIdentifier:
m_UiScaleMode: 0

m_GameObject: {fileID: 1704950560014369677}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 708705254, guid: f70555f144d8491a825f0804e09c671c, type: 3}
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []

m_GameObject: {fileID: 2077722060465813602}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 708705254, guid: f70555f144d8491a825f0804e09c671c, type: 3}
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []

m_GameObject: {fileID: 4230455278956278417}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 708705254, guid: f70555f144d8491a825f0804e09c671c, type: 3}
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []

m_GameObject: {fileID: 4880170283005485334}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 708705254, guid: f70555f144d8491a825f0804e09c671c, type: 3}
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []

m_GameObject: {fileID: 5377521765718574666}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 1980459831, guid: f70555f144d8491a825f0804e09c671c, type: 3}
m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3}
m_Name:
m_EditorClassIdentifier:
m_UiScaleMode: 0

m_GameObject: {fileID: 5488091025762841109}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 1980459831, guid: f70555f144d8491a825f0804e09c671c, type: 3}
m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3}
m_Name:
m_EditorClassIdentifier:
m_UiScaleMode: 0

m_GameObject: {fileID: 5841039003968194311}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 1980459831, guid: f70555f144d8491a825f0804e09c671c, type: 3}
m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3}
m_Name:
m_EditorClassIdentifier:
m_UiScaleMode: 0

m_GameObject: {fileID: 5867018048826954104}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 708705254, guid: f70555f144d8491a825f0804e09c671c, type: 3}
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []

m_GameObject: {fileID: 6108224887597176060}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 1980459831, guid: f70555f144d8491a825f0804e09c671c, type: 3}
m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3}
m_Name:
m_EditorClassIdentifier:
m_UiScaleMode: 0

m_GameObject: {fileID: 6799730675784402451}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 708705254, guid: f70555f144d8491a825f0804e09c671c, type: 3}
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []

m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
m_RayTracingMode: 2
m_RenderingLayerMask: 1
m_RendererPriority: 0
m_Materials:

m_ProbeAnchor: {fileID: 0}
m_LightProbeVolumeOverride: {fileID: 0}
m_ScaleInLightmap: 1
m_ReceiveGI: 1
m_PreserveUVs: 0
m_IgnoreNormalsForChartDetection: 0
m_ImportantGI: 0

m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
m_RayTracingMode: 2
m_RenderingLayerMask: 1
m_RendererPriority: 0
m_Materials:

m_ProbeAnchor: {fileID: 0}
m_LightProbeVolumeOverride: {fileID: 0}
m_ScaleInLightmap: 1
m_ReceiveGI: 1
m_PreserveUVs: 0
m_IgnoreNormalsForChartDetection: 0
m_ImportantGI: 0

m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
m_RayTracingMode: 2
m_RenderingLayerMask: 1
m_RendererPriority: 0
m_Materials:

m_ProbeAnchor: {fileID: 0}
m_LightProbeVolumeOverride: {fileID: 0}
m_ScaleInLightmap: 1
m_ReceiveGI: 1
m_PreserveUVs: 1
m_IgnoreNormalsForChartDetection: 0
m_ImportantGI: 0

m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
m_RayTracingMode: 2
m_RenderingLayerMask: 1
m_RendererPriority: 0
m_Materials:

m_ProbeAnchor: {fileID: 0}
m_LightProbeVolumeOverride: {fileID: 0}
m_ScaleInLightmap: 1
m_ReceiveGI: 1
m_PreserveUVs: 0
m_IgnoreNormalsForChartDetection: 0
m_ImportantGI: 0

m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
m_RayTracingMode: 2
m_RenderingLayerMask: 1
m_RendererPriority: 0
m_Materials:

m_ProbeAnchor: {fileID: 0}
m_LightProbeVolumeOverride: {fileID: 0}
m_ScaleInLightmap: 1
m_ReceiveGI: 1
m_PreserveUVs: 1
m_IgnoreNormalsForChartDetection: 0
m_ImportantGI: 0

onTriggerExitEvent:
m_PersistentCalls:
m_Calls: []
--- !u!114 &1809664679221531284
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8191066182862526894}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 2a501962d056745d1a30e99146ee39fe, type: 3}
m_Name:
m_EditorClassIdentifier:
m_SensorName: GridSensor
m_CellScale: {x: 1, y: 0.01, z: 1}
m_GridSize: {x: 20, y: 1, z: 20}
m_RotateWithAgent: 1
m_DetectableTags:
- wall
- agent
- goal
- blockSmall
- blockLarge
- blockVeryLarge
m_ColliderMask:
serializedVersion: 2
m_Bits: 1
m_MaxColliderBufferSize: 500
m_InitialColliderBufferSize: 16
m_DebugColors:
- {r: 0, g: 0, b: 0, a: 0}
- {r: 0, g: 0.5176471, b: 1, a: 0}
- {r: 0.46666667, g: 0.7058824, b: 0.3529412, a: 0}
- {r: 1, g: 0.99607843, b: 0.9843137, a: 0}
- {r: 0.48235294, g: 0.48235294, b: 0.48235294, a: 0}
- {r: 0.35686275, g: 0.35686275, b: 0.35686275, a: 0}
m_GizmoYOffset: 0
m_ShowGizmos: 0
m_CompressionType: 1
m_ObservationStacks: 1
m_UseOneHotTag: 1
m_CountColliders: 0
--- !u!1 &8191066182918326564
GameObject:
m_ObjectHideFlags: 0

m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
m_RayTracingMode: 2
m_RenderingLayerMask: 1
m_RendererPriority: 0
m_Materials:

m_ProbeAnchor: {fileID: 0}
m_LightProbeVolumeOverride: {fileID: 0}
m_ScaleInLightmap: 1
m_ReceiveGI: 1
m_PreserveUVs: 1
m_IgnoreNormalsForChartDetection: 0
m_ImportantGI: 0

m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
m_RayTracingMode: 2
m_RenderingLayerMask: 1
m_RendererPriority: 0
m_Materials:

m_ProbeAnchor: {fileID: 0}
m_LightProbeVolumeOverride: {fileID: 0}
m_ScaleInLightmap: 1
m_ReceiveGI: 1
m_PreserveUVs: 1
m_IgnoreNormalsForChartDetection: 0
m_ImportantGI: 0

m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
m_RayTracingMode: 2
m_RenderingLayerMask: 1
m_RendererPriority: 0
m_Materials:

m_ProbeAnchor: {fileID: 0}
m_LightProbeVolumeOverride: {fileID: 0}
m_ScaleInLightmap: 1
m_ReceiveGI: 1
m_PreserveUVs: 1
m_IgnoreNormalsForChartDetection: 0
m_ImportantGI: 0

m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
m_RayTracingMode: 2
m_RenderingLayerMask: 1
m_RendererPriority: 0
m_Materials:

m_ProbeAnchor: {fileID: 0}
m_LightProbeVolumeOverride: {fileID: 0}
m_ScaleInLightmap: 1
m_ReceiveGI: 1
m_PreserveUVs: 1
m_IgnoreNormalsForChartDetection: 0
m_ImportantGI: 0

UseRandomAgentPosition: 1
UseRandomBlockRotation: 1
UseRandomBlockPosition: 1
--- !u!114 &4609315540733531199
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8696048509000480032}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 2a501962d056745d1a30e99146ee39fe, type: 3}
m_Name:
m_EditorClassIdentifier:
m_SensorName: GridSensor
m_CellScale: {x: 1, y: 0.01, z: 1}
m_GridSize: {x: 20, y: 1, z: 20}
m_RotateWithAgent: 1
m_DetectableTags:
- wall
- agent
- goal
- blockSmall
- blockLarge
- blockVeryLarge
m_ColliderMask:
serializedVersion: 2
m_Bits: 1
m_MaxColliderBufferSize: 500
m_InitialColliderBufferSize: 16
m_DebugColors:
- {r: 0, g: 0, b: 0, a: 0}
- {r: 0, g: 0.5176471, b: 1, a: 0}
- {r: 0.46666667, g: 0.7058824, b: 0.3529412, a: 0}
- {r: 1, g: 0.99607843, b: 0.9843137, a: 0}
- {r: 0.48235294, g: 0.48235294, b: 0.48235294, a: 0}
- {r: 0.35686275, g: 0.35686275, b: 0.35686275, a: 0}
m_GizmoYOffset: 0
m_ShowGizmos: 0
m_CompressionType: 1
m_ObservationStacks: 1
m_UseOneHotTag: 1
m_CountColliders: 0
--- !u!1 &8821353056066081524
GameObject:
m_ObjectHideFlags: 0

m_GameObject: {fileID: 8821353056066081524}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 1980459831, guid: f70555f144d8491a825f0804e09c671c, type: 3}
m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3}
m_Name:
m_EditorClassIdentifier:
m_UiScaleMode: 0

m_FallbackScreenDPI: 96
m_DefaultSpriteDPI: 96
m_DynamicPixelsPerUnit: 1
--- !u!114 &6319243058783963332
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 9116780590443581137}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 2a501962d056745d1a30e99146ee39fe, type: 3}
m_Name:
m_EditorClassIdentifier:
m_SensorName: GridSensor
m_CellScale: {x: 1, y: 0.01, z: 1}
m_GridSize: {x: 20, y: 1, z: 20}
m_RotateWithAgent: 1
m_DetectableTags:
- wall
- agent
- goal
- blockSmall
- blockLarge
- blockVeryLarge
m_ColliderMask:
serializedVersion: 2
m_Bits: 1
m_MaxColliderBufferSize: 500
m_InitialColliderBufferSize: 16
m_DebugColors:
- {r: 0, g: 0, b: 0, a: 0}
- {r: 0, g: 0.5176471, b: 1, a: 0}
- {r: 0.46666667, g: 0.7058824, b: 0.3529412, a: 0}
- {r: 1, g: 0.99607843, b: 0.9843137, a: 0}
- {r: 0.48235294, g: 0.48235294, b: 0.48235294, a: 0}
- {r: 0.35686275, g: 0.35686275, b: 0.35686275, a: 0}
m_GizmoYOffset: 0
m_ShowGizmos: 0
m_CompressionType: 1
m_ObservationStacks: 1
m_UseOneHotTag: 1
m_CountColliders: 0
--- !u!1001 &6067781793364901444
PrefabInstance:
m_ObjectHideFlags: 0

m_Modifications:
- target: {fileID: 2598450485826216109, guid: ac01d0f42c5e1463e943632a60d99967,
type: 3}
propertyPath: m_Model
value:
objectReference: {fileID: 5022602860645237092, guid: c3aafa29d87154882bcb52488c6446ec,
type: 3}
- target: {fileID: 2708762399863795223, guid: ac01d0f42c5e1463e943632a60d99967,
type: 3}
propertyPath: m_RootOrder
value: 0
objectReference: {fileID: 0}
- target: {fileID: 2708762399863795223, guid: ac01d0f42c5e1463e943632a60d99967,
type: 3}
propertyPath: m_LocalPosition.x

objectReference: {fileID: 0}
- target: {fileID: 2708762399863795223, guid: ac01d0f42c5e1463e943632a60d99967,
type: 3}
propertyPath: m_LocalRotation.x
propertyPath: m_LocalRotation.w
propertyPath: m_LocalRotation.y
value: 1
objectReference: {fileID: 0}
- target: {fileID: 2708762399863795223, guid: ac01d0f42c5e1463e943632a60d99967,
type: 3}
propertyPath: m_LocalRotation.z
propertyPath: m_LocalRotation.x
propertyPath: m_LocalRotation.w
value: 0
propertyPath: m_LocalRotation.y
value: 1
propertyPath: m_RootOrder
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 2708762399863795223, guid: ac01d0f42c5e1463e943632a60d99967,

propertyPath: m_Name
value: PushBlockAgentGridCollab
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedComponents:
- {fileID: 2709359580712052712, guid: ac01d0f42c5e1463e943632a60d99967, type: 3}
--- !u!1 &8191066182862526894 stripped
GameObject:
m_CorrespondingSourceObject: {fileID: 2709359580712052714, guid: ac01d0f42c5e1463e943632a60d99967,
type: 3}
m_PrefabInstance: {fileID: 6067781793364901444}
m_PrefabAsset: {fileID: 0}
--- !u!114 &8190299122290044756 stripped
MonoBehaviour:
m_CorrespondingSourceObject: {fileID: 2710286047221272848, guid: ac01d0f42c5e1463e943632a60d99967,

m_Modification:
m_TransformParent: {fileID: 8188317207052398481}
m_Modifications:
- target: {fileID: 2598450485826216109, guid: ac01d0f42c5e1463e943632a60d99967,
type: 3}
propertyPath: m_Model
value:
objectReference: {fileID: 5022602860645237092, guid: c3aafa29d87154882bcb52488c6446ec,
type: 3}
- target: {fileID: 2708762399863795223, guid: ac01d0f42c5e1463e943632a60d99967,
type: 3}
propertyPath: m_RootOrder
value: 2
objectReference: {fileID: 0}
- target: {fileID: 2708762399863795223, guid: ac01d0f42c5e1463e943632a60d99967,
type: 3}
propertyPath: m_LocalPosition.x

type: 3}
propertyPath: m_LocalPosition.z
value: 9.21
objectReference: {fileID: 0}
- target: {fileID: 2708762399863795223, guid: ac01d0f42c5e1463e943632a60d99967,
type: 3}
propertyPath: m_LocalRotation.w
value: 0
objectReference: {fileID: 0}
- target: {fileID: 2708762399863795223, guid: ac01d0f42c5e1463e943632a60d99967,
type: 3}

objectReference: {fileID: 0}
- target: {fileID: 2708762399863795223, guid: ac01d0f42c5e1463e943632a60d99967,
type: 3}
propertyPath: m_LocalRotation.w
value: 0
objectReference: {fileID: 0}
- target: {fileID: 2708762399863795223, guid: ac01d0f42c5e1463e943632a60d99967,
type: 3}
propertyPath: m_RootOrder
value: 2
objectReference: {fileID: 0}
- target: {fileID: 2708762399863795223, guid: ac01d0f42c5e1463e943632a60d99967,
type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}

propertyPath: m_Materials.Array.data[0]
value:
objectReference: {fileID: 2100000, guid: b0da1813c36914e678ba57f2790424e1, type: 2}
m_RemovedComponents: []
m_RemovedComponents:
- {fileID: 2709359580712052712, guid: ac01d0f42c5e1463e943632a60d99967, type: 3}
--- !u!1 &9116780590443581137 stripped
GameObject:
m_CorrespondingSourceObject: {fileID: 2709359580712052714, guid: ac01d0f42c5e1463e943632a60d99967,
type: 3}
m_PrefabInstance: {fileID: 6565363751102736699}
m_PrefabAsset: {fileID: 0}
--- !u!114 &9115291448867436587 stripped
MonoBehaviour:
m_CorrespondingSourceObject: {fileID: 2710286047221272848, guid: ac01d0f42c5e1463e943632a60d99967,

m_Modification:
m_TransformParent: {fileID: 8188317207052398481}
m_Modifications:
- target: {fileID: 2598450485826216109, guid: ac01d0f42c5e1463e943632a60d99967,
type: 3}
propertyPath: m_Model
value:
objectReference: {fileID: 5022602860645237092, guid: c3aafa29d87154882bcb52488c6446ec,
type: 3}
- target: {fileID: 2708762399863795223, guid: ac01d0f42c5e1463e943632a60d99967,
type: 3}
propertyPath: m_RootOrder
value: 1
objectReference: {fileID: 0}
- target: {fileID: 2708762399863795223, guid: ac01d0f42c5e1463e943632a60d99967,
type: 3}
propertyPath: m_LocalPosition.x

type: 3}
propertyPath: m_LocalPosition.z
value: 9.21
objectReference: {fileID: 0}
- target: {fileID: 2708762399863795223, guid: ac01d0f42c5e1463e943632a60d99967,
type: 3}
propertyPath: m_LocalRotation.w
value: 0
objectReference: {fileID: 0}
- target: {fileID: 2708762399863795223, guid: ac01d0f42c5e1463e943632a60d99967,
type: 3}

objectReference: {fileID: 0}
- target: {fileID: 2708762399863795223, guid: ac01d0f42c5e1463e943632a60d99967,
type: 3}
propertyPath: m_LocalRotation.w
value: 0
objectReference: {fileID: 0}
- target: {fileID: 2708762399863795223, guid: ac01d0f42c5e1463e943632a60d99967,
type: 3}
propertyPath: m_RootOrder
value: 1
objectReference: {fileID: 0}
- target: {fileID: 2708762399863795223, guid: ac01d0f42c5e1463e943632a60d99967,
type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}

propertyPath: m_Materials.Array.data[0]
value:
objectReference: {fileID: 2100000, guid: 52eab8ab5010f438fab93da85735ba1d, type: 2}
m_RemovedComponents: []
m_RemovedComponents:
- {fileID: 2709359580712052712, guid: ac01d0f42c5e1463e943632a60d99967, type: 3}
--- !u!1 &8696048509000480032 stripped
GameObject:
m_CorrespondingSourceObject: {fileID: 2709359580712052714, guid: ac01d0f42c5e1463e943632a60d99967,
type: 3}
m_PrefabInstance: {fileID: 6716844123244810954}
m_PrefabAsset: {fileID: 0}
--- !u!114 &8695281997955662810 stripped
MonoBehaviour:
m_CorrespondingSourceObject: {fileID: 2710286047221272848, guid: ac01d0f42c5e1463e943632a60d99967,

172
Project/Assets/ML-Agents/Examples/PushBlock/Scenes/PushBlockCollab.unity


m_EnableBakedLightmaps: 1
m_EnableRealtimeLightmaps: 1
m_LightmapEditorSettings:
serializedVersion: 10
serializedVersion: 12
m_Resolution: 2
m_BakeResolution: 40
m_AtlasSize: 1024

m_CompAOExponentDirect: 0
m_ExtractAmbientOcclusion: 0
m_Padding: 2
m_LightmapParameters: {fileID: 0}
m_LightmapsBakeMode: 1

m_PVRDirectSampleCount: 32
m_PVRSampleCount: 500
m_PVRBounces: 2
m_PVREnvironmentSampleCount: 500
m_PVREnvironmentReferencePointCount: 2048
m_PVRFilteringMode: 2
m_PVRDenoiserTypeDirect: 0
m_PVRDenoiserTypeIndirect: 0
m_PVRDenoiserTypeAO: 0
m_PVRFilteringMode: 1
m_PVREnvironmentMIS: 0
m_PVRCulling: 1
m_PVRFilteringGaussRadiusDirect: 1
m_PVRFilteringGaussRadiusIndirect: 5

m_PVRFilteringAtrousPositionSigmaAO: 1
m_ShowResolutionOverlay: 1
m_ExportTrainingData: 0
m_TrainingDataDestination: TrainingData
m_LightProbeSampleCountMultiplier: 4
m_LightingDataAsset: {fileID: 112000002, guid: 03723c7f910c3423aa1974f1b9ce8392,
type: 2}
m_UseShadowmask: 1

m_GameObject: {fileID: 255077123}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 1077351063, guid: f70555f144d8491a825f0804e09c671c, type: 3}
m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3}
m_Name:
m_EditorClassIdentifier:
m_HorizontalAxis: Horizontal

m_GameObject: {fileID: 255077123}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: -619905303, guid: f70555f144d8491a825f0804e09c671c, type: 3}
m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3}
m_Name:
m_EditorClassIdentifier:
m_FirstSelected: {fileID: 0}

m_TransformParent: {fileID: 0}
m_Modifications:
- target: {fileID: 4943719350691982, guid: 5889392e3f05b448a8a06c5def6c2dec, type: 3}
propertyPath: m_RootOrder
value: 4
objectReference: {fileID: 0}
- target: {fileID: 4943719350691982, guid: 5889392e3f05b448a8a06c5def6c2dec, type: 3}
propertyPath: m_LocalPosition.x
value: 106.38621
objectReference: {fileID: 0}

value: 34.72934
objectReference: {fileID: 0}
- target: {fileID: 4943719350691982, guid: 5889392e3f05b448a8a06c5def6c2dec, type: 3}
propertyPath: m_LocalRotation.w
value: 0.8681629
objectReference: {fileID: 0}
- target: {fileID: 4943719350691982, guid: 5889392e3f05b448a8a06c5def6c2dec, type: 3}
propertyPath: m_LocalRotation.x
value: 0.31598538
objectReference: {fileID: 0}

propertyPath: m_LocalRotation.z
value: 0.13088542
objectReference: {fileID: 0}
- target: {fileID: 4943719350691982, guid: 5889392e3f05b448a8a06c5def6c2dec, type: 3}
propertyPath: m_LocalRotation.w
value: 0.8681629
objectReference: {fileID: 0}
- target: {fileID: 4943719350691982, guid: 5889392e3f05b448a8a06c5def6c2dec, type: 3}
propertyPath: m_RootOrder
value: 4
objectReference: {fileID: 0}
m_RemovedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 5889392e3f05b448a8a06c5def6c2dec, type: 3}
--- !u!1 &1009000883

m_ClearFlags: 2
m_BackGroundColor: {r: 0.46666667, g: 0.5647059, b: 0.60784316, a: 1}
m_projectionMatrixMode: 1
m_GateFitMode: 2
m_FOVAxisMode: 0
m_GateFitMode: 2
m_FocalLength: 50
m_NormalizedViewPortRect:
serializedVersion: 2

m_Modification:
m_TransformParent: {fileID: 0}
m_Modifications:
- target: {fileID: 8188317207052398481, guid: f5bbed44a6ea747a687fbbb738eb1730,
type: 3}
propertyPath: m_RootOrder
value: 9
objectReference: {fileID: 0}
- target: {fileID: 8188317207052398481, guid: f5bbed44a6ea747a687fbbb738eb1730,
type: 3}
propertyPath: m_LocalPosition.x

objectReference: {fileID: 0}
- target: {fileID: 8188317207052398481, guid: f5bbed44a6ea747a687fbbb738eb1730,
type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 8188317207052398481, guid: f5bbed44a6ea747a687fbbb738eb1730,
type: 3}
propertyPath: m_LocalRotation.x
value: -0
objectReference: {fileID: 0}

type: 3}
propertyPath: m_LocalRotation.z
value: -0
objectReference: {fileID: 0}
- target: {fileID: 8188317207052398481, guid: f5bbed44a6ea747a687fbbb738eb1730,
type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 8188317207052398481, guid: f5bbed44a6ea747a687fbbb738eb1730,
type: 3}
propertyPath: m_RootOrder
value: 9
objectReference: {fileID: 0}
- target: {fileID: 8188317207052398481, guid: f5bbed44a6ea747a687fbbb738eb1730,
type: 3}

m_Modifications:
- target: {fileID: 8188317207052398481, guid: f5bbed44a6ea747a687fbbb738eb1730,
type: 3}
propertyPath: m_RootOrder
value: 7
objectReference: {fileID: 0}
- target: {fileID: 8188317207052398481, guid: f5bbed44a6ea747a687fbbb738eb1730,
type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}

objectReference: {fileID: 0}
- target: {fileID: 8188317207052398481, guid: f5bbed44a6ea747a687fbbb738eb1730,
type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 8188317207052398481, guid: f5bbed44a6ea747a687fbbb738eb1730,
type: 3}
propertyPath: m_LocalRotation.x
value: -0
objectReference: {fileID: 0}

objectReference: {fileID: 0}
- target: {fileID: 8188317207052398481, guid: f5bbed44a6ea747a687fbbb738eb1730,
type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 8188317207052398481, guid: f5bbed44a6ea747a687fbbb738eb1730,
type: 3}
propertyPath: m_RootOrder
value: 7
objectReference: {fileID: 0}
- target: {fileID: 8188317207052398481, guid: f5bbed44a6ea747a687fbbb738eb1730,
type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}

type: 3}
propertyPath: m_Name
value: PushBlockCollabAreaGrid (1)
objectReference: {fileID: 0}
- target: {fileID: 8191903532335653025, guid: f5bbed44a6ea747a687fbbb738eb1730,
type: 3}
propertyPath: m_IsActive
value: 1
objectReference: {fileID: 0}
m_RemovedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: f5bbed44a6ea747a687fbbb738eb1730, type: 3}

m_Modifications:
- target: {fileID: 8188317207052398481, guid: f5bbed44a6ea747a687fbbb738eb1730,
type: 3}
propertyPath: m_RootOrder
value: 8
objectReference: {fileID: 0}
- target: {fileID: 8188317207052398481, guid: f5bbed44a6ea747a687fbbb738eb1730,
type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}

objectReference: {fileID: 0}
- target: {fileID: 8188317207052398481, guid: f5bbed44a6ea747a687fbbb738eb1730,
type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 8188317207052398481, guid: f5bbed44a6ea747a687fbbb738eb1730,
type: 3}
propertyPath: m_LocalRotation.x
value: -0
objectReference: {fileID: 0}

objectReference: {fileID: 0}
- target: {fileID: 8188317207052398481, guid: f5bbed44a6ea747a687fbbb738eb1730,
type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 8188317207052398481, guid: f5bbed44a6ea747a687fbbb738eb1730,
type: 3}
propertyPath: m_RootOrder
value: 8
objectReference: {fileID: 0}
- target: {fileID: 8188317207052398481, guid: f5bbed44a6ea747a687fbbb738eb1730,
type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}

m_Modifications:
- target: {fileID: 224194346362733190, guid: 3ce107b4a79bc4eef83afde434932a68,
type: 3}
propertyPath: m_LocalPosition.x
propertyPath: m_Pivot.x
propertyPath: m_LocalPosition.y
propertyPath: m_Pivot.y
propertyPath: m_LocalPosition.z
value: 0
propertyPath: m_RootOrder
value: 3
propertyPath: m_LocalRotation.x
propertyPath: m_AnchorMax.x
propertyPath: m_LocalRotation.y
propertyPath: m_AnchorMax.y
propertyPath: m_LocalRotation.z
propertyPath: m_AnchorMin.x
propertyPath: m_LocalRotation.w
value: 1
propertyPath: m_AnchorMin.y
value: 0
propertyPath: m_RootOrder
value: 3
propertyPath: m_SizeDelta.x
value: 0
propertyPath: m_AnchoredPosition.x
propertyPath: m_SizeDelta.y
propertyPath: m_AnchoredPosition.y
propertyPath: m_LocalPosition.x
propertyPath: m_SizeDelta.x
propertyPath: m_LocalPosition.y
propertyPath: m_SizeDelta.y
propertyPath: m_LocalPosition.z
propertyPath: m_AnchorMin.x
value: 0
propertyPath: m_LocalRotation.w
value: 1
propertyPath: m_AnchorMin.y
propertyPath: m_LocalRotation.x
propertyPath: m_AnchorMax.x
propertyPath: m_LocalRotation.y
propertyPath: m_AnchorMax.y
propertyPath: m_LocalRotation.z
propertyPath: m_Pivot.x
propertyPath: m_AnchoredPosition.x
propertyPath: m_Pivot.y
propertyPath: m_AnchoredPosition.y
value: 0
objectReference: {fileID: 0}
m_RemovedComponents: []

m_Modifications:
- target: {fileID: 8188317207052398481, guid: f5bbed44a6ea747a687fbbb738eb1730,
type: 3}
propertyPath: m_RootOrder
value: 5
objectReference: {fileID: 0}
- target: {fileID: 8188317207052398481, guid: f5bbed44a6ea747a687fbbb738eb1730,
type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}

type: 3}
propertyPath: m_LocalPosition.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 8188317207052398481, guid: f5bbed44a6ea747a687fbbb738eb1730,
type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 8188317207052398481, guid: f5bbed44a6ea747a687fbbb738eb1730,
type: 3}

objectReference: {fileID: 0}
- target: {fileID: 8188317207052398481, guid: f5bbed44a6ea747a687fbbb738eb1730,
type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 8188317207052398481, guid: f5bbed44a6ea747a687fbbb738eb1730,
type: 3}
propertyPath: m_RootOrder
value: 5
objectReference: {fileID: 0}
- target: {fileID: 8188317207052398481, guid: f5bbed44a6ea747a687fbbb738eb1730,
type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}

- target: {fileID: 8188317207052398481, guid: f5bbed44a6ea747a687fbbb738eb1730,
type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 8191066182862526892, guid: f5bbed44a6ea747a687fbbb738eb1730,
type: 3}
propertyPath: ShowGizmos
value: 0
objectReference: {fileID: 0}
- target: {fileID: 8191903532335653025, guid: f5bbed44a6ea747a687fbbb738eb1730,

995
Project/Assets/ML-Agents/Examples/PushBlock/TFModels/PushBlockCollab.onnx
文件差异内容过多而无法显示
查看文件

8
Project/Assets/ML-Agents/Examples/PushBlock/TFModels/PushBlockCollab.onnx.meta


fileFormatVersion: 2
guid: e35859736a42e4342b3272438be93ea9
guid: c3aafa29d87154882bcb52488c6446ec
fileIDToRecycleName:
11400000: main obj
11400002: model data
internalIDToNameTable: []
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:

treatErrorsAsWarnings: 0
importMode: 1

50
com.unity.ml-agents.extensions/Editor/GridSensorComponentEditor.cs


EditorGUI.BeginDisabledGroup(!EditorUtilities.CanUpdateModelProperties());
{
EditorGUILayout.LabelField("Channel Settings", EditorStyles.boldLabel);
EditorGUILayout.PropertyField(so.FindProperty(nameof(GridSensorComponent.m_DepthType)), true);
// channel depth
var channelDepth = so.FindProperty(nameof(GridSensorComponent.m_ChannelDepths));
var newDepth = EditorGUILayout.IntField("Channel Depth", channelDepth.arraySize);
if (newDepth != channelDepth.arraySize)
{
channelDepth.arraySize = newDepth;
}
EditorGUI.indentLevel++;
for (var i = 0; i < channelDepth.arraySize; i++)
{
var objectTag = channelDepth.GetArrayElementAtIndex(i);
EditorGUILayout.PropertyField(objectTag, new GUIContent("Channel " + i + " Depth"), true);
}
EditorGUI.indentLevel--;
// detectable objects
var detectableObjects = so.FindProperty(nameof(GridSensorComponent.m_DetectableObjects));
var newSize = EditorGUILayout.IntField("Detectable Objects", detectableObjects.arraySize);
if (newSize != detectableObjects.arraySize)
// detectable tags
var detectableTags = so.FindProperty(nameof(GridSensorComponent.m_DetectableTags));
var newSize = EditorGUILayout.IntField("Detectable Tags", detectableTags.arraySize);
if (newSize != detectableTags.arraySize)
detectableObjects.arraySize = newSize;
detectableTags.arraySize = newSize;
for (var i = 0; i < detectableObjects.arraySize; i++)
for (var i = 0; i < detectableTags.arraySize; i++)
var objectTag = detectableObjects.GetArrayElementAtIndex(i);
var objectTag = detectableTags.GetArrayElementAtIndex(i);
EditorGUILayout.LabelField("Collider and Buffer", EditorStyles.boldLabel);
EditorGUILayout.PropertyField(so.FindProperty(nameof(GridSensorComponent.m_MaxColliderBufferSize)), true);
EditorGUILayout.PropertyField(so.FindProperty(nameof(GridSensorComponent.m_InitialColliderBufferSize)), true);
EditorGUILayout.LabelField("Observation Settings", EditorStyles.boldLabel);
EditorGUILayout.PropertyField(so.FindProperty(nameof(GridSensorComponent.m_UseOneHotTag)), new GUIContent("One-Hot Tag Index"), true);
EditorGUILayout.PropertyField(so.FindProperty(nameof(GridSensorComponent.m_CountColliders)), new GUIContent("Detectable Tag Count"), true);
EditorGUILayout.LabelField("Sensor Settings", EditorStyles.boldLabel);
EditorGUILayout.PropertyField(so.FindProperty(nameof(GridSensorComponent.m_ObservationStacks)), true);
EditorGUI.EndDisabledGroup();
EditorGUILayout.PropertyField(so.FindProperty(nameof(GridSensorComponent.m_CompressionType)), true);
EditorGUILayout.LabelField("Sensor Settings", EditorStyles.boldLabel);
EditorGUILayout.PropertyField(so.FindProperty(nameof(GridSensorComponent.m_ObservationStacks)), true);
EditorGUILayout.LabelField("Collider and Buffer", EditorStyles.boldLabel);
EditorGUILayout.PropertyField(so.FindProperty(nameof(GridSensorComponent.m_InitialColliderBufferSize)), true);
EditorGUILayout.PropertyField(so.FindProperty(nameof(GridSensorComponent.m_MaxColliderBufferSize)), true);
EditorGUILayout.PropertyField(so.FindProperty(nameof(GridSensorComponent.m_CompressionType)), true);
EditorGUILayout.LabelField("Debug Gizmo", EditorStyles.boldLabel);
EditorGUILayout.PropertyField(so.FindProperty(nameof(GridSensorComponent.m_ShowGizmos)), true);

var debugColors = so.FindProperty(nameof(GridSensorComponent.m_DebugColors));
var detectableObjectSize = so.FindProperty(nameof(GridSensorComponent.m_DetectableObjects)).arraySize;
var detectableObjectSize = so.FindProperty(nameof(GridSensorComponent.m_DetectableTags)).arraySize;
if (detectableObjectSize != debugColors.arraySize)
{
debugColors.arraySize = detectableObjectSize;

158
com.unity.ml-agents.extensions/Runtime/Sensors/GridSensorComponent.cs


using System.Collections.Generic;
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("Unity.ML-Agents.Extensions.EditorTests")]
namespace Unity.MLAgents.Extensions.Sensors
{
/// <summary>

public class GridSensorComponent : SensorComponent
{
protected GridSensor m_Sensor;
// dummy sensor only used for debug gizmo
GridSensorBase m_DebugSensor;
List<ISensor> m_Sensors;
internal BoxOverlapChecker m_BoxOverlapChecker;
// <summary>
/// <summary>
/// Name of the generated <see cref="GridSensor"/> object.
/// Note that changing this at runtime does not affect how the Agent sorts the sensors.
/// </summary>

}
[HideInInspector, SerializeField]
internal int[] m_ChannelDepths = new int[] { 1 };
/// <summary>
/// Array holding the depth of each channel.
/// Note that changing this after the sensor is created has no effect.
/// </summary>
public int[] ChannelDepths
{
get { return m_ChannelDepths; }
set { m_ChannelDepths = value; }
}
[HideInInspector, SerializeField]
internal string[] m_DetectableObjects;
internal string[] m_DetectableTags;
public string[] DetectableObjects
public string[] DetectableTags
get { return m_DetectableObjects; }
set { m_DetectableObjects = value; }
get { return m_DetectableTags; }
set { m_DetectableTags = value; }
}
[HideInInspector, SerializeField]

}
[HideInInspector, SerializeField]
internal GridDepthType m_DepthType = GridDepthType.Channel;
/// <summary>
/// The data layout that the grid should output.
/// Note that changing this after the sensor is created has no effect.
/// </summary>
public GridDepthType DepthType
{
get { return m_DepthType; }
set { m_DepthType = value; }
}
[HideInInspector, SerializeField]
internal int m_MaxColliderBufferSize = 500;
/// <summary>
/// The absolute max size of the Collider buffer used in the non-allocating Physics calls. In other words

set { m_ObservationStacks = value; }
}
[HideInInspector, SerializeField]
internal bool m_UseOneHotTag = true;
/// <summary>
/// Whether to use one-hot representation of detected tag as observation.
/// Note that changing this after the sensor is created has no effect.
/// </summary>
public bool UseOneHotTag
{
get { return m_UseOneHotTag; }
set { m_UseOneHotTag = value; }
}
[HideInInspector, SerializeField]
internal bool m_CountColliders = false;
/// <summary>
/// Whether to use the number of count for each detectable tag as observation.
/// Note that changing this after the sensor is created has no effect.
/// </summary>
public bool CountColliders
{
get { return m_CountColliders; }
set { m_CountColliders = value; }
}
m_Sensor = new GridSensor(
m_SensorName,
List<ISensor> m_Sensors = new List<ISensor>();
m_BoxOverlapChecker = new BoxOverlapChecker(
m_ChannelDepths,
m_DetectableObjects,
m_DepthType,
m_CompressionType,
m_MaxColliderBufferSize,
m_InitialColliderBufferSize
m_DetectableTags,
m_InitialColliderBufferSize,
m_MaxColliderBufferSize
if (ObservationStacks != 1)
// debug data is positive int value and will trigger data validation exception if SensorCompressionType is not None.
m_DebugSensor = new GridSensorBase("DebugGridSensor", m_CellScale, m_GridSize, m_DetectableTags, SensorCompressionType.None);
m_BoxOverlapChecker.RegisterDebugSensor(m_DebugSensor);
var gridSensors = GetGridSensors();
if (gridSensors == null || gridSensors.Length < 1)
{
throw new UnityAgentsException("GridSensorComponent received no sensors. Specify at least one observation type (OneHot/Counting) to use grid sensors." +
"If you're overriding GridSensorComponent.GetGridSensors(), return at least one grid sensor.");
}
foreach (var sensor in gridSensors)
{
if (ObservationStacks != 1)
{
m_Sensors.Add(new StackingSensor(sensor, ObservationStacks));
}
else
{
m_Sensors.Add(sensor);
}
m_BoxOverlapChecker.RegisterSensor(sensor);
}
// Only one sensor needs to reference the boxOverlapChecker, so that it gets updated exactly once
((GridSensorBase)m_Sensors[0]).m_BoxOverlapChecker = m_BoxOverlapChecker;
return m_Sensors.ToArray();
}
/// <summary>
/// Get an array of GridSensors to be added in this component.
/// Override this method and return custom GridSensor implementations.
/// </summary>
/// <returns>Array of grid sensors to be added to the component.</returns>
protected virtual GridSensorBase[] GetGridSensors()
{
List<GridSensorBase> sensorList = new List<GridSensorBase>();
if (m_UseOneHotTag)
{
var sensor = new OneHotGridSensor(m_SensorName + "-OneHot", m_CellScale, m_GridSize, m_DetectableTags, m_CompressionType);
sensorList.Add(sensor);
}
if (m_CountColliders)
return new ISensor[] { new StackingSensor(m_Sensor, ObservationStacks) };
var sensor = new CountingGridSensor(m_SensorName + "-Counting", m_CellScale, m_GridSize, m_DetectableTags, m_CompressionType);
sensorList.Add(sensor);
return new ISensor[] { m_Sensor };
return sensorList.ToArray();
}
/// <summary>

{
if (m_Sensor != null)
if (m_Sensors != null)
m_Sensor.CompressionType = m_CompressionType;
m_Sensor.RotateWithAgent = m_RotateWithAgent;
m_Sensor.ColliderMask = m_ColliderMask;
m_BoxOverlapChecker.RotateWithAgent = m_RotateWithAgent;
m_BoxOverlapChecker.ColliderMask = m_ColliderMask;
foreach (var sensor in m_Sensors)
{
((GridSensorBase)sensor).CompressionType = m_CompressionType;
}
}
}

{
if (m_Sensor == null)
if (m_BoxOverlapChecker == null || m_DebugSensor == null)
var cellColors = m_Sensor.PerceiveGizmoColor();
var cellPositions = m_Sensor.GetGizmoPositions();
var rotation = m_Sensor.GetGridRotation();
m_DebugSensor.ResetPerceptionBuffer();
m_BoxOverlapChecker.UpdateGizmo();
var cellColors = m_DebugSensor.PerceptionBuffer;
var rotation = m_BoxOverlapChecker.GetGridRotation();
for (var i = 0; i < cellPositions.Length; i++)
for (var i = 0; i < m_DebugSensor.PerceptionBuffer.Length; i++)
var cubeTransform = Matrix4x4.TRS(cellPositions[i] + gizmoYOffset, rotation, scale);
var cellPosition = m_BoxOverlapChecker.GetCellGlobalPosition(i);
var cubeTransform = Matrix4x4.TRS(cellPosition + gizmoYOffset, rotation, scale);
var colorIndex = cellColors[i];
var colorIndex = cellColors[i] - 1;
debugRayColor = m_DebugColors[colorIndex];
debugRayColor = m_DebugColors[(int)colorIndex];
}
Gizmos.color = new Color(debugRayColor.r, debugRayColor.g, debugRayColor.b, .5f);
Gizmos.DrawCube(Vector3.zero, Vector3.one);

2
com.unity.ml-agents.extensions/Runtime/Sensors/BoxOverlapChecker.cs.meta


fileFormatVersion: 2
guid: 801669c0cdece6b40b2e741ad0b119ac
guid: e039296229a084578823e21bce9cf834
MonoImporter:
externalObjects: {}
serializedVersion: 2

2
com.unity.ml-agents.extensions/Tests/Editor/GridSensors/BoxOverlapCheckerTests.cs.meta


fileFormatVersion: 2
guid: a55ecbf349308fc42be9872f9894bafa
guid: 087f04a0f817c45f4a709ed36fe5ba1a
MonoImporter:
externalObjects: {}
serializedVersion: 2

2
com.unity.ml-agents.extensions/Tests/Editor/GridSensors/GridSensorTests.cs.meta


fileFormatVersion: 2
guid: 056b95810b761d543a0dbbf7e7709e20
guid: 2a8626afd640a4edd942dac3d8d6bc85
MonoImporter:
externalObjects: {}
serializedVersion: 2

2
com.unity.ml-agents.extensions/Runtime/Sensors/CountingGridSensor.cs.meta


fileFormatVersion: 2
guid: 630b065522bc281409501355842d8af4
guid: a99e8702817b641c2a3ccb6520403e9b
MonoImporter:
externalObjects: {}
serializedVersion: 2

2
com.unity.ml-agents.extensions/Runtime/Sensors/GridSensorBase.cs.meta


fileFormatVersion: 2
guid: e27c92ddd6b03714bbfcde95c7c2a376
guid: 2454efb6b02aa414dae2cb8573e87682
MonoImporter:
externalObjects: {}
serializedVersion: 2

2
com.unity.ml-agents.extensions/Runtime/Sensors/OneHotGridSensor.cs.meta


fileFormatVersion: 2
guid: e1ae8cd2fe32b0f4ca9b2dfd370fa1b7
guid: 914f5ab90be9e411d83642035abebc2c
MonoImporter:
externalObjects: {}
serializedVersion: 2

2
com.unity.ml-agents.extensions/Tests/Editor/GridSensors/SimpleTestGridSensor.cs.meta


fileFormatVersion: 2
guid: 06b1a7a5dba5ce345ad8dc4d97deef62
guid: 72f121528c63749688e53aa926f2cb0a
MonoImporter:
externalObjects: {}
serializedVersion: 2

254
com.unity.ml-agents.extensions/Runtime/Sensors/BoxOverlapChecker.cs


using System;
using System.Runtime.CompilerServices;
using UnityEngine;
[assembly: InternalsVisibleTo("Unity.ML-Agents.Extensions.EditorTests")]
namespace Unity.MLAgents.Extensions.Sensors
{
internal class BoxOverlapChecker
{
Vector3 m_CellScale;
Vector3Int m_GridSize;
bool m_RotateWithAgent;
LayerMask m_ColliderMask;
GameObject m_RootReference;
string[] m_DetectableTags;
int m_InitialColliderBufferSize;
int m_MaxColliderBufferSize;
int m_NumCells;
Vector3 m_HalfCellScale;
Vector3 m_CellCenterOffset;
Vector3[] m_CellLocalPositions;
Collider[] m_ColliderBuffer;
public event Action<GameObject, int> GridOverlapDetectedAll;
public event Action<GameObject, int> GridOverlapDetectedClosest;
public event Action<GameObject, int> GridOverlapDetectedDebug;
public BoxOverlapChecker(
Vector3 cellScale,
Vector3Int gridSize,
bool rotateWithAgent,
LayerMask colliderMask,
GameObject rootReference,
string[] detectableTags,
int initialColliderBufferSize,
int maxColliderBufferSize)
{
m_CellScale = cellScale;
m_GridSize = gridSize;
m_RotateWithAgent = rotateWithAgent;
m_ColliderMask = colliderMask;
m_RootReference = rootReference;
m_DetectableTags = detectableTags;
m_InitialColliderBufferSize = initialColliderBufferSize;
m_MaxColliderBufferSize = maxColliderBufferSize;
m_NumCells = gridSize.x * gridSize.z;
m_HalfCellScale = new Vector3(cellScale.x / 2f, cellScale.y, cellScale.z / 2f);
m_CellCenterOffset = new Vector3((gridSize.x - 1f) / 2, 0, (gridSize.z - 1f) / 2);
m_ColliderBuffer = new Collider[Math.Min(m_MaxColliderBufferSize, m_InitialColliderBufferSize)];
InitCellLocalPositions();
}
public bool RotateWithAgent
{
get { return m_RotateWithAgent; }
set { m_RotateWithAgent = value; }
}
public LayerMask ColliderMask
{
get { return m_ColliderMask; }
set { m_ColliderMask = value; }
}
/// <summary>
/// Initializes the local location of the cells
/// </summary>
void InitCellLocalPositions()
{
m_CellLocalPositions = new Vector3[m_NumCells];
for (int i = 0; i < m_NumCells; i++)
{
m_CellLocalPositions[i] = GetCellLocalPosition(i);
}
}
/// <summary>Converts the index of the cell to the 3D point (y is zero) relative to grid center</summary>
/// <returns>Vector3 of the position of the center of the cell relative to grid center</returns>
/// <param name="cell">The index of the cell</param>
Vector3 GetCellLocalPosition(int cellIndex)
{
float x = (cellIndex / m_GridSize.z - m_CellCenterOffset.x) * m_CellScale.x;
float z = (cellIndex % m_GridSize.z - m_CellCenterOffset.z) * m_CellScale.z;
return new Vector3(x, 0, z);
}
internal Vector3 GetCellGlobalPosition(int cellIndex)
{
if (m_RotateWithAgent)
{
return m_RootReference.transform.TransformPoint(m_CellLocalPositions[cellIndex]);
}
else
{
return m_CellLocalPositions[cellIndex] + m_RootReference.transform.position;
}
}
internal Quaternion GetGridRotation()
{
return m_RotateWithAgent ? m_RootReference.transform.rotation : Quaternion.identity;
}
/// <summary>
/// This method attempts to perform the Physics.OverlapBoxNonAlloc and will double the size of the Collider buffer
/// if the number of Colliders in the buffer after the call is equal to the length of the buffer.
/// </summary>
/// <param name="cellCenter"></param>
/// <param name="halfCellScale"></param>
/// <param name="rotation"></param>
/// <returns></returns>
int BufferResizingOverlapBoxNonAlloc(Vector3 cellCenter, Vector3 halfCellScale, Quaternion rotation)
{
int numFound;
// Since we can only get a fixed number of results, requery
// until we're sure we can hold them all (or until we hit the max size).
while (true)
{
numFound = Physics.OverlapBoxNonAlloc(cellCenter, halfCellScale, m_ColliderBuffer, rotation, m_ColliderMask);
if (numFound == m_ColliderBuffer.Length && m_ColliderBuffer.Length < m_MaxColliderBufferSize)
{
m_ColliderBuffer = new Collider[Math.Min(m_MaxColliderBufferSize, m_ColliderBuffer.Length * 2)];
m_InitialColliderBufferSize = m_ColliderBuffer.Length;
}
else
{
break;
}
}
return numFound;
}
/// <summary>
/// Perceive the latest grid status. Call OverlapBoxNonAlloc once to detect colliders.
/// Then parse the collider arrays according to all available gridSensor delegates.
/// </summary>
internal void Update()
{
for (var cellIndex = 0; cellIndex < m_NumCells; cellIndex++)
{
var cellCenter = GetCellGlobalPosition(cellIndex);
var numFound = BufferResizingOverlapBoxNonAlloc(cellCenter, m_HalfCellScale, GetGridRotation());
if (GridOverlapDetectedAll != null)
{
ParseCollidersAll(m_ColliderBuffer, numFound, cellIndex, cellCenter, GridOverlapDetectedAll);
}
if (GridOverlapDetectedClosest != null)
{
ParseCollidersClosest(m_ColliderBuffer, numFound, cellIndex, cellCenter, GridOverlapDetectedClosest);
}
}
}
/// <summary>
/// Same as Update(), but only load data for debug gizmo.
/// </summary>
internal void UpdateGizmo()
{
for (var cellIndex = 0; cellIndex < m_NumCells; cellIndex++)
{
var cellCenter = GetCellGlobalPosition(cellIndex);
var numFound = BufferResizingOverlapBoxNonAlloc(cellCenter, m_HalfCellScale, GetGridRotation());
ParseCollidersClosest(m_ColliderBuffer, numFound, cellIndex, cellCenter, GridOverlapDetectedDebug);
}
}
/// <summary>
/// Parses the array of colliders found within a cell. Finds the closest gameobject to the agent root reference within the cell
/// </summary>
void ParseCollidersClosest(Collider[] foundColliders, int numFound, int cellIndex, Vector3 cellCenter, Action<GameObject, int> detectedAction)
{
GameObject closestColliderGo = null;
var minDistanceSquared = float.MaxValue;
for (var i = 0; i < numFound; i++)
{
var currentColliderGo = foundColliders[i].gameObject;
// Continue if the current collider go is the root reference
if (ReferenceEquals(currentColliderGo, m_RootReference))
{
continue;
}
var closestColliderPoint = foundColliders[i].ClosestPointOnBounds(cellCenter);
var currentDistanceSquared = (closestColliderPoint - m_RootReference.transform.position).sqrMagnitude;
if (currentDistanceSquared >= minDistanceSquared)
{
continue;
}
// Checks if our colliders contain a detectable object
var index = -1;
for (var ii = 0; ii < m_DetectableTags.Length; ii++)
{
if (currentColliderGo.CompareTag(m_DetectableTags[ii]))
{
index = ii;
break;
}
}
if (index > -1 && currentDistanceSquared < minDistanceSquared)
{
minDistanceSquared = currentDistanceSquared;
closestColliderGo = currentColliderGo;
}
}
if (!ReferenceEquals(closestColliderGo, null))
{
detectedAction.Invoke(closestColliderGo, cellIndex);
}
}
/// <summary>
/// Parses all colliders in the array of colliders found within a cell.
/// </summary>
void ParseCollidersAll(Collider[] foundColliders, int numFound, int cellIndex, Vector3 cellCenter, Action<GameObject, int> detectedAction)
{
for (int i = 0; i < numFound; i++)
{
var currentColliderGo = foundColliders[i].gameObject;
if (!ReferenceEquals(currentColliderGo, m_RootReference))
{
detectedAction.Invoke(currentColliderGo, cellIndex);
}
}
}
internal void RegisterSensor(GridSensorBase sensor)
{
if (sensor.GetProcessCollidersMethod() == ProcessCollidersMethod.ProcessAllColliders)
{
GridOverlapDetectedAll += sensor.ProcessDetectedObject;
}
else
{
GridOverlapDetectedClosest += sensor.ProcessDetectedObject;
}
}
internal void RegisterDebugSensor(GridSensorBase debugSensor)
{
GridOverlapDetectedDebug += debugSensor.ProcessDetectedObject;
}
}
}

61
com.unity.ml-agents.extensions/Runtime/Sensors/CountingGridSensor.cs


using UnityEngine;
using Unity.MLAgents.Sensors;
namespace Unity.MLAgents.Extensions.Sensors
{
/// <summary>
/// Grid-based sensor that counts the number of detctable objects.
/// </summary>
public class CountingGridSensor : GridSensorBase
{
/// <summary>
/// Create a CountingGridSensor with the specified configuration.
/// </summary>
/// <param name="name">The sensor name</param>
/// <param name="cellScale">The scale of each cell in the grid</param>
/// <param name="gridNum">Number of cells on each side of the grid</param>
/// <param name="detectableTags">Tags to be detected by the sensor</param>
/// <param name="compression">Compression type</param>
public CountingGridSensor(
string name,
Vector3 cellScale,
Vector3Int gridNum,
string[] detectableTags,
SensorCompressionType compression
) : base(name, cellScale, gridNum, detectableTags, compression)
{
CompressionType = SensorCompressionType.None;
}
/// <inheritdoc/>
protected override int GetCellObservationSize()
{
return DetectableTags == null ? 0 : DetectableTags.Length;
}
/// <inheritdoc/>
protected override bool IsDataNormalized()
{
return false;
}
/// <inheritdoc/>
protected internal override ProcessCollidersMethod GetProcessCollidersMethod()
{
return ProcessCollidersMethod.ProcessAllColliders;
}
/// <summary>
/// Get object counts for each detectable tags detected in a cell.
/// </summary>
/// <param name="detectedObject">The game object that was detected within a certain cell</param>
/// <param name="tagIndex">The index of the detectedObject's tag in the DetectableObjects list</param>
/// <param name="dataBuffer">The buffer to write the observation values.
/// The buffer size is configured by <seealso cref="GetCellObservationSize"/>.
/// </param>
protected override void GetObjectData(GameObject detectedObject, int tagIndex, float[] dataBuffer)
{
dataBuffer[tagIndex] += 1;
}
}
}

366
com.unity.ml-agents.extensions/Runtime/Sensors/GridSensorBase.cs


using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using UnityEngine;
using Unity.MLAgents.Sensors;
using UnityEngine.Profiling;
using Object = UnityEngine.Object;
[assembly: InternalsVisibleTo("Unity.ML-Agents.Extensions.EditorTests")]
namespace Unity.MLAgents.Extensions.Sensors
{
/// <summary>
/// The way the GridSensor process detected colliders in a cell.
/// </summary>
public enum ProcessCollidersMethod
{
/// <summary>
/// Get data from all colliders detected in a cell
/// </summary>
ProcessAllColliders,
/// <summary>
/// Get data from the collider closest to the agent
/// </summary>
ProcessClosestColliders
}
/// <summary>
/// Grid-based sensor.
/// </summary>
public class GridSensorBase : ISensor, IBuiltInSensor, IDisposable
{
string m_Name;
Vector3 m_CellScale;
Vector3Int m_GridSize;
string[] m_DetectableTags;
SensorCompressionType m_CompressionType;
ObservationSpec m_ObservationSpec;
internal BoxOverlapChecker m_BoxOverlapChecker;
// Buffers
float[] m_PerceptionBuffer;
Color[] m_PerceptionColors;
Texture2D m_PerceptionTexture;
float[] m_CellDataBuffer;
// Utility Constants Calculated on Init
int m_NumCells;
int m_CellObservationSize;
Vector3 m_CellCenterOffset;
/// <summary>
/// Create a GridSensorBase with the specified configuration.
/// </summary>
/// <param name="name">The sensor name</param>
/// <param name="cellScale">The scale of each cell in the grid</param>
/// <param name="gridNum">Number of cells on each side of the grid</param>
/// <param name="detectableTags">Tags to be detected by the sensor</param>
/// <param name="compression">Compression type</param>
public GridSensorBase(
string name,
Vector3 cellScale,
Vector3Int gridNum,
string[] detectableTags,
SensorCompressionType compression
)
{
m_Name = name;
m_CellScale = cellScale;
m_GridSize = gridNum;
m_DetectableTags = detectableTags;
CompressionType = compression;
if (m_GridSize.y != 1)
{
throw new UnityAgentsException("GridSensor only supports 2D grids.");
}
m_NumCells = m_GridSize.x * m_GridSize.z;
m_CellObservationSize = GetCellObservationSize();
m_ObservationSpec = ObservationSpec.Visual(m_GridSize.x, m_GridSize.z, m_CellObservationSize);
m_PerceptionTexture = new Texture2D(m_GridSize.x, m_GridSize.z, TextureFormat.RGB24, false);
ResetPerceptionBuffer();
}
/// <summary>
/// The compression type used by the sensor.
/// </summary>
public SensorCompressionType CompressionType
{
get { return m_CompressionType; }
set
{
if (!IsDataNormalized() && value == SensorCompressionType.PNG)
{
Debug.LogWarning($"Compression type {value} is only supported with normalized data. " +
"The sensor will not compress the data.");
return;
}
m_CompressionType = value;
}
}
internal float[] PerceptionBuffer
{
get { return m_PerceptionBuffer; }
}
/// <summary>
/// The tags which the sensor dectects.
/// </summary>
protected string[] DetectableTags
{
get { return m_DetectableTags; }
}
/// <inheritdoc/>
public void Reset() { }
/// <summary>
/// Clears the perception buffer before loading in new data.
/// </summary>
public void ResetPerceptionBuffer()
{
if (m_PerceptionBuffer != null)
{
Array.Clear(m_PerceptionBuffer, 0, m_PerceptionBuffer.Length);
Array.Clear(m_CellDataBuffer, 0, m_CellDataBuffer.Length);
}
else
{
m_PerceptionBuffer = new float[m_CellObservationSize * m_NumCells];
m_CellDataBuffer = new float[m_CellObservationSize];
m_PerceptionColors = new Color[m_NumCells];
}
}
/// <inheritdoc/>
public string GetName()
{
return m_Name;
}
/// <inheritdoc/>
public CompressionSpec GetCompressionSpec()
{
return new CompressionSpec(CompressionType);
}
/// <inheritdoc/>
public BuiltInSensorType GetBuiltInSensorType()
{
return BuiltInSensorType.GridSensor;
}
/// <inheritdoc/>
public byte[] GetCompressedObservation()
{
using (TimerStack.Instance.Scoped("GridSensor.GetCompressedObservation"))
{
var allBytes = new List<byte>();
var numImages = (m_CellObservationSize + 2) / 3;
for (int i = 0; i < numImages; i++)
{
var channelIndex = 3 * i;
GridValuesToTexture(channelIndex, Math.Min(3, m_CellObservationSize - channelIndex));
allBytes.AddRange(m_PerceptionTexture.EncodeToPNG());
}
return allBytes.ToArray();
}
}
/// <summary>
/// Convert observation values to texture for PNG compression.
/// </summary>
void GridValuesToTexture(int channelIndex, int numChannelsToAdd)
{
for (int i = 0; i < m_NumCells; i++)
{
for (int j = 0; j < numChannelsToAdd; j++)
{
m_PerceptionColors[i][j] = m_PerceptionBuffer[i * m_CellObservationSize + channelIndex + j];
}
}
m_PerceptionTexture.SetPixels(m_PerceptionColors);
}
/// <summary>
/// Get the observation values of the detected game object.
/// Default is to record the detected tag index.
///
/// This method can be overridden to encode the observation differently or get custom data from the object.
/// When overriding this method, <seealso cref="GetCellObservationSize"/> and <seealso cref="IsDataNormalized"/>
/// might also need to change accordingly.
/// </summary>
/// <param name="detectedObject">The game object that was detected within a certain cell</param>
/// <param name="tagIndex">The index of the detectedObject's tag in the DetectableObjects list</param>
/// <param name="dataBuffer">The buffer to write the observation values.
/// The buffer size is configured by <seealso cref="GetCellObservationSize"/>.
/// </param>
/// <example>
/// Here is an example of overriding GetObjectData to get the velocity of a potential Rigidbody:
/// <code>
/// protected override void GetObjectData(GameObject detectedObject, int tagIndex, float[] dataBuffer)
/// {
/// if (tagIndex == Array.IndexOf(DetectableTags, "RigidBodyObject"))
/// {
/// Rigidbody rigidbody = detectedObject.GetComponent&lt;Rigidbody&gt;();
/// dataBuffer[0] = rigidbody.velocity.x;
/// dataBuffer[1] = rigidbody.velocity.y;
/// dataBuffer[2] = rigidbody.velocity.z;
/// }
/// }
/// </code>
/// </example>
protected virtual void GetObjectData(GameObject detectedObject, int tagIndex, float[] dataBuffer)
{
dataBuffer[0] = tagIndex + 1;
}
/// <summary>
/// Get the observation size for each cell. This will be the size of dataBuffer for <seealso cref="GetObjectData"/>.
/// If overriding <seealso cref="GetObjectData"/>, override this method as well to the custom observation size.
/// </summary>
/// <returns>The observation size of each cell.</returns>
protected virtual int GetCellObservationSize()
{
return 1;
}
/// <summary>
/// Whether the data is normalized within [0, 1]. The sensor can only use PNG compression if the data is normailzed.
/// If overriding <seealso cref="GetObjectData"/>, override this method as well according to the custom observation values.
/// </summary>
/// <returns>Bool value indicating whether data is normalized.</returns>
protected virtual bool IsDataNormalized()
{
return false;
}
/// <summary>
/// Whether to process all detected colliders in a cell. Default to false and only use the one closest to the agent.
/// If overriding <seealso cref="GetObjectData"/>, consider override this method when needed.
/// </summary>
/// <returns>Bool value indicating whether to process all detected colliders in a cell.</returns>
protected internal virtual ProcessCollidersMethod GetProcessCollidersMethod()
{
return ProcessCollidersMethod.ProcessClosestColliders;
}
/// <summary>
/// If using PNG compression, check if the values are normalized.
/// </summary>
void ValidateValues(float[] dataValues, GameObject detectedObject)
{
if (m_CompressionType != SensorCompressionType.PNG)
{
return;
}
for (int j = 0; j < dataValues.Length; j++)
{
if (dataValues[j] < 0 || dataValues[j] > 1)
throw new UnityAgentsException($"When using compression type {m_CompressionType} the data value has to be normalized between 0-1. " +
$"Received value[{dataValues[j]}] for {detectedObject.name}");
}
}
/// <summary>
/// Collect data from the detected object if a detectable tag is matched.
/// </summary>
internal void ProcessDetectedObject(GameObject detectedObject, int cellIndex)
{
Profiler.BeginSample("GridSensor.ProcessDetectedObject");
for (var i = 0; i < m_DetectableTags.Length; i++)
{
if (!ReferenceEquals(detectedObject, null) && detectedObject.CompareTag(m_DetectableTags[i]))
{
if (GetProcessCollidersMethod() == ProcessCollidersMethod.ProcessAllColliders)
{
Array.Copy(m_PerceptionBuffer, cellIndex * m_CellObservationSize, m_CellDataBuffer, 0, m_CellObservationSize);
}
else
{
Array.Clear(m_CellDataBuffer, 0, m_CellDataBuffer.Length);
}
GetObjectData(detectedObject, i, m_CellDataBuffer);
ValidateValues(m_CellDataBuffer, detectedObject);
Array.Copy(m_CellDataBuffer, 0, m_PerceptionBuffer, cellIndex * m_CellObservationSize, m_CellObservationSize);
break;
}
}
Profiler.EndSample();
}
/// <inheritdoc/>
public void Update()
{
ResetPerceptionBuffer();
using (TimerStack.Instance.Scoped("GridSensor.Update"))
{
if (m_BoxOverlapChecker != null)
{
m_BoxOverlapChecker.Update();
}
}
}
/// <inheritdoc/>
public ObservationSpec GetObservationSpec()
{
return m_ObservationSpec;
}
/// <inheritdoc/>
public int Write(ObservationWriter writer)
{
using (TimerStack.Instance.Scoped("GridSensor.Write"))
{
int index = 0;
for (var h = m_GridSize.z - 1; h >= 0; h--)
{
for (var w = 0; w < m_GridSize.x; w++)
{
for (var d = 0; d < m_CellObservationSize; d++)
{
writer[h, w, d] = m_PerceptionBuffer[index];
index++;
}
}
}
return index;
}
}
/// <summary>
/// Clean up the internal objects.
/// </summary>
public void Dispose()
{
if (!ReferenceEquals(null, m_PerceptionTexture))
{
DestroyTexture(m_PerceptionTexture);
m_PerceptionTexture = null;
}
}
static void DestroyTexture(Texture2D texture)
{
if (Application.isEditor)
{
// Edit Mode tests complain if we use Destroy()
// TODO move to extension methods for UnityEngine.Object?
Object.DestroyImmediate(texture);
}
else
{
Object.Destroy(texture);
}
}
}
}

60
com.unity.ml-agents.extensions/Runtime/Sensors/OneHotGridSensor.cs


using UnityEngine;
using Unity.MLAgents.Sensors;
namespace Unity.MLAgents.Extensions.Sensors
{
/// <summary>
/// Grid-based sensor with one-hot observations.
/// </summary>
public class OneHotGridSensor : GridSensorBase
{
/// <summary>
/// Create a OneHotGridSensor with the specified configuration.
/// </summary>
/// <param name="name">The sensor name</param>
/// <param name="cellScale">The scale of each cell in the grid</param>
/// <param name="gridNum">Number of cells on each side of the grid</param>
/// <param name="detectableTags">Tags to be detected by the sensor</param>
/// <param name="compression">Compression type</param>
public OneHotGridSensor(
string name,
Vector3 cellScale,
Vector3Int gridNum,
string[] detectableTags,
SensorCompressionType compression
) : base(name, cellScale, gridNum, detectableTags, compression)
{
}
/// <inheritdoc/>
protected override int GetCellObservationSize()
{
return DetectableTags == null ? 0 : DetectableTags.Length;
}
/// <inheritdoc/>
protected override bool IsDataNormalized()
{
return true;
}
/// <inheritdoc/>
protected internal override ProcessCollidersMethod GetProcessCollidersMethod()
{
return ProcessCollidersMethod.ProcessClosestColliders;
}
/// <summary>
/// Get the one-hot representation of the detected game object's tag.
/// </summary>
/// <param name="detectedObject">The game object that was detected within a certain cell</param>
/// <param name="tagIndex">The index of the detectedObject's tag in the DetectableObjects list</param>
/// <param name="dataBuffer">The buffer to write the observation values.
/// The buffer size is configured by <seealso cref="GetCellObservationSize"/>.
/// </param>
protected override void GetObjectData(GameObject detectedObject, int tagIndex, float[] dataBuffer)
{
dataBuffer[tagIndex] = 1;
}
}
}

8
com.unity.ml-agents.extensions/Tests/Editor/GridSensors.meta


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

297
com.unity.ml-agents.extensions/Tests/Editor/GridSensors/BoxOverlapCheckerTests.cs


using System.Collections.Generic;
using System.Reflection;
using NUnit.Framework;
using UnityEngine;
using Unity.MLAgents.Extensions.Sensors;
namespace Unity.MLAgents.Extensions.Tests.GridSensors
{
internal class TestBoxOverlapChecker : BoxOverlapChecker
{
public TestBoxOverlapChecker(
Vector3 cellScale,
Vector3Int gridSize,
bool rotateWithAgent,
LayerMask colliderMask,
GameObject rootReference,
string[] detectableTags,
int initialColliderBufferSize,
int maxColliderBufferSize
) : base(
cellScale,
gridSize,
rotateWithAgent,
colliderMask,
rootReference,
detectableTags,
initialColliderBufferSize,
maxColliderBufferSize)
{ }
public Vector3[] CellLocalPositions
{
get
{
return (Vector3[])typeof(BoxOverlapChecker).GetField("m_CellLocalPositions",
BindingFlags.Instance | BindingFlags.NonPublic).GetValue(this);
}
}
public Collider[] ColliderBuffer
{
get
{
return (Collider[])typeof(BoxOverlapChecker).GetField("m_ColliderBuffer",
BindingFlags.Instance | BindingFlags.NonPublic).GetValue(this);
}
}
public static TestBoxOverlapChecker CreateChecker(
float cellScaleX = 1f,
float cellScaleZ = 1f,
int gridSizeX = 10,
int gridSizeZ = 10,
bool rotateWithAgent = true,
GameObject rootReference = null,
string[] detectableTags = null,
int initialColliderBufferSize = 4,
int maxColliderBufferSize = 500)
{
return new TestBoxOverlapChecker(
new Vector3(cellScaleX, 0.01f, cellScaleZ),
new Vector3Int(gridSizeX, 1, gridSizeZ),
rotateWithAgent,
LayerMask.GetMask("Default"),
rootReference,
detectableTags,
initialColliderBufferSize,
maxColliderBufferSize);
}
}
public class BoxOverlapCheckerTests
{
[Test]
public void TestCellLocalPosition()
{
var testGo = new GameObject("test");
testGo.transform.position = Vector3.zero;
var boxOverlapSquare = TestBoxOverlapChecker.CreateChecker(gridSizeX: 10, gridSizeZ: 10, rotateWithAgent: false, rootReference: testGo);
var localPos = boxOverlapSquare.CellLocalPositions;
Assert.AreEqual(new Vector3(-4.5f, 0, -4.5f), localPos[0]);
Assert.AreEqual(new Vector3(-4.5f, 0, 4.5f), localPos[9]);
Assert.AreEqual(new Vector3(4.5f, 0, -4.5f), localPos[90]);
Assert.AreEqual(new Vector3(4.5f, 0, 4.5f), localPos[99]);
Object.DestroyImmediate(testGo);
var testGo2 = new GameObject("test");
testGo2.transform.position = new Vector3(3.5f, 8f, 17f); // random, should have no effect on local positions
var boxOverlapRect = TestBoxOverlapChecker.CreateChecker(gridSizeX: 5, gridSizeZ: 15, rotateWithAgent: true, rootReference: testGo);
localPos = boxOverlapRect.CellLocalPositions;
Assert.AreEqual(new Vector3(-2f, 0, -7f), localPos[0]);
Assert.AreEqual(new Vector3(-2f, 0, 7f), localPos[14]);
Assert.AreEqual(new Vector3(2f, 0, -7f), localPos[60]);
Assert.AreEqual(new Vector3(2f, 0, 7f), localPos[74]);
Object.DestroyImmediate(testGo2);
}
[Test]
public void TestCellGlobalPositionNoRotate()
{
var testGo = new GameObject("test");
var position = new Vector3(3.5f, 8f, 17f);
testGo.transform.position = position;
var boxOverlap = TestBoxOverlapChecker.CreateChecker(gridSizeX: 10, gridSizeZ: 10, rotateWithAgent: false, rootReference: testGo);
Assert.AreEqual(new Vector3(-4.5f, 0, -4.5f) + position, boxOverlap.GetCellGlobalPosition(0));
Assert.AreEqual(new Vector3(-4.5f, 0, 4.5f) + position, boxOverlap.GetCellGlobalPosition(9));
Assert.AreEqual(new Vector3(4.5f, 0, -4.5f) + position, boxOverlap.GetCellGlobalPosition(90));
Assert.AreEqual(new Vector3(4.5f, 0, 4.5f) + position, boxOverlap.GetCellGlobalPosition(99));
testGo.transform.Rotate(0, 90, 0); // should have no effect on positions
Assert.AreEqual(new Vector3(-4.5f, 0, -4.5f) + position, boxOverlap.GetCellGlobalPosition(0));
Assert.AreEqual(new Vector3(-4.5f, 0, 4.5f) + position, boxOverlap.GetCellGlobalPosition(9));
Assert.AreEqual(new Vector3(4.5f, 0, -4.5f) + position, boxOverlap.GetCellGlobalPosition(90));
Assert.AreEqual(new Vector3(4.5f, 0, 4.5f) + position, boxOverlap.GetCellGlobalPosition(99));
Object.DestroyImmediate(testGo);
}
[Test]
public void TestCellGlobalPositionRotate()
{
var testGo = new GameObject("test");
var position = new Vector3(15f, 6f, 13f);
testGo.transform.position = position;
var boxOverlap = TestBoxOverlapChecker.CreateChecker(gridSizeX: 5, gridSizeZ: 15, rotateWithAgent: true, rootReference: testGo);
Assert.AreEqual(new Vector3(-2f, 0, -7f) + position, boxOverlap.GetCellGlobalPosition(0));
Assert.AreEqual(new Vector3(-2f, 0, 7f) + position, boxOverlap.GetCellGlobalPosition(14));
Assert.AreEqual(new Vector3(2f, 0, -7f) + position, boxOverlap.GetCellGlobalPosition(60));
Assert.AreEqual(new Vector3(2f, 0, 7f) + position, boxOverlap.GetCellGlobalPosition(74));
testGo.transform.Rotate(0, 90, 0);
// round to int to ignore numeric errors
Assert.AreEqual(Vector3Int.RoundToInt(new Vector3(-7f, 0, 2f) + position), Vector3Int.RoundToInt(boxOverlap.GetCellGlobalPosition(0)));
Assert.AreEqual(Vector3Int.RoundToInt(new Vector3(7f, 0, 2f) + position), Vector3Int.RoundToInt(boxOverlap.GetCellGlobalPosition(14)));
Assert.AreEqual(Vector3Int.RoundToInt(new Vector3(-7f, 0, -2f) + position), Vector3Int.RoundToInt(boxOverlap.GetCellGlobalPosition(60)));
Assert.AreEqual(Vector3Int.RoundToInt(new Vector3(7f, 0, -2f) + position), Vector3Int.RoundToInt(boxOverlap.GetCellGlobalPosition(74)));
Object.DestroyImmediate(testGo);
}
[Test]
public void TestBufferResize()
{
List<GameObject> testObjects = new List<GameObject>();
var testGo = new GameObject("test");
testGo.transform.position = Vector3.zero;
testObjects.Add(testGo);
var boxOverlap = TestBoxOverlapChecker.CreateChecker(rootReference: testGo, initialColliderBufferSize: 2, maxColliderBufferSize: 5);
boxOverlap.Update();
Assert.AreEqual(2, boxOverlap.ColliderBuffer.Length);
for (var i = 0; i < 3; i++)
{
var boxGo = new GameObject("test");
boxGo.transform.position = Vector3.zero;
boxGo.AddComponent<BoxCollider>();
testObjects.Add(boxGo);
}
boxOverlap.Update();
Assert.AreEqual(4, boxOverlap.ColliderBuffer.Length);
for (var i = 0; i < 2; i++)
{
var boxGo = new GameObject("test");
boxGo.transform.position = Vector3.zero;
boxGo.AddComponent<BoxCollider>();
testObjects.Add(boxGo);
}
boxOverlap.Update();
Assert.AreEqual(5, boxOverlap.ColliderBuffer.Length);
Object.DestroyImmediate(testGo);
foreach (var go in testObjects)
{
Object.DestroyImmediate(go);
}
}
[Test]
public void TestParseCollidersClosest()
{
var tag1 = "Player";
List<GameObject> testObjects = new List<GameObject>();
var testGo = new GameObject("test");
testGo.transform.position = Vector3.zero;
var boxOverlap = TestBoxOverlapChecker.CreateChecker(
cellScaleX: 10f,
cellScaleZ: 10f,
gridSizeX: 2,
gridSizeZ: 2,
rootReference: testGo,
detectableTags: new string[] { tag1 });
var helper = new VerifyParseCollidersHelper();
boxOverlap.GridOverlapDetectedClosest += helper.DetectedAction;
for (var i = 0; i < 3; i++)
{
var boxGo = new GameObject("test");
boxGo.transform.position = new Vector3(i + 1, 0, 1);
boxGo.AddComponent<BoxCollider>();
boxGo.tag = tag1;
testObjects.Add(boxGo);
}
boxOverlap.Update();
helper.Verify(1, new List<GameObject> { testObjects[0] });
Object.DestroyImmediate(testGo);
foreach (var go in testObjects)
{
Object.DestroyImmediate(go);
}
}
[Test]
public void TestParseCollidersAll()
{
var tag1 = "Player";
List<GameObject> testObjects = new List<GameObject>();
var testGo = new GameObject("test");
testGo.transform.position = Vector3.zero;
var boxOverlap = TestBoxOverlapChecker.CreateChecker(
cellScaleX: 10f,
cellScaleZ: 10f,
gridSizeX: 2,
gridSizeZ: 2,
rootReference: testGo,
detectableTags: new string[] { tag1 });
var helper = new VerifyParseCollidersHelper();
boxOverlap.GridOverlapDetectedAll += helper.DetectedAction;
for (var i = 0; i < 3; i++)
{
var boxGo = new GameObject("test");
boxGo.transform.position = new Vector3(i + 1, 0, 1);
boxGo.AddComponent<BoxCollider>();
boxGo.tag = tag1;
testObjects.Add(boxGo);
}
boxOverlap.Update();
helper.Verify(3, testObjects);
Object.DestroyImmediate(testGo);
foreach (var go in testObjects)
{
Object.DestroyImmediate(go);
}
}
public class VerifyParseCollidersHelper
{
int m_NumInvoked;
List<GameObject> m_ParsedObjects = new List<GameObject>();
public void DetectedAction(GameObject go, int cellIndex)
{
m_NumInvoked += 1;
m_ParsedObjects.Add(go);
}
public void Verify(int expectNumInvoke, List<GameObject> expectedObjects)
{
Assert.AreEqual(expectNumInvoke, m_NumInvoked);
Assert.AreEqual(expectedObjects.Count, m_ParsedObjects.Count);
foreach (var obj in expectedObjects)
{
Assert.Contains(obj, m_ParsedObjects);
}
}
}
[Test]
public void TestOnlyOneChecker()
{
var testGo = new GameObject("test");
testGo.transform.position = Vector3.zero;
var gridSensorComponent = testGo.AddComponent<SimpleTestGridSensorComponent>();
gridSensorComponent.SetComponentParameters(useGridSensorBase: true, useOneHotTag: true, countColliders: true);
var sensors = gridSensorComponent.CreateSensors();
int numChecker = 0;
foreach (var sensor in sensors)
{
var gridsensor = (GridSensorBase)sensor;
if (gridsensor.m_BoxOverlapChecker != null)
{
numChecker += 1;
}
}
Assert.AreEqual(1, numChecker);
}
}
}

88
com.unity.ml-agents.extensions/Tests/Editor/GridSensors/GridSensorTestUtils.cs


using NUnit.Framework;
using System;
using System.Linq;
namespace Unity.MLAgents.Extensions.Tests.GridSensors
{
public static class GridObsTestUtils
{
/// <summary>
/// Utility function to duplicate an array into an array of arrays
/// </summary>
/// <param name="array">array to duplicate</param>
/// <param name="numCopies">number of times to duplicate</param>
/// <returns>array of duplicated arrays</returns>
public static float[][] DuplicateArray(float[] array, int numCopies)
{
float[][] duplicated = new float[numCopies][];
for (int i = 0; i < numCopies; i++)
{
duplicated[i] = array;
}
return duplicated;
}
/// <summary>
/// Asserts that the sub-arrays of the total array are equal to specific subarrays at specific subarray indicies and equal to a default everywhere else.
/// </summary>
/// <param name="total">Array containing all data of the grid observation. Is a concatenation of N subarrays all of the same length</param>
/// <param name="indicies">The indicies to verify that differ from the default array</param>
/// <param name="expectedArrays">The sub arrays values that differ from the default array</param>
/// <param name="expectedDefaultArray">The default value of a sub array</param>
/// <example>
/// If the total array is data from a 4x4x2 grid observation, total will be an array of size 32 and each sub array will have a size of 2.
/// Let 3 cells at indicies (0, 1), (2, 2), and (3, 0) with values ([.1, .5]), ([.9, .7]), ([0, .2]), respectively.
/// If the default values of cells are ([0, 0]) then the grid observation will be as follows:
/// [ [0, 0], [.1, .5], [ 0, 0 ], [0, 0],
/// [0, 0], [ 0, 0 ], [ 0, 0 ], [0, 0],
/// [0, 0], [ 0, 0 ], [.9, .7], [0, 0],
/// [0, .2], [ 0, 0 ], [ 0, 0 ], [0, 0] ]
///
/// Which will make the total array will be the flattened array
/// total = [0, 0, .1, .5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, .9, .7, 0, 0, 0, .2, 0, 0, 0, 0, 0]
///
/// The indicies of the activated cells in the flattened array will be 1, 10, and 12
///
/// So to verify that the total array is as expected, AssertSubarraysAtIndex should be called as
/// AssertSubarraysAtIndex(
/// total,
/// indicies = new int[] {1, 10, 12},
/// expectedArrays = new float[][] { new float[] {.1, .5}, new float[] {.9, .7}, new float[] {0, .2}},
/// expecedDefaultArray = new float[] {0, 0}
/// )
/// </example>
public static void AssertSubarraysAtIndex(float[] total, int[] indicies, float[][] expectedArrays, float[] expectedDefaultArray)
{
int totalIndex = 0;
int subIndex = 0;
int subarrayIndex = 0;
int lenOfData = expectedDefaultArray.Length;
int numArrays = total.Length / lenOfData;
for (int i = 0; i < numArrays; i++)
{
totalIndex = i * lenOfData;
if (indicies.Contains(i))
{
subarrayIndex = Array.IndexOf(indicies, i);
for (subIndex = 0; subIndex < lenOfData; subIndex++)
{
Assert.AreEqual(expectedArrays[subarrayIndex][subIndex], total[totalIndex],
"Expected " + expectedArrays[subarrayIndex][subIndex] + " at subarray index " + totalIndex + ", index = " + subIndex + " but was " + total[totalIndex]);
totalIndex++;
}
}
else
{
for (subIndex = 0; subIndex < lenOfData; subIndex++)
{
Assert.AreEqual(expectedDefaultArray[subIndex], total[totalIndex],
"Expected default value " + expectedDefaultArray[subIndex] + " at subarray index " + totalIndex + ", index = " + subIndex + " but was " + total[totalIndex]);
totalIndex++;
}
}
}
}
}
}

210
com.unity.ml-agents.extensions/Tests/Editor/GridSensors/GridSensorTests.cs


using System.Collections;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
using Unity.MLAgents.Sensors;
using Unity.MLAgents.Extensions.Sensors;
namespace Unity.MLAgents.Extensions.Tests.GridSensors
{
public class GridSensorTests
{
GameObject testGo;
GameObject boxGo;
SimpleTestGridSensorComponent gridSensorComponent;
// Use built-in tags
const string k_Tag1 = "Player";
const string k_Tag2 = "Respawn";
[UnitySetUp]
public IEnumerator SetupScene()
{
testGo = new GameObject("test");
testGo.transform.position = Vector3.zero;
gridSensorComponent = testGo.AddComponent<SimpleTestGridSensorComponent>();
boxGo = new GameObject("block");
boxGo.tag = k_Tag1;
boxGo.transform.position = new Vector3(3f, 0f, 3f);
boxGo.AddComponent<BoxCollider>();
TestGridSensorConfig.Reset();
yield return null;
}
[TearDown]
public void ClearScene()
{
Object.DestroyImmediate(boxGo);
Object.DestroyImmediate(testGo);
}
[Test]
public void TestBufferSize()
{
testGo.tag = k_Tag2;
string[] tags = { k_Tag1, k_Tag2 };
gridSensorComponent.SetComponentParameters(tags, gridSizeX: 3, gridSizeZ: 4, useTestingGridSensor: true);
TestGridSensorConfig.SetParameters(5, true, false);
var gridSensor = (SimpleTestGridSensor)gridSensorComponent.CreateSensors()[0];
Assert.AreEqual(gridSensor.PerceptionBuffer.Length, 3 * 4 * 5);
}
[Test]
public void TestInvalidSizeConfiguration()
{
testGo.tag = k_Tag2;
string[] tags = { k_Tag1, k_Tag2 };
gridSensorComponent.SetComponentParameters(tags, gridSizeY: 10, useTestingGridSensor: true);
gridSensorComponent.CreateSensors(); // expect no exception
gridSensorComponent.m_GridSize.y = 10;
Assert.Throws<UnityAgentsException>(() =>
{
gridSensorComponent.CreateSensors();
});
}
[Test]
public void TestInvalidCompressionConfiguration()
{
testGo.tag = k_Tag2;
string[] tags = { k_Tag1, k_Tag2 };
gridSensorComponent.SetComponentParameters(tags, compression: SensorCompressionType.PNG, useTestingGridSensor: true);
var gridSensor = (GridSensorBase)gridSensorComponent.CreateSensors()[0];
LogAssert.Expect(LogType.Warning, $"Compression type {SensorCompressionType.PNG} is only supported with normalized data. " +
"The sensor will not compress the data.");
Assert.AreEqual(gridSensor.CompressionType, SensorCompressionType.None);
}
[Test]
public void PerceiveNotSelf()
{
testGo.tag = k_Tag2;
string[] tags = { k_Tag1, k_Tag2 };
gridSensorComponent.SetComponentParameters(tags, useGridSensorBase: true);
var gridSensor = (GridSensorBase)gridSensorComponent.CreateSensors()[0];
gridSensor.Update();
int[] subarrayIndicies = new int[] { 77, 78, 87, 88 };
float[][] expectedSubarrays = GridObsTestUtils.DuplicateArray(new float[] { 1 }, 4);
float[] expectedDefault = new float[] { 0 };
GridObsTestUtils.AssertSubarraysAtIndex(gridSensor.PerceptionBuffer, subarrayIndicies, expectedSubarrays, expectedDefault);
}
[Test]
public void TestReset()
{
testGo.tag = k_Tag2;
string[] tags = { k_Tag1, k_Tag2 };
gridSensorComponent.SetComponentParameters(tags, useGridSensorBase: true);
TestGridSensorConfig.SetParameters(3, false, false);
var gridSensor = (GridSensorBase)gridSensorComponent.CreateSensors()[0];
gridSensor.Update();
int[] subarrayIndicies = new int[] { 77, 78, 87, 88 };
float[][] expectedSubarrays = GridObsTestUtils.DuplicateArray(new float[] { 1 }, 4);
float[] expectedDefault = new float[] { 0 };
GridObsTestUtils.AssertSubarraysAtIndex(gridSensor.PerceptionBuffer, subarrayIndicies, expectedSubarrays, expectedDefault);
Object.DestroyImmediate(boxGo);
gridSensor.Update();
subarrayIndicies = new int[0];
expectedSubarrays = new float[0][];
GridObsTestUtils.AssertSubarraysAtIndex(gridSensor.PerceptionBuffer, subarrayIndicies, expectedSubarrays, expectedDefault);
}
[Test]
public void TestOneHotSensor()
{
testGo.tag = k_Tag2;
string[] tags = { k_Tag1, k_Tag2 };
gridSensorComponent.SetComponentParameters(tags, useOneHotTag: true);
var gridSensor = (OneHotGridSensor)gridSensorComponent.CreateSensors()[0];
Assert.AreEqual(gridSensor.PerceptionBuffer.Length, 10 * 10 * 2);
gridSensor.Update();
int[] subarrayIndicies = new int[] { 77, 78, 87, 88 };
float[][] expectedSubarrays = GridObsTestUtils.DuplicateArray(new float[] { 1, 0 }, 4);
float[] expectedDefault = new float[] { 0, 0 };
GridObsTestUtils.AssertSubarraysAtIndex(gridSensor.PerceptionBuffer, subarrayIndicies, expectedSubarrays, expectedDefault);
}
[Test]
public void TestCountingSensor()
{
testGo.tag = k_Tag2;
string[] tags = { k_Tag1, k_Tag2 };
gridSensorComponent.SetComponentParameters(tags, countColliders: true);
var gridSensor = (CountingGridSensor)gridSensorComponent.CreateSensors()[0];
Assert.AreEqual(gridSensor.PerceptionBuffer.Length, 10 * 10 * 2);
gridSensor.Update();
int[] subarrayIndicies = new int[] { 77, 78, 87, 88 };
float[][] expectedSubarrays = GridObsTestUtils.DuplicateArray(new float[] { 1, 0 }, 4);
float[] expectedDefault = new float[] { 0, 0 };
GridObsTestUtils.AssertSubarraysAtIndex(gridSensor.PerceptionBuffer, subarrayIndicies, expectedSubarrays, expectedDefault);
var boxGo2 = new GameObject("block");
boxGo2.tag = k_Tag1;
boxGo2.transform.position = new Vector3(3.1f, 0f, 3f);
boxGo2.AddComponent<BoxCollider>();
gridSensor.Update();
subarrayIndicies = new int[] { 77, 78, 87, 88 };
expectedSubarrays = GridObsTestUtils.DuplicateArray(new float[] { 2, 0 }, 4);
expectedDefault = new float[] { 0, 0 };
GridObsTestUtils.AssertSubarraysAtIndex(gridSensor.PerceptionBuffer, subarrayIndicies, expectedSubarrays, expectedDefault);
Object.DestroyImmediate(boxGo2);
}
[Test]
public void TestCustomSensorInvalidData()
{
testGo.tag = k_Tag2;
string[] tags = { k_Tag1, k_Tag2 };
gridSensorComponent.SetComponentParameters(tags, compression: SensorCompressionType.PNG, useTestingGridSensor: true);
TestGridSensorConfig.SetParameters(5, true, false);
var gridSensor = (SimpleTestGridSensor)gridSensorComponent.CreateSensors()[0];
gridSensor.DummyData = new float[] { 1, 2, 3, 4, 5 };
Assert.Throws<UnityAgentsException>(() =>
{
gridSensor.Update();
});
}
[Test]
public void TestMultipleSensors()
{
testGo.tag = k_Tag2;
string[] tags = { k_Tag1, k_Tag2 };
gridSensorComponent.SetComponentParameters(tags, useOneHotTag: true, countColliders: true, useTestingGridSensor: true);
var gridSensors = gridSensorComponent.CreateSensors();
Assert.IsNotNull(((GridSensorBase)gridSensors[0]).m_BoxOverlapChecker);
Assert.IsNull(((GridSensorBase)gridSensors[1]).m_BoxOverlapChecker);
Assert.IsNull(((GridSensorBase)gridSensors[2]).m_BoxOverlapChecker);
}
[Test]
public void TestNoSensors()
{
testGo.tag = k_Tag2;
string[] tags = { k_Tag1, k_Tag2 };
gridSensorComponent.SetComponentParameters(tags);
Assert.Throws<UnityAgentsException>(() =>
{
gridSensorComponent.CreateSensors();
});
}
}
}

131
com.unity.ml-agents.extensions/Tests/Editor/GridSensors/SimpleTestGridSensor.cs


using System.Linq;
using UnityEngine;
using Unity.MLAgents.Sensors;
using Unity.MLAgents.Extensions.Sensors;
namespace Unity.MLAgents.Extensions.Tests.GridSensors
{
public static class TestGridSensorConfig
{
public static int ObservationSize;
public static bool IsNormalized;
public static bool ParseAllColliders;
public static void SetParameters(int observationSize, bool isNormalized, bool parseAllColliders)
{
ObservationSize = observationSize;
IsNormalized = isNormalized;
ParseAllColliders = parseAllColliders;
}
public static void Reset()
{
ObservationSize = 0;
IsNormalized = false;
ParseAllColliders = false;
}
}
public class SimpleTestGridSensor : GridSensorBase
{
public float[] DummyData;
public SimpleTestGridSensor(
string name,
Vector3 cellScale,
Vector3Int gridSize,
string[] detectableTags,
SensorCompressionType compression
) : base(
name,
cellScale,
gridSize,
detectableTags,
compression)
{ }
protected override int GetCellObservationSize()
{
return TestGridSensorConfig.ObservationSize;
}
protected override bool IsDataNormalized()
{
return TestGridSensorConfig.IsNormalized;
}
protected internal override ProcessCollidersMethod GetProcessCollidersMethod()
{
return TestGridSensorConfig.ParseAllColliders ? ProcessCollidersMethod.ProcessAllColliders : ProcessCollidersMethod.ProcessClosestColliders;
}
protected override void GetObjectData(GameObject detectedObject, int typeIndex, float[] dataBuffer)
{
for (var i = 0; i < DummyData.Length; i++)
{
dataBuffer[i] = DummyData[i];
}
}
}
public class SimpleTestGridSensorComponent : GridSensorComponent
{
bool m_UseTestingGridSensor;
bool m_UseGridSensorBase;
protected override GridSensorBase[] GetGridSensors()
{
var sensorList = base.GetGridSensors().ToList();
if (m_UseGridSensorBase)
{
var testSensor = new GridSensorBase(
SensorName,
CellScale,
GridSize,
DetectableTags,
CompressionType
);
sensorList.Add(testSensor);
}
if (m_UseTestingGridSensor)
{
var testSensor = new SimpleTestGridSensor(
SensorName,
CellScale,
GridSize,
DetectableTags,
CompressionType
);
sensorList.Add(testSensor);
}
return sensorList.ToArray();
}
public void SetComponentParameters(
string[] detectableTags = null,
float cellScaleX = 1f,
float cellScaleZ = 1f,
int gridSizeX = 10,
int gridSizeY = 1,
int gridSizeZ = 10,
int colliderMaskInt = -1,
SensorCompressionType compression = SensorCompressionType.None,
bool rotateWithAgent = false,
bool useOneHotTag = false,
bool countColliders = false,
bool useTestingGridSensor = false,
bool useGridSensorBase = false
)
{
DetectableTags = detectableTags;
CellScale = new Vector3(cellScaleX, 0.01f, cellScaleZ);
GridSize = new Vector3Int(gridSizeX, gridSizeY, gridSizeZ);
ColliderMask = colliderMaskInt < 0 ? LayerMask.GetMask("Default") : colliderMaskInt;
RotateWithAgent = rotateWithAgent;
CompressionType = compression;
UseOneHotTag = useOneHotTag;
CountColliders = countColliders;
m_UseGridSensorBase = useGridSensorBase;
m_UseTestingGridSensor = useTestingGridSensor;
}
}
}

661
com.unity.ml-agents.extensions/Runtime/Sensors/GridSensor.cs


using System;
using System.Linq;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using UnityEngine;
using UnityEngine.Assertions;
using Unity.MLAgents.Sensors;
using UnityEngine.Profiling;
[assembly: InternalsVisibleTo("Unity.ML-Agents.Extensions.EditorTests")]
namespace Unity.MLAgents.Extensions.Sensors
{
/// <summary>
/// Enum describing what kind of depth type the data should be organized as
/// </summary>
public enum GridDepthType { Channel, ChannelHot, Counting };
/// <summary>
/// Grid-based sensor.
/// </summary>
public class GridSensor : ISensor, IBuiltInSensor
{
string m_Name;
Vector3 m_CellScale;
Vector3Int m_GridSize;
bool m_RotateWithAgent;
GameObject m_RootReference;
int m_MaxColliderBufferSize;
int m_InitialColliderBufferSize;
LayerMask m_ColliderMask;
GridDepthType m_GridDepthType;
int[] m_ChannelDepths;
string[] m_DetectableObjects;
SensorCompressionType m_CompressionType;
ObservationSpec m_ObservationSpec;
// Buffers
internal float[] m_PerceptionBuffer;
Color[] m_PerceptionColors;
Texture2D m_PerceptionTexture;
Collider[] m_ColliderBuffer;
float[] m_CellDataBuffer;
int[] m_ChannelOffsets;
Vector3[] m_CellLocalPositions;
int[] m_GizmoColorIndexes;
Vector3[] m_CellGlobalPosition;
// Utility Constants Calculated on Init
int m_NumCells;
int m_CellObservationSize;
Vector3 m_CellCenterOffset;
public GridSensor(
string name,
Vector3 cellScale,
Vector3Int gridNum,
bool rotateWithAgent,
int[] channelDepths,
string[] detectableObjects,
LayerMask colliderMask,
GridDepthType depthType,
GameObject rootReference,
SensorCompressionType compression,
int maxColliderBufferSize,
int initialColliderBufferSize
)
{
m_Name = name;
m_CellScale = cellScale;
m_GridSize = gridNum;
m_RotateWithAgent = rotateWithAgent;
m_RootReference = rootReference;
m_MaxColliderBufferSize = maxColliderBufferSize;
m_InitialColliderBufferSize = initialColliderBufferSize;
m_ColliderMask = colliderMask;
m_GridDepthType = depthType;
m_ChannelDepths = channelDepths;
m_DetectableObjects = detectableObjects;
m_CompressionType = compression;
if (m_GridSize.y != 1)
{
throw new UnityAgentsException("GridSensor only supports 2D grids.");
}
if (m_GridDepthType == GridDepthType.Counting && m_DetectableObjects.Length != m_ChannelDepths.Length)
{
throw new UnityAgentsException("The channels of a CountingGridSensor is equal to the number of detectableObjects");
}
InitGridParameters();
InitDepthType();
InitCellPoints();
ResetPerceptionBuffer();
m_ObservationSpec = ObservationSpec.Visual(m_GridSize.x, m_GridSize.z, m_CellObservationSize);
m_PerceptionTexture = new Texture2D(m_GridSize.x, m_GridSize.z, TextureFormat.RGB24, false);
m_ColliderBuffer = new Collider[Math.Min(m_MaxColliderBufferSize, m_InitialColliderBufferSize)];
}
public SensorCompressionType CompressionType
{
get { return m_CompressionType; }
set { m_CompressionType = value; }
}
public bool RotateWithAgent
{
get { return m_RotateWithAgent; }
set { m_RotateWithAgent = value; }
}
public LayerMask ColliderMask
{
get { return m_ColliderMask; }
set { m_ColliderMask = value; }
}
/// <summary>
/// Initializes the constant parameters used within the perceive method call
/// </summary>
void InitGridParameters()
{
m_NumCells = m_GridSize.x * m_GridSize.z;
m_CellCenterOffset = new Vector3((m_GridSize.x - 1f) / 2, 0, (m_GridSize.z - 1f) / 2);
}
/// <summary>
/// Initializes the constant parameters that are based on the Grid Depth Type
/// Sets the ObservationPerCell and the ChannelOffsets properties
/// </summary>
void InitDepthType()
{
if (m_GridDepthType == GridDepthType.ChannelHot)
{
m_CellObservationSize = m_ChannelDepths.Sum();
m_ChannelOffsets = new int[m_ChannelDepths.Length];
for (int i = 1; i < m_ChannelDepths.Length; i++)
{
m_ChannelOffsets[i] = m_ChannelOffsets[i - 1] + m_ChannelDepths[i - 1];
}
}
else
{
m_CellObservationSize = m_ChannelDepths.Length;
}
// The maximum number of channels in the final output must be less than 255 * 3 because the "number of PNG images" to generate must fit in one byte
Assert.IsTrue(m_CellObservationSize < (255 * 3), "The maximum number of channels per cell must be less than 255 * 3");
}
/// <summary>
/// Initializes the location of the CellPoints property
/// </summary>
void InitCellPoints()
{
m_CellLocalPositions = new Vector3[m_NumCells];
for (int i = 0; i < m_NumCells; i++)
{
m_CellLocalPositions[i] = CellToLocalPoint(i);
}
}
/// <inheritdoc/>
public void Reset() { }
/// <summary>
/// Clears the perception buffer before loading in new data. If the gridDepthType is ChannelHot, then it initializes the
/// Reset() also reinits the cell activity array (for debug)
/// </summary>
public void ResetPerceptionBuffer()
{
if (m_PerceptionBuffer != null)
{
Array.Clear(m_PerceptionBuffer, 0, m_PerceptionBuffer.Length);
}
else
{
m_PerceptionBuffer = new float[m_CellObservationSize * m_NumCells];
m_ColliderBuffer = new Collider[Math.Min(m_MaxColliderBufferSize, m_InitialColliderBufferSize)];
m_CellDataBuffer = new float[m_ChannelDepths.Length];
m_PerceptionColors = new Color[m_NumCells];
m_CellGlobalPosition = new Vector3[m_NumCells];
}
}
public void ResetGizmoBuffer()
{
// Ensure to init arrays if not yet assigned (for editor)
if (m_GizmoColorIndexes == null)
m_GizmoColorIndexes = new int[m_NumCells];
// Assign the default color to the cell activities
for (int i = 0; i < m_NumCells; i++)
{
m_GizmoColorIndexes[i] = -1;
}
}
/// <inheritdoc/>
public string GetName()
{
return m_Name;
}
/// <inheritdoc/>
public CompressionSpec GetCompressionSpec()
{
return new CompressionSpec(CompressionType);
}
/// <inheritdoc/>
public BuiltInSensorType GetBuiltInSensorType()
{
return BuiltInSensorType.GridSensor;
}
/// <summary>
/// GetCompressedObservation - Calls Perceive then puts the data stored on the perception buffer
/// onto the m_perceptionTexture2D to be converted to a byte array and returned
/// </summary>
/// <returns>byte[] containing the compressed observation of the grid observation</returns>
public byte[] GetCompressedObservation()
{
using (TimerStack.Instance.Scoped("GridSensor.GetCompressedObservation"))
{
var allBytes = new List<byte>();
var numImages = (m_CellObservationSize + 2) / 3;
for (int i = 0; i < numImages; i++)
{
var channelIndex = 3 * i;
ChannelsToTexture(channelIndex, Math.Min(3, m_CellObservationSize - channelIndex));
allBytes.AddRange(m_PerceptionTexture.EncodeToPNG());
}
return allBytes.ToArray();
}
}
/// <summary>
/// ChannelsToTexture - Takes the channel index and the numChannelsToAdd.
/// For each cell and for each channel to add, sets it to a value of the color specified for that cell.
/// All colors are then set to the perceptionTexture via SetPixels.
/// m_perceptionTexture2D can then be read as an image as it now contains all of the information that was
/// stored in the channels
/// </summary>
/// <param name="channelIndex"></param>
/// <param name="numChannelsToAdd"></param>
void ChannelsToTexture(int channelIndex, int numChannelsToAdd)
{
for (int i = 0; i < m_NumCells; i++)
{
for (int j = 0; j < numChannelsToAdd; j++)
{
m_PerceptionColors[i][j] = m_PerceptionBuffer[i * m_CellObservationSize + channelIndex + j];
}
}
m_PerceptionTexture.SetPixels(m_PerceptionColors);
}
/// <summary>
/// Perceive - Clears the buffers, calls overlap box on the actual cell (the actual perception part)
/// for all found colliders, LoadObjectData is called
/// </summary>
internal void Perceive()
{
if (m_ColliderBuffer == null)
{
return;
}
ResetPerceptionBuffer();
using (TimerStack.Instance.Scoped("GridSensor.Perceive"))
{
var halfCellScale = new Vector3(m_CellScale.x / 2f, m_CellScale.y, m_CellScale.z / 2f);
for (var cellIndex = 0; cellIndex < m_NumCells; cellIndex++)
{
var cellCenter = GetCellGlobalPosition(cellIndex);
var numFound = BufferResizingOverlapBoxNonAlloc(cellCenter, halfCellScale, GetGridRotation());
if (numFound > 0)
{
if (m_GridDepthType == GridDepthType.Counting)
{
ParseCollidersAll(m_ColliderBuffer, numFound, cellIndex, cellCenter);
}
else
{
ParseCollidersClosest(m_ColliderBuffer, numFound, cellIndex, cellCenter);
}
}
}
}
}
/// <summary>
/// This method attempts to perform the Physics.OverlapBoxNonAlloc and will double the size of the Collider buffer
/// if the number of Colliders in the buffer after the call is equal to the length of the buffer.
/// </summary>
/// <param name="cellCenter"></param>
/// <param name="halfCellScale"></param>
/// <param name="rotation"></param>
/// <returns></returns>
int BufferResizingOverlapBoxNonAlloc(Vector3 cellCenter, Vector3 halfCellScale, Quaternion rotation)
{
int numFound;
// Since we can only get a fixed number of results, requery
// until we're sure we can hold them all (or until we hit the max size).
while (true)
{
numFound = Physics.OverlapBoxNonAlloc(cellCenter, halfCellScale, m_ColliderBuffer, rotation, m_ColliderMask);
if (numFound == m_ColliderBuffer.Length && m_ColliderBuffer.Length < m_MaxColliderBufferSize)
{
m_ColliderBuffer = new Collider[Math.Min(m_MaxColliderBufferSize, m_ColliderBuffer.Length * 2)];
m_InitialColliderBufferSize = m_ColliderBuffer.Length;
}
else
{
break;
}
}
return numFound;
}
/// <summary>
/// Parses the array of colliders found within a cell. Finds the closest gameobject to the agent root reference within the cell
/// </summary>
/// <param name="foundColliders">Array of the colliders found within the cell</param>
/// <param name="numFound">Number of colliders found.</param>
/// <param name="cellIndex">The index of the cell</param>
/// <param name="cellCenter">The center position of the cell</param>
void ParseCollidersClosest(Collider[] foundColliders, int numFound, int cellIndex, Vector3 cellCenter)
{
Profiler.BeginSample("GridSensor.ParseColliders");
GameObject closestColliderGo = null;
var minDistanceSquared = float.MaxValue;
for (var i = 0; i < numFound; i++)
{
var currentColliderGo = foundColliders[i].gameObject;
// Continue if the current collider go is the root reference
if (ReferenceEquals(currentColliderGo, m_RootReference))
continue;
var closestColliderPoint = foundColliders[i].ClosestPointOnBounds(cellCenter);
var currentDistanceSquared = (closestColliderPoint - m_RootReference.transform.position).sqrMagnitude;
// Checks if our colliders contain a detectable object
var index = -1;
for (var ii = 0; ii < m_DetectableObjects.Length; ii++)
{
if (currentColliderGo.CompareTag(m_DetectableObjects[ii]))
{
index = ii;
break;
}
}
if (index > -1 && currentDistanceSquared < minDistanceSquared)
{
minDistanceSquared = currentDistanceSquared;
closestColliderGo = currentColliderGo;
}
}
if (!ReferenceEquals(closestColliderGo, null))
{
LoadObjectData(closestColliderGo, cellIndex);
}
Profiler.EndSample();
}
/// <summary>
/// For each collider, calls LoadObjectData on the gameobejct
/// </summary>
/// <param name="foundColliders">The array of colliders</param>
/// <param name="cellIndex">The cell index the collider is in</param>
/// <param name="cellCenter">the center of the cell the collider is in</param>
void ParseCollidersAll(Collider[] foundColliders, int numFound, int cellIndex, Vector3 cellCenter)
{
Profiler.BeginSample("GridSensor.ParseColliders");
GameObject currentColliderGo = null;
Vector3 closestColliderPoint = Vector3.zero;
for (int i = 0; i < numFound; i++)
{
currentColliderGo = foundColliders[i].gameObject;
// Continue if the current collider go is the root reference
if (currentColliderGo == m_RootReference)
continue;
closestColliderPoint = foundColliders[i].ClosestPointOnBounds(cellCenter);
LoadObjectData(currentColliderGo, cellIndex);
}
Profiler.EndSample();
}
/// <summary>
/// GetObjectData - returns an array of values that represent the game object
/// This is one of the few methods that one may need to override to get their required functionality
/// For instance, if one wants specific information about the current gameobject, they can use this method
/// to extract it and then return it in an array format.
/// </summary>
/// <returns>
/// A float[] containing the data that holds the representative information of the passed in gameObject
/// </returns>
/// <param name="currentColliderGo">The game object that was found colliding with a certain cell</param>
/// <param name="typeIndex">The index of the type (tag) of the gameObject.
/// (e.g., if this GameObject had the 3rd tag out of 4, type_index would be 2.0f)</param>
/// <param name="normalizedDistance">A float between 0 and 1 describing the ratio of
/// the distance currentColliderGo is compared to the edge of the gridsensor</param>
/// <example>
/// Here is an example of extenind GetObjectData to include information about a potential Rigidbody:
/// <code>
/// protected override float[] GetObjectData(GameObject currentColliderGo,
/// float type_index, float normalized_distance)
/// {
/// float[] channelValues = new float[ChannelDepth.Length]; // ChannelDepth.Length = 4 in this example
/// channelValues[0] = type_index;
/// Rigidbody goRb = currentColliderGo.GetComponent&lt;Rigidbody&gt;();
/// if (goRb != null)
/// {
/// channelValues[1] = goRb.velocity.x;
/// channelValues[2] = goRb.velocity.y;
/// channelValues[3] = goRb.velocity.z;
/// }
/// return channelValues;
/// }
/// </code>
/// </example>
protected virtual float[] GetObjectData(GameObject currentColliderGo, int typeIndex)
{
Array.Clear(m_CellDataBuffer, 0, m_CellDataBuffer.Length);
m_CellDataBuffer[0] = typeIndex;
return m_CellDataBuffer;
}
/// <summary>
/// Runs basic validation assertions to check that the values can be normalized
/// </summary>
/// <param name="channelValues">The values to be validated</param>
/// <param name="currentColliderGo">The gameobject used for better error messages</param>
protected virtual void ValidateValues(float[] channelValues, GameObject currentColliderGo)
{
for (int j = 0; j < channelValues.Length; j++)
{
if (channelValues[j] < 0)
throw new UnityAgentsException("Expected ChannelValue[" + j + "] for " + currentColliderGo.name + " to be non-negative, was " + channelValues[j]);
if (channelValues[j] > m_ChannelDepths[j])
throw new UnityAgentsException("Expected ChannelValue[" + j + "] for " + currentColliderGo.name + " to be less than ChannelDepth[" + j + "] (" + m_ChannelDepths[j] + "), was " + channelValues[j]);
}
}
/// <summary>
/// LoadObjectData - If the GameObject matches a tag, GetObjectData is called to extract the data from the GameObject
/// then the data is transformed based on the GridDepthType of the gridsensor.
/// Further documetation on the GridDepthType can be found below
/// </summary>
/// <param name="currentColliderGo">The game object that was found colliding with a certain cell</param>
/// <param name="cellIndex">The index of the current cell</param>
protected virtual void LoadObjectData(GameObject currentColliderGo, int cellIndex)
{
Profiler.BeginSample("GridSensor.LoadObjectData");
var channelHotVals = new ArraySegment<float>(m_PerceptionBuffer, cellIndex * m_CellObservationSize, m_CellObservationSize);
for (var i = 0; i < m_DetectableObjects.Length; i++)
{
if (!ReferenceEquals(currentColliderGo, null) && currentColliderGo.CompareTag(m_DetectableObjects[i]))
{
// TODO: Create the array already then set the values using "out" in GetObjectData
var channelValues = GetObjectData(currentColliderGo, i);
ValidateValues(channelValues, currentColliderGo);
switch (m_GridDepthType)
{
case GridDepthType.Channel:
{
// The observations are "channel based" so each grid is WxHxC where C is the number of channels
// This typically means that each channel value is normalized between 0 and 1
// If channelDepth is 1, the value is assumed normalized, else the value is normalized by the channelDepth
// The channels are then stored consecutively in PerceptionBuffer.
// NOTE: This is the only grid type that uses floating point values
// For example, if a cell contains the 3rd type of 5 possible on the 2nd team of 3 possible teams:
// channelValues = {2, 1}
// ObservationPerCell = channelValues.Length
// channelValues = {2f/5f, 1f/3f} = {.4, .33..}
// Array.Copy(channelValues, 0, PerceptionBuffer, cell_id*ObservationPerCell, ObservationPerCell);
for (int j = 0; j < channelValues.Length; j++)
{
channelValues[j] /= m_ChannelDepths[j];
}
Array.Copy(channelValues, 0, m_PerceptionBuffer, cellIndex * m_CellObservationSize, m_CellObservationSize);
break;
}
case GridDepthType.ChannelHot:
{
// The observations are "channel hot" so each grid is WxHxD where D is the sum of all of the channel depths
// The opposite of the "channel based" case, the channel values are represented as one hot vector per channel and then concatenated together
// Thus channelDepth is assumed to be greater than 1.
// For example, if a cell contains the 3rd type of 5 possible on the 2nd team of 3 possible teams,
// channelValues = {2, 1}
// channelOffsets = {5, 3}
// ObservationPerCell = 5 + 3 = 8
// channelHotVals = {0, 0, 1, 0, 0, 0, 1, 0}
// Array.Copy(channelHotVals, 0, PerceptionBuffer, cell_id*ObservationPerCell, ObservationPerCell);
for (int j = 0; j < channelValues.Length; j++)
{
if (m_ChannelDepths[j] > 1)
{
m_PerceptionBuffer[channelHotVals.Offset + (int)channelValues[j] + m_ChannelOffsets[j]] = 1f;
}
else
{
m_PerceptionBuffer[channelHotVals.Offset + m_ChannelOffsets[j]] = channelValues[j];
}
}
break;
}
case GridDepthType.Counting:
{
// The observations are "channel count" so each grid is WxHxC where C is the number of tags
// This means that each value channelValues[i] is a counter of gameobject included into grid cells
// where i is the index of the tag in DetectableObjects
int countIndex = cellIndex * m_CellObservationSize + i;
m_PerceptionBuffer[countIndex] = Mathf.Min(1f, m_PerceptionBuffer[countIndex] + 1f / m_ChannelDepths[i]);
break;
}
}
break;
}
}
Profiler.EndSample();
}
/// <summary>Converts the index of the cell to the 3D point (y is zero) relative to grid center</summary>
/// <returns>Vector3 of the position of the center of the cell relative to grid center</returns>
/// <param name="cell">The index of the cell</param>
Vector3 CellToLocalPoint(int cellIndex)
{
float x = (cellIndex / m_GridSize.z - m_CellCenterOffset.x) * m_CellScale.x;
float z = (cellIndex % m_GridSize.z - m_CellCenterOffset.z) * m_CellScale.z;
return new Vector3(x, 0, z);
}
internal Vector3 GetCellGlobalPosition(int cellIndex)
{
if (m_RotateWithAgent)
{
return m_RootReference.transform.TransformPoint(m_CellLocalPositions[cellIndex]);
}
else
{
return m_CellLocalPositions[cellIndex] + m_RootReference.transform.position;
}
}
internal Quaternion GetGridRotation()
{
return m_RotateWithAgent ? m_RootReference.transform.rotation : Quaternion.identity;
}
/// <inheritdoc/>
public void Update()
{
using (TimerStack.Instance.Scoped("GridSensor.Update"))
{
Perceive();
}
}
/// <inheritdoc/>
public ObservationSpec GetObservationSpec()
{
return m_ObservationSpec;
}
/// <inheritdoc/>
public int Write(ObservationWriter writer)
{
using (TimerStack.Instance.Scoped("GridSensor.Write"))
{
int index = 0;
for (var h = m_GridSize.z - 1; h >= 0; h--)
{
for (var w = 0; w < m_GridSize.x; w++)
{
for (var d = 0; d < m_CellObservationSize; d++)
{
writer[h, w, d] = m_PerceptionBuffer[index];
index++;
}
}
}
return index;
}
}
internal int[] PerceiveGizmoColor()
{
ResetGizmoBuffer();
var halfCellScale = new Vector3(m_CellScale.x / 2f, m_CellScale.y, m_CellScale.z / 2f);
for (var cellIndex = 0; cellIndex < m_NumCells; cellIndex++)
{
var cellCenter = GetCellGlobalPosition(cellIndex);
var numFound = BufferResizingOverlapBoxNonAlloc(cellCenter, halfCellScale, GetGridRotation());
var minDistanceSquared = float.MaxValue;
var tagIndex = -1;
for (var i = 0; i < numFound; i++)
{
var currentColliderGo = m_ColliderBuffer[i].gameObject;
if (ReferenceEquals(currentColliderGo, m_RootReference))
continue;
var closestColliderPoint = m_ColliderBuffer[i].ClosestPointOnBounds(cellCenter);
var currentDistanceSquared = (closestColliderPoint - m_RootReference.transform.position).sqrMagnitude;
// Checks if our colliders contain a detectable object
var index = -1;
for (var ii = 0; ii < m_DetectableObjects.Length; ii++)
{
if (currentColliderGo.CompareTag(m_DetectableObjects[ii]))
{
index = ii;
break;
}
}
if (index > -1 && currentDistanceSquared < minDistanceSquared)
{
minDistanceSquared = currentDistanceSquared;
tagIndex = index;
}
}
m_GizmoColorIndexes[cellIndex] = tagIndex;
}
return m_GizmoColorIndexes;
}
internal Vector3[] GetGizmoPositions()
{
for (var i = 0; i < m_NumCells; i++)
{
m_CellGlobalPosition[i] = GetCellGlobalPosition(i);
}
return m_CellGlobalPosition;
}
}
}

8
com.unity.ml-agents.extensions/Tests/Editor/Sensors.meta


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

8
com.unity.ml-agents.extensions/Tests/Utils.meta


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

/com.unity.ml-agents.extensions/Runtime/Sensors/GridSensor.cs.meta → /com.unity.ml-agents.extensions/Runtime/Sensors/BoxOverlapChecker.cs.meta

/com.unity.ml-agents.extensions/Tests/Editor/Sensors/ChannelHotPerceiveTests.cs.meta → /com.unity.ml-agents.extensions/Tests/Editor/GridSensors/BoxOverlapCheckerTests.cs.meta

/com.unity.ml-agents.extensions/Tests/Editor/Sensors/ChannelHotShapeTests.cs.meta → /com.unity.ml-agents.extensions/Tests/Editor/GridSensors/GridSensorTests.cs.meta

/com.unity.ml-agents.extensions/Tests/Editor/Sensors/ChannelPerceiveTests.cs.meta → /com.unity.ml-agents.extensions/Runtime/Sensors/CountingGridSensor.cs.meta

/com.unity.ml-agents.extensions/Tests/Editor/Sensors/ChannelShapeTests.cs.meta → /com.unity.ml-agents.extensions/Runtime/Sensors/GridSensorBase.cs.meta

/com.unity.ml-agents.extensions/Tests/Editor/Sensors/CountingGridSensorPerceiveTests.cs.meta → /com.unity.ml-agents.extensions/Runtime/Sensors/OneHotGridSensor.cs.meta

/com.unity.ml-agents.extensions/Tests/Editor/Sensors/GridSensorTestUtils.cs.meta → /com.unity.ml-agents.extensions/Tests/Editor/GridSensors/GridSensorTestUtils.cs.meta

/com.unity.ml-agents.extensions/Tests/Utils/GridObsTestComponents/SimpleTestGridSensor.cs.meta → /com.unity.ml-agents.extensions/Tests/Editor/GridSensors/SimpleTestGridSensor.cs.meta

正在加载...
取消
保存