public IEnumerator RayInteractorSamplePointsContinuesThroughGeometry([ValueSource(nameof(s_LineTypes))] XRRayInteractor.LineType lineType) { TestUtilities.CreateInteractionManager(); TestUtilities.CreateXRRig(); var interactor = TestUtilities.CreateRayInteractor(); interactor.xrController.enabled = false; interactor.transform.position = Vector3.zero; interactor.transform.rotation = Quaternion.Euler(-45f, 0f, 0f); const int sampleFrequency = 5; interactor.sampleFrequency = sampleFrequency; interactor.maxRaycastDistance = 20f; // These produce a curve that is the rough equivalent of the default projectile curve // in order to keep the assertions the same between the test cases. interactor.controlPointHeight = 0f; interactor.controlPointDistance = 22.6f; interactor.endPointHeight = -38.9f; interactor.endPointDistance = 45.2f; interactor.lineType = lineType; var lineVisual = interactor.GetComponent <XRInteractorLineVisual>(); Assert.That(lineVisual, Is.Not.Null); Assert.That(lineVisual.enabled, Is.True); lineVisual.overrideInteractorLineLength = false; lineVisual.stopLineAtFirstRaycastHit = false; var lineRenderer = interactor.GetComponent <LineRenderer>(); Assert.That(lineRenderer, Is.Not.Null); Assert.That(lineRenderer.enabled, Is.True); yield return(null); Vector3[] samplePoints = null; var isValid = interactor.GetLinePoints(ref samplePoints, out var samplePointsCount); Assert.That(isValid, Is.True); Assert.That(samplePoints, Is.Not.Null); Assert.That(samplePointsCount, Is.EqualTo(lineType == XRRayInteractor.LineType.StraightLine ? 2 : sampleFrequency)); Assert.That(samplePoints.Length, Is.GreaterThanOrEqualTo(samplePointsCount)); // Verify that the Ray Interactor is not hitting anything var isHitInfoValid = interactor.TryGetHitInfo(out _, out _, out var hitPositionInLine, out var isValidTarget); Assert.That(isHitInfoValid, Is.False); Assert.That(isValidTarget, Is.False); Assert.That(hitPositionInLine, Is.EqualTo(0)); yield return(null); // The Line Renderer should match Assert.That(lineVisual.enabled, Is.True); Assert.That(lineRenderer.enabled, Is.True); var lineRendererPositions = new Vector3[samplePointsCount]; // LineRenderer.GetPositions always returns 0 when running with the -batchmode flag if (!Application.isBatchMode) { var lineRendererPositionsCount = lineRenderer.GetPositions(lineRendererPositions); Assert.That(lineRendererPositionsCount, Is.EqualTo(samplePointsCount)); Assert.That(lineRendererPositions, Is.EquivalentTo(samplePoints).Using(Vector3ComparerWithEqualsOperator.Instance)); Assert.That(lineRenderer.positionCount, Is.EqualTo(samplePointsCount)); } // Create and place a plane between sample index 1 and 2 var plane = GameObject.CreatePrimitive(PrimitiveType.Plane); plane.transform.localPosition = new Vector3(0f, 0f, 13f); plane.transform.localRotation = Quaternion.Euler(-90f, 0f, 0f); plane.transform.localScale = new Vector3(10f, 1f, 10f); // Wait for Physics update for hit and onBeforeRender callback to be invoked in XRInteractorLineVisual yield return(new WaitForFixedUpdate()); yield return(null); yield return(null); // Verify that the Ray Interactor is hitting the plane isHitInfoValid = interactor.TryGetHitInfo(out var hitPosition, out var hitNormal, out hitPositionInLine, out isValidTarget); Assert.That(isHitInfoValid, Is.True); Assert.That(isValidTarget, Is.False); Assert.That(hitPositionInLine, Is.EqualTo(lineType == XRRayInteractor.LineType.StraightLine ? 1 : 2)); Assert.That(hitPosition.z, Is.EqualTo(plane.transform.position.z).Using(FloatEqualityComparer.Instance)); Assert.That(hitNormal, Is.EqualTo(plane.transform.up).Using(Vector3ComparerWithEqualsOperator.Instance)); // The sample points should continue beyond the hit to allow the // Line Visual behavior to render them Vector3[] samplePointsWithPlane = null; isValid = interactor.GetLinePoints(ref samplePointsWithPlane, out var samplePointsCountWithPlane); Assert.That(isValid, Is.True); Assert.That(samplePointsWithPlane, Is.Not.Null); Assert.That(samplePointsCountWithPlane, Is.EqualTo(lineType == XRRayInteractor.LineType.StraightLine ? 2 : sampleFrequency)); Assert.That(samplePointsWithPlane.Length, Is.GreaterThanOrEqualTo(samplePointsCountWithPlane)); Assert.That(samplePointsWithPlane, Is.EquivalentTo(samplePoints).Using(Vector3ComparerWithEqualsOperator.Instance)); // The Line Renderer should still match Assert.That(lineVisual.enabled, Is.True); Assert.That(lineRenderer.enabled, Is.True); if (!Application.isBatchMode) { var lineRendererPositionsCount = lineRenderer.GetPositions(lineRendererPositions); Assert.That(lineRendererPositionsCount, Is.EqualTo(samplePointsCount)); Assert.That(lineRendererPositions, Is.EquivalentTo(samplePoints).Using(Vector3ComparerWithEqualsOperator.Instance)); Assert.That(lineRenderer.positionCount, Is.EqualTo(samplePointsCount)); } lineVisual.stopLineAtFirstRaycastHit = true; // Wait for onBeforeRender callback to be invoked in XRInteractorLineVisual yield return(null); yield return(null); // The Line Renderer should now stop at the first hit Assert.That(lineVisual.enabled, Is.True); Assert.That(lineRenderer.enabled, Is.True); if (!Application.isBatchMode) { var lineRendererPositionsCount = lineRenderer.GetPositions(lineRendererPositions); Assert.That(lineRendererPositionsCount, Is.EqualTo(hitPositionInLine + 1)); var expectedLineRendererPositions = samplePoints.Take(hitPositionInLine).ToList(); expectedLineRendererPositions.Add(hitPosition); Assert.That(lineRendererPositions.Take(hitPositionInLine + 1), Is.EquivalentTo(expectedLineRendererPositions).Using(Vector3ComparerWithEqualsOperator.Instance)); Assert.That(lineRenderer.positionCount, Is.EqualTo(hitPositionInLine + 1)); } }
public IEnumerator RayInteractorHitsAllAlongCurve([ValueSource(nameof(s_LineTypes))] XRRayInteractor.LineType lineType) { TestUtilities.CreateInteractionManager(); TestUtilities.CreateXRRig(); var interactor = TestUtilities.CreateRayInteractor(); interactor.xrController.enabled = false; const int sampleFrequency = 5; interactor.sampleFrequency = sampleFrequency; interactor.hitClosestOnly = false; interactor.lineType = lineType; yield return(null); // Get the Sample Points to determine where to place the Interactable Planes in different segments Vector3[] samplePoints = null; var isValid = interactor.GetLinePoints(ref samplePoints, out var samplePointsCount); Assert.That(isValid, Is.True); Assert.That(samplePoints, Is.Not.Null); Assert.That(samplePointsCount, Is.EqualTo(lineType == XRRayInteractor.LineType.StraightLine ? 2 : sampleFrequency)); Assert.That(samplePoints.Length, Is.GreaterThanOrEqualTo(samplePointsCount)); // Verify that valid targets and hover targets is empty var targets = new List <XRBaseInteractable>(); interactor.GetValidTargets(targets); Assert.That(targets, Is.Empty); interactor.GetHoverTargets(targets); Assert.That(targets, Is.Empty); // Create two Interactable Planes such that they are within two separate line segments of the curve // (although for Straight Line, there is only the one line segment). // Add Interactable Plane near the end of the curve var from = samplePoints[samplePointsCount - 2]; var to = samplePoints[samplePointsCount - 1]; var farInteractable = CreatePlaneInteractable(Vector3.Lerp(from, to, 0.75f)); // Add Interactable Plane near the start of the curve from = samplePoints[0]; to = samplePoints[1]; var nearInteractable = CreatePlaneInteractable(Vector3.Lerp(from, to, 0.25f)); // Wait for Physics update for hit yield return(new WaitForFixedUpdate()); yield return(null); // Verify that both Interactable Planes are hit interactor.GetValidTargets(targets); Assert.That(targets, Is.EqualTo(new[] { nearInteractable, farInteractable })); interactor.GetHoverTargets(targets); Assert.That(targets, Is.EqualTo(new[] { nearInteractable, farInteractable })); XRBaseInteractable CreatePlaneInteractable(Vector3 position) { var planeGO = GameObject.CreatePrimitive(PrimitiveType.Plane); var interactable = planeGO.AddComponent <XRSimpleInteractable>(); planeGO.transform.localPosition = position; planeGO.transform.localRotation = Quaternion.Euler(-90f, 0f, 0f); planeGO.transform.localScale = new Vector3(100f, 1f, 100f); return(interactable); } }