module RSAGL.Extras.ColorPhysics (plancksLaw, blackBody, blackBodyRGB, spectralRGB) where import RSAGL.Color import RSAGL.Math.AbstractVector import RSAGL.Auxiliary.Auxiliary import RSAGL.Math.Interpolation import RSAGL.Math.Types -- | Evaluates planck's law respecting blackbody radiation. -- Accepts temperature in Kelvins (K) and wavelength in nanometers (nm). plancksLaw :: RSdouble -> RSdouble -> RSdouble plancksLaw t w = (8 * pi * h * c / w^5) / (exp (h*c/w/k/t) - 1) where h = 6.626070e-34 -- (J*s) c = 2.997924e17 -- (nm/s) k = 1.3806504e-23 -- (J/K) -- | Indicates the intensity of black body radiation in terms of temperature and wavelength, as percieved by the human eye -- with a white point at which all wavelengths equal 1.0 at 5800K. -- Accepts temperature in Kelvins (K) and wavelength in nanometers (nm). blackBody :: RSdouble -> RSdouble -> RSdouble blackBody t w = plancksLaw t w / plancksLaw 5800 w -- | Indicates the percieved color of a black body radiator, where @rgb 1.0 1.0 1.0@ is the white point representing 5800K. -- Accepts temperature in Kelvins (K). It is suggested to use 'maximizeRGB' or some other filter as very dark or overbright -- colors are easily generated from this function. In particular @maximizeRGB . blackBodyRGB@ tends to approach roughly -- @rgb 0.0 0.0 1.0@ for very low temperatures and roughly @rgb 0.50 0.53 1.0@ for very high temperatures. blackBodyRGB :: RSdouble -> RGB blackBodyRGB t = spectralRGB (blackBody t) -- | Interprets a spectral function as an 'RGB' color by sampling in the red, green, blue, and indigo wavelengths. -- This is pretty rough, and actually interprets monochromatic spectral yellow or monochromatic spectral cyan as -- black, for example. It also does not take into account the relative responsiveness of the human eye to -- different wavelengths, so passing @'plancksLaw' 5800@ directly to this function results in bright green. spectralRGB :: (RSdouble -> RSdouble) -> RGB spectralRGB f = rgb (abstractAverage $ (map (f . (flip lerp (625,740))) $ zeroToOne 5) ++ [f 415]) (abstractAverage $ map (f . (flip lerp (520,570))) $ zeroToOne 5) (abstractAverage $ map (f . (flip lerp (440,490))) $ zeroToOne 5)