private bool UserIsOnNavMesh(StepByStepComponent sbs, TeleportNavMesh tnm, VRRaycastOutputs raycastOutputs, LayerMask excludedLayers, out float3 newCameraRigPos) { Transform vrCamTransform = VRSF_Components.VRCamera.transform; Transform cameraRigTransform = VRSF_Components.CameraRig.transform; // We calculate the direction and the distance Vectors var directionVector = raycastOutputs.RayVar.direction; float distanceVector = cameraRigTransform.localScale.y * sbs.DistanceStepByStep; // Check if we hit a collider on the way. If it's the case, we reduce the distance. if (Physics.Raycast(vrCamTransform.position, directionVector, out RaycastHit hit, distanceVector, ~excludedLayers)) { distanceVector = hit.distance - 0.1f; } // We multiply the direction vector by the distance to which the user should be going directionVector *= distanceVector; // We check the theoritic position for the cameraRig newCameraRigPos = GetNewTheoriticPos(directionVector, true); // We check the theoritic new user pos float3 newCameraPos = GetNewTheoriticPos(directionVector, false); // We calculate a vector down based on the new Camera Pos. var downVectorDistance = Mathf.Abs(vrCamTransform.localPosition.y + VRSF_Components.FloorOffset.transform.localPosition.y) + sbs.StepHeight; var downVector = newCameraPos + (new float3(0.0f, -1.0f, 0.0f) * downVectorDistance); // We calculate the linecast between the newUserPos and the downVector and check if it hits the NavMesh TeleportNavMeshHelper.Linecast ( newCameraPos, downVector, out bool endOnNavmesh, excludedLayers, out newCameraPos, out _, tnm ); // We set the camera rig pos in y to the camera pos in y newCameraRigPos.y = newCameraPos.y; return(endOnNavmesh); /// <summary> /// We get the theoritic position for the CameraRig and the VRCamera based on the scaled direction (direction * distance) /// </summary> /// <param name="scaledDirection">The direction multiplied by the distance to go to</param> /// <param name="isCheckingCameraRig">Whether the check is for the CameraRig or the VRCamera</param> /// <returns>The new Theoritic position</returns> float3 GetNewTheoriticPos(Vector3 scaledDirection, bool isCheckingCameraRig) { float3 origin = isCheckingCameraRig ? cameraRigTransform.position : vrCamTransform.position; return(origin + new float3(scaledDirection.x, 0.0f, scaledDirection.z)); } }
/// <summary> /// Sample a bunch of points along a parabolic curve until you hit gnd. At that point, cut off the parabola /// </summary> /// /// <param name="p0">starting point of parabola</param> /// <param name="v0">initial parabola velocity</param> /// <param name="a">initial acceleration</param> /// <param name="dist">distance between sample points</param> /// <param name="points">number of sample points</param> /// <param name="tnm">Vive Nav Mesh used to teleport</param> /// <param name="outPts">List that will be populated by new points</param> /// <param name="normal">normal of hit point</param> /// /// <returns>true if the the parabole is at the end of the NavMesh</returns> private static bool CalculateParabolicCurve(float3 p0, Vector3 v0, Vector3 a, float dist, int points, TeleportNavMesh tnm, int excludedLayer, out NativeArray <Translation> outPts, out float3 normal, out int lastPointIndex) { // Init new list of points with p0 as the first point outPts = new NativeArray <Translation>(points, Allocator.TempJob); outPts[0] = new Translation { Value = p0 }; float3 last = p0; float t = 0; for (int i = 0; i < points; i++) { t += dist / ParabolicCurveDeriv(v0, a, t).magnitude; float3 next = ParabolicCurve(p0, v0, a, t); if (TeleportNavMeshHelper.Linecast(last, next, out bool endOnNavmesh, excludedLayer, out float3 castHit, out float3 norm, tnm)) { outPts[i] = new Translation { Value = castHit }; normal = norm; lastPointIndex = i; return(endOnNavmesh); }
/// <summary> /// Calculate the points on the way of the Parabola /// </summary> /// <param name="e">The reference to the entity to check</param> /// <param name="velocity">The velocity of the Parabole</param> /// <returns>The normal of the Curve</returns> public static float3 ParabolaPointsCalculations(ref NativeArray <Translation> pp, ref CurveTeleporterCalculations ctc, ParabolPointsParameters ppp, TeleportNavMesh tnm, float3 parabolOrigin, LayerMask excludedLayer, Vector3 velocity) { ctc.PointOnNavMesh = CalculateParabolicCurve ( parabolOrigin, velocity, ctc.Acceleration, ppp.PointSpacing, ppp.PointCount, tnm, excludedLayer, out pp, out float3 normal, out ctc.LastPointIndex ); ctc.PointToGoTo = pp[ctc.LastPointIndex].Value; return(normal); }
/// <summary> /// Casts a ray against the Navmesh and attempts to calculate the ray's worldspace intersection with it. /// This uses Physics raycasts to perform the raycast calculation, so the teleport surface must have a collider on it. /// </summary> /// /// <param name="p1">First (origin) point of ray</param> /// <param name="p2">Last (end) point of ray</param> /// <param name="pointOnNavmesh">If the raycast hit something on the navmesh</param> /// <param name="hitPoint">If hit, the point of the hit. Otherwise zero.</param> /// <param name="normal">If hit, the normal of the hit surface. Otherwise (0, 1, 0)</param> /// /// <returns>If the raycast hit something.</returns> public static bool Linecast(float3 p1, float3 p2, out bool pointOnNavmesh, int excludedLayer, out float3 hitPoint, out float3 normal, TeleportNavMesh tnm) { Vector3 dir = p2 - p1; float dist = dir.magnitude; dir /= dist; if (Physics.Raycast(p1, dir, out RaycastHit hit, dist, ~excludedLayer, (QueryTriggerInteraction)tnm.QueryTriggerInteraction)) { normal = hit.normal; hitPoint = hit.point; if (tnm.IgnoreSlopedSurfaces && math.dot(Vector3.up, hit.normal) < 0.99f) { pointOnNavmesh = false; return(true); } pointOnNavmesh = NavMesh.SamplePosition(hitPoint, out NavMeshHit navHit, tnm.SampleRadius, tnm.NavAreaMask); // Get the closest position on the navMesh if (Vector3IsCorrect(navHit.position)) { hitPoint = navHit.position; } return(true); }