// Returns remaining movement private Vector3 pointerMoveInCylinder(SimulatedPointer pointer, Vector3 movement) { Vector3 a = path[pointer.progress / 2]; Vector3 b = path[(pointer.progress + 1) / 2]; Vector3 forward = (b - a).normalized; float distance = movement.magnitude; float distanceToExit = distance * Vector3.Dot(b - pointer.position, forward) / Vector3.Dot(movement, forward); if (float.IsInfinity(distanceToExit) || distanceToExit < 0) { distanceToExit = float.PositiveInfinity; } float distanceToStart = distance * Vector3.Dot(a - pointer.position, forward) / Vector3.Dot(movement, forward); if (float.IsInfinity(distanceToStart) || distanceToStart < 0) { distanceToStart = float.PositiveInfinity; } if (distance < distanceToExit && distance < distanceToStart) { pointer.position += movement; Vector3 outVec = Vector3.ProjectOnPlane(pointer.position - a, forward); if (outVec.sqrMagnitude > pathRadius * pathRadius) { pointer.position = a + Vector3.Project(pointer.position - a, forward) + outVec.normalized * pathRadius; pointer.overshoot += outVec.magnitude - pathRadius; if (pointer.overshoot > (b - a).magnitude * pathOvershootFactor) { pointer.progress = -1; } } return(Vector3.zero); } else if (distance >= distanceToExit) { pointer.position += forward * distanceToExit; Vector3 outVec = Vector3.ProjectOnPlane(pointer.position - a, forward); if (outVec.sqrMagnitude > pathRadius * pathRadius) { pointer.position = a + Vector3.Project(pointer.position - a, forward) + outVec.normalized * pathRadius; } pointer.progress++; pointer.overshoot = 0; return(forward * (distance - distanceToExit)); } else { pointer.progress = -1; return(Vector3.zero); } }
// Returns remaining movement private Vector3 pointerMoveInSphere(SimulatedPointer pointer, Vector3 movement) { Vector3 center = path[pointer.progress / 2]; Vector3 right = Vector3.Cross(pointer.position - center, movement); Vector3 up = Vector3.Cross(movement, right).normalized; Vector3 forward = movement.normalized; Vector3 outDirection = pointer.progress < (path.Length - 1) * 2 ? (path[pointer.progress / 2 + 1] - center).normalized : Vector3.zero; float outThreshold = Mathf.Sqrt(jointRadius * jointRadius - pathRadius * pathRadius); float height = Vector3.Dot(pointer.position - center, up); float halfLength = Mathf.Sqrt(jointRadius * jointRadius - height * height); float distance = movement.magnitude; float distanceToBorder = halfLength - Vector3.Dot(pointer.position - center, forward); if (distance < distanceToBorder) { pointer.position += distance * forward; return(Vector3.zero); } else { Vector3 contactPosition = pointer.position + distanceToBorder * forward; if (Vector3.Dot(contactPosition - center, outDirection) > outThreshold) { // Progress to the next segment pointer.position = contactPosition; pointer.progress++; pointer.overshoot = 0; return((distance - distanceToBorder) * forward); } else { Vector3 finalPoint = pointer.position + distance * forward; finalPoint = center + (finalPoint - center).normalized * jointRadius; pointer.position = finalPoint; pointer.overshoot += distance - distanceToBorder; if (Vector3.Dot(finalPoint - center, outDirection) > outThreshold) { pointer.progress++; pointer.overshoot = 0; } else if (pointer.progress >= 2 && pointer.overshoot > (center - path[pointer.progress / 2 - 1]).magnitude * jointOvershootFactor) { pointer.progress = -1; } return(Vector3.zero); } } }
void Update() { if (LeapControl.handState == LeapControl.HandState.Pointing) { input = Vector3.ProjectOnPlane(LeapControl.fingerPoint, Vector3.forward); for (int s = minScaleLevel; s <= maxScaleLevel; s++) { SimulatedPointer newPointer = new SimulatedPointer(path[0], input); newPointer.multiplier = Mathf.Pow(scaleFactor, s); pointers.Add(newPointer); } } else { clear(); } foreach (SimulatedPointer pointer in pointers) { if (Time.time - pointer.startTime > maxDuration) { pointer.progress = -1; continue; } Vector3 movement = input - prevInput; while (movement.sqrMagnitude > 0) { if (pointer.progress < 0) { break; } if (pointer.progress == (path.Length - 1) * 2) { finish(); break; } if (pointer.progress % 2 == 0) { movement = pointerMoveInSphere(pointer, movement * pointer.multiplier); } else { movement = pointerMoveInCylinder(pointer, movement * pointer.multiplier); } } } if (visualizing) { foreach (SimulatedPointer pointer in pointers) { if (pointer.progress < 0) { if (visualMarkers.ContainsKey(pointer)) { Destroy(visualMarkers[pointer]); } } else { if (!visualMarkers.ContainsKey(pointer)) { GameObject newMarker = Instantiate(marker); newMarker.transform.SetParent(visualizationContainer.transform, false); visualMarkers.Add(pointer, newMarker); } visualMarkers[pointer].transform.localPosition = pointer.position; } } } pointers.RemoveWhere(pointer => pointer.progress < 0); prevInput = input; }