Mitsuba Renderer  0.5.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
spectrum.h
Go to the documentation of this file.
1 /*
2  This file is part of Mitsuba, a physically based rendering system.
3 
4  Copyright (c) 2007-2014 by Wenzel Jakob and others.
5 
6  Mitsuba is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License Version 3
8  as published by the Free Software Foundation.
9 
10  Mitsuba is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18 
19 #pragma once
20 #if !defined(__MITSUBA_CORE_SPECTRUM_H_)
21 #define __MITSUBA_CORE_SPECTRUM_H_
22 
23 #include <mitsuba/mitsuba.h>
24 
25 #if !defined(SPECTRUM_SAMPLES)
26 #error The desired number of spectral samples must be \
27  specified in the configuration file!
28 #endif
29 
30 #define SPECTRUM_MIN_WAVELENGTH 360
31 #define SPECTRUM_MAX_WAVELENGTH 830
32 #define SPECTRUM_RANGE \
33  (SPECTRUM_MAX_WAVELENGTH-SPECTRUM_MIN_WAVELENGTH)
34 
36 
37 /**
38  * \brief Abstract continous spectral power distribution data type,
39  * which supports evaluation at arbitrary wavelengths.
40  *
41  * Here, the term 'continous' doesn't necessarily mean that the
42  * underlying spectrum is continous, but rather emphasizes the fact
43  * that it is a function over the reals (as opposed to the discrete
44  * spectrum, which only stores samples for a discrete set of wavelengths).
45  *
46  * \ingroup libpython
47  * \ingroup libcore
48  */
50 public:
51  /**
52  * Evaluate the value of the spectral power distribution
53  * at the given wavelength.
54  *
55  * \param lambda A wavelength in nanometers
56  */
57  virtual Float eval(Float lambda) const = 0;
58 
59  /**
60  * \brief Integrate the spectral power distribution
61  * over a given interval and return the average value
62  *
63  * Unless overridden in a subclass, the integration is done
64  * using adaptive Gauss-Lobatto quadrature.
65  *
66  * \param lambdaMin
67  * The lower interval bound in nanometers
68  *
69  * \param lambdaMax
70  * The upper interval bound in nanometers
71  *
72  * \remark If \c lambdaMin >= \c lambdaMax, the
73  * implementation will return zero.
74  */
75  virtual Float average(Float lambdaMin, Float lambdaMax) const;
76 
77  /// \brief Return a string representation
78  virtual std::string toString() const = 0;
79 
80  /// Virtual destructor
81  virtual ~ContinuousSpectrum() { }
82 };
83 
84 /**
85  * \brief Spectral power distribution based on Planck's black body law
86  *
87  * Computes the spectral power distribution of a black body of the
88  * specified temperature.
89  *
90  * \ingroup libcore
91  */
93 public:
94  /**
95  * \brief Construct a new black body spectrum given the emitter's
96  * temperature in Kelvin.
97  */
98  inline BlackBodySpectrum(Float temperature) {
99  m_temperature = temperature;
100  }
101 
102  virtual ~BlackBodySpectrum() { }
103 
104  /** \brief Return the value of the spectral power distribution
105  * at the given wavelength.
106  *
107  * The units are Watts per unit surface area (m^-2)
108  * per unit wavelength (nm^-1) per steradian (sr^-1)
109  */
110  virtual Float eval(Float lambda) const;
111 
112  /// Return a string representation
113  std::string toString() const;
114 private:
115  Float m_temperature;
116 };
117 
118 /**
119  * \brief Spectral distribution for rendering participating media
120  * with Rayleigh scattering.
121  *
122  * This distribution captures the 1/lambda^4 wavelength dependence
123  * of Rayleigh scattering. It can provide both the scattering and
124  * extinction coefficient needed for simulating planetary
125  * atmospheres with participating media.
126  *
127  * \ingroup libcore
128  */
130 public:
131  enum EMode {
132  /// Compute the scattering coefficient
134  /// Compute the extinction coefficient
135  ESigmaT
136  };
137 
138  /**
139  * \brief Create a Rayleigh spectrum instance
140  *
141  * \param mode Specifies the requested type of spectrum
142  * \param eta Refractive index of the medium (e.g. air)
143  * \param height Height above sea level (in meters)
144  */
145  RayleighSpectrum(EMode mode, Float eta = 1.000277f, Float height = 0);
146 
147  virtual ~RayleighSpectrum() { }
148 
149  /** \brief Evaluate the extinction/scattering coefficient for
150  * a specified wavelength.
151  *
152  * The returned value is in units of 1/meter.
153  */
154  virtual Float eval(Float lambda) const;
155 
156  /// Return a string representation
157  std::string toString() const;
158 private:
159  Float m_precomp;
160 };
161 
162 /**
163  * \brief This spectral power distribution is defined as the
164  * product of two other continuous spectra.
165  */
167 public:
168  /** \brief Return the value of the spectral power distribution
169  * at the given wavelength.
170  */
172  const ContinuousSpectrum &s2) : m_spec1(s1),
173  m_spec2(s2) { }
174 
175  /** \brief Return the value of the spectral power distribution
176  * at the given wavelength.
177  */
178  virtual Float eval(Float lambda) const;
179 
180  /// Virtual destructor
181  virtual ~ProductSpectrum() { }
182 
183  /// Return a string representation
184  std::string toString() const;
185 private:
186  const ContinuousSpectrum &m_spec1;
187  const ContinuousSpectrum &m_spec2;
188 };
189 
190 /**
191  * \brief Linearly interpolated spectral power distribution
192  *
193  * This class implements a linearly interpolated spectral
194  * power distribution that is defined over a discrete set of
195  * measurements at different wavelengths. Outside of the
196  * specified range, the spectrum is assumed to be zero. Hence,
197  * at least two entries are required to produce a nonzero
198  * spectrum.
199  *
200  * \ingroup libcore
201  * \ingroup libpython
202  */
204 public:
205  /**
206  * \brief Create a new interpolated spectrum with space
207  * for the specified number of samples
208  */
209  InterpolatedSpectrum(size_t size = 0);
210 
211  /**
212  * \brief Create a interpolated spectrum instance from
213  * a float array
214  */
215  InterpolatedSpectrum(const Float *wavelengths,
216  const Float *values, size_t nEntries);
217 
218  /**
219  * \brief Read an interpolated spectrum from a simple
220  * ASCII format.
221  *
222  * Each line of the file should contain an entry of the form
223  * \verbatim
224  * <wavelength in nm> <value>
225  * \endverbatim
226  * Comments preceded by '#' are also valid.
227  */
228  InterpolatedSpectrum(const fs::path &path);
229 
230  /**
231  * \brief Append an entry to the spectral power distribution.
232  *
233  * Entries must be added in order of increasing wavelength
234  */
235  void append(Float lambda, Float value);
236 
237  /**
238  * \brief This function adds a zero entry before and after
239  * the stored wavelength range.
240  *
241  * This is useful when handling datasets that don't fall
242  * off to zero at the ends. The spacing of the added entries
243  * is determined by computing the average spacing of the
244  * existing samples.
245  */
246  void zeroExtend();
247 
248  /// Clear all stored entries
249  void clear();
250 
251  /**
252  * \brief Return the value of the spectral power distribution
253  * at the given wavelength.
254  */
255  Float eval(Float lambda) const;
256 
257  /**
258  * \brief Integrate the spectral power distribution
259  * over a given interval and return the average value
260  *
261  * This method overrides the implementation in
262  * \ref ContinousSpectrum, since the integral can be
263  * analytically computed for linearly interpolated spectra.
264  *
265  * \param lambdaMin
266  * The lower interval bound in nanometers
267  *
268  * \param lambdaMax
269  * The upper interval bound in nanometers
270  *
271  * \remark If \c lambdaMin >= \c lambdaMax, the
272  * implementation will return zero.
273  */
274  Float average(Float lambdaMin, Float lambdaMax) const;
275 
276  /// \brief Return a string representation
277  std::string toString() const;
278 
279  /// Virtual destructor
280  virtual ~InterpolatedSpectrum() { }
281 protected:
282  std::vector<Float> m_wavelengths, m_values;
283 };
284 
285 /**
286  * \brief Abstract spectral power distribution data type
287  *
288  * This class defines a vector-like data type that can be used for
289  * computations involving radiance. A concrete instantiation for the
290  * precision and spectral discretization chosen at compile time is
291  * given by the \ref Spectrum data type.
292  *
293  * \ingroup libcore
294  */
295 template <typename T, int N> struct TSpectrum {
296 public:
297  typedef T Scalar;
298 
299  /// Number of dimensions
300  const static int dim = N;
301 
302  /// Create a new spectral power distribution, but don't initialize the contents
303 #if !defined(MTS_DEBUG_UNINITIALIZED)
304  inline TSpectrum() { }
305 #else
306  inline TSpectrum() {
307  for (int i=0; i<N; i++)
308  s[i] = std::numeric_limits<Scalar>::quiet_NaN();
309  }
310 #endif
311 
312  /// Create a new spectral power distribution with all samples set to the given value
313  explicit inline TSpectrum(Scalar v) {
314  for (int i=0; i<N; i++)
315  s[i] = v;
316  }
317 
318  /// Copy a spectral power distribution
319  explicit inline TSpectrum(Scalar spec[N]) {
320  memcpy(s, spec, sizeof(Scalar)*N);
321  }
322 
323  /// Unserialize a spectral power distribution from a binary data stream
324  explicit inline TSpectrum(Stream *stream) {
325  stream->readArray(s, N);
326  }
327 
328  /// Initialize with a TSpectrum data type based on a alternate representation
329  template <typename AltScalar> explicit TSpectrum(const TSpectrum<AltScalar, N> &v) {
330  for (int i=0; i<N; ++i)
331  s[i] = (Scalar) v[i];
332  }
333 
334  /// Add two spectral power distributions
335  inline TSpectrum operator+(const TSpectrum &spec) const {
336  TSpectrum value = *this;
337  for (int i=0; i<N; i++)
338  value.s[i] += spec.s[i];
339  return value;
340  }
341 
342  /// Add a spectral power distribution to this instance
343  inline TSpectrum& operator+=(const TSpectrum &spec) {
344  for (int i=0; i<N; i++)
345  s[i] += spec.s[i];
346  return *this;
347  }
348 
349  /// Subtract a spectral power distribution
350  inline TSpectrum operator-(const TSpectrum &spec) const {
351  TSpectrum value = *this;
352  for (int i=0; i<N; i++)
353  value.s[i] -= spec.s[i];
354  return value;
355  }
356 
357  /// Subtract a spectral power distribution from this instance
358  inline TSpectrum& operator-=(const TSpectrum &spec) {
359  for (int i=0; i<N; i++)
360  s[i] -= spec.s[i];
361  return *this;
362  }
363 
364  /// Multiply by a scalar
365  inline TSpectrum operator*(Scalar f) const {
366  TSpectrum value = *this;
367  for (int i=0; i<N; i++)
368  value.s[i] *= f;
369  return value;
370  }
371 
372  /// Multiply by a scalar
373  inline friend TSpectrum operator*(Scalar f, const TSpectrum &spec) {
374  return spec * f;
375  }
376 
377  /// Multiply by a scalar
379  for (int i=0; i<N; i++)
380  s[i] *= f;
381  return *this;
382  }
383 
384  /// Perform a component-wise multiplication by another spectrum
385  inline TSpectrum operator*(const TSpectrum &spec) const {
386  TSpectrum value = *this;
387  for (int i=0; i<N; i++)
388  value.s[i] *= spec.s[i];
389  return value;
390  }
391 
392  /// Perform a component-wise multiplication by another spectrum
393  inline TSpectrum& operator*=(const TSpectrum &spec) {
394  for (int i=0; i<N; i++)
395  s[i] *= spec.s[i];
396  return *this;
397  }
398 
399  /// Perform a component-wise division by another spectrum
400  inline TSpectrum& operator/=(const TSpectrum &spec) {
401  for (int i=0; i<N; i++)
402  s[i] /= spec.s[i];
403  return *this;
404  }
405 
406  /// Perform a component-wise division by another spectrum
407  inline TSpectrum operator/(const TSpectrum &spec) const {
408  TSpectrum value = *this;
409  for (int i=0; i<N; i++)
410  value.s[i] /= spec.s[i];
411  return value;
412  }
413 
414  /// Divide by a scalar
415  inline TSpectrum operator/(Scalar f) const {
416  TSpectrum value = *this;
417 #ifdef MTS_DEBUG
418  if (f == 0)
419  SLog(EWarn, "TSpectrum: Division by zero!");
420 #endif
421  Scalar recip = 1.0f / f;
422  for (int i=0; i<N; i++)
423  value.s[i] *= recip;
424  return value;
425  }
426 
427  /// Equality test
428  inline bool operator==(const TSpectrum &spec) const {
429  for (int i=0; i<N; i++) {
430  if (s[i] != spec.s[i])
431  return false;
432  }
433  return true;
434  }
435 
436  /// Inequality test
437  inline bool operator!=(const TSpectrum &spec) const {
438  return !operator==(spec);
439  }
440 
441  /// Divide by a scalar
442  inline friend TSpectrum operator/(Scalar f, TSpectrum &spec) {
443  return TSpectrum(f) / spec;
444  }
445 
446  /// Divide by a scalar
448 #ifdef MTS_DEBUG
449  if (f == 0)
450  SLog(EWarn, "TTSpectrum: Division by zero!");
451 #endif
452  Scalar recip = 1.0f / f;
453  for (int i=0; i<N; i++)
454  s[i] *= recip;
455  return *this;
456  }
457 
458  /// Check for NaNs
459  inline bool isNaN() const {
460  for (int i=0; i<N; i++)
461  if (std::isnan(s[i]))
462  return true;
463  return false;
464  }
465 
466  /// Returns whether the spectrum only contains valid (non-NaN, nonnegative) samples
467  inline bool isValid() const {
468  for (int i=0; i<N; i++)
469  if (!std::isfinite(s[i]) || s[i] < 0.0f)
470  return false;
471  return true;
472  }
473 
474  /// Multiply-accumulate operation, adds \a weight * \a spec
475  inline void addWeighted(Scalar weight, const TSpectrum &spec) {
476  for (int i=0; i<N; i++)
477  s[i] += weight * spec.s[i];
478  }
479 
480  /// Return the average over all wavelengths
481  inline Scalar average() const {
482  Scalar result = 0.0f;
483  for (int i=0; i<N; i++)
484  result += s[i];
485  return result * (1.0f / N);
486  }
487 
488  /// Component-wise absolute value
489  inline TSpectrum abs() const {
490  TSpectrum value;
491  for (int i=0; i<N; i++)
492  value.s[i] = std::abs(s[i]);
493  return value;
494  }
495 
496  /// Component-wise square root
497  inline TSpectrum sqrt() const {
498  TSpectrum value;
499  for (int i=0; i<N; i++)
500  value.s[i] = std::sqrt(s[i]);
501  return value;
502  }
503 
504  /// Component-wise square root
505  inline TSpectrum safe_sqrt() const {
506  TSpectrum value;
507  for (int i=0; i<N; i++)
508  value.s[i] = math::safe_sqrt(s[i]);
509  return value;
510  }
511 
512  /// Component-wise logarithm
513  inline TSpectrum log() const {
514  TSpectrum value;
515  for (int i=0; i<N; i++)
516  value.s[i] = math::fastlog(s[i]);
517  return value;
518  }
519 
520  /// Component-wise exponentation
521  inline TSpectrum exp() const {
522  TSpectrum value;
523  for (int i=0; i<N; i++)
524  value.s[i] = math::fastexp(s[i]);
525  return value;
526  }
527 
528  /// Component-wise power
529  inline TSpectrum pow(Scalar f) const {
530  TSpectrum value;
531  for (int i=0; i<N; i++)
532  value.s[i] = std::pow(s[i], f);
533  return value;
534  }
535 
536  /// Clamp negative values
537  inline void clampNegative() {
538  for (int i=0; i<N; i++)
539  s[i] = std::max((Scalar) 0.0f, s[i]);
540  }
541 
542  /// Return the highest-valued spectral sample
543  inline Scalar max() const {
544  Scalar result = s[0];
545  for (int i=1; i<N; i++)
546  result = std::max(result, s[i]);
547  return result;
548  }
549 
550  /// Return the lowest-valued spectral sample
551  inline Scalar min() const {
552  Scalar result = s[0];
553  for (int i=1; i<N; i++)
554  result = std::min(result, s[i]);
555  return result;
556  }
557 
558  /// Negate
559  inline TSpectrum operator-() const {
560  TSpectrum value;
561  for (int i=0; i<N; i++)
562  value.s[i] = -s[i];
563  return value;
564  }
565 
566  /// Indexing operator
567  inline Scalar &operator[](int entry) {
568  return s[entry];
569  }
570 
571  /// Indexing operator
572  inline Scalar operator[](int entry) const {
573  return s[entry];
574  }
575 
576  /// Check if this spectrum is zero at all wavelengths
577  inline bool isZero() const {
578  for (int i=0; i<N; i++) {
579  if (s[i] != 0.0f)
580  return false;
581  }
582  return true;
583  }
584 
585  /// Serialize this spectrum to a stream
586  inline void serialize(Stream *stream) const {
587  stream->writeArray(s, N);
588  }
589 
590  std::string toString() const {
591  std::ostringstream oss;
592  oss << "[";
593  for (int i=0; i<N; i++) {
594  oss << s[i];
595  if (i < N - 1)
596  oss << ", ";
597  }
598  oss << "]";
599  return oss.str();
600  }
601 
602 protected:
603  Scalar s[N];
604 };
605 
606 
607 /** \brief RGB color data type
608  *
609  * \ingroup libcore
610  * \ingroup libpython
611  */
612 struct MTS_EXPORT_CORE Color3 : public TSpectrum<Float, 3> {
613 public:
615 
616  /// Create a new color value, but don't initialize the contents
617 #if !defined(MTS_DEBUG_UNINITIALIZED)
618  inline Color3() { }
619 #else
620  inline Color3() {
621  for (int i=0; i<3; i++)
622  s[i] = std::numeric_limits<Scalar>::quiet_NaN();
623  }
624 #endif
625 
626  /// Copy constructor
627  inline Color3(const Parent &s) : Parent(s) { }
628 
629  /// Initialize to a constant value
630  inline Color3(Float value) : Parent(value) { }
631 
632  /// Initialize to the given RGB value
633  inline Color3(Float r, Float g, Float b) {
634  s[0] = r; s[1] = g; s[2] = b;
635  }
636 
637  /// Return the luminance (assuming the color value is expressed in linear sRGB)
638  inline Float getLuminance() const {
639  return s[0] * 0.212671f + s[1] * 0.715160f + s[2] * 0.072169f;
640  }
641 };
642 
643 
644 /** \brief Discrete spectral power distribution based on a number
645  * of wavelength bins over the 360-830 nm range.
646  *
647  * This class defines a vector-like data type that can be used for
648  * computations involving radiance.
649  *
650  * When configured for spectral rendering (i.e. when the compile-time flag
651  * \c SPECTRUM_SAMPLES is set to a value != 3), the implementation discretizes
652  * the visible spectrum of light into a set of intervals, where the
653  * distribution within each bin is modeled as being uniform.
654  *
655  * When SPECTRUM_SAMPLES == 3, the class reverts to a simple linear
656  * RGB-based internal representation.
657  *
658  * The implementation of this class is based on PBRT.
659  *
660  * \ingroup libcore
661  * \ingroup libpython
662  */
663 struct MTS_EXPORT_CORE Spectrum : public TSpectrum<Float, SPECTRUM_SAMPLES> {
664 public:
666 
667  /**
668  * \brief When converting from RGB reflectance values to
669  * discretized color spectra, the following `intent' flag
670  * can be provided to improve the results of this highly
671  * under-constrained problem.
672  */
674  /// Unitless reflectance data is converted
676 
677  /// Radiance-valued illumination data is converted
678  EIlluminant
679  };
680 
681  /// Create a new spectral power distribution, but don't initialize the contents
682 #if !defined(MTS_DEBUG_UNINITIALIZED)
683  inline Spectrum() { }
684 #else
685  inline Spectrum() {
686  for (int i=0; i<SPECTRUM_SAMPLES; i++)
687  s[i] = std::numeric_limits<Scalar>::quiet_NaN();
688  }
689 #endif
690 
691  /// Construct from a TSpectrum instance
692  inline Spectrum(const Parent &s) : Parent(s) { }
693 
694  /// Initialize with a TSpectrum data type based on a alternate representation
695  template <typename AltScalar> explicit Spectrum(const TSpectrum<AltScalar, SPECTRUM_SAMPLES> &v) {
696  for (int i=0; i<SPECTRUM_SAMPLES; ++i)
697  s[i] = (Scalar) v[i];
698  }
699 
700  /// Create a new spectral power distribution with all samples set to the given value
701  explicit inline Spectrum(Float v) {
702  for (int i=0; i<SPECTRUM_SAMPLES; i++)
703  s[i] = v;
704  }
705 
706  /// Copy a spectral power distribution
707  explicit inline Spectrum(Float value[SPECTRUM_SAMPLES]) {
708  memcpy(s, value, sizeof(Float)*SPECTRUM_SAMPLES);
709  }
710 
711  /// Unserialize a spectral power distribution from a binary data stream
712  explicit inline Spectrum(Stream *stream) : Parent(stream) { }
713 
714  /**
715  * \brief Evaluate the SPD for the given wavelength
716  * in nanometers.
717  */
718  Float eval(Float lambda) const;
719 
720  /// \brief Return the wavelength range covered by a spectral bin
721  static std::pair<Float, Float> getBinCoverage(size_t index);
722 
723  /// Return the luminance in candelas.
724 #if SPECTRUM_SAMPLES == 3
725  inline Float getLuminance() const {
726  return s[0] * 0.212671f + s[1] * 0.715160f + s[2] * 0.072169f;
727  }
728 #else
729  Float getLuminance() const;
730 #endif
731 
732  /**
733  * \brief Convert from a spectral power distribution to XYZ
734  * tristimulus values
735  *
736  * In the Python API, this function returns a 3-tuple
737  * with the result of the operation.
738  */
739  void toXYZ(Float &x, Float &y, Float &z) const;
740 
741  /**
742  * \brief Convert XYZ tristimulus into a plausible spectral
743  * reflectance or spectral power distribution
744  *
745  * The \ref EConversionIntent parameter can be used to provide more
746  * information on how to solve this highly under-constrained problem.
747  * The default is \ref EReflectance.
748  */
749  void fromXYZ(Float x, Float y, Float z,
750  EConversionIntent intent = EReflectance);
751 
752  /**
753  * \brief Convert from a spectral power distribution to
754  * the perceptually uniform IPT color space by Ebner and Fairchild
755  *
756  * This is useful e.g. for computing color differences.
757  * \c I encodes intensity, \c P (protan) roughly encodes
758  * red-green color opponency, and \c T (tritan) encodes
759  * blue-red color opponency. For normalized input, the
760  * range of attainable values is given by
761  * \f$ I\in $[0,1], P,T\in [-1,1]\f$.
762  *
763  * In the Python API, this function returns a 3-tuple
764  * with the result of the operation.
765  */
766  void toIPT(Float &I, Float &P, Float &T) const;
767 
768  /**
769  * \brief Convert a color value represented in the IPT
770  * space into a plausible spectral reflectance or
771  * spectral power distribution.
772  *
773  * The \ref EConversionIntent parameter can be used to provide more
774  * information on how to solve this highly under-constrained problem.
775  * The default is \ref EReflectance.
776  */
777  void fromIPT(Float I, Float P, Float T,
778  EConversionIntent intent = EReflectance);
779 
780 #if SPECTRUM_SAMPLES == 3
781  /**
782  * \brief Convert to linear RGB
783  *
784  * In the Python API, this function returns a 3-tuple
785  * with the result of the operation.
786  */
787  inline void toLinearRGB(Float &r, Float &g, Float &b) const {
788  /* Nothing to do -- the renderer is in RGB mode */
789  r = s[0]; g = s[1]; b = s[2];
790  }
791 
792  /// Convert from linear RGB
793  inline void fromLinearRGB(Float r, Float g, Float b,
794  EConversionIntent intent = EReflectance /* unused */) {
795  /* Nothing to do -- the renderer is in RGB mode */
796  s[0] = r; s[1] = g; s[2] = b;
797  }
798 #else
799  /**
800  * \brief Convert to linear RGB
801  *
802  * In the Python API, this function returns a 3-tuple
803  * with the result of the operation.
804  */
805  void toLinearRGB(Float &r, Float &g, Float &b) const;
806 
807  /**
808  * \brief Convert linear RGB colors into a plausible
809  * spectral power distribution
810  *
811  * The \ref EConversionIntent parameter can be used to provide more
812  * information on how to solve this highly under-constrained problem.
813  * The default is \ref EReflectance.
814  */
815  void fromLinearRGB(Float r, Float g, Float b,
816  EConversionIntent intent = EReflectance);
817 #endif
818 
819  /**
820  * \brief Convert to sRGB
821  *
822  * In the Python API, this function returns a 3-tuple
823  * with the result of the operation.
824  */
825  void toSRGB(Float &r, Float &g, Float &b) const;
826 
827  /**
828  * \brief Convert sRGB color values into a plausible spectral
829  * power distribution
830  *
831  * Note that compared to \ref fromLinearRGB, no \c intent parameter
832  * is available. For sRGB colors, it is assumed that the intent is
833  * always \ref EReflectance.
834  */
835  void fromSRGB(Float r, Float g, Float b);
836 
837  /**
838  * \brief Convert linear RGBE colors into a plausible
839  * spectral power distribution
840  *
841  * Based on code by Bruce Walter and Greg ward.
842  *
843  * The \ref EConversionIntent parameter can be used to provide more
844  * information on how to solve this highly under-constrained problem.
845  * For RGBE values, the default is \ref EIlluminant.
846  */
847  void fromRGBE(const uint8_t rgbe[4], EConversionIntent intent = EIlluminant);
848 
849  /// Linear RGBE conversion based on Bruce Walter's and Greg Ward's code
850  void toRGBE(uint8_t rgbe[4]) const;
851 
852  /// Initialize with spectral values from a smooth spectrum representation
853  void fromContinuousSpectrum(const ContinuousSpectrum &smooth);
854 
855  /// Equality test
856  inline bool operator==(const Spectrum &val) const {
857  for (int i=0; i<SPECTRUM_SAMPLES; i++) {
858  if (s[i] != val.s[i])
859  return false;
860  }
861  return true;
862  }
863 
864  /// Inequality test
865  inline bool operator!=(const Spectrum &val) const {
866  return !operator==(val);
867  }
868 
869  /// Return a string representation
870  std::string toString() const;
871 
872  /**
873  * \brief Return a spectral color distribution of the
874  * D65 white point (with unit luminance)
875  */
876  inline static const Spectrum &getD65() { return CIE_D65; }
877 
878  /**
879  * \brief Static initialization (should be called once during the
880  * application's initialization phase)
881  *
882  * This function is responsible for choosing the wavelengths
883  * that will be used during rendering. It also pre-integrates
884  * the CIE matching curves so that sampled spectra can
885  * efficiently be converted to XYZ tristimulus values.
886  * Finally, it sets up pre-integrated color spectra for conversions
887  * from linear RGB to plausible spectral color distributions.
888  */
889  static void staticInitialization();
890  static void staticShutdown();
891 protected:
892  #if SPECTRUM_SAMPLES != 3
893  /// Configured wavelengths bins in nanometers
894  static Float m_wavelengths[SPECTRUM_SAMPLES+1];
895 
896  /// @{ \name Pre-integrated CIE 1931 XYZ color matching functions.
897  static Spectrum CIE_X;
898  static Spectrum CIE_Y;
899  static Spectrum CIE_Z;
901  /// @}
902 
903  /**
904  * @{ \name Pre-integrated Smits-style RGB to Spectrum
905  * conversion spectra, data by Karl vom Berge
906  */
921  /// @}
922  #endif
923 
924  /// Pre-integrated D65 illuminant
926 };
927 
929 
930 #endif /* __MITSUBA_CORE_SPECTRUM_H_ */
float fastlog(float value)
Definition: math.h:209
Color3()
Create a new color value, but don&#39;t initialize the contents.
Definition: spectrum.h:618
T Scalar
Definition: spectrum.h:297
Scalar max() const
Return the highest-valued spectral sample.
Definition: spectrum.h:543
bool operator!=(const TSpectrum &spec) const
Inequality test.
Definition: spectrum.h:437
static Spectrum CIE_Y
Definition: spectrum.h:898
Spectrum(const Parent &s)
Construct from a TSpectrum instance.
Definition: spectrum.h:692
static Spectrum rgbRefl2SpecGreen
Definition: spectrum.h:912
static Spectrum rgbRefl2SpecWhite
Definition: spectrum.h:907
Spectrum(Float v)
Create a new spectral power distribution with all samples set to the given value. ...
Definition: spectrum.h:701
Spectrum(Float value[SPECTRUM_SAMPLES])
Copy a spectral power distribution.
Definition: spectrum.h:707
friend TSpectrum operator/(Scalar f, TSpectrum &spec)
Divide by a scalar.
Definition: spectrum.h:442
virtual ~ContinuousSpectrum()
Virtual destructor.
Definition: spectrum.h:81
TSpectrum(Scalar v)
Create a new spectral power distribution with all samples set to the given value. ...
Definition: spectrum.h:313
TSpectrum operator*(Scalar f) const
Multiply by a scalar.
Definition: spectrum.h:365
Float getLuminance() const
Return the luminance (assuming the color value is expressed in linear sRGB)
Definition: spectrum.h:638
Abstract continous spectral power distribution data type, which supports evaluation at arbitrary wave...
Definition: spectrum.h:49
friend TSpectrum operator*(Scalar f, const TSpectrum &spec)
Multiply by a scalar.
Definition: spectrum.h:373
Compute the scattering coefficient.
Definition: spectrum.h:133
Scalar min() const
Return the lowest-valued spectral sample.
Definition: spectrum.h:551
TSpectrum< Float, SPECTRUM_SAMPLES > Parent
Definition: spectrum.h:665
Color3(Float value)
Initialize to a constant value.
Definition: spectrum.h:630
std::string toString() const
Definition: spectrum.h:590
TSpectrum()
Create a new spectral power distribution, but don&#39;t initialize the contents.
Definition: spectrum.h:304
bool operator==(const TSpectrum &spec) const
Equality test.
Definition: spectrum.h:428
TSpectrum(const TSpectrum< AltScalar, N > &v)
Initialize with a TSpectrum data type based on a alternate representation.
Definition: spectrum.h:329
bool isZero() const
Check if this spectrum is zero at all wavelengths.
Definition: spectrum.h:577
Spectral distribution for rendering participating media with Rayleigh scattering. ...
Definition: spectrum.h:129
Spectral power distribution based on Planck&#39;s black body law.
Definition: spectrum.h:92
virtual ~ProductSpectrum()
Virtual destructor.
Definition: spectrum.h:181
static const Spectrum & getD65()
Return a spectral color distribution of the D65 white point (with unit luminance) ...
Definition: spectrum.h:876
#define MTS_EXPORT_CORE
Definition: getopt.h:29
#define SLog(level, fmt,...)
Write a Log message to the console (static version - to be used outside of classes that derive from O...
Definition: logger.h:49
TSpectrum operator/(const TSpectrum &spec) const
Perform a component-wise division by another spectrum.
Definition: spectrum.h:407
virtual ~InterpolatedSpectrum()
Virtual destructor.
Definition: spectrum.h:280
Spectrum()
Create a new spectral power distribution, but don&#39;t initialize the contents.
Definition: spectrum.h:683
virtual Float average(Float lambdaMin, Float lambdaMax) const
Integrate the spectral power distribution over a given interval and return the average value...
static Spectrum rgbRefl2SpecRed
Definition: spectrum.h:911
#define MTS_NAMESPACE_BEGIN
Definition: platform.h:137
void writeArray(const T *array, size_t count)
Write an array to the stream (uses partial template specialization to select a method appropriate to ...
Definition: stream.h:520
TSpectrum sqrt() const
Component-wise square root.
Definition: spectrum.h:497
virtual ~RayleighSpectrum()
Definition: spectrum.h:147
Linearly interpolated spectral power distribution.
Definition: spectrum.h:203
TSpectrum & operator/=(Scalar f)
Divide by a scalar.
Definition: spectrum.h:447
static Float CIE_normalization
Definition: spectrum.h:900
virtual std::string toString() const =0
Return a string representation.
Spectrum(Stream *stream)
Unserialize a spectral power distribution from a binary data stream.
Definition: spectrum.h:712
TSpectrum< Float, 3 > Parent
Definition: spectrum.h:614
EMode
Definition: spectrum.h:131
static Spectrum rgbRefl2SpecYellow
Definition: spectrum.h:910
TSpectrum & operator-=(const TSpectrum &spec)
Subtract a spectral power distribution from this instance.
Definition: spectrum.h:358
RGB color data type.
Definition: spectrum.h:612
TSpectrum operator/(Scalar f) const
Divide by a scalar.
Definition: spectrum.h:415
bool operator!=(const Spectrum &val) const
Inequality test.
Definition: spectrum.h:865
static Spectrum rgbRefl2SpecCyan
Definition: spectrum.h:908
bool isNaN() const
Check for NaNs.
Definition: spectrum.h:459
Abstract spectral power distribution data type.
Definition: spectrum.h:295
TSpectrum operator-() const
Negate.
Definition: spectrum.h:559
TSpectrum operator*(const TSpectrum &spec) const
Perform a component-wise multiplication by another spectrum.
Definition: spectrum.h:385
static Spectrum rgbRefl2SpecMagenta
Definition: spectrum.h:909
static Spectrum rgbIllum2SpecYellow
Definition: spectrum.h:917
void serialize(Stream *stream) const
Serialize this spectrum to a stream.
Definition: spectrum.h:586
TSpectrum operator+(const TSpectrum &spec) const
Add two spectral power distributions.
Definition: spectrum.h:335
virtual Float eval(Float lambda) const =0
Unitless reflectance data is converted.
Definition: spectrum.h:675
static Spectrum CIE_X
Definition: spectrum.h:897
Spectrum(const TSpectrum< AltScalar, SPECTRUM_SAMPLES > &v)
Initialize with a TSpectrum data type based on a alternate representation.
Definition: spectrum.h:695
This spectral power distribution is defined as the product of two other continuous spectra...
Definition: spectrum.h:166
Abstract seekable stream class.
Definition: stream.h:58
static Spectrum rgbIllum2SpecMagenta
Definition: spectrum.h:916
static Spectrum rgbRefl2SpecBlue
Definition: spectrum.h:913
std::vector< Float > m_wavelengths
Definition: spectrum.h:282
BlackBodySpectrum(Float temperature)
Construct a new black body spectrum given the emitter&#39;s temperature in Kelvin.
Definition: spectrum.h:98
static Spectrum rgbIllum2SpecRed
Definition: spectrum.h:918
Warning message.
Definition: formatter.h:32
EConversionIntent
When converting from RGB reflectance values to discretized color spectra, the following `intent&#39; flag...
Definition: spectrum.h:673
Scalar & operator[](int entry)
Indexing operator.
Definition: spectrum.h:567
static Spectrum rgbIllum2SpecWhite
Definition: spectrum.h:914
TSpectrum exp() const
Component-wise exponentation.
Definition: spectrum.h:521
TSpectrum log() const
Component-wise logarithm.
Definition: spectrum.h:513
TSpectrum & operator/=(const TSpectrum &spec)
Perform a component-wise division by another spectrum.
Definition: spectrum.h:400
ProductSpectrum(const ContinuousSpectrum &s1, const ContinuousSpectrum &s2)
Return the value of the spectral power distribution at the given wavelength.
Definition: spectrum.h:171
bool operator==(const Spectrum &val) const
Equality test.
Definition: spectrum.h:856
Scalar s[N]
Definition: spectrum.h:603
static Spectrum CIE_D65
Pre-integrated D65 illuminant.
Definition: spectrum.h:925
static Spectrum CIE_Z
Definition: spectrum.h:899
bool isValid() const
Returns whether the spectrum only contains valid (non-NaN, nonnegative) samples.
Definition: spectrum.h:467
TSpectrum safe_sqrt() const
Component-wise square root.
Definition: spectrum.h:505
TSpectrum(Scalar spec[N])
Copy a spectral power distribution.
Definition: spectrum.h:319
void clampNegative()
Clamp negative values.
Definition: spectrum.h:537
TSpectrum & operator*=(const TSpectrum &spec)
Perform a component-wise multiplication by another spectrum.
Definition: spectrum.h:393
Color3(Float r, Float g, Float b)
Initialize to the given RGB value.
Definition: spectrum.h:633
float safe_sqrt(float value)
Square root variant that gracefully handles arguments &lt; 0 that are due to roundoff errors...
Definition: math.h:260
void readArray(T *array, size_t count)
Read an array from the stream (uses partial template specialization to select a method appropriate to...
Definition: stream.h:516
TSpectrum(Stream *stream)
Unserialize a spectral power distribution from a binary data stream.
Definition: spectrum.h:324
static Spectrum rgbIllum2SpecBlue
Definition: spectrum.h:920
TSpectrum & operator+=(const TSpectrum &spec)
Add a spectral power distribution to this instance.
Definition: spectrum.h:343
static Spectrum rgbIllum2SpecCyan
Definition: spectrum.h:915
virtual ~BlackBodySpectrum()
Definition: spectrum.h:102
Scalar average() const
Return the average over all wavelengths.
Definition: spectrum.h:481
TSpectrum operator-(const TSpectrum &spec) const
Subtract a spectral power distribution.
Definition: spectrum.h:350
Discrete spectral power distribution based on a number of wavelength bins over the 360-830 nm range...
Definition: spectrum.h:663
float fastexp(float value)
Definition: math.h:201
TSpectrum abs() const
Component-wise absolute value.
Definition: spectrum.h:489
TSpectrum pow(Scalar f) const
Component-wise power.
Definition: spectrum.h:529
#define MTS_NAMESPACE_END
Definition: platform.h:138
Color3(const Parent &s)
Copy constructor.
Definition: spectrum.h:627
void addWeighted(Scalar weight, const TSpectrum &spec)
Multiply-accumulate operation, adds weight * spec.
Definition: spectrum.h:475
TSpectrum & operator*=(Scalar f)
Multiply by a scalar.
Definition: spectrum.h:378
static Spectrum rgbIllum2SpecGreen
Definition: spectrum.h:919
Scalar operator[](int entry) const
Indexing operator.
Definition: spectrum.h:572