further spectrum-related cleanups

metadata
Wenzel Jakob 2011-07-06 17:52:02 +02:00
parent c552a79902
commit 5c8201d764
20 changed files with 1229 additions and 632 deletions

View File

@ -11,142 +11,19 @@ A quick video tutorial on using the GUI can be found here: \url{http://vimeo.com
\subsection{Command line interface}
\label{sec:mitsuba}
The \texttt{mitsuba} binary is an alternative non-interactive rendering
frontend for command-line use and batch job operation.
frontend for command-line usage and batch job operation.
To get a listing of the parameters it supports, run
the executable without parameters:
\begin{shell}
$\texttt{\$}$ mitsuba
\end{shell}
\lstref{mitsuba-cli} shows the output resulting from this command. The most common
mode of operation is to render a single scene, which is provided as a parameter, e.g.
\begin{shell}
$\texttt{\$}$ mitsuba path-to/my-scene.xml
\end{shell}
It is also possible to connect to network render nodes, which essentially lets Mitsuba parallelize
over additional cores. To do this, pass a semicolon-separated list of machines to
the \code{-c} parameter.
\begin{shell}
$\texttt{\$}$ mitsuba -c machine1;machine2;... path-to/my-scene.xml
\end{shell}
There are two different ways in which you can access render nodes:
\begin{itemize}
\item\textbf{Direct}: Here, you create a direct connection to a running \code{mtssrv} instance on
another machine (\code{mtssrv} is the Mitsuba server process). From the the performance
standpoint, this approach should always be preferred over the SSH method described below when there is
a choice between them. There are some disadvantages though: first, you need to manually start
\code{mtssrv} on every machine you want to use.
And perhaps more importantly: the direct communication
protocol makes no provisions for a malicious user on the remote side. It is too costly
to constantly check the communication stream for illegal data sequences, so Mitsuba simply doesn't do it.
The consequence of this is that you should only use the direct communication approach within
trusted networks.
For direct connections, you can specify the remote port as follows:
\begin{shell}
$\texttt{\$}$ mitsuba -c machine:1234 path-to/my-scene.xml
\end{shell}
When none is given, Mitsuba assumes that the server uses default port 7554.
\item \textbf{SSH}:
This approach works as follows: The renderer creates a SSH connection
to the remote side, where it launches a Mitsuba worker instance.
All subsequent communication then passes through the encrypted link.
This is completely secure but slower due to the encryption overhead.
If you are rendering a complex scene, there is a good chance that it
won't matter much since most time is spent doing computations rather than
communicating
Such an SSH link can be created simply by using a slightly different syntax:
\begin{shell}
$\texttt{\$}$ mitsuba -c username@machine path-to/my-scene.xml
\end{shell}
The above line assumes that the remote home directory contains
a Mitsuba source directory (with compiled binaries) named \code{mitsuba}.
If that is not the case, you need to provide the path to such a directory manually, e.g:
\begin{shell}
$\texttt{\$}$ mitsuba -c username@machine:/opt/mitsuba path-to/my-scene.xml
\end{shell}
For the SSH connection approach to work, you \emph{must} enable passwordless
authentication.
Try opening a terminal window and running the command \code{ssh username@machine}
(replace with the details of your remote connection).
If you are asked for a password, something is not set up correctly --- please see
\url{http://www.debian-administration.org/articles/152} for instructions.
On Windows, the situation is a bit more difficult since there is no suitable SSH client by
default. To get SSH connections to work, Mitsuba requires \code{plink.exe} (from PuTTY) to
be on the path. For passwordless authentication with a Linux/OSX-based
server, convert your private key to PuTTY's format using \code{puttygen.exe}.
Afterwards, start \code{pageant.exe} to load and authenticate the key. All
of these binaries are available from the PuTTY website, and there is also
a copy in the \code{tools/windows/bin}
directory in the Mitsuba repository.
It is possible to mix the two approaches to access some machines directly and others
over SSH.
\end{itemize}
When doing many network-based renders over the command line, it can become tedious to
specify the connections every time. They can alternatively be loaded from a text file
where each line contains a separate connection description as discussed previously:
\begin{shell}
$\texttt{\$}$ mitsuba -s servers.txt path-to/my-scene.xml
\end{shell}
where \code{servers.txt} e.g. contains
\begin{shell}
user1@machine1.domain.org:/opt/mitsuba
machine2.domain.org
machine3.domain.org:7346
\end{shell}
\subsubsection{Passing parameters}
Any attribute in the scene XML file can be parameterized from the
command line.
For instance, you can render a scene several times with different reflectance values
on a certain material by changing its description to something like
\begin{xml}
<bsdf type="lambertian">
<spectrum name="reflectance" value="$\texttt{\$}$reflectance"/>
</bsdf>
\end{xml}
and running Mitsuba as follows:
\begin{shell}
$\texttt{\$}$ mitsuba -Dreflectance=0.1 -o ref_0.1.exr scene.xml
$\texttt{\$}$ mitsuba -Dreflectance=0.2 -o ref_0.2.exr scene.xml
$\texttt{\$}$ mitsuba -Dreflectance=0.5 -o ref_0.5.exr scene.xml
\end{shell}
\subsubsection{Writing partial images to disk}
When doing lengthy command line renders on Linux or OSX, it is possible
to send a signal to the process using
\begin{shell}
$\texttt{\$}$ killall -HUP mitsuba
\end{shell}
This causes the renderer to write out the partially finished
image, after which it continues rendering. This can sometimes be useful to
check if everything is working correctly.
\subsubsection{Rendering an animation}
The command line interface is ideally suited for rendering large amounts of files in batch
operation. You can simply pass in the files using a wildcard in the filename. If you've
already rendered a subset of the frames and you only want to complete the remainder, add the
\texttt{-x} flag, and all files with existing output will be skipped. You can also
let the scheduler work on several scenes at once using the \texttt{-j} parameter --- this is
especially useful when you are
parallelizing over multiple machines: as some of the participating cores
finish rendering the current frame, they can immediately start working on the next one
instead of having to wait for all other cores to finish. Altogether, you
might start the renderer something like this
\begin{shell}
$\texttt{\$}$ mitsuba -xj 2 -c machine1;machine2;... animation/frame_*.xml
\end{shell}
\begin{console}[label=lst:mitsuba-cli,caption=Command line options of the \texttt{mitsuba} binary]
Mitsuba version 0.1.1, Copyright (c) 2010 Wenzel Jakob
Mitsuba version 0.2.1, Copyright (c) 2011 Wenzel Jakob
Usage: mitsuba [options] <One or more scene XML files>
Options/Arguments:
-h Display this help text
-D key=val Define a constant, which can referenced as "$\texttt{\$}$key" in the scene
-D key=val Define a constant, which can referenced as "$\$$key" in the scene
-o fname Write the output image to the file denoted by "fname"
@ -179,15 +56,139 @@ Options/Arguments:
-x Skip rendering of files where output already exists
-r sec Write (partial) output images every 'sec' seconds
-b res Specify the block resolution used to split images into parallel
workloads (default: 32). Only applies to some integrators.
-v Be more verbose
-b Disable progress bars
-w Treat warnings as errors
The README file included with the distribution contains further information.
-z Disable progress bars
For documentation, please refer to http://www.mitsuba-renderer.org/docs.html
\end{console}
\lstref{mitsuba-cli} shows the output resulting from this command. The most common
mode of operation is to render a single scene, which is provided as a parameter, e.g.
\begin{shell}
$\texttt{\$}$ mitsuba path-to/my-scene.xml
\end{shell}
It is also possible to connect to network render nodes, which essentially lets Mitsuba parallelize
over additional cores. To do this, pass a semicolon-separated list of machines to
the \code{-c} parameter.
\begin{shell}
$\texttt{\$}$ mitsuba -c machine1;machine2;... path-to/my-scene.xml
\end{shell}
There are two different ways in which you can access render nodes:
\begin{itemize}
\item\textbf{Direct}: Here, you create a direct connection to a running \code{mtssrv} instance on
another machine (\code{mtssrv} is the Mitsuba server process). From the the performance
standpoint, this approach should always be preferred over the SSH method described below when there is
a choice between them. There are some disadvantages though: first, you need to manually start
\code{mtssrv} on every machine you want to use.
And perhaps more importantly: the direct communication
protocol makes no provisions for a malicious user on the remote side. It is too costly
to constantly check the communication stream for illegal data sequences, so Mitsuba simply doesn't do it.
The consequence of this is that you should only use the direct communication approach within
trusted networks.
For direct connections, you can specify the remote port as follows:
\begin{shell}
$\texttt{\$}$ mitsuba -c machine:1234 path-to/my-scene.xml
\end{shell}
When no port is explicitly specified, Mitsuba uses default value of 7554.
\item \textbf{SSH}:
This approach works as follows: The renderer creates a SSH connection
to the remote side, where it launches a Mitsuba worker instance.
All subsequent communication then passes through the encrypted link.
This is completely secure but slower due to the encryption overhead.
If you are rendering a complex scene, there is a good chance that it
won't matter much since most time is spent doing computations rather than
communicating
Such an SSH link can be created simply by using a slightly different syntax:
\begin{shell}
$\texttt{\$}$ mitsuba -c username@machine path-to/my-scene.xml
\end{shell}
The above line assumes that the remote home directory contains
a Mitsuba source directory named \code{mitsuba},
which contains the compiled Mitsuba binaries.
If that is not the case, you need to provide the path to such a directory manually, e.g:
\begin{shell}
$\texttt{\$}$ mitsuba -c username@machine:/opt/mitsuba path-to/my-scene.xml
\end{shell}
For the SSH connection approach to work, you \emph{must} enable passwordless
authentication.
Try opening a terminal window and running the command \code{ssh username@machine}
(replace with the details of your remote connection).
If you are asked for a password, something is not set up correctly --- please see
\url{http://www.debian-administration.org/articles/152} for instructions.
On Windows, the situation is a bit more difficult since there is no suitable SSH client by
default. To get SSH connections to work, Mitsuba requires \code{plink.exe} (from PuTTY) to
be on the path. For passwordless authentication with a Linux/OSX-based
server, convert your private key to PuTTY's format using \code{puttygen.exe}.
Afterwards, start \code{pageant.exe} to load and authenticate the key. All
of these binaries are available from the PuTTY website.
It is possible to mix the two approaches to access some machines directly and others
over SSH.
\end{itemize}
When doing many network-based renders over the command line, it can become tedious to
specify the connections every time. They can alternatively be loaded from a text file
where each line contains a separate connection description as discussed previously:
\begin{shell}
$\texttt{\$}$ mitsuba -s servers.txt path-to/my-scene.xml
\end{shell}
where \code{servers.txt} e.g. contains
\begin{shell}
user1@machine1.domain.org:/opt/mitsuba
machine2.domain.org
machine3.domain.org:7346
\end{shell}
\subsubsection{Passing parameters}
Any attribute in the XML-based scene description language can be parameterized from the
command line.
For instance, you can render a scene several times with different reflectance values
on a certain material by changing its description to something like
\begin{xml}
<bsdf type="diffuse">
<spectrum name="reflectance" value="$\texttt{\$}$reflectance"/>
</bsdf>
\end{xml}
and running Mitsuba as follows:
\begin{shell}
$\texttt{\$}$ mitsuba -Dreflectance=0.1 -o ref_0.1.exr scene.xml
$\texttt{\$}$ mitsuba -Dreflectance=0.2 -o ref_0.2.exr scene.xml
$\texttt{\$}$ mitsuba -Dreflectance=0.5 -o ref_0.5.exr scene.xml
\end{shell}
\subsubsection{Writing partial images to disk}
When doing lengthy command line renders on Linux or OSX, it is possible
to send a signal to the process using
\begin{shell}
$\texttt{\$}$ killall -HUP mitsuba
\end{shell}
This causes the renderer to write out the partially finished
image, after which it continues rendering. This can sometimes be useful to
check if everything is working correctly.
\subsubsection{Rendering an animation}
The command line interface is ideally suited for rendering large amounts of files in batch
operation. You can simply pass in the files using a wildcard in the filename.
If you've already rendered a subset of the frames and you only want to complete the remainder,
add the \texttt{-x} flag, and all files with existing output will be skipped. You can also
let the scheduler work on several scenes at once using the \texttt{-j} parameter --- this is
especially useful when parallelizing over multiple machines: as some of the participating machines
finish rendering the current frame, they can immediately start working on the next one
instead of having to wait for all other cores to finish. Altogether, you
might start the with parameters such as the following
\begin{shell}
$\texttt{\$}$ mitsuba -xj 2 -c machine1;machine2;... animation/frame_*.xml
\end{shell}
\subsection{Direct connection server}
A Mitsuba compute node can be created using the \code{mtssrv} executable. By default,
it will listen on port 7554:
@ -204,13 +205,19 @@ $\texttt{\$}$ mtssrv -i maxwell.cs.cornell.edu
\end{shell}
As advised in Section~\ref{sec:mitsuba}, it is advised to run \code{mtssrv} \emph{only} in trusted networks.
One nice feature of \code{mtssrv} is that it (like \code{mitsuba}) also supports the \code{-c} and \code{-s}
parameters, which can be used to connect to additional compute servers.
This allows building large hierarchies of nodes,
where communication occurs only amongst neighbors and the root node presents itself as
a computer with hundreds of cores.
Connecting clients will not be able to distinguish additional cores obtained in this manner
from the actual server cores.
One nice feature of \code{mtssrv} is that it (like the \code{mitsuba} executable)
also supports the \code{-c} and \code{-s} parameters, which create connections
to additional compute servers.
Using this feature, one can create hierarchies of compute nodes. For instance,
the root \code{mttsrv} instance of such a hierarchy could share its work with a
number of other machines running \code{mtssrv}, and each of these might also
share their work with further machines, and so on...
The parallelization over such hierarchies happens transparently---when
connecting a renderering process to the root node, it sees a machine
with hundreds or thousands of cores, to which it can submit work without
needing to worry about how exactly it is going to be spread out in
the hierarchy.
Such hierarchies are mainly useful to reduce communication bottlenecks when distributing
large resources (such as scenes) to remote machines. Imagine the following hypothetical scenario:
@ -222,7 +229,7 @@ connection and the need to transmit your scene to every single compute node invo
Using \code{mtssrv}, you can
instead designate a central scheduling node at your workplace, which accepts connections and delegates
rendering tasks to the other machines. In this case, you will only have to transmit the scene once,
and the remaining distribution happens over the comparatively fast ethernet at your workplace.
and the remaining distribution happens over the fast local network at your workplace.
\subsection{Utility launcher}
\label{sec:mtsutil}
When working on a larger project, one often needs to implement various utility programs that

View File

@ -1,4 +1,5 @@
\section{Compiling the renderer}
\label{sec:compiling}
To compile Mitsuba, you will need a recent C++ compiler (e.g. GCC 4.1+ or
Visual Studio 2008+) and some additional libraries, which Mitsuba uses internally.
Builds on all supported platforms are done using a unified system
@ -33,6 +34,8 @@ build/config-icl12-msvc2010-win32.py
build/config-icl12-msvc2010-win64.py
\end{shell}
\subsection{Compilation flags}
\label{sec:compiling-flags}
Usually, you will not have to make any modification to this file, but sometimes a few minor
edits may be necessary. In particular, you might want to add or remove certain
compilation flags from the \code{CXXFLAGS} parameter. The following settings
@ -50,9 +53,7 @@ Off by default.
\item[\texttt{MTS\_SSE}]Activate optimized SSE routines. On by default.
\item[\texttt{MTS\_HAS\_COHERENT\_RT}]Include coherent ray tracing support (depends on \texttt{MTS\_SSE}). This flag is activated by default.
\item[\texttt{MTS\_DEBUG\_FP}]Generated NaNs and overflows will cause floating point exceptions, which can be caught in a debugger. This is slow and mainly meant as a debugging tool for developers. Off by default.
\item[\texttt{MTS\_SPECTRUM\_SAMPLES=}$\langle ..\rangle$]This setting defines the number of spectral samples (in the 400-700 $nm$ range) used to render scenes.
The default is 3 samples, in which case the renderer automatically turns into an RGB-based system. For high-quality spectral rendering, this should
be set to 30 or higher.
\item[\texttt{SPECTRUM\_SAMPLES=}$\langle ..\rangle$]This setting defines the number of spectral samples (in the 368-830 $nm$ range) that are used to render scenes. The default is 3 samples, in which case the renderer automatically turns into an RGB-based system. For high-quality spectral rendering, this should be set to 30 or higher.
\item[\texttt{SINGLE\_PRECISION}] Do all computation in single precision. This is normally sufficient and therefore used as the default setting.
\item[\texttt{DOUBLE\_PRECISION}] Do all computation in double precision. This flag is incompatible with
\texttt{MTS\_SSE}, \texttt{MTS\_HAS\_COHERENT\_RT}, and \texttt{MTS\_DEBUG\_FP}.

View File

@ -122,40 +122,77 @@ Integer and floating point values can be passed as follows:
Note that you must adhere to the format expected by the object, i.e. you can't pass an integer property
to an object, which expects a floating-point value associated with that name.
\subsubsection{Strings}
Passing strings is very straightforward:
Passing strings is straightforward:
\begin{xml}
<string name="stringProperty" value="This is a string"/>
\end{xml}
\subsubsection{Color spectra}
There are several different ways of passing color spectra to objects, which can be used interchangeably.
The most basic one is to supply linear RGB or sRGB values as floating-point triplets or hex values
Depending on the compilation flags of Mitsuba (see \secref{compiling-flags} for
details), the renderer internally either represents colors using discretized color spectra
(when \texttt{SPECTRUM\_SAMPLES} is set to a value other than 3), or it
uses a basic linear RGB representation\footnote{The official
releases all use linear RGB---to do spectral renderings, you will have
to compile Mitsuba yourself.}.
Irrespective of which internal representation is used, Mitsuba supports
several different ways of specifying color information, which is then
converted appropriately.
The preferred way of passing color spectra to the renderer is to explicitly
denote the associated wavelengths of each value:
\begin{xml}
<spectrum name="spectrumProperty" value="400:0.56, 500:0.18, 600:0.58, 700:0.24"/>
\end{xml}
This is a mapping from wavelength in nanometers (before the colon)
to a reflectance or intensity value (after the colon).
Values in between are linearly interpolated from the two closest neighbors.
A useful shortcut to get a completely uniform spectrum, it is to provide
only a single value:
\begin{xml}
<spectrum name="spectrumProperty" value="0.56"/>
\end{xml}
Another (discouraged) option is to directly provide the spectrum in Mitsuba's
internal representation, avoiding the need for any kind of conversion.
However, this is problematic, since the associated scene will likely not work
anymore when Mitsuba is compiled with a different value of
\texttt{SPECTRUM\_SAMPLES}.
For completeness, the possibility is explained nonetheless. Assuming that
the 360-830$nm$ range is discretized into ten 47$nm$-sized blocks
(i.e. \texttt{SPECTRUM\_SAMPLES} is set to 10), their values can be specified
as follows:
\begin{xml}
<spectrum name="spectrumProperty" value=".2, .2, .8, .4, .6, .5, .1, .9, .4, .2"/>
\end{xml}
Another convenient way of providing color spectra is by specifying linear RGB
or sRGB values using floating-point triplets or hex values:
\begin{xml}
<rgb name="spectrumProperty" value="0.2, 0.8, 0.4"/>
<srgb name="spectrumProperty" value="0.4, 0.3, 0.2"/>
<srgb name="spectrumProperty" value="#f9aa34"/>
\end{xml}
When Mitsuba is compiled with the default settings, it internally uses linear RGB to represent colors, so
these values are directly used. The renderer can also be configured to sample the color spectrum using a specified
number of samples, in which case the RGB values are first converted into spectra using a simple heuristic.
When Mitsuba is compiled with the default settings, it internally uses
linear RGB to represent colors, so these values can directly be used.
However, when configured for doing spectral rendering, a suitable color
spectrum with the requested RGB reflectance must be found. This is a tricky
problem, since there is an infinite number of spectra with this property.
You can also directly supply the spectral color samples that Mitsuba internally uses if spectral rendering is
active. This unfortunately closely couples the interpretation of a scene to how Mitsuba is compiled, which
can be a disadvantage.
For instance, the below example assumes that 6 spectral samples in the 400-700nm range are being used:
Mitsuba uses a method by Smits et al. \cite{Smits2005RGB} to find a
``plausible'' spectrum that is as smooth as possible. To do so, it uses
one of two methods depending on whether the spectrum contains a
unitless reflectance value, or a radiance-valued intensity.
\begin{xml}
<spectrum name="spectrumProperty" value="0.2, 0.8, 0.4, 0.6, 0.1, 0.9"/>
<rgb name="spectrumProperty" intent="reflectance" value="0.2, 0.8, 0.4"/>
<rgb name="spectrumProperty" intent="illuminant" value="0.2, 0.8, 0.4"/>
\end{xml}
A safer way is to specify a linearly interpolated spectral power distribution, which is converted into
the internal spectral representation when the scene is loaded.
\begin{xml}
<spectrum name="spectrumProperty" value="400:0.56, 500:0.18, 600:0.58, 700:0.24"/>
\end{xml}
This is essentially a mapping from wavelength in nanometers (before the colon) to a reflectance or
intensity value (after the colon). Missing values are linearly interpolated from the two closest neighbors.
The \texttt{reflectance} intent is used by default, so remember to
set it to \texttt{illuminant} when defining the brightness of a
light source with the \texttt{<rgb>} tag.
When spectral power distributions are obtained from measurements (e.g. at 10nm intervals), they are
usually quite unwiedy and can clutter the scene description. For this reason,
there is yet another way to pass a spectrum by loading it from an external
When spectral power distributions are obtained from measurements
(e.g. at 10$nm$ intervals), they are usually quite unwiedy and can clutter
the scene description. For this reason, there is yet another way to pass
a spectrum by loading it from an external
file:
\begin{xml}
<spectrum name="spectrumProperty" filename="measuredSpectrum.spd"/>
@ -173,11 +210,6 @@ are allowed. Here is an example:
...
\end{xml}
Passing a single value to \texttt{spectrum} will result in a a completely flat spectral power distribution:
\begin{xml}
<spectrum name="spectrumProperty" value="0.56"/>
\end{xml}
Finally, it is also possible to specify the spectral distribution of a black body emitter, where the temperature is given in Kelvin.
\begin{xml}
<blackbody name="spectrumProperty" temperature="5000"/>
@ -233,8 +265,8 @@ choices are available:
\end{xml}
\item Scaling operations. The coefficients may also be negative to obtain a flip, e.g.
\begin{xml}
<scale x="2" y="1" z="-1"/>
<scale value="5"/> <!-- (uniform scale) -->
<scale value="5"/> <!-- uniform scale -->
<scale x="2" y="1" z="-1"/> <!-- non-unform scale -->
\end{xml}
\item Explicit 4$\times$4 matrices, e.g
\begin{xml}

View File

@ -1,23 +1,33 @@
\section{Introduction}
\textbf{Disclaimer:} This is manual is currently a work in progress---please
bear with me while things are coming together.
\textbf{Disclaimer:} This is manual documents the usage, file format, and
internal design of the Mitsuba rendering system. It is currently a work
in progress, hence some parts may still be incomplete or missing.
\subsection{About Mitsuba}
Mitsuba is an extensible rendering framework written in portable C++. It implements unbiased
as well as biased techniques and contains heavy optimizations targeted towards current CPU
architectures.
In comparison to other open source renderers, Mitsuba places a strong emphasis on recent research-oriented
rendering techniques, such as path-based formulations of Metropolis Light Transport and volumetric
modeling approaches.
Mitsuba is a research-oriented rendering system in the style of PBRT
(\url{www.pbrt.org}), from which it derives much inspiration.
It is written in portable C++, implements unbiased as well
as biased techniques, and contains heavy optimizations targeted
towards current CPU architectures.
\paragraph{Performance:}
In comparison to other open source renderers, Mitsuba places a strong
emphasis on experimental rendering techniques, such as path-based
formulations of Metropolis Light Transport and volumetric
modeling approaches. Thus, it may be of genuine interest to those who
would like to experiment with such techniques that haven't yet found
their way into mainstream renderers, and it also provides a solid
foundation for research in this domain.
Other design considerations are are:
\parheader{Performance:}
One important goal of Mitsuba is to provide optimized implementations of the most commonly
used rendering algorithms. By virtue of running on a shared foundation, comparisons between them can
better highlight the merits and limitations of different approaches. This is in contrast to, say,
comparing two completely different rendering products, where technical information on the underlying
implementation is often intentionally not provided.
\paragraph{Robustness:}
\parheader{Robustness:}
In many cases, physically-based rendering packages force the user to model scenes with the underlying
algorithm (specifically: its convergence behavior) in mind. For instance, glass windows are routinely
replaced with light portals, photons must be manually guided to the relevant parts of a scene, and
@ -25,18 +35,18 @@ interactions with complex materials are taboo, since they cannot be importance s
One focus of Mitsuba will be to develop path-space light transport algorithms, which handle such
cases more gracefully.
\paragraph{Scalability:} Mitsuba instances can be merged into large clusters, which transparently distribute and
\parheader{Scalability:} Mitsuba instances can be merged into large clusters, which transparently distribute and
jointly execute tasks assigned to them using only node-to-node communcation. It has successfully
scaled to large-scale renderings that involved 1024 cores working on a single image.
scaled to large-scale renderings that involved more than 1000 cores working on a single image.
Most algorithms in Mitsuba are written using a generic parallelization layer, which can tap
into this cluster-wide parallelism. The principle is that if any component of the renderer produces
work that takes longer than a second or so, it at least ought to use all of the processing power
it can get.
The renderer also tries to be very conservative in its use of memory, which lets it handle
The renderer also tries to be very conservative in its use of memory, which allows it to handle
large scenes (>30 million triangles) and multi-gigabyte heterogeneous volumes on consumer hardware.
\paragraph{Usability:}
\parheader{Usability:}
Mitsuba comes with a graphical user interface to interactively explore scenes. Once a suitable
viewpoint has been found, it is straightforward to perform renderings using any of the
implemented rendering techniques, while tweaking their parameters to find the most suitable

View File

@ -23,6 +23,7 @@
\newcommand{\MtsVer}{\color{lstattrib}\texttt{"\MitsubaVersion"}}
\newcommand{\showbreak}{$\rhookswarrow$ }
\newcommand{\parheader}[1]{\vspace{2mm}\textbf{\color{myblue}#1}}
\newcommand{\otoprule}{\midrule[.8pt]}
\newlength\fboxrulebackup

View File

@ -12,3 +12,12 @@
year = {2011},
month = {July}
}
@article{Smits2005RGB,
title = {{An RGB-to-spectrum conversion for reflectances}},
author = {Smits, Brian},
journal = {Graphics tools: The jgt editors' choice},
pages = {291},
year = {2005},
publisher = {AK Peters, Ltd.}
}

View File

@ -68,11 +68,15 @@ public:
* \param useConvergenceEstimate Estimate the convergence behavior
* of the GL-quadrature by comparing the 4, 7 and 13-point
* variants and increase the absolute tolerance accordingly.
*
* \param warn Should the integrator warn when the number of
* function evaluations is exceeded?
*/
GaussLobattoIntegrator(size_t maxEvals,
Float absError = 0,
Float relError = 0,
bool useConvergenceEstimate = true);
bool useConvergenceEstimate = true,
bool warn = true);
/**
* \brief Integrate the function \c f from \c a to \c b.
@ -106,8 +110,8 @@ protected:
protected:
Float m_absError, m_relError;
size_t m_maxEvals;
bool m_exceededEvals;
const bool m_useConvergenceEstimate;
bool m_useConvergenceEstimate;
bool m_warn;
static const Float m_alpha;
static const Float m_beta;
static const Float m_x1;

View File

@ -29,8 +29,8 @@ namespace fs = boost::filesystem;
specified in the configuration file!
#endif
#define SPECTRUM_MIN_WAVELENGTH 400
#define SPECTRUM_MAX_WAVELENGTH 700
#define SPECTRUM_MIN_WAVELENGTH 360
#define SPECTRUM_MAX_WAVELENGTH 830
#define SPECTRUM_RANGE \
(SPECTRUM_MAX_WAVELENGTH-SPECTRUM_MIN_WAVELENGTH)
@ -154,8 +154,8 @@ public:
* for the specified number of samples
*/
inline InterpolatedSpectrum(size_t size = 0) {
m_wavelength.reserve(size);
m_value.reserve(size);
m_wavelengths.reserve(size);
m_values.reserve(size);
}
/**
@ -195,6 +195,9 @@ public:
*/
void zeroExtend();
/// Clear all stored entries
void clear();
/**
* \brief Return the value of the spectral power distribution
* at the given wavelength.
@ -226,11 +229,11 @@ public:
/// Virtual destructor
virtual ~InterpolatedSpectrum() { }
private:
std::vector<Float> m_wavelength, m_value;
std::vector<Float> m_wavelengths, m_values;
};
/** \brief Discrete spectral power distribution based on a number
* of wavelength bins over the 400-700 nm range.
* of wavelength bins over the 360-830 nm range.
*
* This class defines a vector-like data type that can be used for
* computations involving radiance.
@ -524,7 +527,7 @@ public:
Float eval(Float lambda) const;
/// \brief Return the wavelength range covered by a spectral bin
std::pair<Float, Float> getBinCoverage(size_t index) const;
static std::pair<Float, Float> getBinCoverage(size_t index);
/// Return the luminance in candelas.
#if SPECTRUM_SAMPLES == 3
@ -558,7 +561,7 @@ public:
/// Convert from linear RGB
inline void fromLinearRGB(Float r, Float g, Float b,
EConversionIntent /* unused */) {
EConversionIntent intent = EReflectance /* unused */) {
/* Nothing to do -- the renderer is in RGB mode */
s[0] = r; s[1] = g; s[2] = b;
}

View File

@ -71,6 +71,9 @@ protected:
/// Asserts that the two floating point values are equal
void assertEqualsImpl(Float expected, Float actual, Float epsilon, const char *file, int line);
/// Asserts that the two spectral power distributions are equal
void assertEqualsImpl(const Spectrum &expected, const Spectrum &actual, Float epsilon, const char *file, int line);
/// Asserts that the two 2D vectors are equal
void assertEqualsImpl(const Vector2 &expected, const Vector2 &actual, Float epsilon, const char *file, int line);

View File

@ -22,7 +22,7 @@
<xsd:element name="transform" type="transform"/>
<xsd:element name="string" type="string"/>
<xsd:element name="spectrum" type="spectrum"/>
<xsd:element name="rgb" type="string"/>
<xsd:element name="rgb" type="rgb"/>
<xsd:element name="srgb" type="string"/>
<xsd:element name="blackbody" type="blackbody"/>
</xsd:choice>
@ -42,7 +42,7 @@
<xsd:element name="transform" type="transform"/>
<xsd:element name="string" type="string"/>
<xsd:element name="spectrum" type="spectrum"/>
<xsd:element name="rgb" type="string"/>
<xsd:element name="rgb" type="rgb"/>
<xsd:element name="srgb" type="string"/>
<xsd:element name="blackbody" type="blackbody"/>
</xsd:choice>
@ -276,6 +276,12 @@
<xsd:attribute name="value" type="xsd:string" use="required"/>
</xsd:complexType>
<xsd:complexType name="rgb">
<xsd:attribute name="name" type="xsd:string" use="required"/>
<xsd:attribute name="value" type="xsd:string" use="required"/>
<xsd:attribute name="intent" type="xsd:string" use="optional"/>
</xsd:complexType>
<xsd:complexType name="spectrum">
<xsd:attribute name="name" type="xsd:string" use="required"/>
<xsd:attribute name="filename" type="xsd:string" use="optional"/>

103
src/bsdfs/conductor.cpp Normal file
View File

@ -0,0 +1,103 @@
/*
This file is part of Mitsuba, a physically based rendering system.
Copyright (c) 2007-2011 by Wenzel Jakob and others.
Mitsuba is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License Version 3
as published by the Free Software Foundation.
Mitsuba is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <mitsuba/render/bsdf.h>
#include <mitsuba/render/consttexture.h>
#include "ior.h"
MTS_NAMESPACE_BEGIN
/*! \plugin{conductor}{Smooth conductor}
*/
class SmoothConductor : public BSDF {
public:
SmoothConductor(const Properties &props) : BSDF(props) {
m_specularReflectance = new ConstantSpectrumTexture(
props.getSpectrum("specularReflectance", Spectrum(1.0f)));
m_eta = props.getSpectrum("eta");
m_k = props.getSpectrum("k");
m_components.push_back(EDeltaReflection | EFrontSide);
m_usesRayDifferentials = false;
}
SmoothConductor(Stream *stream, InstanceManager *manager)
: BSDF(stream, manager) {
m_specularReflectance = static_cast<Texture *>(manager->getInstance(stream));
m_eta = Spectrum(stream);
m_k = Spectrum(stream);
m_components.push_back(EDeltaReflection | EFrontSide);
m_usesRayDifferentials =
m_specularReflectance->usesRayDifferentials();
}
virtual ~SmoothConductor() { }
void serialize(Stream *stream, InstanceManager *manager) const {
BSDF::serialize(stream, manager);
manager->serialize(stream, m_specularReflectance.get());
m_eta.serialize(stream);
m_k.serialize(stream);
}
void addChild(const std::string &name, ConfigurableObject *child) {
if (child->getClass()->derivesFrom(MTS_CLASS(Texture)) && name == "specularReflectance") {
m_specularReflectance = static_cast<Texture *>(child);
m_usesRayDifferentials |= m_specularReflectance->usesRayDifferentials();
} else {
BSDF::addChild(name, child);
}
}
Spectrum sample(BSDFQueryRecord &bRec, const Point2 &sample) const {
return Spectrum(0.0f);
}
Spectrum eval(const BSDFQueryRecord &bRec, EMeasure measure) const {
return Spectrum(0.0f);
}
Spectrum sample(BSDFQueryRecord &bRec, Float &pdf, const Point2 &sample) const {
return Spectrum(0.0f);
}
Float pdf(const BSDFQueryRecord &bRec, EMeasure measure) const {
return 0.0f;
}
std::string toString() const {
std::ostringstream oss;
oss << "SmoothConductor[" << endl
<< " eta = " << m_eta.toString() << "," << endl
<< " k = " << m_k.toString() << "," << endl
<< " specularReflectance = " << indent(m_specularReflectance->toString()) << endl
<< "]";
return oss.str();
}
MTS_DECLARE_CLASS()
private:
ref<Texture> m_specularReflectance;
Spectrum m_eta;
Spectrum m_k;
};
MTS_IMPLEMENT_CLASS_S(SmoothConductor, false, BSDF)
MTS_EXPORT_PLUGIN(SmoothConductor, "Smooth conductor");
MTS_NAMESPACE_END

238
src/bsdfs/microfacet.h Normal file
View File

@ -0,0 +1,238 @@
/*
This file is part of Mitsuba, a physically based rendering system.
Copyright (c) 2007-2011 by Wenzel Jakob and others.
Mitsuba is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License Version 3
as published by the Free Software Foundation.
Mitsuba is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if !defined(__MICROFACET_H)
#define __MICROFACET_H
#include <mitsuba/mitsuba.h>
#include <boost/algorithm/string.hpp>
MTS_NAMESPACE_BEGIN
/**
* Implements the microfacet distributions discussed in
* "Microfacet Models for Refraction through Rough Surfaces"
* by Bruce Walter, Stephen R. Marschner, Hongsong Li, and Kenneth E. Torrance
*/
class MicrofacetDistribution {
public:
/// Supported distribution types
enum EType {
/// Beckmann distribution derived from Gaussian random surfaces
EBeckmann = 0,
/// Classical Phong distribution
EPhong = 1,
/// Long-tailed distribution proposed by Walter et al.
EGGX = 2
};
/// Create a microfacet distribution of the specified type
MicrofacetDistribution(EType type = EBeckmann)
: m_type(type) { }
/**
* \brief Create a microfacet distribution of the specified name
* (ggx/phong/beckmann)
*/
MicrofacetDistribution(const std::string &name) {
std::string distr =
boost::to_lower_copy(props.getString("distribution", "beckmann"));
if (distr == "beckmann")
m_type = EBeckmann;
else if (distr == "phong")
m_type = EPhong;
else if (distr == "ggx")
m_type = EGGX;
else
SLog(EError, "Specified an invalid distribution \"%s\", must be "
"\"beckmann\", \"phong\", or \"ggx\"!", distr.c_str());
}
/// Return the distribution type
inline EType getType() const { return m_type; }
/**
* \brief Convert the roughness values so that they behave similarly to the
* Beckmann distribution.
*
* Also clamps to the minimal roughness 1e-4 to avoid numerical issues
* (For lower roughness values, please switch to the smooth BSDF variants)
*/
Float transformRoughness(Float value) const {
if (m_type == EPhong)
value = 2 / (value * value) - 2;
return std::max(value, (Float) 1e-4f);
}
/**
* \brief Implements the microfacet distribution function D
*
* \param m The microsurface normal
* \param v An arbitrary direction
*/
Float eval(const Vector &m, Float alpha) const {
if (Frame::cosTheta(m) <= 0)
return 0.0f;
Float result;
switch (m_type) {
case EBeckmann: {
/* Beckmann distribution function for Gaussian random surfaces */
const Float ex = Frame::tanTheta(m) / alpha;
result = std::exp(-(ex*ex)) / (M_PI * alpha*alpha *
std::pow(Frame::cosTheta(m), (Float) 4.0f));
}
break;
case EPhong: {
/* Phong distribution function */
result = (alpha + 2) * INV_TWOPI
* std::pow(Frame::cosTheta(m), alpha);
}
break;
case EGGX: {
/* Empirical GGX distribution function for rough surfaces */
const Float tanTheta = Frame::tanTheta(m),
cosTheta = Frame::cosTheta(m);
const Float root = alpha / (cosTheta*cosTheta *
(alpha*alpha + tanTheta*tanTheta));
result = INV_PI * (root * root);
}
break;
default:
SLog(EError, "Invalid distribution function!");
return 0.0f;
}
/* Prevent potential numerical issues in other stages of the model */
if (result < 1e-20f)
result = 0;
return result;
}
/**
* \brief Sample microsurface normals according to
* the selected distribution
*
* \param sample A uniformly distributed 2D sample
* \param alpha Surface roughness
*/
Normal sample(const Point2 &sample, Float alpha) const {
/* The azimuthal component is always selected
uniformly regardless of the distribution */
Float phiM = (2.0f * M_PI) * sample.y,
thetaM = 0.0f;
switch (m_type) {
case EBeckmann:
thetaM = std::atan(std::sqrt(-alpha*alpha *
std::log(1.0f - sample.x)));
break;
case EPhong:
thetaM = std::acos(std::pow(sample.x, (Float) 1 /
(alpha + 2)));
break;
case EGGX:
thetaM = std::atan(alpha * std::sqrt(sample.x) /
std::sqrt(1.0f - sample.x));
break;
default:
SLog(EError, "Invalid distribution function!");
}
return Normal(sphericalDirection(thetaM, phiM));
}
/**
* \brief Smith's shadow-masking function G1 for each
* of the supported microfacet distributions
*
* \param m The microsurface normal
* \param v An arbitrary direction
* \param alpha The surface roughness
*/
Float smithG1(const Vector &v, const Vector &m, Float alpha) const {
const Float tanTheta = std::abs(Frame::tanTheta(v));
/* perpendicular incidence -- no shadowing/masking */
if (tanTheta == 0.0f)
return 1.0f;
/* Can't see the back side from the front and vice versa */
if (dot(v, m) * Frame::cosTheta(v) <= 0)
return 0.0f;
switch (m_type) {
case EPhong:
/* Approximation recommended by Bruce Walter: Use
the Beckmann shadowing-masking function with
specially chosen roughness value */
alpha = std::sqrt(0.5f * alpha + 1) / tanTheta;
case EBeckmann: {
/* Use a fast and accurate (<0.35% rel. error) rational
approximation to the shadowing-masking function */
const Float a = 1.0f / (alpha * tanTheta);
const Float aSqr = a * a;
if (a >= 1.6f)
return 1.0f;
return (3.535f * a + 2.181f * aSqr)
/ (1.0f + 2.276f * a + 2.577f * aSqr);
}
break;
case EGGX: {
const Float root = alpha * tanTheta;
return 2.0f / (1.0f + std::sqrt(1.0f + root*root));
}
break;
default:
SLog(EError, "Invalid distribution function!");
return 0.0f;
}
}
std::string toString() const {
switch (m_distribution) {
case EBeckmann: return "beckmann"; break;
case EPhong: return "phong"; break;
case EGGX: return "ggx"; break;
default:
SLog(EError, "Invalid distribution function");
return "";
}
}
private:
EType type;
};
MTS_NAMESPACE_END
#endif /* __MICROFACET_H */

View File

@ -23,7 +23,6 @@ MTS_NAMESPACE_BEGIN
FOR A PARTICULAR PURPOSE. See the license for more details.
*/
const Float GaussLobattoIntegrator::m_alpha = (Float) std::sqrt(2.0/3.0);
const Float GaussLobattoIntegrator::m_beta = (Float) (1.0/std::sqrt(5.0));
const Float GaussLobattoIntegrator::m_x1 = (Float) 0.94288241569547971906;
@ -31,11 +30,12 @@ const Float GaussLobattoIntegrator::m_x2 = (Float) 0.64185334234578130578;
const Float GaussLobattoIntegrator::m_x3 = (Float) 0.23638319966214988028;
GaussLobattoIntegrator::GaussLobattoIntegrator(size_t maxEvals,
Float absError, Float relError, bool useConvergenceEstimate)
Float absError, Float relError, bool useConvergenceEstimate, bool warn)
: m_absError(absError),
m_relError(relError),
m_maxEvals(maxEvals),
m_useConvergenceEstimate(useConvergenceEstimate) {
m_useConvergenceEstimate(useConvergenceEstimate),
m_warn(warn) {
if (m_absError == 0 && m_relError == 0)
SLog(EError, "GaussLobattoIntegrator:: Absolute and relative "
"error requirements can't both be zero!");
@ -53,9 +53,9 @@ Float GaussLobattoIntegrator::integrate(
}
const Float absTolerance = calculateAbsTolerance(f, a, b, evals);
evals += 2;
if (evals >= m_maxEvals)
SLog(EWarn, "GaussLobattoIntegrator: Maximum number of evaluations reached!");
Float result = factor * adaptiveGaussLobattoStep(f, a, b, f(a), f(b), absTolerance, evals);
if (evals >= m_maxEvals && m_warn)
SLog(EWarn, "GaussLobattoIntegrator: Maximum number of evaluations reached!");
if (_evals)
*_evals = evals;
return result;
@ -73,18 +73,15 @@ Float GaussLobattoIntegrator::calculateAbsTolerance(
const Float y11= f(m+m_alpha*h);
const Float y13= f(b);
Float acc=h*((Float) 0.0158271919734801831*(y1+y13)
+(Float) 0.0942738402188500455*(f(m-m_x1*h)+f(m+m_x1*h))
+(Float) 0.1550719873365853963*(y3+y11)
+(Float) 0.1888215739601824544*(f(m-m_x2*h)+ f(m+m_x2*h))
+(Float) 0.1997734052268585268*(y5+y9)
+(Float) 0.2249264653333395270*(f(m-m_x3*h)+f(m+m_x3*h))
+(Float) 0.2426110719014077338*y7);
Float acc = h*((Float) 0.0158271919734801831*(y1+y13)
+ (Float) 0.0942738402188500455*(f(m-m_x1*h)+f(m+m_x1*h))
+ (Float) 0.1550719873365853963*(y3+y11)
+ (Float) 0.1888215739601824544*(f(m-m_x2*h)+ f(m+m_x2*h))
+ (Float) 0.1997734052268585268*(y5+y9)
+ (Float) 0.2249264653333395270*(f(m-m_x3*h)+f(m+m_x3*h))
+ (Float) 0.2426110719014077338*y7);
evals += 13;
if (acc == 0)
SLog(EError, "GaussLobattoIntegrator: Cannot calculate absolute error from relative error");
Float r = 1.0;
if (m_useConvergenceEstimate) {
const Float integral2 = (h/6)*(y1+y13+5*(y5+y9));
@ -98,7 +95,7 @@ Float GaussLobattoIntegrator::calculateAbsTolerance(
}
Float result = std::numeric_limits<Float>::infinity();
if (m_relError != 0)
if (m_relError != 0 && acc != 0)
result = acc * std::max(m_relError,
std::numeric_limits<Float>::epsilon())
/ (r*std::numeric_limits<Float>::epsilon());
@ -134,16 +131,11 @@ Float GaussLobattoIntegrator::adaptiveGaussLobattoStep(
evals += 5;
if (evals >= m_maxEvals) {
if (evals-5 < m_maxEvals) // Warn once
SLog(EWarn, "GaussLobattoIntegrator: Maximum number of evaluations reached!");
if (evals >= m_maxEvals)
return integral1;
}
Float dist = acc + (integral1-integral2);
if(dist==acc || mll<=a || b<=mrr) {
if (m<=a || b<=m)
SLog(EWarn, "GaussLobattoIntegrator: Interval contains no more machine numbers!");
if (dist==acc || mll<=a || b<=mrr) {
return integral1;
} else {
return adaptiveGaussLobattoStep(f,a,mll,fa,fmll,acc,evals)

View File

@ -160,15 +160,12 @@ void Spectrum::staticShutdown() {
void Spectrum::fromContinuousSpectrum(const ContinuousSpectrum &smooth) {
#if SPECTRUM_SAMPLES == 3
/* Convolve with the XYZ matching functions and convert to RGB */
Float start = CIE_wavelengths[0], end = CIE_wavelengths[CIE_samples-1];
Float X = smooth->average(ProductSpectrum(smooth, CIE_X_interp),
(Float) CIE_start, (Float) CIE_end);
Float Y = smooth->average(ProductSpectrum(smooth, CIE_Y_interp),
(Float) CIE_start, (Float) CIE_end);
Float Z = smooth->average(ProductSpectrum(smooth, CIE_Z_interp),
(Float) CIE_start, (Float) CIE_end);
Float normalization = 1.0f /
CIE_Y_interp.average((Float) CIE_start, (Float) CIE_end);
Float X = ProductSpectrum(smooth, CIE_X_interp).average(start, end);
Float Y = ProductSpectrum(smooth, CIE_Y_interp).average(start, end);
Float Z = ProductSpectrum(smooth, CIE_Z_interp).average(start, end);
Float normalization = 1.0f / CIE_Y_interp.average(start, end);
X *= normalization; Y *= normalization; Z *= normalization;
@ -197,7 +194,7 @@ Float Spectrum::eval(Float lambda) const {
#endif
}
std::pair<Float, Float> Spectrum::getBinCoverage(size_t index) const {
std::pair<Float, Float> Spectrum::getBinCoverage(size_t index) {
#if SPECTRUM_SAMPLES == 3
SLog(EError, "Spectrum::getBinCoverage() is not supported when Mitsuba "
"is configured for RGB-based rendering");
@ -413,7 +410,8 @@ std::string Spectrum::toString() const {
#if SPECTRUM_SAMPLES == 3
oss << s[i];
#else
oss << m_wavelengths[i] << " => " << s[i];
oss << m_wavelengths[i] << "-"
<< m_wavelengths[i+1] << "nm => " << s[i];
#endif
if (i < SPECTRUM_SAMPLES - 1)
oss << ", ";
@ -441,14 +439,27 @@ Float ProductSpectrum::eval(Float lambda) const {
}
Float ContinuousSpectrum::average(Float lambdaMin, Float lambdaMax) const {
GaussLobattoIntegrator integrator(10000, Epsilon, Epsilon);
GaussLobattoIntegrator integrator(10000, Epsilon, Epsilon, false, false);
if (lambdaMax <= lambdaMin)
return 0.0f;
return integrator.integrate(
boost::bind(&ContinuousSpectrum::eval, this, _1), lambdaMin, lambdaMax)
/ (lambdaMax - lambdaMin);
Float integral = 0;
/// Integrate over 50nm-sized regions
size_t nSteps = std::max((size_t) 1,
(size_t) std::ceil((lambdaMax - lambdaMin) / 50));
Float stepSize = (lambdaMax - lambdaMin) / nSteps,
pos = lambdaMin;
for (size_t i=0; i<nSteps; ++i) {
integral += integrator.integrate(
boost::bind(&ContinuousSpectrum::eval, this, _1),
pos, pos + stepSize);
pos+= stepSize;
}
return integral / (lambdaMax - lambdaMin);
}
InterpolatedSpectrum::InterpolatedSpectrum(const fs::path &path) {
@ -471,72 +482,81 @@ InterpolatedSpectrum::InterpolatedSpectrum(const fs::path &path) {
append(lambda, value);
}
SLog(EInfo, "\"%s\": loaded a spectral power distribution with " SIZE_T_FMT
" entries", path.leaf().c_str(), m_wavelength.size());
" entries", path.leaf().c_str(), m_wavelengths.size());
}
InterpolatedSpectrum::InterpolatedSpectrum(const Float *wavelengths, const Float *values, size_t nEntries) {
m_wavelength.resize(nEntries);
m_value.resize(nEntries);
m_wavelengths.resize(nEntries);
m_values.resize(nEntries);
for (size_t i=0; i<nEntries; ++i) {
m_wavelength[i] = *wavelengths++;
if (i > 0 && m_wavelength[i-1] >= m_wavelength[i])
m_wavelengths[i] = *wavelengths++;
if (i > 0 && m_wavelengths[i-1] >= m_wavelengths[i])
SLog(EError, "InterpolatedSpectrum: spectral power distribution values must "
"be provided in order of increasing wavelength!");
m_value[i] = *values++;
m_values[i] = *values++;
}
}
void InterpolatedSpectrum::append(Float lambda, Float value) {
if (m_wavelength.size() != 0 && m_wavelength[m_wavelength.size()-1] >= lambda)
if (m_wavelengths.size() != 0 && m_wavelengths[m_wavelengths.size()-1] >= lambda)
SLog(EError, "InterpolatedSpectrum: spectral power distribution values must "
"be provided in order of increasing wavelength!");
m_wavelength.push_back(lambda);
m_value.push_back(value);
m_wavelengths.push_back(lambda);
m_values.push_back(value);
}
void InterpolatedSpectrum::clear() {
m_wavelengths.clear();
m_values.clear();
}
void InterpolatedSpectrum::zeroExtend() {
if (m_wavelength.size() < 2)
if (m_wavelengths.size() < 2)
SLog(EError, "InterpolatedSpectrum::zeroExtend() -- at least 2 "
"entries are needed!");
Float avgSpacing = 0;
for (size_t i=0; i<m_wavelength.size()-1; ++i)
avgSpacing += m_wavelength[i+1] - m_wavelength[i];
for (size_t i=0; i<m_wavelengths.size()-1; ++i)
avgSpacing += m_wavelengths[i+1] - m_wavelengths[i];
avgSpacing /= m_wavelength.size()-1;
m_wavelength.insert(m_wavelength.begin(), m_wavelength[0] - avgSpacing);
m_wavelength.push_back(m_wavelength[m_wavelength.size()-1] + avgSpacing);
m_value.insert(m_value.begin(), 0.0f);
m_value.push_back(0);
avgSpacing /= m_wavelengths.size()-1;
if (m_values[0] != 0) {
m_wavelengths.insert(m_wavelengths.begin(), m_wavelengths[0] - avgSpacing);
m_values.insert(m_values.begin(), 0.0f);
}
if (m_values[m_values.size()-1] != 0) {
m_wavelengths.push_back(m_wavelengths[m_wavelengths.size()-1] + avgSpacing);
m_values.push_back(0);
}
}
Float InterpolatedSpectrum::average(Float lambdaMin, Float lambdaMax) const {
typedef std::vector<Float>::const_iterator iterator;
if (m_wavelength.size() < 2)
if (m_wavelengths.size() < 2)
return 0.0f;
Float rangeStart = std::max(lambdaMin, m_wavelength[0]);
Float rangeEnd = std::min(lambdaMax, m_wavelength[m_wavelength.size()-1]);
Float rangeStart = std::max(lambdaMin, m_wavelengths[0]);
Float rangeEnd = std::min(lambdaMax, m_wavelengths[m_wavelengths.size()-1]);
if (rangeEnd <= rangeStart)
return 0.0f;
/* Find the starting index using binary search */
size_t entry = std::max((size_t) (std::lower_bound(m_wavelength.begin(),
m_wavelength.end(), rangeStart) - m_wavelength.begin()), (size_t) 1) - 1;
size_t entry = std::max((size_t) (std::lower_bound(m_wavelengths.begin(),
m_wavelengths.end(), rangeStart) - m_wavelengths.begin()), (size_t) 1) - 1;
Float result = 0.0f;
for (; entry+1 < m_wavelength.size() && rangeEnd >= m_wavelength[entry]; ++entry) {
for (; entry+1 < m_wavelengths.size() && rangeEnd >= m_wavelengths[entry]; ++entry) {
/* Step through the samples and integrate trapezoids */
Float a = m_wavelength[entry],
b = m_wavelength[entry+1],
Float a = m_wavelengths[entry],
b = m_wavelengths[entry+1],
ca = std::max(a, rangeStart),
cb = std::min(b, rangeEnd),
fa = m_value[entry],
fb = m_value[entry+1],
fa = m_values[entry],
fb = m_values[entry+1],
invAB = 1.0f / (b - a);
if (cb <= ca)
@ -553,26 +573,26 @@ Float InterpolatedSpectrum::average(Float lambdaMin, Float lambdaMax) const {
Float InterpolatedSpectrum::eval(Float lambda) const {
typedef std::vector<Float>::const_iterator iterator;
if (m_wavelength.size() < 2 ||
lambda < m_wavelength[0] ||
lambda > m_wavelength[m_wavelength.size()-1])
if (m_wavelengths.size() < 2 ||
lambda < m_wavelengths[0] ||
lambda > m_wavelengths[m_wavelengths.size()-1])
return 0;
/* Find the associated table entries using binary search */
std::pair<iterator, iterator> result =
std::equal_range(m_wavelength.begin(), m_wavelength.end(), lambda);
std::equal_range(m_wavelengths.begin(), m_wavelengths.end(), lambda);
size_t idx1 = result.first - m_wavelength.begin();
size_t idx2 = result.second - m_wavelength.begin();
size_t idx1 = result.first - m_wavelengths.begin();
size_t idx2 = result.second - m_wavelengths.begin();
if (idx1 == idx2) {
Float a = m_wavelength[idx1-1],
b = m_wavelength[idx1],
fa = m_value[idx1-1],
fb = m_value[idx1];
Float a = m_wavelengths[idx1-1],
b = m_wavelengths[idx1],
fa = m_values[idx1-1],
fb = m_values[idx1];
return lerp((lambda - a) / (b-a), fb, fa);
} else if (idx2 == idx1+1) {
/* Hit a value exactly */
return m_value[idx1];
return m_values[idx1];
} else {
SLog(EError, "Internal error while interpolating spectrum values");
return 0;
@ -582,9 +602,9 @@ Float InterpolatedSpectrum::eval(Float lambda) const {
std::string InterpolatedSpectrum::toString() const {
std::ostringstream oss;
oss << "InterpolatedSpectrum[" << endl;
for (size_t i=0; i<m_wavelength.size(); ++i) {
oss << " " << m_wavelength[i] << " nm => " << m_value[i];
if (i+1 < m_wavelength.size())
for (size_t i=0; i<m_wavelengths.size(); ++i) {
oss << " " << m_wavelengths[i] << " nm => " << m_values[i];
if (i+1 < m_wavelengths.size())
oss << ",";
oss << endl;
}
@ -633,369 +653,367 @@ const Float CIE_wavelengths[CIE_samples] = {
808, 809, 810, 811, 812, 813, 814, 815, 816, 817, 818, 819, 820, 821,
822, 823, 824, 825, 826, 827, 828, 829, 830 };
const Float CIE_X_entries[CIE_samples] = {
0.0001299000f, 0.0001458470f, 0.0001638021f, 0.0001840037f,
0.0002066902f, 0.0002321000f, 0.0002607280f, 0.0002930750f,
0.0003293880f, 0.0003699140f, 0.0004149000f, 0.0004641587f,
0.0005189860f, 0.0005818540f, 0.0006552347f, 0.0007416000f,
0.0008450296f, 0.0009645268f, 0.001094949f, 0.001231154f,
0.001368000f, 0.001502050f, 0.001642328f, 0.001802382f,
0.001995757f, 0.002236000f, 0.002535385f, 0.002892603f,
0.003300829f, 0.003753236f, 0.004243000f, 0.004762389f,
0.005330048f, 0.005978712f, 0.006741117f, 0.007650000f,
0.008751373f, 0.01002888f, 0.01142170f, 0.01286901f,
0.01431000f, 0.01570443f, 0.01714744f, 0.01878122f,
0.02074801f, 0.02319000f, 0.02620736f, 0.02978248f,
0.03388092f, 0.03846824f, 0.04351000f, 0.04899560f,
0.05502260f, 0.06171880f, 0.06921200f, 0.07763000f,
0.08695811f, 0.09717672f, 0.1084063f, 0.1207672f,
0.1343800f, 0.1493582f, 0.1653957f, 0.1819831f,
0.1986110f, 0.2147700f, 0.2301868f, 0.2448797f,
0.2587773f, 0.2718079f, 0.2839000f, 0.2949438f,
0.3048965f, 0.3137873f, 0.3216454f, 0.3285000f,
0.3343513f, 0.3392101f, 0.3431213f, 0.3461296f,
0.3482800f, 0.3495999f, 0.3501474f, 0.3500130f,
0.3492870f, 0.3480600f, 0.3463733f, 0.3442624f,
0.3418088f, 0.3390941f, 0.3362000f, 0.3331977f,
0.3300411f, 0.3266357f, 0.3228868f, 0.3187000f,
0.3140251f, 0.3088840f, 0.3032904f, 0.2972579f,
0.2908000f, 0.2839701f, 0.2767214f, 0.2689178f,
0.2604227f, 0.2511000f, 0.2408475f, 0.2298512f,
0.2184072f, 0.2068115f, 0.1953600f, 0.1842136f,
0.1733273f, 0.1626881f, 0.1522833f, 0.1421000f,
0.1321786f, 0.1225696f, 0.1132752f, 0.1042979f,
0.09564000f, 0.08729955f, 0.07930804f, 0.07171776f,
0.06458099f, 0.05795001f, 0.05186211f, 0.04628152f,
0.04115088f, 0.03641283f, 0.03201000f, 0.02791720f,
0.02414440f, 0.02068700f, 0.01754040f, 0.01470000f,
0.01216179f, 0.009919960f, 0.007967240f, 0.006296346f,
0.004900000f, 0.003777173f, 0.002945320f, 0.002424880f,
0.002236293f, 0.002400000f, 0.002925520f, 0.003836560f,
0.005174840f, 0.006982080f, 0.009300000f, 0.01214949f,
0.01553588f, 0.01947752f, 0.02399277f, 0.02910000f,
0.03481485f, 0.04112016f, 0.04798504f, 0.05537861f,
0.06327000f, 0.07163501f, 0.08046224f, 0.08973996f,
0.09945645f, 0.1096000f, 0.1201674f, 0.1311145f,
0.1423679f, 0.1538542f, 0.1655000f, 0.1772571f,
0.1891400f, 0.2011694f, 0.2133658f, 0.2257499f,
0.2383209f, 0.2510668f, 0.2639922f, 0.2771017f,
0.2904000f, 0.3038912f, 0.3175726f, 0.3314384f,
0.3454828f, 0.3597000f, 0.3740839f, 0.3886396f,
0.4033784f, 0.4183115f, 0.4334499f, 0.4487953f,
0.4643360f, 0.4800640f, 0.4959713f, 0.5120501f,
0.5282959f, 0.5446916f, 0.5612094f, 0.5778215f,
0.5945000f, 0.6112209f, 0.6279758f, 0.6447602f,
0.6615697f, 0.6784000f, 0.6952392f, 0.7120586f,
0.7288284f, 0.7455188f, 0.7621000f, 0.7785432f,
0.7948256f, 0.8109264f, 0.8268248f, 0.8425000f,
0.8579325f, 0.8730816f, 0.8878944f, 0.9023181f,
0.9163000f, 0.9297995f, 0.9427984f, 0.9552776f,
0.9672179f, 0.9786000f, 0.9893856f, 0.9995488f,
1.0090892f, 1.0180064f, 1.0263000f, 1.0339827f,
1.0409860f, 1.0471880f, 1.0524667f, 1.0567000f,
1.0597944f, 1.0617992f, 1.0628068f, 1.0629096f,
1.0622000f, 1.0607352f, 1.0584436f, 1.0552244f,
1.0509768f, 1.0456000f, 1.0390369f, 1.0313608f,
1.0226662f, 1.0130477f, 1.0026000f, 0.9913675f,
0.9793314f, 0.9664916f, 0.9528479f, 0.9384000f,
0.9231940f, 0.9072440f, 0.8905020f, 0.8729200f,
0.8544499f, 0.8350840f, 0.8149460f, 0.7941860f,
0.7729540f, 0.7514000f, 0.7295836f, 0.7075888f,
0.6856022f, 0.6638104f, 0.6424000f, 0.6215149f,
0.6011138f, 0.5811052f, 0.5613977f, 0.5419000f,
0.5225995f, 0.5035464f, 0.4847436f, 0.4661939f,
0.4479000f, 0.4298613f, 0.4120980f, 0.3946440f,
0.3775333f, 0.3608000f, 0.3444563f, 0.3285168f,
0.3130192f, 0.2980011f, 0.2835000f, 0.2695448f,
0.2561184f, 0.2431896f, 0.2307272f, 0.2187000f,
0.2070971f, 0.1959232f, 0.1851708f, 0.1748323f,
0.1649000f, 0.1553667f, 0.1462300f, 0.1374900f,
0.1291467f, 0.1212000f, 0.1136397f, 0.1064650f,
0.09969044f, 0.09333061f, 0.08740000f, 0.08190096f,
0.07680428f, 0.07207712f, 0.06768664f, 0.06360000f,
0.05980685f, 0.05628216f, 0.05297104f, 0.04981861f,
0.04677000f, 0.04378405f, 0.04087536f, 0.03807264f,
0.03540461f, 0.03290000f, 0.03056419f, 0.02838056f,
0.02634484f, 0.02445275f, 0.02270000f, 0.02108429f,
0.01959988f, 0.01823732f, 0.01698717f, 0.01584000f,
0.01479064f, 0.01383132f, 0.01294868f, 0.01212920f,
0.01135916f, 0.01062935f, 0.009938846f, 0.009288422f,
0.008678854f, 0.008110916f, 0.007582388f, 0.007088746f,
0.006627313f, 0.006195408f, 0.005790346f, 0.005409826f,
0.005052583f, 0.004717512f, 0.004403507f, 0.004109457f,
0.003833913f, 0.003575748f, 0.003334342f, 0.003109075f,
0.002899327f, 0.002704348f, 0.002523020f, 0.002354168f,
0.002196616f, 0.002049190f, 0.001910960f, 0.001781438f,
0.001660110f, 0.001546459f, 0.001439971f, 0.001340042f,
0.001246275f, 0.001158471f, 0.001076430f, 0.0009999493f,
0.0009287358f, 0.0008624332f, 0.0008007503f, 0.0007433960f,
0.0006900786f, 0.0006405156f, 0.0005945021f, 0.0005518646f,
0.0005124290f, 0.0004760213f, 0.0004424536f, 0.0004115117f,
0.0003829814f, 0.0003566491f, 0.0003323011f, 0.0003097586f,
0.0002888871f, 0.0002695394f, 0.0002515682f, 0.0002348261f,
0.0002191710f, 0.0002045258f, 0.0001908405f, 0.0001780654f,
0.0001661505f, 0.0001550236f, 0.0001446219f, 0.0001349098f,
0.0001258520f, 0.0001174130f, 0.0001095515f, 0.0001022245f,
0.00009539445f, 0.00008902390f, 0.00008307527f, 0.00007751269f,
0.00007231304f, 0.00006745778f, 0.00006292844f, 0.00005870652f,
0.00005477028f, 0.00005109918f, 0.00004767654f, 0.00004448567f,
0.00004150994f, 0.00003873324f, 0.00003614203f, 0.00003372352f,
0.00003146487f, 0.00002935326f, 0.00002737573f, 0.00002552433f,
0.00002379376f, 0.00002217870f, 0.00002067383f, 0.00001927226f,
0.00001796640f, 0.00001674991f, 0.00001561648f, 0.00001455977f,
0.00001357387f, 0.00001265436f, 0.00001179723f, 0.00001099844f,
0.00001025398f, 0.000009559646f, 0.000008912044f, 0.000008308358f,
0.000007745769f, 0.000007221456f, 0.000006732475f, 0.000006276423f,
0.000005851304f, 0.000005455118f, 0.000005085868f, 0.000004741466f,
0.000004420236f, 0.000004120783f, 0.000003841716f, 0.000003581652f,
0.000003339127f, 0.000003112949f, 0.000002902121f, 0.000002705645f,
0.000002522525f, 0.000002351726f, 0.000002192415f, 0.000002043902f,
0.000001905497f, 0.000001776509f, 0.000001656215f, 0.000001544022f,
0.000001439440f, 0.000001341977f, 0.000001251141f
0.0001299000, 0.0001458470, 0.0001638021, 0.0001840037,
0.0002066902, 0.0002321000, 0.0002607280, 0.0002930750,
0.0003293880, 0.0003699140, 0.0004149000, 0.0004641587,
0.0005189860, 0.0005818540, 0.0006552347, 0.0007416000,
0.0008450296, 0.0009645268, 0.001094949, 0.001231154,
0.001368000, 0.001502050, 0.001642328, 0.001802382,
0.001995757, 0.002236000, 0.002535385, 0.002892603,
0.003300829, 0.003753236, 0.004243000, 0.004762389,
0.005330048, 0.005978712, 0.006741117, 0.007650000,
0.008751373, 0.01002888, 0.01142170, 0.01286901,
0.01431000, 0.01570443, 0.01714744, 0.01878122,
0.02074801, 0.02319000, 0.02620736, 0.02978248,
0.03388092, 0.03846824, 0.04351000, 0.04899560,
0.05502260, 0.06171880, 0.06921200, 0.07763000,
0.08695811, 0.09717672, 0.1084063, 0.1207672,
0.1343800, 0.1493582, 0.1653957, 0.1819831,
0.1986110, 0.2147700, 0.2301868, 0.2448797,
0.2587773, 0.2718079, 0.2839000, 0.2949438,
0.3048965, 0.3137873, 0.3216454, 0.3285000,
0.3343513, 0.3392101, 0.3431213, 0.3461296,
0.3482800, 0.3495999, 0.3501474, 0.3500130,
0.3492870, 0.3480600, 0.3463733, 0.3442624,
0.3418088, 0.3390941, 0.3362000, 0.3331977,
0.3300411, 0.3266357, 0.3228868, 0.3187000,
0.3140251, 0.3088840, 0.3032904, 0.2972579,
0.2908000, 0.2839701, 0.2767214, 0.2689178,
0.2604227, 0.2511000, 0.2408475, 0.2298512,
0.2184072, 0.2068115, 0.1953600, 0.1842136,
0.1733273, 0.1626881, 0.1522833, 0.1421000,
0.1321786, 0.1225696, 0.1132752, 0.1042979,
0.09564000, 0.08729955, 0.07930804, 0.07171776,
0.06458099, 0.05795001, 0.05186211, 0.04628152,
0.04115088, 0.03641283, 0.03201000, 0.02791720,
0.02414440, 0.02068700, 0.01754040, 0.01470000,
0.01216179, 0.009919960, 0.007967240, 0.006296346,
0.004900000, 0.003777173, 0.002945320, 0.002424880,
0.002236293, 0.002400000, 0.002925520, 0.003836560,
0.005174840, 0.006982080, 0.009300000, 0.01214949,
0.01553588, 0.01947752, 0.02399277, 0.02910000,
0.03481485, 0.04112016, 0.04798504, 0.05537861,
0.06327000, 0.07163501, 0.08046224, 0.08973996,
0.09945645, 0.1096000, 0.1201674, 0.1311145,
0.1423679, 0.1538542, 0.1655000, 0.1772571,
0.1891400, 0.2011694, 0.2133658, 0.2257499,
0.2383209, 0.2510668, 0.2639922, 0.2771017,
0.2904000, 0.3038912, 0.3175726, 0.3314384,
0.3454828, 0.3597000, 0.3740839, 0.3886396,
0.4033784, 0.4183115, 0.4334499, 0.4487953,
0.4643360, 0.4800640, 0.4959713, 0.5120501,
0.5282959, 0.5446916, 0.5612094, 0.5778215,
0.5945000, 0.6112209, 0.6279758, 0.6447602,
0.6615697, 0.6784000, 0.6952392, 0.7120586,
0.7288284, 0.7455188, 0.7621000, 0.7785432,
0.7948256, 0.8109264, 0.8268248, 0.8425000,
0.8579325, 0.8730816, 0.8878944, 0.9023181,
0.9163000, 0.9297995, 0.9427984, 0.9552776,
0.9672179, 0.9786000, 0.9893856, 0.9995488,
1.0090892, 1.0180064, 1.0263000, 1.0339827,
1.0409860, 1.0471880, 1.0524667, 1.0567000,
1.0597944, 1.0617992, 1.0628068, 1.0629096,
1.0622000, 1.0607352, 1.0584436, 1.0552244,
1.0509768, 1.0456000, 1.0390369, 1.0313608,
1.0226662, 1.0130477, 1.0026000, 0.9913675,
0.9793314, 0.9664916, 0.9528479, 0.9384000,
0.9231940, 0.9072440, 0.8905020, 0.8729200,
0.8544499, 0.8350840, 0.8149460, 0.7941860,
0.7729540, 0.7514000, 0.7295836, 0.7075888,
0.6856022, 0.6638104, 0.6424000, 0.6215149,
0.6011138, 0.5811052, 0.5613977, 0.5419000,
0.5225995, 0.5035464, 0.4847436, 0.4661939,
0.4479000, 0.4298613, 0.4120980, 0.3946440,
0.3775333, 0.3608000, 0.3444563, 0.3285168,
0.3130192, 0.2980011, 0.2835000, 0.2695448,
0.2561184, 0.2431896, 0.2307272, 0.2187000,
0.2070971, 0.1959232, 0.1851708, 0.1748323,
0.1649000, 0.1553667, 0.1462300, 0.1374900,
0.1291467, 0.1212000, 0.1136397, 0.1064650,
0.09969044, 0.09333061, 0.08740000, 0.08190096,
0.07680428, 0.07207712, 0.06768664, 0.06360000,
0.05980685, 0.05628216, 0.05297104, 0.04981861,
0.04677000, 0.04378405, 0.04087536, 0.03807264,
0.03540461, 0.03290000, 0.03056419, 0.02838056,
0.02634484, 0.02445275, 0.02270000, 0.02108429,
0.01959988, 0.01823732, 0.01698717, 0.01584000,
0.01479064, 0.01383132, 0.01294868, 0.01212920,
0.01135916, 0.01062935, 0.009938846, 0.009288422,
0.008678854, 0.008110916, 0.007582388, 0.007088746,
0.006627313, 0.006195408, 0.005790346, 0.005409826,
0.005052583, 0.004717512, 0.004403507, 0.004109457,
0.003833913, 0.003575748, 0.003334342, 0.003109075,
0.002899327, 0.002704348, 0.002523020, 0.002354168,
0.002196616, 0.002049190, 0.001910960, 0.001781438,
0.001660110, 0.001546459, 0.001439971, 0.001340042,
0.001246275, 0.001158471, 0.001076430, 0.0009999493,
0.0009287358, 0.0008624332, 0.0008007503, 0.0007433960,
0.0006900786, 0.0006405156, 0.0005945021, 0.0005518646,
0.0005124290, 0.0004760213, 0.0004424536, 0.0004115117,
0.0003829814, 0.0003566491, 0.0003323011, 0.0003097586,
0.0002888871, 0.0002695394, 0.0002515682, 0.0002348261,
0.0002191710, 0.0002045258, 0.0001908405, 0.0001780654,
0.0001661505, 0.0001550236, 0.0001446219, 0.0001349098,
0.0001258520, 0.0001174130, 0.0001095515, 0.0001022245,
0.00009539445, 0.00008902390, 0.00008307527, 0.00007751269,
0.00007231304, 0.00006745778, 0.00006292844, 0.00005870652,
0.00005477028, 0.00005109918, 0.00004767654, 0.00004448567,
0.00004150994, 0.00003873324, 0.00003614203, 0.00003372352,
0.00003146487, 0.00002935326, 0.00002737573, 0.00002552433,
0.00002379376, 0.00002217870, 0.00002067383, 0.00001927226,
0.00001796640, 0.00001674991, 0.00001561648, 0.00001455977,
0.00001357387, 0.00001265436, 0.00001179723, 0.00001099844,
0.00001025398, 0.000009559646, 0.000008912044, 0.000008308358,
0.000007745769, 0.000007221456, 0.000006732475, 0.000006276423,
0.000005851304, 0.000005455118, 0.000005085868, 0.000004741466,
0.000004420236, 0.000004120783, 0.000003841716, 0.000003581652,
0.000003339127, 0.000003112949, 0.000002902121, 0.000002705645,
0.000002522525, 0.000002351726, 0.000002192415, 0.000002043902,
0.000001905497, 0.000001776509, 0.000001656215, 0.000001544022,
0.000001439440, 0.000001341977, 0.000001251141
};
const Float CIE_Y_entries[CIE_samples] = {
0.000003917000f, 0.000004393581f, 0.000004929604f, 0.000005532136f,
0.000006208245f, 0.000006965000f, 0.000007813219f, 0.000008767336f,
0.000009839844f, 0.00001104323f, 0.00001239000f, 0.00001388641f,
0.00001555728f, 0.00001744296f, 0.00001958375f, 0.00002202000f,
0.00002483965f, 0.00002804126f, 0.00003153104f, 0.00003521521f,
0.00003900000f, 0.00004282640f, 0.00004691460f, 0.00005158960f,
0.00005717640f, 0.00006400000f, 0.00007234421f, 0.00008221224f,
0.00009350816f, 0.0001061361f, 0.0001200000f, 0.0001349840f,
0.0001514920f, 0.0001702080f, 0.0001918160f, 0.0002170000f,
0.0002469067f, 0.0002812400f, 0.0003185200f, 0.0003572667f,
0.0003960000f, 0.0004337147f, 0.0004730240f, 0.0005178760f,
0.0005722187f, 0.0006400000f, 0.0007245600f, 0.0008255000f,
0.0009411600f, 0.001069880f, 0.001210000f, 0.001362091f,
0.001530752f, 0.001720368f, 0.001935323f, 0.002180000f,
0.002454800f, 0.002764000f, 0.003117800f, 0.003526400f,
0.004000000f, 0.004546240f, 0.005159320f, 0.005829280f,
0.006546160f, 0.007300000f, 0.008086507f, 0.008908720f,
0.009767680f, 0.01066443f, 0.01160000f, 0.01257317f,
0.01358272f, 0.01462968f, 0.01571509f, 0.01684000f,
0.01800736f, 0.01921448f, 0.02045392f, 0.02171824f,
0.02300000f, 0.02429461f, 0.02561024f, 0.02695857f,
0.02835125f, 0.02980000f, 0.03131083f, 0.03288368f,
0.03452112f, 0.03622571f, 0.03800000f, 0.03984667f,
0.04176800f, 0.04376600f, 0.04584267f, 0.04800000f,
0.05024368f, 0.05257304f, 0.05498056f, 0.05745872f,
0.06000000f, 0.06260197f, 0.06527752f, 0.06804208f,
0.07091109f, 0.07390000f, 0.07701600f, 0.08026640f,
0.08366680f, 0.08723280f, 0.09098000f, 0.09491755f,
0.09904584f, 0.1033674f, 0.1078846f, 0.1126000f,
0.1175320f, 0.1226744f, 0.1279928f, 0.1334528f,
0.1390200f, 0.1446764f, 0.1504693f, 0.1564619f,
0.1627177f, 0.1693000f, 0.1762431f, 0.1835581f,
0.1912735f, 0.1994180f, 0.2080200f, 0.2171199f,
0.2267345f, 0.2368571f, 0.2474812f, 0.2586000f,
0.2701849f, 0.2822939f, 0.2950505f, 0.3085780f,
0.3230000f, 0.3384021f, 0.3546858f, 0.3716986f,
0.3892875f, 0.4073000f, 0.4256299f, 0.4443096f,
0.4633944f, 0.4829395f, 0.5030000f, 0.5235693f,
0.5445120f, 0.5656900f, 0.5869653f, 0.6082000f,
0.6293456f, 0.6503068f, 0.6708752f, 0.6908424f,
0.7100000f, 0.7281852f, 0.7454636f, 0.7619694f,
0.7778368f, 0.7932000f, 0.8081104f, 0.8224962f,
0.8363068f, 0.8494916f, 0.8620000f, 0.8738108f,
0.8849624f, 0.8954936f, 0.9054432f, 0.9148501f,
0.9237348f, 0.9320924f, 0.9399226f, 0.9472252f,
0.9540000f, 0.9602561f, 0.9660074f, 0.9712606f,
0.9760225f, 0.9803000f, 0.9840924f, 0.9874812f,
0.9903128f, 0.9928116f, 0.9949501f, 0.9967108f,
0.9980983f, 0.9991120f, 0.9997482f, 1.0000000f,
0.9998567f, 0.9993046f, 0.9983255f, 0.9968987f,
0.9950000f, 0.9926005f, 0.9897426f, 0.9864444f,
0.9827241f, 0.9786000f, 0.9740837f, 0.9691712f,
0.9638568f, 0.9581349f, 0.9520000f, 0.9454504f,
0.9384992f, 0.9311628f, 0.9234576f, 0.9154000f,
0.9070064f, 0.8982772f, 0.8892048f, 0.8797816f,
0.8700000f, 0.8598613f, 0.8493920f, 0.8386220f,
0.8275813f, 0.8163000f, 0.8047947f, 0.7930820f,
0.7811920f, 0.7691547f, 0.7570000f, 0.7447541f,
0.7324224f, 0.7200036f, 0.7074965f, 0.6949000f,
0.6822192f, 0.6694716f, 0.6566744f, 0.6438448f,
0.6310000f, 0.6181555f, 0.6053144f, 0.5924756f,
0.5796379f, 0.5668000f, 0.5539611f, 0.5411372f,
0.5283528f, 0.5156323f, 0.5030000f, 0.4904688f,
0.4780304f, 0.4656776f, 0.4534032f, 0.4412000f,
0.4290800f, 0.4170360f, 0.4050320f, 0.3930320f,
0.3810000f, 0.3689184f, 0.3568272f, 0.3447768f,
0.3328176f, 0.3210000f, 0.3093381f, 0.2978504f,
0.2865936f, 0.2756245f, 0.2650000f, 0.2547632f,
0.2448896f, 0.2353344f, 0.2260528f, 0.2170000f,
0.2081616f, 0.1995488f, 0.1911552f, 0.1829744f,
0.1750000f, 0.1672235f, 0.1596464f, 0.1522776f,
0.1451259f, 0.1382000f, 0.1315003f, 0.1250248f,
0.1187792f, 0.1127691f, 0.1070000f, 0.1014762f,
0.09618864f, 0.09112296f, 0.08626485f, 0.08160000f,
0.07712064f, 0.07282552f, 0.06871008f, 0.06476976f,
0.06100000f, 0.05739621f, 0.05395504f, 0.05067376f,
0.04754965f, 0.04458000f, 0.04175872f, 0.03908496f,
0.03656384f, 0.03420048f, 0.03200000f, 0.02996261f,
0.02807664f, 0.02632936f, 0.02470805f, 0.02320000f,
0.02180077f, 0.02050112f, 0.01928108f, 0.01812069f,
0.01700000f, 0.01590379f, 0.01483718f, 0.01381068f,
0.01283478f, 0.01192000f, 0.01106831f, 0.01027339f,
0.009533311f, 0.008846157f, 0.008210000f, 0.007623781f,
0.007085424f, 0.006591476f, 0.006138485f, 0.005723000f,
0.005343059f, 0.004995796f, 0.004676404f, 0.004380075f,
0.004102000f, 0.003838453f, 0.003589099f, 0.003354219f,
0.003134093f, 0.002929000f, 0.002738139f, 0.002559876f,
0.002393244f, 0.002237275f, 0.002091000f, 0.001953587f,
0.001824580f, 0.001703580f, 0.001590187f, 0.001484000f,
0.001384496f, 0.001291268f, 0.001204092f, 0.001122744f,
0.001047000f, 0.0009765896f, 0.0009111088f, 0.0008501332f,
0.0007932384f, 0.0007400000f, 0.0006900827f, 0.0006433100f,
0.0005994960f, 0.0005584547f, 0.0005200000f, 0.0004839136f,
0.0004500528f, 0.0004183452f, 0.0003887184f, 0.0003611000f,
0.0003353835f, 0.0003114404f, 0.0002891656f, 0.0002684539f,
0.0002492000f, 0.0002313019f, 0.0002146856f, 0.0001992884f,
0.0001850475f, 0.0001719000f, 0.0001597781f, 0.0001486044f,
0.0001383016f, 0.0001287925f, 0.0001200000f, 0.0001118595f,
0.0001043224f, 0.00009733560f, 0.00009084587f, 0.00008480000f,
0.00007914667f, 0.00007385800f, 0.00006891600f, 0.00006430267f,
0.00006000000f, 0.00005598187f, 0.00005222560f, 0.00004871840f,
0.00004544747f, 0.00004240000f, 0.00003956104f, 0.00003691512f,
0.00003444868f, 0.00003214816f, 0.00003000000f, 0.00002799125f,
0.00002611356f, 0.00002436024f, 0.00002272461f, 0.00002120000f,
0.00001977855f, 0.00001845285f, 0.00001721687f, 0.00001606459f,
0.00001499000f, 0.00001398728f, 0.00001305155f, 0.00001217818f,
0.00001136254f, 0.00001060000f, 0.000009885877f, 0.000009217304f,
0.000008592362f, 0.000008009133f, 0.000007465700f, 0.000006959567f,
0.000006487995f, 0.000006048699f, 0.000005639396f, 0.000005257800f,
0.000004901771f, 0.000004569720f, 0.000004260194f, 0.000003971739f,
0.000003702900f, 0.000003452163f, 0.000003218302f, 0.000003000300f,
0.000002797139f, 0.000002607800f, 0.000002431220f, 0.000002266531f,
0.000002113013f, 0.000001969943f, 0.000001836600f, 0.000001712230f,
0.000001596228f, 0.000001488090f, 0.000001387314f, 0.000001293400f,
0.000001205820f, 0.000001124143f, 0.000001048009f, 0.0000009770578f,
0.0000009109300f, 0.0000008492513f, 0.0000007917212f, 0.0000007380904f,
0.0000006881098f, 0.0000006415300f, 0.0000005980895f, 0.0000005575746f,
0.0000005198080f, 0.0000004846123f, 0.0000004518100f
0.000003917000, 0.000004393581, 0.000004929604, 0.000005532136,
0.000006208245, 0.000006965000, 0.000007813219, 0.000008767336,
0.000009839844, 0.00001104323, 0.00001239000, 0.00001388641,
0.00001555728, 0.00001744296, 0.00001958375, 0.00002202000,
0.00002483965, 0.00002804126, 0.00003153104, 0.00003521521,
0.00003900000, 0.00004282640, 0.00004691460, 0.00005158960,
0.00005717640, 0.00006400000, 0.00007234421, 0.00008221224,
0.00009350816, 0.0001061361, 0.0001200000, 0.0001349840,
0.0001514920, 0.0001702080, 0.0001918160, 0.0002170000,
0.0002469067, 0.0002812400, 0.0003185200, 0.0003572667,
0.0003960000, 0.0004337147, 0.0004730240, 0.0005178760,
0.0005722187, 0.0006400000, 0.0007245600, 0.0008255000,
0.0009411600, 0.001069880, 0.001210000, 0.001362091,
0.001530752, 0.001720368, 0.001935323, 0.002180000,
0.002454800, 0.002764000, 0.003117800, 0.003526400,
0.004000000, 0.004546240, 0.005159320, 0.005829280,
0.006546160, 0.007300000, 0.008086507, 0.008908720,
0.009767680, 0.01066443, 0.01160000, 0.01257317,
0.01358272, 0.01462968, 0.01571509, 0.01684000,
0.01800736, 0.01921448, 0.02045392, 0.02171824,
0.02300000, 0.02429461, 0.02561024, 0.02695857,
0.02835125, 0.02980000, 0.03131083, 0.03288368,
0.03452112, 0.03622571, 0.03800000, 0.03984667,
0.04176800, 0.04376600, 0.04584267, 0.04800000,
0.05024368, 0.05257304, 0.05498056, 0.05745872,
0.06000000, 0.06260197, 0.06527752, 0.06804208,
0.07091109, 0.07390000, 0.07701600, 0.08026640,
0.08366680, 0.08723280, 0.09098000, 0.09491755,
0.09904584, 0.1033674, 0.1078846, 0.1126000,
0.1175320, 0.1226744, 0.1279928, 0.1334528,
0.1390200, 0.1446764, 0.1504693, 0.1564619,
0.1627177, 0.1693000, 0.1762431, 0.1835581,
0.1912735, 0.1994180, 0.2080200, 0.2171199,
0.2267345, 0.2368571, 0.2474812, 0.2586000,
0.2701849, 0.2822939, 0.2950505, 0.3085780,
0.3230000, 0.3384021, 0.3546858, 0.3716986,
0.3892875, 0.4073000, 0.4256299, 0.4443096,
0.4633944, 0.4829395, 0.5030000, 0.5235693,
0.5445120, 0.5656900, 0.5869653, 0.6082000,
0.6293456, 0.6503068, 0.6708752, 0.6908424,
0.7100000, 0.7281852, 0.7454636, 0.7619694,
0.7778368, 0.7932000, 0.8081104, 0.8224962,
0.8363068, 0.8494916, 0.8620000, 0.8738108,
0.8849624, 0.8954936, 0.9054432, 0.9148501,
0.9237348, 0.9320924, 0.9399226, 0.9472252,
0.9540000, 0.9602561, 0.9660074, 0.9712606,
0.9760225, 0.9803000, 0.9840924, 0.9874812,
0.9903128, 0.9928116, 0.9949501, 0.9967108,
0.9980983, 0.9991120, 0.9997482, 1.0000000,
0.9998567, 0.9993046, 0.9983255, 0.9968987,
0.9950000, 0.9926005, 0.9897426, 0.9864444,
0.9827241, 0.9786000, 0.9740837, 0.9691712,
0.9638568, 0.9581349, 0.9520000, 0.9454504,
0.9384992, 0.9311628, 0.9234576, 0.9154000,
0.9070064, 0.8982772, 0.8892048, 0.8797816,
0.8700000, 0.8598613, 0.8493920, 0.8386220,
0.8275813, 0.8163000, 0.8047947, 0.7930820,
0.7811920, 0.7691547, 0.7570000, 0.7447541,
0.7324224, 0.7200036, 0.7074965, 0.6949000,
0.6822192, 0.6694716, 0.6566744, 0.6438448,
0.6310000, 0.6181555, 0.6053144, 0.5924756,
0.5796379, 0.5668000, 0.5539611, 0.5411372,
0.5283528, 0.5156323, 0.5030000, 0.4904688,
0.4780304, 0.4656776, 0.4534032, 0.4412000,
0.4290800, 0.4170360, 0.4050320, 0.3930320,
0.3810000, 0.3689184, 0.3568272, 0.3447768,
0.3328176, 0.3210000, 0.3093381, 0.2978504,
0.2865936, 0.2756245, 0.2650000, 0.2547632,
0.2448896, 0.2353344, 0.2260528, 0.2170000,
0.2081616, 0.1995488, 0.1911552, 0.1829744,
0.1750000, 0.1672235, 0.1596464, 0.1522776,
0.1451259, 0.1382000, 0.1315003, 0.1250248,
0.1187792, 0.1127691, 0.1070000, 0.1014762,
0.09618864, 0.09112296, 0.08626485, 0.08160000,
0.07712064, 0.07282552, 0.06871008, 0.06476976,
0.06100000, 0.05739621, 0.05395504, 0.05067376,
0.04754965, 0.04458000, 0.04175872, 0.03908496,
0.03656384, 0.03420048, 0.03200000, 0.02996261,
0.02807664, 0.02632936, 0.02470805, 0.02320000,
0.02180077, 0.02050112, 0.01928108, 0.01812069,
0.01700000, 0.01590379, 0.01483718, 0.01381068,
0.01283478, 0.01192000, 0.01106831, 0.01027339,
0.009533311, 0.008846157, 0.008210000, 0.007623781,
0.007085424, 0.006591476, 0.006138485, 0.005723000,
0.005343059, 0.004995796, 0.004676404, 0.004380075,
0.004102000, 0.003838453, 0.003589099, 0.003354219,
0.003134093, 0.002929000, 0.002738139, 0.002559876,
0.002393244, 0.002237275, 0.002091000, 0.001953587,
0.001824580, 0.001703580, 0.001590187, 0.001484000,
0.001384496, 0.001291268, 0.001204092, 0.001122744,
0.001047000, 0.0009765896, 0.0009111088, 0.0008501332,
0.0007932384, 0.0007400000, 0.0006900827, 0.0006433100,
0.0005994960, 0.0005584547, 0.0005200000, 0.0004839136,
0.0004500528, 0.0004183452, 0.0003887184, 0.0003611000,
0.0003353835, 0.0003114404, 0.0002891656, 0.0002684539,
0.0002492000, 0.0002313019, 0.0002146856, 0.0001992884,
0.0001850475, 0.0001719000, 0.0001597781, 0.0001486044,
0.0001383016, 0.0001287925, 0.0001200000, 0.0001118595,
0.0001043224, 0.00009733560, 0.00009084587, 0.00008480000,
0.00007914667, 0.00007385800, 0.00006891600, 0.00006430267,
0.00006000000, 0.00005598187, 0.00005222560, 0.00004871840,
0.00004544747, 0.00004240000, 0.00003956104, 0.00003691512,
0.00003444868, 0.00003214816, 0.00003000000, 0.00002799125,
0.00002611356, 0.00002436024, 0.00002272461, 0.00002120000,
0.00001977855, 0.00001845285, 0.00001721687, 0.00001606459,
0.00001499000, 0.00001398728, 0.00001305155, 0.00001217818,
0.00001136254, 0.00001060000, 0.000009885877, 0.000009217304,
0.000008592362, 0.000008009133, 0.000007465700, 0.000006959567,
0.000006487995, 0.000006048699, 0.000005639396, 0.000005257800,
0.000004901771, 0.000004569720, 0.000004260194, 0.000003971739,
0.000003702900, 0.000003452163, 0.000003218302, 0.000003000300,
0.000002797139, 0.000002607800, 0.000002431220, 0.000002266531,
0.000002113013, 0.000001969943, 0.000001836600, 0.000001712230,
0.000001596228, 0.000001488090, 0.000001387314, 0.000001293400,
0.000001205820, 0.000001124143, 0.000001048009, 0.0000009770578,
0.0000009109300, 0.0000008492513, 0.0000007917212, 0.0000007380904,
0.0000006881098, 0.0000006415300, 0.0000005980895, 0.0000005575746,
0.0000005198080, 0.0000004846123, 0.0000004518100
};
const Float CIE_Z_entries[CIE_samples] = {
0.0006061000f, 0.0006808792f, 0.0007651456f, 0.0008600124f,
0.0009665928f, 0.001086000f, 0.001220586f, 0.001372729f,
0.001543579f, 0.001734286f, 0.001946000f, 0.002177777f,
0.002435809f, 0.002731953f, 0.003078064f, 0.003486000f,
0.003975227f, 0.004540880f, 0.005158320f, 0.005802907f,
0.006450001f, 0.007083216f, 0.007745488f, 0.008501152f,
0.009414544f, 0.01054999f, 0.01196580f, 0.01365587f,
0.01558805f, 0.01773015f, 0.02005001f, 0.02251136f,
0.02520288f, 0.02827972f, 0.03189704f, 0.03621000f,
0.04143771f, 0.04750372f, 0.05411988f, 0.06099803f,
0.06785001f, 0.07448632f, 0.08136156f, 0.08915364f,
0.09854048f, 0.1102000f, 0.1246133f, 0.1417017f,
0.1613035f, 0.1832568f, 0.2074000f, 0.2336921f,
0.2626114f, 0.2947746f, 0.3307985f, 0.3713000f,
0.4162091f, 0.4654642f, 0.5196948f, 0.5795303f,
0.6456000f, 0.7184838f, 0.7967133f, 0.8778459f,
0.9594390f, 1.0390501f, 1.1153673f, 1.1884971f,
1.2581233f, 1.3239296f, 1.3856000f, 1.4426352f,
1.4948035f, 1.5421903f, 1.5848807f, 1.6229600f,
1.6564048f, 1.6852959f, 1.7098745f, 1.7303821f,
1.7470600f, 1.7600446f, 1.7696233f, 1.7762637f,
1.7804334f, 1.7826000f, 1.7829682f, 1.7816998f,
1.7791982f, 1.7758671f, 1.7721100f, 1.7682589f,
1.7640390f, 1.7589438f, 1.7524663f, 1.7441000f,
1.7335595f, 1.7208581f, 1.7059369f, 1.6887372f,
1.6692000f, 1.6475287f, 1.6234127f, 1.5960223f,
1.5645280f, 1.5281000f, 1.4861114f, 1.4395215f,
1.3898799f, 1.3387362f, 1.2876400f, 1.2374223f,
1.1878243f, 1.1387611f, 1.0901480f, 1.0419000f,
0.9941976f, 0.9473473f, 0.9014531f, 0.8566193f,
0.8129501f, 0.7705173f, 0.7294448f, 0.6899136f,
0.6521049f, 0.6162000f, 0.5823286f, 0.5504162f,
0.5203376f, 0.4919673f, 0.4651800f, 0.4399246f,
0.4161836f, 0.3938822f, 0.3729459f, 0.3533000f,
0.3348578f, 0.3175521f, 0.3013375f, 0.2861686f,
0.2720000f, 0.2588171f, 0.2464838f, 0.2347718f,
0.2234533f, 0.2123000f, 0.2011692f, 0.1901196f,
0.1792254f, 0.1685608f, 0.1582000f, 0.1481383f,
0.1383758f, 0.1289942f, 0.1200751f, 0.1117000f,
0.1039048f, 0.09666748f, 0.08998272f, 0.08384531f,
0.07824999f, 0.07320899f, 0.06867816f, 0.06456784f,
0.06078835f, 0.05725001f, 0.05390435f, 0.05074664f,
0.04775276f, 0.04489859f, 0.04216000f, 0.03950728f,
0.03693564f, 0.03445836f, 0.03208872f, 0.02984000f,
0.02771181f, 0.02569444f, 0.02378716f, 0.02198925f,
0.02030000f, 0.01871805f, 0.01724036f, 0.01586364f,
0.01458461f, 0.01340000f, 0.01230723f, 0.01130188f,
0.01037792f, 0.009529306f, 0.008749999f, 0.008035200f,
0.007381600f, 0.006785400f, 0.006242800f, 0.005749999f,
0.005303600f, 0.004899800f, 0.004534200f, 0.004202400f,
0.003900000f, 0.003623200f, 0.003370600f, 0.003141400f,
0.002934800f, 0.002749999f, 0.002585200f, 0.002438600f,
0.002309400f, 0.002196800f, 0.002100000f, 0.002017733f,
0.001948200f, 0.001889800f, 0.001840933f, 0.001800000f,
0.001766267f, 0.001737800f, 0.001711200f, 0.001683067f,
0.001650001f, 0.001610133f, 0.001564400f, 0.001513600f,
0.001458533f, 0.001400000f, 0.001336667f, 0.001270000f,
0.001205000f, 0.001146667f, 0.001100000f, 0.001068800f,
0.001049400f, 0.001035600f, 0.001021200f, 0.001000000f,
0.0009686400f, 0.0009299200f, 0.0008868800f, 0.0008425600f,
0.0008000000f, 0.0007609600f, 0.0007236800f, 0.0006859200f,
0.0006454400f, 0.0006000000f, 0.0005478667f, 0.0004916000f,
0.0004354000f, 0.0003834667f, 0.0003400000f, 0.0003072533f,
0.0002831600f, 0.0002654400f, 0.0002518133f, 0.0002400000f,
0.0002295467f, 0.0002206400f, 0.0002119600f, 0.0002021867f,
0.0001900000f, 0.0001742133f, 0.0001556400f, 0.0001359600f,
0.0001168533f, 0.0001000000f, 0.00008613333f, 0.00007460000f,
0.00006500000f, 0.00005693333f, 0.00004999999f, 0.00004416000f,
0.00003948000f, 0.00003572000f, 0.00003264000f, 0.00003000000f,
0.00002765333f, 0.00002556000f, 0.00002364000f, 0.00002181333f,
0.00002000000f, 0.00001813333f, 0.00001620000f, 0.00001420000f,
0.00001213333f, 0.00001000000f, 0.000007733333f, 0.000005400000f,
0.000003200000f, 0.000001333333f, 0.000000000000f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f
0.0006061000, 0.0006808792, 0.0007651456, 0.0008600124,
0.0009665928, 0.001086000, 0.001220586, 0.001372729,
0.001543579, 0.001734286, 0.001946000, 0.002177777,
0.002435809, 0.002731953, 0.003078064, 0.003486000,
0.003975227, 0.004540880, 0.005158320, 0.005802907,
0.006450001, 0.007083216, 0.007745488, 0.008501152,
0.009414544, 0.01054999, 0.01196580, 0.01365587,
0.01558805, 0.01773015, 0.02005001, 0.02251136,
0.02520288, 0.02827972, 0.03189704, 0.03621000,
0.04143771, 0.04750372, 0.05411988, 0.06099803,
0.06785001, 0.07448632, 0.08136156, 0.08915364,
0.09854048, 0.1102000, 0.1246133, 0.1417017,
0.1613035, 0.1832568, 0.2074000, 0.2336921,
0.2626114, 0.2947746, 0.3307985, 0.3713000,
0.4162091, 0.4654642, 0.5196948, 0.5795303,
0.6456000, 0.7184838, 0.7967133, 0.8778459,
0.9594390, 1.0390501, 1.1153673, 1.1884971,
1.2581233, 1.3239296, 1.3856000, 1.4426352,
1.4948035, 1.5421903, 1.5848807, 1.6229600,
1.6564048, 1.6852959, 1.7098745, 1.7303821,
1.7470600, 1.7600446, 1.7696233, 1.7762637,
1.7804334, 1.7826000, 1.7829682, 1.7816998,
1.7791982, 1.7758671, 1.7721100, 1.7682589,
1.7640390, 1.7589438, 1.7524663, 1.7441000,
1.7335595, 1.7208581, 1.7059369, 1.6887372,
1.6692000, 1.6475287, 1.6234127, 1.5960223,
1.5645280, 1.5281000, 1.4861114, 1.4395215,
1.3898799, 1.3387362, 1.2876400, 1.2374223,
1.1878243, 1.1387611, 1.0901480, 1.0419000,
0.9941976, 0.9473473, 0.9014531, 0.8566193,
0.8129501, 0.7705173, 0.7294448, 0.6899136,
0.6521049, 0.6162000, 0.5823286, 0.5504162,
0.5203376, 0.4919673, 0.4651800, 0.4399246,
0.4161836, 0.3938822, 0.3729459, 0.3533000,
0.3348578, 0.3175521, 0.3013375, 0.2861686,
0.2720000, 0.2588171, 0.2464838, 0.2347718,
0.2234533, 0.2123000, 0.2011692, 0.1901196,
0.1792254, 0.1685608, 0.1582000, 0.1481383,
0.1383758, 0.1289942, 0.1200751, 0.1117000,
0.1039048, 0.09666748, 0.08998272, 0.08384531,
0.07824999, 0.07320899, 0.06867816, 0.06456784,
0.06078835, 0.05725001, 0.05390435, 0.05074664,
0.04775276, 0.04489859, 0.04216000, 0.03950728,
0.03693564, 0.03445836, 0.03208872, 0.02984000,
0.02771181, 0.02569444, 0.02378716, 0.02198925,
0.02030000, 0.01871805, 0.01724036, 0.01586364,
0.01458461, 0.01340000, 0.01230723, 0.01130188,
0.01037792, 0.009529306, 0.008749999, 0.008035200,
0.007381600, 0.006785400, 0.006242800, 0.005749999,
0.005303600, 0.004899800, 0.004534200, 0.004202400,
0.003900000, 0.003623200, 0.003370600, 0.003141400,
0.002934800, 0.002749999, 0.002585200, 0.002438600,
0.002309400, 0.002196800, 0.002100000, 0.002017733,
0.001948200, 0.001889800, 0.001840933, 0.001800000,
0.001766267, 0.001737800, 0.001711200, 0.001683067,
0.001650001, 0.001610133, 0.001564400, 0.001513600,
0.001458533, 0.001400000, 0.001336667, 0.001270000,
0.001205000, 0.001146667, 0.001100000, 0.001068800,
0.001049400, 0.001035600, 0.001021200, 0.001000000,
0.0009686400, 0.0009299200, 0.0008868800, 0.0008425600,
0.0008000000, 0.0007609600, 0.0007236800, 0.0006859200,
0.0006454400, 0.0006000000, 0.0005478667, 0.0004916000,
0.0004354000, 0.0003834667, 0.0003400000, 0.0003072533,
0.0002831600, 0.0002654400, 0.0002518133, 0.0002400000,
0.0002295467, 0.0002206400, 0.0002119600, 0.0002021867,
0.0001900000, 0.0001742133, 0.0001556400, 0.0001359600,
0.0001168533, 0.0001000000, 0.00008613333, 0.00007460000,
0.00006500000, 0.00005693333, 0.00004999999, 0.00004416000,
0.00003948000, 0.00003572000, 0.00003264000, 0.00003000000,
0.00002765333, 0.00002556000, 0.00002364000, 0.00002181333,
0.00002000000, 0.00001813333, 0.00001620000, 0.00001420000,
0.00001213333, 0.00001000000, 0.000007733333, 0.000005400000,
0.000003200000, 0.000001333333, 0.000000000000, 0.0,
0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0
};
const Float RGB2Spec_wavelengths[RGB2Spec_samples] = {

View File

@ -286,6 +286,18 @@ void SceneHandler::endElement(const XMLCh* const xmlName) {
context.parent->properties.setPoint(context.attributes["name"], Point(x, y, z));
} else if (name == "rgb") {
Spectrum::EConversionIntent intent = Spectrum::EReflectance;
if (context.attributes.find("intent") != context.attributes.end()) {
std::string intentString = boost::to_lower_copy(context.attributes["intent"]);
if (intentString == "reflectance")
intent = Spectrum::EReflectance;
else if (intentString == "illuminant")
intent = Spectrum::EIlluminant;
else
SLog(EError, "Invalid intent \"%s\", must be "
"\"reflectance\" or \"illuminant\"", intentString.c_str());
}
std::string valueStr = context.attributes["value"];
std::vector<std::string> tokens = tokenize(valueStr, ", ");
Float value[3];
@ -308,7 +320,7 @@ void SceneHandler::endElement(const XMLCh* const xmlName) {
XMLLog(EError, "Invalid RGB value specified");
}
Spectrum specValue;
specValue.fromLinearRGB(value[0], value[1], value[2]);
specValue.fromLinearRGB(value[0], value[1], value[2], intent);
context.parent->properties.setSpectrum(context.attributes["name"],
specValue);
} else if (name == "srgb") {

View File

@ -48,6 +48,16 @@ void TestCase::assertEqualsImpl(Float expected, Float actual, Float epsilon, con
"expected floating point value %f, got %f.", expected, actual);
}
void TestCase::assertEqualsImpl(const Spectrum &expected, const Spectrum &actual, Float epsilon, const char *file, int line) {
bool match = true;
for (int i=0; i<SPECTRUM_SAMPLES; ++i)
if (std::abs(expected[i]-actual[i]) > epsilon)
match = false;
if (!match)
Thread::getThread()->getLogger()->log(EError, NULL, file, line, "Assertion failure: "
"expected vector %s, got %s.", expected.toString().c_str(), actual.toString().c_str());
}
void TestCase::assertEqualsImpl(const Vector2 &expected, const Vector2 &actual, Float epsilon, const char *file, int line) {
bool match = true;
for (int i=0; i<2; ++i)
@ -58,6 +68,7 @@ void TestCase::assertEqualsImpl(const Vector2 &expected, const Vector2 &actual,
"expected vector %s, got %s.", expected.toString().c_str(), actual.toString().c_str());
}
void TestCase::assertEqualsImpl(const Point2 &expected, const Point2 &actual, Float epsilon, const char *file, int line) {
bool match = true;
for (int i=0; i<2; ++i)

View File

@ -71,7 +71,7 @@ void help() {
cout << " -v Be more verbose" << endl << endl;
cout << " -w Treat warnings as errors" << endl << endl;
cout << " -z Disable progress bars" << endl << endl;
cout << " The README file included with the distribution contains further information." << endl;
cout << " For documentation, please refer to http://www.mitsuba-renderer.org/docs.html" << endl;
}
ref<RenderQueue> renderQueue = NULL;

View File

@ -180,7 +180,7 @@ int ubi_main(int argc, char **argv) {
cout << " To listen on stdin, specify \"-ls\" (implies -q)" << endl << endl;
cout << " -n name Assign a node name to this instance (Default: host name)" << endl << endl;
cout << " -v Be more verbose" << endl << endl;
cout << " The README file included with the distribution contains further information." << endl;
cout << " For documentation, please refer to http://www.mitsuba-renderer.org/docs.html" << endl;
return 0;
}
}

View File

@ -119,7 +119,8 @@ void help() {
}
}
cout << testcases.str() << utilities.str();
cout << testcases.str() << utilities.str() << endl;
cout << " For documentation, please refer to http://www.mitsuba-renderer.org/docs.html" << endl << endl;
}

146
src/tests/test_spectrum.cpp Normal file
View File

@ -0,0 +1,146 @@
/*
This file is part of Mitsuba, a physically based rendering system.
Copyright (c) 2007-2011 by Wenzel Jakob and others.
Mitsuba is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License Version 3
as published by the Free Software Foundation.
Mitsuba is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <mitsuba/render/testcase.h>
#include <mitsuba/core/bitmap.h>
#include <mitsuba/core/fstream.h>
MTS_NAMESPACE_BEGIN
class TestSpectrum : public TestCase {
public:
MTS_BEGIN_TESTCASE()
MTS_DECLARE_TEST(test01_spectrum)
MTS_DECLARE_TEST(test02_interpolatedSpectrum)
MTS_DECLARE_TEST(test03_blackBody)
MTS_END_TESTCASE()
void test01_spectrum() {
#if SPECTRUM_SAMPLES > 3
Spectrum spec(0.0f);
Float binStart = Spectrum::getBinCoverage(2).first;
Float binEnd = Spectrum::getBinCoverage(2).second;
spec[2] = 1.0f;
assertEquals(spec.eval(binStart+Epsilon), 1.0f);
assertEquals(spec.eval(binEnd-Epsilon), 1.0f);
assertEquals(spec.eval(binStart-Epsilon), 0.0f);
assertEquals(spec.eval(binEnd+Epsilon), 0.0f);
#endif
assertEqualsEpsilon(Spectrum(1.0f).getLuminance(), 1.0f, 1e-5f);
#if SPECTRUM_SAMPLES == 30
/* Verify against the implementation in PBRT */
Spectrum test;
Float r, g, b;
test.fromLinearRGB(0.1f, 0.2f, 0.3f, Spectrum::EReflectance);
test.toLinearRGB(r, g, b);
assertEqualsEpsilon(r, 0.124274f, 1e-5f);
assertEqualsEpsilon(g, 0.190133f, 1e-5f);
assertEqualsEpsilon(b, 0.270029f, 1e-5f);
test.fromLinearRGB(0.1f, 0.2f, 0.3f, Spectrum::EIlluminant);
test.toLinearRGB(r, g, b);
assertEqualsEpsilon(r, 0.0961602f, 1e-5f);
assertEqualsEpsilon(g, 0.184446f, 1e-5f);
assertEqualsEpsilon(b, 0.273519f, 1e-5f);
#elif SPECTRUM_SAMPLES == 3
Spectrum test;
Float x, y, z;
test.fromXYZ(0.1f, 0.2f, 0.3f);
test.toXYZ(x, y, z);
assertEqualsEpsilon(x, 0.1, 1e-5f);
assertEqualsEpsilon(y, 0.2, 1e-5f);
assertEqualsEpsilon(z, 0.3, 1e-5f);
#endif
}
void test02_interpolatedSpectrum() {
/* Test the interpolated spectrum
evaluation and integration routines */
InterpolatedSpectrum spec;
spec.append(500, 1);
spec.append(700, 2);
spec.append(800, 3);
InterpolatedSpectrum spec2 = spec;
assertEquals(spec.eval(499), 0.0f);
assertEquals(spec.eval(500), 1.0f);
assertEquals(spec.eval(600), 1.5f);
assertEquals(spec.eval(700), 2.0f);
assertEquals(spec.eval(750), 2.5f);
assertEquals(spec.eval(800), 3.0f);
assertEquals(spec.eval(801), 0.0f);
assertEqualsEpsilon(spec.average(0, 1000), 550.0f/1000.0f, 1e-6f);
assertEqualsEpsilon(spec.average(550, 551), 1.2525f, 1e-6f);
spec2.zeroExtend();
assertEquals(spec2.eval(500.0f-150.0f), 0.0f);
assertEquals(spec2.eval(500.0f-150.0f/2.0f), 0.5f);
spec2.clear();
spec2.append(0, 1);
spec2.append(1000, 1);
Spectrum spec3;
spec3.fromContinuousSpectrum(spec2);
#if SPECTRUM_SAMPLES > 3
assertEqualsEpsilon(spec3, Spectrum(1.0f), 1e-5f);
#endif
Float x, y, z;
spec3.toXYZ(x, y, z);
assertEqualsEpsilon(x, 1.0f, 1e-3f);
assertEqualsEpsilon(y, 1.0f, 1e-3f);
assertEqualsEpsilon(z, 1.0f, 1e-3f);
#if SPECTRUM_SAMPLES > 3
spec2.clear();
spec2.append(Spectrum::getBinCoverage(0).first, 0);
spec2.append(Spectrum::getBinCoverage(1).first, 1);
spec2.append(Spectrum::getBinCoverage(2).first, 1);
spec2.append(Spectrum::getBinCoverage(2).second, 0);
spec3.fromContinuousSpectrum(spec2);
Spectrum spec4(0.0f);
spec4[0] = 0.5f;
spec4[1] = 1.0f;
spec4[2] = 0.5f;
assertEqualsEpsilon(spec3, spec4, 1e-5f);
#endif
}
void test03_blackBody() {
/* Spot-check a 5000 Kelvin spectrum against values obtained at
https://www.sensiac.org/external/resources/calculators/infrared_radiance_calculator.jsf
Mitsuba uses units of W * m^-2 * sr^-1 * nm^-1, whereas that
page uses W * cm^-2 * sr^-1 * um^-1 --- this is the reason for
the factor of 10-difference.
*/
BlackBodySpectrum spec(5000);
assertEqualsEpsilon(spec.eval(400)/10, 874, .5f);
assertEqualsEpsilon(spec.eval(500)/10, 1211, .5f);
assertEqualsEpsilon(spec.eval(600)/10, 1276, .5f);
assertEqualsEpsilon(spec.eval(2000)/10, 115.8f, .5f);
assertEqualsEpsilon(spec.average(100, 1000) * .09f, 715, 1);
}
};
MTS_EXPORT_TESTCASE(TestSpectrum, "Testcase for manipulating spectral data")
MTS_NAMESPACE_END