public static List <Vector3> GenerateSphereBorderPoints(Camera camera, Vector3 sphereCenter, float sphereRadius, int numPoints) { if (numPoints < 3) { return(new List <Vector3>()); } Transform cameraTransform = camera.transform; List <Vector3> borderPoints = Generate3DCircleBorderPoints(sphereCenter, sphereRadius, cameraTransform.right, cameraTransform.up, numPoints); for (int ptIndex = 0; ptIndex < numPoints; ++ptIndex) { Vector3 borderPt = borderPoints[ptIndex]; Vector3 borderNormal = (borderPt - sphereCenter).normalized; Vector3 cameraRay = (borderPt - cameraTransform.position).normalized; if (camera.orthographic) { cameraRay = cameraTransform.forward; } float dot = Vector3.Dot(borderNormal, cameraRay); if (Mathf.Abs(dot) > 1e-5f) { float angle = MathEx.SafeAcos(dot) * Mathf.Rad2Deg; Vector3 rotationAxis = Vector3.Cross(cameraRay, borderNormal).normalized; Quaternion rotation = Quaternion.AngleAxis(90.0f - angle, rotationAxis); borderNormal = (rotation * borderNormal).normalized; borderPoints[ptIndex] = sphereCenter + borderNormal * sphereRadius; } } return(borderPoints); }
public static List <Vector3> GenerateSphereBorderPoints(Camera camera, Vector3 sphereCenter, float sphereRadius, int numPoints) { if (numPoints < 3) { return(new List <Vector3>()); } Transform cameraTransform = camera.transform; Plane cullPlane = new Plane(cameraTransform.forward, cameraTransform.position); List <Vector3> borderPoints = Generate3DCircleBorderPoints(sphereCenter, sphereRadius, cameraTransform.right, cameraTransform.up, numPoints); for (int ptIndex = 0; ptIndex < numPoints; ++ptIndex) { Vector3 borderPt = borderPoints[ptIndex]; Vector3 borderNormal = (borderPt - sphereCenter).normalized; Vector3 cameraRay = (borderPt - cameraTransform.position).normalized; if (camera.orthographic) { cameraRay = cameraTransform.forward; } float dot = Vector3.Dot(borderNormal, cameraRay); if (Mathf.Abs(dot) > 1e-5f) { float angle = MathEx.SafeAcos(dot) * Mathf.Rad2Deg; Vector3 rotationAxis = Vector3.Cross(cameraRay, borderNormal).normalized; Quaternion rotation = Quaternion.AngleAxis(90.0f - angle, rotationAxis); borderNormal = (rotation * borderNormal).normalized; borderPoints[ptIndex] = sphereCenter + borderNormal * sphereRadius; // Note: Reject if any point lies behind the camera. In that case, we get // invalid points when converted by the client in screen space. if (cullPlane.GetDistanceToPoint(borderPoints[ptIndex]) < 0.0f) { return(new List <Vector3>()); } } } return(borderPoints); }
public static Quaternion FromToRotation2D(Vector2 from, Vector2 to) { from = from.normalized; to = to.normalized; float dot = Vector2.Dot(from, to); if (1.0f - dot < 1e-5f) { return(Quaternion.identity); } if (1.0f + dot < 1e-5f) { return(Quaternion.AngleAxis(180.0f, Vector3.forward)); } float angle = MathEx.SafeAcos(dot) * Mathf.Rad2Deg; Vector3 rotationAxis = Vector3.Cross(from, to).normalized; return(Quaternion.AngleAxis(angle, rotationAxis)); }
// Unity versions below 2017 don't have Vector3.SignedAngle public static float SignedAngle(Vector3 from, Vector3 to, Vector3 axis) { float dot = Vector3.Dot(from.normalized, to.normalized); if ((1.0f - dot) < 1e-5f) { return(0.0f); } if ((1.0f + dot) < 1e-5f) { return(180.0f); } Vector3 cross = Vector3.Cross(from, to).normalized; float angle = MathEx.SafeAcos(dot) * Mathf.Rad2Deg; if (Vector3.Dot(cross, axis) < 0.0f) { angle = -angle; } return(angle); }