/// <summary> /// Creates the RayPerceptionSensor. /// </summary> /// <param name="name">The name of the sensor.</param> /// <param name="rayInput">The inputs for the sensor.</param> public RayPerceptionSensor(string name, RayPerceptionInput rayInput) { m_Name = name; m_RayPerceptionInput = rayInput; SetNumObservations(rayInput.OutputSize()); m_DebugLastFrameCount = Time.frameCount; m_RayPerceptionOutput = new RayPerceptionOutput(); }
/// <summary> /// Creates the RayPerceptionSensor. /// </summary> /// <param name="name">The name of the sensor.</param> /// <param name="rayInput">The inputs for the sensor.</param> public RayPerceptionSensor(string name, RayPerceptionInput rayInput) { m_Name = name; m_RayPerceptionInput = rayInput; SetNumObservations(rayInput.OutputSize()); if (Application.isEditor) { m_DebugDisplayInfo = new DebugDisplayInfo(); } }
/// <summary> /// Evaluates the raycasts to be used as part of an observation of an agent. /// </summary> /// <param name="input">Input defining the rays that will be cast.</param> /// <returns>Output struct containing the raycast results.</returns> public static RayPerceptionOutput Perceive(RayPerceptionInput input) { RayPerceptionOutput output = new RayPerceptionOutput(); output.RayOutputs = new RayPerceptionOutput.RayOutput[input.Angles.Count]; for (var rayIndex = 0; rayIndex < input.Angles.Count; rayIndex++) { output.RayOutputs[rayIndex] = PerceiveSingleRay(input, rayIndex); } return(output); }
internal void SetRayPerceptionInput(RayPerceptionInput rayInput) { // Note that change the number of rays or tags doesn't directly call this, // but changing them and then changing another field will. if (m_RayPerceptionInput.OutputSize() != rayInput.OutputSize()) { Debug.Log( "Changing the number of tags or rays at runtime is not " + "supported and may cause errors in training or inference." ); // Changing the shape will probably break things downstream, but we can at least // keep this consistent. SetNumObservations(rayInput.OutputSize()); } m_RayPerceptionInput = rayInput; }
/// <summary> /// Evaluate the raycast results of a single ray from the RayPerceptionInput. /// </summary> /// <param name="input"></param> /// <param name="rayIndex"></param> /// <param name="debugRayOut"></param> /// <returns></returns> internal static RayPerceptionOutput.RayOutput PerceiveSingleRay( RayPerceptionInput input, int rayIndex, out DebugDisplayInfo.RayInfo debugRayOut ) { var unscaledRayLength = input.RayLength; var unscaledCastRadius = input.CastRadius; var extents = input.RayExtents(rayIndex); var startPositionWorld = extents.StartPositionWorld; var endPositionWorld = extents.EndPositionWorld; var rayDirection = endPositionWorld - startPositionWorld; // If there is non-unity scale, |rayDirection| will be different from rayLength. // We want to use this transformed ray length for determining cast length, hit fraction etc. // We also it to scale up or down the sphere or circle radii var scaledRayLength = rayDirection.magnitude; // Avoid 0/0 if unscaledRayLength is 0 var scaledCastRadius = unscaledRayLength > 0 ? unscaledCastRadius * scaledRayLength / unscaledRayLength : unscaledCastRadius; // Do the cast and assign the hit information for each detectable tag. bool castHit; float hitFraction; GameObject hitObject; if (input.CastType == RayPerceptionCastType.Cast3D) { RaycastHit rayHit; if (scaledCastRadius > 0f) { castHit = Physics.SphereCast(startPositionWorld, scaledCastRadius, rayDirection, out rayHit, scaledRayLength, input.LayerMask); } else { castHit = Physics.Raycast(startPositionWorld, rayDirection, out rayHit, scaledRayLength, input.LayerMask); } // If scaledRayLength is 0, we still could have a hit with sphere casts (maybe?). // To avoid 0/0, set the fraction to 0. hitFraction = castHit ? (scaledRayLength > 0 ? rayHit.distance / scaledRayLength : 0.0f) : 1.0f; hitObject = castHit ? rayHit.collider.gameObject : null; } else { RaycastHit2D rayHit; if (scaledCastRadius > 0f) { rayHit = Physics2D.CircleCast(startPositionWorld, scaledCastRadius, rayDirection, scaledRayLength, input.LayerMask); } else { rayHit = Physics2D.Raycast(startPositionWorld, rayDirection, scaledRayLength, input.LayerMask); } castHit = rayHit; hitFraction = castHit ? rayHit.fraction : 1.0f; hitObject = castHit ? rayHit.collider.gameObject : null; } var rayOutput = new RayPerceptionOutput.RayOutput { HasHit = castHit, HitFraction = hitFraction, HitTaggedObject = false, HitTagIndex = -1, HitGameObject = hitObject }; if (castHit) { // Find the index of the tag of the object that was hit. var numTags = input.DetectableTags?.Count ?? 0; for (var i = 0; i < numTags; i++) { var tagsEqual = false; try { var tag = input.DetectableTags[i]; if (!string.IsNullOrEmpty(tag)) { tagsEqual = hitObject.CompareTag(tag); } } catch (UnityException e) { // If the tag is null, empty, or not a valid tag, just ignore it. } if (tagsEqual) { rayOutput.HitTaggedObject = true; rayOutput.HitTagIndex = i; break; } } } debugRayOut.worldStart = startPositionWorld; debugRayOut.worldEnd = endPositionWorld; debugRayOut.rayOutput = rayOutput; debugRayOut.castRadius = scaledCastRadius; return(rayOutput); }
/// <summary> /// Evaluate the raycast results of a single ray from the RayPerceptionInput. /// </summary> /// <param name="input"></param> /// <param name="rayIndex"></param> /// <param name="debugRayOut"></param> /// <returns></returns> internal static RayPerceptionOutput.RayOutput PerceiveSingleRay( RayPerceptionInput input, int rayIndex, out DebugDisplayInfo.RayInfo debugRayOut ) { var unscaledRayLength = input.RayLength; var unscaledCastRadius = input.CastRadius; var extents = input.RayExtents(rayIndex); var startPositionWorld = extents.StartPositionWorld; var endPositionWorld = extents.EndPositionWorld; var rayDirection = endPositionWorld - startPositionWorld; // If there is non-unity scale, |rayDirection| will be different from rayLength. // We want to use this transformed ray length for determining cast length, hit fraction etc. // We also it to scale up or down the sphere or circle radii var scaledRayLength = rayDirection.magnitude; // Avoid 0/0 if unscaledRayLength is 0 var scaledCastRadius = unscaledRayLength > 0 ? unscaledCastRadius * scaledRayLength / unscaledRayLength : unscaledCastRadius; // Do the cast and assign the hit information for each detectable tag. bool castHit; float hitFraction; GameObject hitObject; RaycastHit rayHit = new RaycastHit();; if (input.CastType == RayPerceptionCastType.Cast3D) { if (scaledCastRadius > 0f) { // castHit = Physics.SphereCast(startPositionWorld, scaledCastRadius, rayDirection, out rayHit, // scaledRayLength, input.LayerMask); System.Random rnd = new System.Random(); castHit = (rnd.Next(2) == 0); } else { // castHit = Physics.Raycast(startPositionWorld, rayDirection, out rayHit, // scaledRayLength, input.LayerMask); System.Random rnd = new System.Random(); castHit = (rnd.Next(2) == 0); } // If scaledRayLength is 0, we still could have a hit with sphere casts (maybe?). // To avoid 0/0, set the fraction to 0. hitFraction = castHit ? (scaledRayLength > 0 ? rayHit.distance / scaledRayLength : 0.0f) : 1.0f; // hitObject = castHit ? rayHit.collider.gameObject : null; } else { RaycastHit2D ray2Hit; if (scaledCastRadius > 0f) { ray2Hit = Physics2D.CircleCast(startPositionWorld, scaledCastRadius, rayDirection, scaledRayLength, input.LayerMask); } else { ray2Hit = Physics2D.Raycast(startPositionWorld, rayDirection, scaledRayLength, input.LayerMask); } castHit = ray2Hit; hitFraction = castHit ? ray2Hit.fraction : 1.0f; // hitObject = castHit ? ray2Hit.collider.gameObject : null; } var rayOutput = new RayPerceptionOutput.RayOutput { HasHit = castHit, HitFraction = hitFraction, HitTaggedObject = false, HitTagIndex = -1 }; if (castHit) { // Find the index of the tag of the object that was hit. for (var i = 0; i < input.DetectableTags.Count; i++) { // if (hitObject.CompareTag(input.DetectableTags[i])) // { rayOutput.HitTaggedObject = true; rayOutput.HitTagIndex = i; break; // } } } debugRayOut.worldStart = startPositionWorld; debugRayOut.worldEnd = endPositionWorld; debugRayOut.rayOutput = rayOutput; debugRayOut.castRadius = scaledCastRadius; return(rayOutput); }