fastApproximateAtan.glsl 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455
  1. /**
  2. * Approxiamtes atan over the range [0, 1]. Safe to flip output for negative input.
  3. *
  4. * Based on Michal Drobot's approximation from ShaderFastLibs, which in turn is based on
  5. * "Efficient approximations for the arctangent function," Rajan, S. Sichun Wang Inkol, R. Joyal, A., May 2006.
  6. * Adapted from ShaderFastLibs under MIT License.
  7. *
  8. * Chosen for the following characteristics over range [0, 1]:
  9. * - basically no error at 0 and 1, important for getting around range limit (naive atan2 via atan requires infinite range atan)
  10. * - no visible artifacts from first-derivative discontinuities, unlike latitude via range-reduced sqrt asin approximations (at equator)
  11. *
  12. * The original code is x * (-0.1784 * abs(x) - 0.0663 * x * x + 1.0301);
  13. * Removed the abs() in here because it isn't needed, the input range is guaranteed as [0, 1] by how we're approximating atan2.
  14. *
  15. * @name czm_fastApproximateAtan
  16. * @glslFunction
  17. *
  18. * @param {float} x Value between 0 and 1 inclusive.
  19. *
  20. * @returns {float} Approximation of atan(x)
  21. */
  22. float czm_fastApproximateAtan(float x) {
  23. return x * (-0.1784 * x - 0.0663 * x * x + 1.0301);
  24. }
  25. /**
  26. * Approximation of atan2.
  27. *
  28. * Range reduction math based on nvidia's cg reference implementation for atan2: http://developer.download.nvidia.com/cg/atan2.html
  29. * However, we replaced their atan curve with Michael Drobot's (see above).
  30. *
  31. * @name czm_fastApproximateAtan
  32. * @glslFunction
  33. *
  34. * @param {float} x Value between -1 and 1 inclusive.
  35. * @param {float} y Value between -1 and 1 inclusive.
  36. *
  37. * @returns {float} Approximation of atan2(x, y)
  38. */
  39. float czm_fastApproximateAtan(float x, float y) {
  40. // atan approximations are usually only reliable over [-1, 1], or, in our case, [0, 1] due to modifications.
  41. // So range-reduce using abs and by flipping whether x or y is on top.
  42. float t = abs(x); // t used as swap and atan result.
  43. float opposite = abs(y);
  44. float adjacent = max(t, opposite);
  45. opposite = min(t, opposite);
  46. t = czm_fastApproximateAtan(opposite / adjacent);
  47. // Undo range reduction
  48. t = czm_branchFreeTernary(abs(y) > abs(x), czm_piOverTwo - t, t);
  49. t = czm_branchFreeTernary(x < 0.0, czm_pi - t, t);
  50. t = czm_branchFreeTernary(y < 0.0, -t, t);
  51. return t;
  52. }