diff --git a/doc/gendoc.py b/doc/gendoc.py
index 8e10a5c7..27a2b49e 100755
--- a/doc/gendoc.py
+++ b/doc/gendoc.py
@@ -69,6 +69,8 @@ f.write('\input{section_media}\n')
os.path.walk('../src/medium', traverse, f)
f.write('\input{section_phase}\n')
os.path.walk('../src/phase', traverse, f)
+f.write('\input{section_volumes}\n')
+os.path.walk('../src/volume', traverse, f)
f.write('\input{section_luminaires}\n')
os.path.walk('../src/luminaires', traverse, f)
f.write('\input{section_integrators}\n')
diff --git a/doc/main.tex b/doc/main.tex
index 673d7eec..5f9d3684 100644
--- a/doc/main.tex
+++ b/doc/main.tex
@@ -109,7 +109,7 @@
string,transform,ref,rgb,srgb,spectrum,blackbody,
medium,camera,film,sampler,integrator,luminaire,
translate,rotate,scale,lookAt,point,vector,matrix,
- include,fscat
+ include,fscat,volume
},
}
diff --git a/doc/section_volumes.tex b/doc/section_volumes.tex
new file mode 100644
index 00000000..e1763e65
--- /dev/null
+++ b/doc/section_volumes.tex
@@ -0,0 +1,7 @@
+\newpage
+\subsection{Volume data sources}
+\label{sec:volumes}
+This section covers the different types of volume data sources included with
+Mitsuba. These plugins are intended to be used together with the
+\pluginref{heterogeneous} medium plugin and provide three-dimensional spatially varying
+density, albedo, and orientation fields.
diff --git a/src/medium/heterogeneous.cpp b/src/medium/heterogeneous.cpp
index 1546cda4..f704713d 100644
--- a/src/medium/heterogeneous.cpp
+++ b/src/medium/heterogeneous.cpp
@@ -86,10 +86,10 @@ static StatsCounter earlyExits("Heterogeneous volume",
* }
* }
*
- * This plugin provides a flexible hheterogeneous medium implementation, which
+ * This plugin provides a flexible heterogeneous medium implementation, which
* acquires its data from nested \code{volume} instances. These can be
* constant, use a procedural function, or fetch data from disk, e.g. using a
- * memory-mapped density grid.
+ * memory-mapped density grid. See \secref{volumes} for details.
*
* Instead of allowing separate volumes to be provided for the scattering
* absorption parameters \code{sigmaS} and \code{sigmaA} (as is done in
diff --git a/src/volume/constvolume.cpp b/src/volume/constvolume.cpp
index 842d027e..f72e0f88 100644
--- a/src/volume/constvolume.cpp
+++ b/src/volume/constvolume.cpp
@@ -21,6 +21,29 @@
MTS_NAMESPACE_BEGIN
+/*!\plugin{constvolume}{Constant-valued volume data source}
+ * \parameters{
+ * \parameter{value}{\Float\Or\Spectrum\Or\Vector}{
+ * Specifies the value of the volume
+ * }
+ * }
+ *
+ * This plugin provides a volume data source that is
+ * constant throughout its domain. Depending on how it is used,
+ * its value can either be a scalar, a color spectrum,
+ * or a 3D vector.
+ *
+ * \begin{xml}[caption={Definition of a heterogeneous medium with constant albedo}]
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ * \end{xml}
+ */
class ConstantDataSource : public VolumeDataSource {
public:
ConstantDataSource(const Properties &props)
diff --git a/src/volume/gridvolume.cpp b/src/volume/gridvolume.cpp
index b1356a9f..6c61b089 100644
--- a/src/volume/gridvolume.cpp
+++ b/src/volume/gridvolume.cpp
@@ -34,49 +34,69 @@
MTS_NAMESPACE_BEGIN
-/**
- * \brief This class implements access to volume data stored on a
+/*!\plugin{gridvolume}{Grid-based volume data source}
+ * \parameters{
+ * \parameter{filename}{\String}{
+ * Specifies the filename of the volume data file to be loaded
+ * }
+ * \parameter{sendData}{\Boolean}{
+ * When this parameter is set to \code{true}, the implementation will
+ * send all volume data to other network render nodes. Otherwise, they
+ * are expected to have access to an identical volume data file that can be
+ * mapped into memory. \default{\code{false}}
+ * }
+ * \parameter{toWorld}{\Transform}{
+ * Optional linear transformation that should be applied to the data
+ * }
+ * \parameter{min, max}{\Point}{
+ * Optional parameter that can be used to re-scale the data so that
+ * it lies in the bounding box between \code{min} and \code{max}.
+ * }
+ * }
+ *
+ * This class implements access to memory-mapped volume data stored on a
* 3D grid using a simple binary exchange format.
+ * The format uses a little endian encoding and is specified as
+ * follows:\vspace{3mm}
*
- * The format uses a little endian encoding and is specified as follows:
- *
- * Bytes 1-3 : ASCII Bytes 'V', 'O', and 'L'
- * Byte 4 : Version identifier (currently 3)
- * Bytes 5-8 : Encoding identifier using a double word
- *
- * 1 => Dense float32-based representation
- *
- * 2 => Dense float16-based representation
- * NOT YET SUPPORTED BY THIS IMPLEMENTATION
- *
- * 3 => Dense uint8-based representation
- * The range 0..255 will be mapped to 0..1.
- *
- * 4 => Dense quantized directions
- * The directions are stored in spherical coordinates,
- * with a total storage cost of 16 bit per entry.
- *
- * Bytes 9-12 : Number of cells along the X axis (double word)
- * Bytes 13-16 : Number of cells along the Y axis (double word)
- * Bytes 17-20 : Number of cells along the Z axis (double word)
- * Bytes 21-24 : Number of channels (double word, supported values: 1 or 3)
- * Bytes 25-48 : Axis-aligned bounding box of the data stored in single
- * precision (order: xmin, ymin, zmin, xmax, ymax, zmax)
- * Bytes 49-* : Binary data of the volume stored in the specified encoding.
+ * \begin{center}
+ * \begin{tabular}{>{\bfseries}p{2cm}p{11cm}}
+ * \toprule
+ * Position & Content\\
+ * \midrule
+ * Bytes 1-3& ASCII Bytes '\code{V}', '\code{O}', and '\code{L}' \\
+ * Byte 4& File format version number (currently 3)\\
+ * Bytes 5-8& Encoding identifier using a 32-bit integer
+ * \begin{enumerate}[(i)]
+ * \item Dense \code{float32}-based representation
+ * \item Dense \code{float16}-based representation (\emph{currently not supported by this implementation})
+ * \item Dense \code{uint8}-based representation (The range 0..255 will be mapped to 0..1)
+ * \item Dense quantized directions. The directions are stored in spherical
+ * coordinates with a total storage cost of 16 bit per entry.
+ * \end{enumerate}\\
+ * Bytes 9-12 & Number of cells along the X axis (32 bit integer)\\
+ * Bytes 13-16 & Number of cells along the Y axis (32 bit integer)\\
+ * Bytes 17-20 & Number of cells along the Z axis (32 bit integer)\\
+ * Bytes 21-24 & Number of channels (32 bit integer, supported values: 1 or 3)\\
+ * Bytes 25-48 & Axis-aligned bounding box of the data stored in single
+ * precision (order: xmin, ymin, zmin, xmax, ymax, zmax)\\
+ * Bytes 49-* & Binary data of the volume stored in the specified encoding.
* The data are ordered so that the following C-style indexing
- * operation makes sense after the file has been mapped into memory:
- * "data[((zpos*yres + ypos)*xres + xpos)*channels + chan]"
- * where (xpos, ypos, zpos, chan) denotes the lookup location.
+ * operation makes sense after the file has been mapped into memory:\newline
+ * \ \ \code{data[((zpos*yres + ypos)*xres + xpos)*channels + chan]}\newline
+ * where \code{(xpos, ypos, zpos, chan)} denotes the lookup location.\\
+ *
+ * \bottomrule
+ * \end{tabular}
+ * \end{center}
*
* Note that Mitsuba expects that entries in direction volumes are either
* zero or valid unit vectors.
*
* When using this data source to represent floating point density volumes,
* please ensure that the values are all normalized to lie in the
- * range [0, 1] -- otherwise, the Woocock-Tracking integration method in
- * heterogeneous.cpp will produce incorrect results. You can use
- * the 'densityMultiplier' parameter of that class to re-scale the
- * densities if neccessary.
+ * range $[0, 1]$---otherwise, the Woocock-Tracking integration method in
+ * \pluginref{heterogeneous} will produce incorrect results.
*/
class GridDataSource : public VolumeDataSource {
public:
diff --git a/src/volume/volcache.cpp b/src/volume/volcache.cpp
index b85c6325..035caad9 100644
--- a/src/volume/volcache.cpp
+++ b/src/volume/volcache.cpp
@@ -43,10 +43,37 @@ struct Vector3iKeyOrder : public std::binary_function
}
};
-/**
- * This class sits in between the renderer and another data source, for which
- * it caches all data lookups using a LRU scheme. This is useful if the nested
- * volume data source is expensive to evaluate.
+/*!\plugin{volcache}{Caching volume data source}
+ * \parameters{
+ * \parameter{blockSize}{\Integer}{
+ * Size of the individual cache blocks
+ * \default{8, i.e. $8\times8\times 8$}
+ * }
+ * \parameter{voxelWidth}{\Float}{
+ * Width of a voxel (in a cache block) expressed in
+ * world-space units. \default{automatic}
+ * }
+ * \parameter{memoryLimit}{\Integer}{
+ * Max. allowed memory usage in MiB. \default{1024, i.e. 1 GiB}
+ * }
+ * \parameter{toWorld}{\Transform}{
+ * Optional linear transformation that should be applied to the data
+ * }
+ * \parameter{\Unnamed}{\Volume}{
+ * A nested volume data source
+ * }
+ * }
+ *
+ * This plugin can be added between the renderer and another
+ * data source, for which it caches all data lookups using a
+ * LRU scheme. This is useful when the nested volume data source
+ * is expensive to evaluate.
+ *
+ * The cache works by performing on-demand rasterization of subregions
+ * of the nested volume into blocks ($8\times 8 \times 8$ by default).
+ * These are kept in memory until a user-specifiable threshold is exeeded,
+ * after which point a \emph{least recently used} (LRU) policy removes
+ * records that haven't been accessed in a long time.
*/
class CachingDataSource : public VolumeDataSource {
public:
@@ -55,7 +82,7 @@ public:
CachingDataSource(const Properties &props)
: VolumeDataSource(props) {
/// Size of an individual block (must be a power of 2)
- m_blockSize = props.getInteger("blockSize", 4);
+ m_blockSize = props.getInteger("blockSize", 8);
if (!isPowerOfTwo(m_blockSize))
Log(EError, "Block size must be a power of two!");
@@ -65,7 +92,7 @@ public:
m_voxelWidth = props.getFloat("voxelWidth", -1);
/* Permissible memory usage in MiB. Default: 1GiB */
- m_memoryLimit = (size_t) props.getLong("memoryLimit", 32) * 1024 * 1024;
+ m_memoryLimit = (size_t) props.getLong("memoryLimit", 1024) * 1024 * 1024;
m_stepSizeMultiplier = (Float) props.getFloat("stepSizeMultiplier", 1.0f);