SphereUtility.cs 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. namespace Funly.SkyStudio
  5. {
  6. // Helper functions for working with points and angles on spheres.
  7. public abstract class SphereUtility : System.Object
  8. {
  9. private const float k_HalfPI = Mathf.PI / 2.0f;
  10. // Convert a world direction into a spherical coordinates in radians.
  11. public static Vector2 DirectionToSphericalCoordinate(Vector3 direction)
  12. {
  13. Vector3 normDirection = direction.normalized;
  14. float horizontalRotation = Atan2Positive(normDirection.z, normDirection.x);
  15. float verticalRotation = 0;
  16. float angleToUp = Vector3.Angle(direction, Vector3.up) * Mathf.Deg2Rad;
  17. if (angleToUp <= k_HalfPI) {
  18. verticalRotation = k_HalfPI - angleToUp;
  19. } else {
  20. verticalRotation = -1 * (angleToUp - k_HalfPI);
  21. }
  22. return new Vector2(horizontalRotation, verticalRotation);
  23. }
  24. // We could have used AngleAxis however we do it this way to exercise the same logic in the shader.
  25. public static Vector3 SphericalCoordinateToDirection(Vector2 coord)
  26. {
  27. // Find the y coordinate and radius.
  28. float x = Mathf.Cos(coord.y);
  29. float y = Mathf.Sin(coord.y);
  30. float radius = x;
  31. float z = 0.0f;
  32. x = radius * Mathf.Cos(coord.x);
  33. z = radius * Mathf.Sin(coord.x);
  34. return new Vector3(x, y, z);
  35. }
  36. public static float RadiusAtHeight(float yPos)
  37. {
  38. return Mathf.Abs(Mathf.Cos(Mathf.Asin(yPos)));
  39. }
  40. public static Vector3 SphericalToPoint(float yPosition, float radAngle)
  41. {
  42. float radius = RadiusAtHeight(yPosition);
  43. Vector3 p = new Vector3(
  44. radius * Mathf.Cos(radAngle),
  45. yPosition,
  46. radius * Mathf.Sin(radAngle));
  47. return p;
  48. }
  49. public static float RadAngleToPercent(float radAngle)
  50. {
  51. return radAngle / (2 * Mathf.PI);
  52. }
  53. public static float PercentToRadAngle(float percent)
  54. {
  55. return percent * (2 * Mathf.PI);
  56. }
  57. // Y value is assumed to be -1/1 value range (radius).
  58. public static float HeightToPercent(float yValue)
  59. {
  60. return yValue / 2.0f + .5f;
  61. }
  62. public static float PercentToHeight(float hPercent)
  63. {
  64. return Mathf.Lerp(-1.0f, 1.0f, hPercent);
  65. }
  66. public static float AngleToReachTarget(Vector2 point, float targetAngle)
  67. {
  68. // Always move in a positive angle to the target.
  69. float angle = Atan2Positive(point.y, point.x);
  70. return ((Mathf.PI * 2) - angle) + targetAngle;
  71. }
  72. // Returns angle in radians.
  73. public static float Atan2Positive(float y, float x)
  74. {
  75. float angle = Mathf.Atan2(y, x);
  76. if (angle < 0) {
  77. angle = Mathf.PI + (Mathf.PI + angle);
  78. }
  79. return angle;
  80. }
  81. public static Vector3 RotateAroundXAxis(Vector3 point, float angle)
  82. {
  83. Vector2 rotation = Rotate2d(new Vector2(point.z, point.y), angle);
  84. return new Vector3(point.x, rotation.y, rotation.x);
  85. }
  86. public static Vector3 RotateAroundYAxis(Vector3 point, float angle)
  87. {
  88. Vector2 rotation = Rotate2d(new Vector2(point.x, point.z), angle);
  89. return new Vector3(rotation.x, point.y, rotation.y);
  90. }
  91. public static Vector3 RotatePoint(Vector3 point, float xAxisRotation, float yAxisRotation)
  92. {
  93. Vector3 rotated = RotateAroundYAxis(point, yAxisRotation);
  94. rotated = RotateAroundXAxis(rotated, xAxisRotation);
  95. return rotated;
  96. }
  97. public static Vector2 Rotate2d(Vector2 pos, float angle)
  98. {
  99. Vector4 matrix = new Vector4(
  100. Mathf.Cos(angle), -Mathf.Sin(angle),
  101. Mathf.Sin(angle), Mathf.Cos(angle));
  102. return Matrix2x2Mult(matrix, pos);
  103. }
  104. // Simulate a matrix multiplication against a vector.
  105. public static Vector2 Matrix2x2Mult(Vector4 matrix, Vector2 pos)
  106. {
  107. return new Vector2(
  108. (matrix[0] * pos[0]) + (matrix[1] * pos[1]),
  109. (matrix[2] * pos[0]) + (matrix[3] * pos[1])
  110. );
  111. }
  112. public static void CalculateStarRotation(Vector3 star, out float xRotationAngle, out float yRotationAngle)
  113. {
  114. Vector3 starPos = new Vector3(star.x, star.y, star.z);
  115. yRotationAngle = AngleToReachTarget(
  116. new Vector2(starPos.x, starPos.z),
  117. 90.0f * Mathf.Deg2Rad);
  118. starPos = RotateAroundYAxis(starPos, yRotationAngle);
  119. xRotationAngle = AngleToReachTarget(
  120. new Vector3(starPos.z, starPos.y),
  121. 0.0f * Mathf.Deg2Rad);
  122. }
  123. // Convert a 2D UV percent into spherical rotations.
  124. public static Vector2 ConvertUVToSphericalCoordinate(Vector2 uv) {
  125. const float halfPi = Mathf.PI / 2.0f;
  126. return new Vector2(
  127. Mathf.Lerp(0.0f, Mathf.PI * 2.0f, uv.x),
  128. Mathf.Lerp(-halfPi, halfPi, uv.y));
  129. }
  130. // Convert spherical rotations into a 2D UV percent.
  131. public static Vector2 ConvertSphericalCoordateToUV(Vector2 sphereCoord) {
  132. const float halfPi = Mathf.PI / 2.0f;
  133. return new Vector2(
  134. sphereCoord.x / (Mathf.PI * 2.0f),
  135. (sphereCoord.y + halfPi) / Mathf.PI);
  136. }
  137. }
  138. }