SkyMathUtilities.cginc 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. #ifndef SKY_MATH_UTILITIES
  2. #define SKY_MATH_UTILITIES
  3. // Copyright(c) 2018 Funly LLC
  4. //
  5. // Author: Jason Ederle
  6. // Description: Math utility functions for working with skyboxes.
  7. // Contact: jason@funly.io
  8. #include "UnityCG.cginc"
  9. float rand(float2 co) {
  10. return frac(sin(dot(co.xy, float2(12.9898, 78.233))) * 43758.5453);
  11. }
  12. float AngleBetweenNormalizedVectors(float3 v1, float3 v2) {
  13. return acos(dot(v1, v2));
  14. }
  15. float Atan2Positive(float y, float x) {
  16. float angle = atan2(y, x);
  17. // This is the same as: angle = (angle > 0) ? angle : UNITY_PI + (UNITY_PI + angle)
  18. float isPositive = step(0, angle);
  19. float posAngle = angle * isPositive;
  20. float negAngle = (UNITY_PI + (UNITY_PI + angle)) * !isPositive;
  21. return posAngle + negAngle;
  22. }
  23. float2 DirectionToSphericalCoordinate(float3 direction) {
  24. float3 normDirection = normalize(direction);
  25. float horizontalRotation = Atan2Positive(normDirection.z, normDirection.x);
  26. float verticalRotation = 0;
  27. float angleToUp = AngleBetweenNormalizedVectors(direction, float3(0.0f, 1.0f, 0.0f));
  28. bool angleGreater = step(angleToUp, UNITY_HALF_PI);
  29. bool angleLesser = !angleGreater;
  30. float greaterValue = (-1.0f * (angleToUp - UNITY_HALF_PI)) * angleGreater;
  31. float lesserValue = (UNITY_HALF_PI - angleToUp) * angleLesser;
  32. verticalRotation = greaterValue + lesserValue;
  33. // This is the logic for the previous few lines.
  34. // if (angleToUp <= UNITY_HALF_PI) {
  35. // verticalRotation = UNITY_HALF_PI - angleToUp;
  36. // }
  37. // else {
  38. // verticalRotation = -1.0f * (angleToUp - UNITY_HALF_PI);
  39. // }
  40. return float2(horizontalRotation, verticalRotation);
  41. }
  42. float3 SphericalCoordinateToDirection(float2 spherePoint) {
  43. // Find the y coordinate and radius.
  44. float x = cos(spherePoint.y);
  45. float y = sin(spherePoint.y);
  46. float radius = x;
  47. float z = 0.0f;
  48. x = radius * cos(spherePoint.x);
  49. z = radius * sin(spherePoint.x);
  50. return normalize(float3(x, y, z));
  51. }
  52. inline float2 Rotate2d(float2 p, float angle) {
  53. return mul(float2x2(cos(angle), -sin(angle),
  54. sin(angle), cos(angle)),
  55. p);
  56. }
  57. float3 RotateAroundXAxis(float3 p, float angle) {
  58. float2 rotation = Rotate2d(p.zy, angle);
  59. return float3(p.x, rotation.y, rotation.x);
  60. }
  61. float3 RotateAroundYAxis(float3 p, float angle) {
  62. float2 rotation = Rotate2d(p.xz, angle);
  63. return float3(rotation.x, p.y, rotation.y);
  64. }
  65. float3 RotatePoint(float3 p, float xAxisRotation, float yAxisRotation) {
  66. float3 rotated = RotateAroundYAxis(p, yAxisRotation);
  67. return RotateAroundXAxis(rotated, xAxisRotation);
  68. }
  69. float AngleToReachTarget(float2 spot, float targetAngle) {
  70. float angle = Atan2Positive(spot.y, spot.x);
  71. return (UNITY_TWO_PI - angle) + targetAngle;
  72. }
  73. // Convert a 2D UV percent into spherical rotations.
  74. float2 ConvertUVToSphericalCoordinate(float2 uv) {
  75. return float2(
  76. lerp(0.0f, UNITY_TWO_PI, uv.x),
  77. lerp(-UNITY_HALF_PI, UNITY_HALF_PI, uv.y));
  78. }
  79. // Convert spherical rotations into a 2D UV percent.
  80. float2 ConvertSphericalCoordateToUV(float2 sphereCoord) {
  81. return float2(
  82. sphereCoord.x / UNITY_TWO_PI,
  83. (sphereCoord.y + UNITY_HALF_PI) / UNITY_PI
  84. );
  85. }
  86. float2 ConvertSphericalCoordinateToPercentage(float2 sphereCoord) {
  87. return float2(
  88. sphereCoord.x / UNITY_TWO_PI,
  89. (sphereCoord.y + UNITY_HALF_PI) / UNITY_PI
  90. );
  91. }
  92. float2 ConvertPercentToSphericalCoordinate(float2 percents) {
  93. return float2(
  94. lerp(0, UNITY_TWO_PI, percents.x),
  95. lerp(-UNITY_HALF_PI, UNITY_HALF_PI, percents.y)
  96. );
  97. }
  98. float2 ConvertPointToPercents(float3 starPoint) {
  99. float2 sphericalCoord = DirectionToSphericalCoordinate(starPoint);
  100. return ConvertSphericalCoordinateToPercentage(sphericalCoord);
  101. }
  102. float3 ConvertPercentToPoint(float2 percents) {
  103. float2 sphericalCoord = ConvertPercentToSphericalCoordinate(percents);
  104. return SphericalCoordinateToDirection(sphericalCoord);
  105. }
  106. bool IsSamePoint(float3 p1, float3 p2) {
  107. float xDelta = p1.x - p2.x;
  108. float yDelta = p1.y - p2.y;
  109. float zDelta = p1.z - p2.z;
  110. float nearZero = .01f;
  111. return xDelta < nearZero && yDelta < nearZero && zDelta < nearZero;
  112. }
  113. float2 GetPixelCeneteredUV(float2 uv, int imageSize) {
  114. float cellSize = 1.0f / (float)imageSize;
  115. float halfCellSize = cellSize / 2.0f;
  116. int xUnits = uv.x / cellSize;
  117. int yUnits = uv.y / cellSize;
  118. return float2(xUnits * cellSize + halfCellSize,
  119. yUnits * cellSize + halfCellSize);
  120. }
  121. #endif