💿🐜 Antkeeper source code https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

268 lines
6.8 KiB

  1. /*
  2. * Copyright (C) 2021 Christopher J. Howard
  3. *
  4. * This file is part of Antkeeper source code.
  5. *
  6. * Antkeeper source code is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Antkeeper source code is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #ifndef ANTKEEPER_COLOR_XYZ_HPP
  20. #define ANTKEEPER_COLOR_XYZ_HPP
  21. #include "math/math.hpp"
  22. namespace color {
  23. /**
  24. * Functions which operate in the CIE XYZ colorspace.
  25. *
  26. * @see https://en.wikipedia.org/wiki/CIE_1931_color_space
  27. */
  28. namespace xyz {
  29. /**
  30. * Returns the luminance of a CIE XYZ color.
  31. *
  32. * @param x CIE XYZ color.
  33. * @return return Luminance of @p x.
  34. */
  35. template <class T>
  36. T luminance(const math::vector3<T>& x);
  37. /**
  38. * Fitted piecewise gaussian approximation to the CIE 1931 standard observer color matching function.
  39. *
  40. * @param lambda Wavelength of light, in nanometers.
  41. * @return Matching CIE XYZ color.
  42. *
  43. * @see match_x(T)
  44. * @see match_y(T)
  45. * @see match_z(T)
  46. *
  47. * @see Wyman, C., Sloan, P.J., & Shirley, P. (2013). Simple Analytic Approximations to the CIE XYZ Color Matching Functions.
  48. */
  49. template <class T>
  50. math::vector3<T> match(T lambda);
  51. /**
  52. * CIE 1931 standard observer color matching function for the X tristimulus value.
  53. *
  54. * @param lambda Wavelength of light, in nanometers.
  55. * @return Matching X tristimulus value.
  56. *
  57. * @see match(T)
  58. */
  59. template <class T>
  60. T match_x(T lambda);
  61. /**
  62. * CIE 1931 standard observer color matching function for the Y tristimulus value.
  63. *
  64. * @param lambda Wavelength of light, in nanometers.
  65. * @return Matching Y tristimulus value.
  66. *
  67. * @see match(T)
  68. */
  69. template <class T>
  70. T match_y(T lambda);
  71. /**
  72. * CIE 1931 standard observer color matching function for the Z tristimulus value.
  73. *
  74. * @param lambda Wavelength of light, in nanometers.
  75. * @return Matching Z tristimulus value.
  76. *
  77. * @see match(T)
  78. */
  79. template <class T>
  80. T match_z(T lambda);
  81. /**
  82. * Transforms a CIE XYZ color into the ACEScg colorspace.
  83. *
  84. * @param x CIE XYZ color.
  85. * @return ACEScg color.
  86. */
  87. template <class T>
  88. math::vector3<T> to_acescg(const math::vector3<T>& x);
  89. /**
  90. * Transforms a CIE XYZ color into the linear sRGB colorspace.
  91. *
  92. * @param x CIE XYZ color.
  93. * @return Linear sRGB color.
  94. */
  95. template <class T>
  96. math::vector3<T> to_srgb(const math::vector3<T>& x);
  97. /**
  98. * Transforms a CIE XYZ color into the CIE xyY colorspace.
  99. *
  100. * @param x CIE XYZ color.
  101. * @return CIE xyY color.
  102. */
  103. template <class T>
  104. math::vector3<T> to_xyy(const math::vector3<T>& x);
  105. /// Chromatic Adaptation Transforms (CATs).
  106. namespace cat {
  107. /**
  108. * Transforms a CIE XYZ color with an ACES (~D60) illuminant to a CIE XYZ color with a D65 illuminant using the Bradford chromatic adaption transform.
  109. *
  110. * @param x CIE XYZ color with an ACES (~D60) illuminant.
  111. * @return CIE XYZ color with a D65 illuminant.
  112. */
  113. template <class T>
  114. math::vector3<T> aces_to_d65(const math::vector3<T>& x);
  115. /**
  116. * Transforms a CIE XYZ color with a D65 illuminant to a CIE XYZ color with an ACES (~D60) illuminant using the Bradford chromatic adaption transform.
  117. *
  118. * @param x CIE XYZ color with a D65 illuminant.
  119. * @return CIE XYZ color with an ACES (~D60) illuminant.
  120. */
  121. template <class T>
  122. math::vector3<T> d65_to_aces(const math::vector3<T>& x);
  123. } // namespace cat
  124. template <class T>
  125. inline T luminance(const math::vector3<T>& x)
  126. {
  127. return x[1];
  128. }
  129. template <class T>
  130. math::vector3<T> match(T lambda)
  131. {
  132. return math::vector3<T>
  133. {
  134. match_x<T>(lambda),
  135. match_y<T>(lambda),
  136. match_z<T>(lambda)
  137. };
  138. }
  139. template <class T>
  140. T match_x(T lambda)
  141. {
  142. const T t0 = (lambda - T(442.0)) * ((lambda < T(442.0)) ? T(0.0624) : T(0.0374));
  143. const T t1 = (lambda - T(599.8)) * ((lambda < T(599.8)) ? T(0.0264) : T(0.0323));
  144. const T t2 = (lambda - T(501.1)) * ((lambda < T(501.1)) ? T(0.0490) : T(0.0382));
  145. const T x0 = T( 0.362) * std::exp(T(-0.5) * t0 * t0);
  146. const T x1 = T( 1.056) * std::exp(T(-0.5) * t1 * t1);
  147. const T x2 = T(-0.056) * std::exp(T(-0.5) * t2 * t2);
  148. return x0 + x1 + x2;
  149. }
  150. template <class T>
  151. T match_y(T lambda)
  152. {
  153. const T t0 = (lambda - T(568.8)) * ((lambda < T(568.8)) ? T(0.0213) : T(0.0247));
  154. const T t1 = (lambda - T(530.9)) * ((lambda < T(530.9)) ? T(0.0613) : T(0.0322));
  155. const T y0 = T(0.821) * std::exp(T(-0.5) * t0 * t0);
  156. const T y1 = T(0.286) * std::exp(T(-0.5) * t1 * t1);
  157. return y0 + y1;
  158. }
  159. template <class T>
  160. T match_z(T lambda)
  161. {
  162. const T t0 = (lambda - T(437.0)) * ((lambda < T(437.0)) ? T(0.0845) : T(0.0278));
  163. const T t1 = (lambda - T(459.0)) * ((lambda < T(459.0)) ? T(0.0385) : T(0.0725));
  164. const T z0 = T(1.217) * std::exp(T(-0.5) * t0 * t0);
  165. const T z1 = T(0.681) * std::exp(T(-0.5) * t1 * t1);
  166. return z0 + z1;
  167. }
  168. template <class T>
  169. math::vector3<T> to_acescg(const math::vector3<T>& x)
  170. {
  171. static const math::matrix3<T> xyz_to_acescg
  172. {{
  173. { 1.641023379694326, -0.663662858722983, 0.011721894328375},
  174. {-0.324803294184790, 1.615331591657338, -0.008284441996237},
  175. {-0.236424695237612, 0.016756347685530, 0.988394858539022}
  176. }};
  177. return xyz_to_acescg * x;
  178. }
  179. template <class T>
  180. math::vector3<T> to_srgb(const math::vector3<T>& x)
  181. {
  182. static const math::matrix3<T> xyz_to_srgb
  183. {{
  184. { 3.240969941904523, -0.969243636280880, 0.055630079696994},
  185. {-1.537383177570094, 1.875967501507721, -0.203976958888977},
  186. {-0.498610760293003, 0.041555057407176, 1.056971514242879}
  187. }};
  188. return xyz_to_srgb * x;
  189. }
  190. template <class T>
  191. math::vector3<T> to_xyy(const math::vector3<T>& x)
  192. {
  193. const T sum = x[0] + x[1] + x[2];
  194. return math::vector3<T>
  195. {
  196. x[0] / sum
  197. x[1] / sum,
  198. x[1]
  199. };
  200. }
  201. namespace cat {
  202. template <class T>
  203. math::vector3<T> aces_to_d65(const math::vector3<T>& x)
  204. {
  205. static const math::matrix3<T> cat_aces_to_d65
  206. {{
  207. { 0.987225397551079, -0.007603864790602, 0.003066041131217},
  208. {-0.006114800968213, 1.001874800208719, -0.005084242870792},
  209. { 0.015926393295811, 0.005322023893623, 1.081519155692042}
  210. }};
  211. return cat_aces_to_d65 * x;
  212. }
  213. template <class T>
  214. math::vector3<T> d65_to_aces(const math::vector3<T>& x)
  215. {
  216. static const math::matrix3<T> cat_d65_to_aces
  217. {{
  218. { 1.013033366661459, 0.007703617525351, -0.002835673220262},
  219. { 0.006107049021859, 0.998150224406968, 0.004675010768250},
  220. {-0.014947927269674, -0.005025218608126, 0.924644077051100}
  221. }};
  222. return cat_d65_to_aces * x;
  223. }
  224. } // namespace cat
  225. } // namespace xyz
  226. } // namespace color
  227. #endif // ANTKEEPER_COLOR_XYZ_HPP