diff --git a/.hgtags b/.hgtags
index 4c18e738..9f9ab9e1 100644
--- a/.hgtags
+++ b/.hgtags
@@ -7,3 +7,4 @@ cb6e89af8012fac22cc0f3c5ad247c98c701bdda v0.3.0
ee26517b27207353b0c8a7d357bcb4977b5d93fb v0.4.0
7db07694ea00eb1655f7a1adcc3ae880e8e116f9 v0.4.1
13a39b11aceee517c19d2e2cec2e6b875546062c v0.4.2
+f1b73d39617071297167cc7ce96f3892f21105fc v0.4.3
diff --git a/build/mitsuba-msvc2010.vcxproj b/build/mitsuba-msvc2010.vcxproj
index 1ee777d5..fb1a61ec 100644
--- a/build/mitsuba-msvc2010.vcxproj
+++ b/build/mitsuba-msvc2010.vcxproj
@@ -125,13 +125,15 @@
-
+
-
+
-
+
-
+
+
+
@@ -203,6 +205,8 @@
+
+
@@ -287,14 +291,14 @@
+
+
-
-
@@ -385,6 +389,8 @@
+
+
@@ -409,6 +415,8 @@
+
+
@@ -431,6 +439,8 @@
+
+
@@ -455,8 +465,6 @@
-
-
@@ -511,6 +519,8 @@
+
+
@@ -629,8 +639,6 @@
-
-
@@ -757,6 +765,8 @@
+
+
@@ -805,6 +815,10 @@
+
+
+
+
@@ -937,6 +951,8 @@
+
+
@@ -1001,12 +1017,8 @@
-
-
-
-
@@ -1021,6 +1033,8 @@
+
+
@@ -1033,9 +1047,9 @@
-
+
-
+
diff --git a/build/mitsuba-msvc2010.vcxproj.filters b/build/mitsuba-msvc2010.vcxproj.filters
index 2a0fca14..353385b3 100644
--- a/build/mitsuba-msvc2010.vcxproj.filters
+++ b/build/mitsuba-msvc2010.vcxproj.filters
@@ -9,136 +9,136 @@
cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
- {b54fb131-7e86-4e08-bba2-828939a038ff}
+ {81dd9e3e-7bca-44a1-a313-76fb5af5ab0c}
- {62e70ba9-1509-4ecb-9c06-8de3ef48cd47}
+ {7112f301-f6d5-4351-ae06-4a29910a3766}
- {81da027f-f282-46cb-a88d-abc84969dbf8}
+ {15522c16-64b9-487e-b9fe-dea0094cb5c1}
- {8364b08a-50e5-471b-bfaa-4e45915df101}
+ {4df10a81-6f13-45ae-9a39-ce009db3a659}
- {bb52270c-4a49-423b-ad02-4a7c042295c2}
+ {0c722d61-5189-477d-b242-2fa2ad26c83c}
- {c4330c75-0353-41ab-a809-1471f359aec6}
+ {d849b48a-b61d-4540-81ab-f5228fd6fa93}
+
+
+ {32a38ee8-b255-4e23-8efc-9491fc27c645}
- {0f1ec875-44fb-46b2-9116-26d659410d97}
+ {9f6ef52b-2504-4722-a200-7aaa9603088a}
- {ab910bc2-a0a5-4f02-8232-396937071149}
+ {6c49af9f-8cac-477f-825b-ccb368e313c6}
- {dff3f942-f016-4bad-aa2c-63c444401a94}
+ {182aef81-5fdf-4eb1-a7d3-5b1d7d5de2b5}
- {855b0594-d28c-486a-b081-72991219654e}
+ {81241aff-695b-4556-bf46-e9d3ac4aa7fb}
- {08449c4a-89f1-4b5b-a756-2bd2f03bf566}
-
-
- {8437086b-afc9-48b6-a358-53d4df044974}
+ {f4218b48-d878-435b-915a-8da9727666b1}
- {d9802d62-8614-401a-afa6-941271c63386}
+ {e6e1a06f-b795-4a12-9b0c-0c730e0b2ac6}
- {65e0e20a-2809-4352-8c81-69a0a3824fa9}
+ {231a82e9-6b4b-4a95-995c-8abd0b6149b3}
- {8ea19f58-a2c0-4a30-bc79-817da2f1a1ed}
+ {4c70e19a-a935-4b0f-88e3-10683b03f66c}
- {753c9d80-ceb0-4932-8097-5c7cac92e091}
+ {4a433329-84ca-4a8b-938e-4d06c21ec6ff}
- {b4290489-566b-4576-847b-392b4c45f1f1}
+ {4414bb60-269f-4934-9dc9-58bbed35bc1d}
- {ad07dceb-214e-42e1-933d-c8ceeecd1389}
+ {4bc23857-f9a2-453d-bc64-8c9ebc5aff42}
- {3ee94c12-30fb-4f65-8781-f7b5e8a95db2}
+ {a9318f22-caaa-40af-b8fc-9b8051ec0859}
- {813aba46-5b9d-4290-9a31-18e77952929e}
+ {fba5da81-e3f2-4fbe-98d7-807aaa2c2cf3}
- {55bcc3cd-7f6b-4bb6-b22e-b731ed0451fb}
+ {abd6883d-375b-4d85-bb93-12952995332d}
- {6ebccae2-fbfd-4a3f-9bfc-7e9dbd2b6d74}
+ {4c9fdf84-d6a6-47f8-8d58-c01ed8351fa0}
- {a339ab19-2bed-4d03-afdc-d73223648b72}
+ {366f9975-2268-4124-81b9-87e7c2c03b1e}
- {87b01999-0b73-481b-b8fa-b66f594f65be}
+ {8d2d02ea-1957-4256-8046-f525d13e7ba5}
- {5870cf94-fb1b-44c0-90f2-32c3c8cbf6b7}
+ {8438e074-8733-4689-95ba-86145dd9fd9d}
- {90263b28-e65b-4d41-92cb-a0d1dac22564}
+ {9d35d85d-280c-49ef-869a-ffaa0602f9f5}
- {453d13c1-1847-4a18-8f2e-028913b4ec43}
+ {6df94c72-e89d-451e-ad6b-160ea0313077}
- {e4baad7e-ee3c-4085-961f-2851c0ed2b8f}
+ {7bec8429-3bb9-4dfd-8008-a10c675a9818}
- {a7ab51c2-5596-458f-b5f0-1129dc3dbbf5}
+ {747a1613-4c01-46ef-ba17-92d2286890ad}
- {a7456898-2253-48d8-abec-9c86311cca64}
+ {516a0fc3-a824-4486-b50c-f3165d1d8361}
- {cb9f48b8-6f25-4c9d-9d2c-b1a67cc80427}
+ {bddbc784-474a-4cd3-bbea-3123048dbfaa}
- {b44ee927-e827-4c46-bbce-c7a1b705b63b}
+ {7bba2a7a-8cd3-47bd-9ab2-e33939d4eba6}
- {40540c0e-02d6-4296-bbdf-87dfd9f7f213}
+ {32cdfdd7-c3bb-41f2-b433-10165963f9ed}
- {430d27a2-66db-4169-bb48-aeb0b65e4d1a}
+ {49edc93d-4305-45a8-a6d9-ae283837d46a}
- {a247e523-dbaf-4fb8-b284-6c8c5cbc09a5}
+ {d24cf1e6-a301-42e8-9fc1-26fe0ddc3f04}
- {91d6db52-180b-4dde-9339-807917e42f4e}
+ {3df649be-39d5-4416-8776-427a1696c016}
- {8ae0e3a3-87db-4e93-bb20-9d198040ae86}
+ {2e68088f-97e2-4dee-91f5-c85e3e36dd74}
- {0049f7d1-4211-4010-b53c-3ee99244046e}
+ {f7674a86-b0a5-484c-9db3-a20500b9bbf9}
- {8bddb89b-fa54-448a-a4b3-294f18d45ded}
+ {f41987e3-e0b9-431d-b37b-5931db380b09}
- {082f589c-eb3f-47a4-b2f6-fbd6d89dec07}
+ {88ed597b-50ba-4d6f-bf50-ae8f5fa17789}
- {a7f59027-bc87-4d28-9b90-eb5be186d8a7}
+ {5499a8e9-ef31-4ab9-a58f-d3a36a784004}
- {f5410d0f-0a22-4579-afbf-8e13db8fa3d5}
+ {b74f25a9-ff20-4888-8dfc-57dd968b0b8d}
- {ebe2b998-26de-4e92-8618-c739cb43a5f2}
+ {18246123-74da-4fee-8581-bd2860451c40}
- {4f4d9d4b-3f44-4d56-9a18-16b94e753706}
+ {3fdeab5a-5ccf-41c6-bf05-d9f7f510c741}
@@ -247,9 +247,6 @@
Source Files\librender
-
- Source Files\librender
-
Source Files\librender
@@ -439,6 +436,9 @@
Source Files\libhw
+
+ Source Files\libhw
+
Source Files\libhw
@@ -511,6 +511,12 @@
Source Files\libcore
+
+ Source Files\libcore
+
+
+ Source Files\libcore
+
Source Files\libcore
@@ -709,6 +715,9 @@
Source Files\mtsgui
+
+ Source Files\mtsgui
+
Source Files\mtsgui
@@ -805,15 +814,9 @@
Source Files\utils
-
- Source Files\utils
-
Source Files\utils
-
- Source Files\utils
-
Source Files\utils
@@ -835,6 +838,9 @@
Source Files\shapes\ply
+
+ Source Files\shapes
+
Source Files\shapes
@@ -853,10 +859,10 @@
Source Files\shapes
-
+
Source Files\shapes
-
+
Source Files\shapes
@@ -1035,17 +1041,20 @@
Source Files\samplers
-
- Source Files\libhw
+
+ Source Files\libhw\data
-
- Source Files\libhw
+
+ Source Files\libhw\data
-
- Source Files\libhw
+
+ Source Files\libhw\data
-
- Source Files\libhw
+
+ Source Files\libhw\data
+
+
+ Source Files\libhw\data
Source Files\medium
@@ -1152,6 +1161,9 @@
Source Files\films
+
+ Source Files\films
+
Source Files\shapes
@@ -1278,6 +1290,9 @@
Header Files\mitsuba\render
+
+ Header Files\mitsuba\render
+
Header Files\mitsuba\render
@@ -1287,9 +1302,6 @@
Header Files\mitsuba\render
-
- Header Files\mitsuba\render
-
Header Files\mitsuba\render
@@ -1425,6 +1437,9 @@
Header Files\mitsuba\core
+
+ Header Files\mitsuba\core
+
Header Files\mitsuba\core
@@ -1461,6 +1476,9 @@
Header Files\mitsuba\core
+
+ Header Files\mitsuba\core
+
Header Files\mitsuba\core
@@ -1494,6 +1512,9 @@
Header Files\mitsuba\core
+
+ Header Files\mitsuba\core
+
Header Files\mitsuba\core
@@ -1530,9 +1551,6 @@
Header Files\mitsuba\core
-
- Header Files\mitsuba\core
-
Header Files\mitsuba\core
@@ -1614,6 +1632,9 @@
Header Files\mitsuba\hw
+
+ Header Files\mitsuba\hw
+
Header Files\mitsuba\hw
diff --git a/data/linux/debian/changelog b/data/linux/debian/changelog
index 561acd80..1443a9e7 100644
--- a/data/linux/debian/changelog
+++ b/data/linux/debian/changelog
@@ -1,3 +1,39 @@
+mitsuba (0.4.3-1) unstable; urgency=low
+ * Motion blur: Support for arbitrary linear camera, object, and sensor motion
+ to produce motion blur in renderings.
+ * Render-time annotations: added the ability to tag image files with additional
+ information by means of metadata or text labels.
+ * Hide directly visible emitters: convenient feature for removing an environment
+ light source so that an image can be composited onto documents having a
+ different color.
+ * Improved instancing: more robust instancing code with support for
+ non-rigid transformations.
+ * Threading on Windows: fixed various threading-related issues on Windows that
+ previously caused crashes and deadlocks.
+ * Caching: Caching mechanism to further accelerate the loading of
+ .serialized files.
+ * File dialogs: Native File Open/Save dialogs are now used on Windows.
+ * Python: Improved python bindings; easier usage on MacOS X.
+ * Blender interaction: Fixed a issue where GUI tabs containing scenes created
+ in Blender could not be cloned.
+ * Non-uniform scales: All triangle mesh-based shapes now permit
+ non-uniform scales.
+ * NaNs and friends: Increased resilience against various numerical corner cases.
+ * Index-matched participating media: Fixed an unfortunate regression in volpath
+ regarding index-matched media that was accidentally introduced in 0.4.2.
+ * roughdiffuse: Fixed texturing support in the roughdiffuse plugin.
+ * Photon mapping: Fixed some inaccuracies involving participating media when
+ rendered by the photon mapper and the Beam Radiance Estimate.
+ * Conductors: Switched Fresnel reflectance computations for conductors to the
+ exact expressions predicted by geometric optics (an approximation was
+ previously used).
+ * New cube shape: Added a cube shape plugin for convenience. This does
+ exactly what one would expect.
+ * The rest: As usual, a large number of smaller bugfixes and improvements
+ were below the threshold and are thus not listed individually. The
+ repository log has more details.
+ -- Wenzel Jakob Tue, 29 Jan 2013 00:00:00 -0400
+
mitsuba (0.4.2-1) unstable; urgency=low
* Volumetric path tracers: improved sampling when dealing with index-matched medium transitions. This is essentially a re-implementation of an optimization that Mitsuba 0.3.1 already had, but which got lost in the bidirectional rewrite.
* Batch tonemapper: due to an unfortunate bug, the batch tonemapper in the last release produced invalid results for images containing an alpha channel. This is now fixed.
@@ -50,15 +86,15 @@ mitsuba (0.4.0-1) unstable; urgency=low
mitsuba (0.3.1-1) unstable; urgency=low
- * Photon mapper: The photon mapper had some serious issues in the
+ * Photon mapper: The photon mapper had some serious issues in the
last release. These are now fixed, and it should run faster too.
- * On Linux/x86_64, the performance of the single precision exp() and log()
+ * On Linux/x86_64, the performance of the single precision exp() and log()
math library functions is extremely poor. Mitsuba now uses the double
prevision versions of these functions by default.
* Primitive clipping: Fixed numerical issues that occurred when using
primitive clipping in a double precision build.
* The adaptive integrator now better interacts with certain sub-integrators.
- * Instanced analytic shapes (e.g. spheres, cylinders, ..) are now supported,
+ * Instanced analytic shapes (e.g. spheres, cylinders, ..) are now supported,
and an error involving network rendering with instanced geometry is fixed.
* Fixed a serious issue that could destroy a scene file when saving from a cloned tab!
* Fixed some bad GUI behavior in multi-screen setups
@@ -72,30 +108,30 @@ mitsuba (0.3.0-1) unstable; urgency=low
* Added Python bindings that can be used to instantiate plugins
and control rendering processes.
- * Spectral rendering: most of the code pertaining to spectral
- rendering has seen a significant overhaul. It is now faster and
+ * Spectral rendering: most of the code pertaining to spectral
+ rendering has seen a significant overhaul. It is now faster and
in certain cases more accurate.
- * Flexible material classes: this release introduces a robust and
- very general suite of eight physically-based smooth and rough
+ * Flexible material classes: this release introduces a robust and
+ very general suite of eight physically-based smooth and rough
(microfacet-based) material classes.
* Material modifiers: two new material modifiers (bump & coating)
can be applied to BSDFs to create new materials.
- * Material verification: the sampling methods of all material
- models in Mitsuba are now automatically verified with the help
+ * Material verification: the sampling methods of all material
+ models in Mitsuba are now automatically verified with the help
of statistical hypothesis tests (using Chi^2-tests).
- * Generated documentation: there is now a javadoc-like system,
- which extracts documentation directly from the plugin source code
+ * Generated documentation: there is now a javadoc-like system,
+ which extracts documentation directly from the plugin source code
and stitches it into a LaTeX reference document.
- * lookAt: Mitsuba inherited a bug from PBRT, where the
- tag changed the handedness of the coordinate system. This is now
+ * lookAt: Mitsuba inherited a bug from PBRT, where the
+ tag changed the handedness of the coordinate system. This is now
fixed--also, the syntax of this tag has changed to make it easier to read.
* Scene portability: A new conversion tool ensures that old and incompatible
- scenes can be translated into the scene description format of the
+ scenes can be translated into the scene description format of the
most recent version.
- * Contributed plugins: Tom Kazimiers and Papas have contributed
+ * Contributed plugins: Tom Kazimiers and Papas have contributed
implementations of the Preetham Sun & Sky model and the Hanrahan-Krueger
scattering model.
- * Photon mapping: The Photon map integrator has been rewritten for
+ * Photon mapping: The Photon map integrator has been rewritten for
improved accuracy and better performance. Furthermore, the underlying
data structure has been replaced with a ~50% faster implementation.
@@ -140,8 +176,8 @@ mitsuba (0.2.0-1) unstable; urgency=low
mitsuba (0.1.3-1) unstable; urgency=low
- This is mainly a bugfix release to address a serious regression in the
- material system. Other notable changes are:
+ This is mainly a bugfix release to address a serious regression in the
+ material system. Other notable changes are:
* Imported scenes now store relative paths
* OBJ importing works on Windows
@@ -149,7 +185,7 @@ mitsuba (0.1.3-1) unstable; urgency=low
* The anisotropic Ward BRDF is now supported in the preview
* Faster texture loading
* The renderer now has a testcase framework similar to JUnit
-
+
-- Wenzel Jakob Wed, 8 Sep 2010 09:59:00 -0400
mitsuba (0.1.2-1) unstable; urgency=low
@@ -165,8 +201,8 @@ mitsuba (0.1.2-1) unstable; urgency=low
is lacking some required OpenGL features.
* Create default cameras/lightsources if none are specified in a scene
* Support for drag & drop in the user interface
- * The Mitsuba user interface now also doubles as an EXR viewer / tonemapper.
- Drag an EXR file onto the UI or open it using the File menu, and the image
+ * The Mitsuba user interface now also doubles as an EXR viewer / tonemapper.
+ Drag an EXR file onto the UI or open it using the File menu, and the image
opens in a new tab. Afterwards, it is possible to export the image as a tonemapped
8-bit PNG image.
* The realtime preview now has a 'force diffuse' feature to improve
@@ -180,6 +216,6 @@ mitsuba (0.1.2-1) unstable; urgency=low
mitsuba (0.1.1-1) unstable; urgency=low
- * Initial release
+ * Initial release
-- Wenzel Jakob Sat, 17 Jul 2010 23:56:03 -0400
diff --git a/data/linux/fedora/mitsuba.spec b/data/linux/fedora/mitsuba.spec
index aeb0a0f3..5aa083ee 100644
--- a/data/linux/fedora/mitsuba.spec
+++ b/data/linux/fedora/mitsuba.spec
@@ -1,7 +1,7 @@
Name: mitsuba
-Version: 0.4.2
+Version: 0.4.3
Release: 1%{?dist}
-Summary: Mitsuba renderer
+Summary: Mitsuba renderer
Group: Applications/Graphics
License: GPL-3
URL: http://www.mitsuba-renderer.org
@@ -10,11 +10,11 @@ BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX)
BuildRequires: gcc-c++ scons boost-devel qt4-devel OpenEXR-devel xerces-c-devel python-devel glew-devel collada-dom-devel eigen3-devel
Requires: boost qt4 OpenEXR-libs xerces-c python libGLEWmx collada-dom
%description
-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.
+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.
The program currently runs on Linux, MacOS X and Microsoft Windows and makes use of SSE2 optimizations on x86 and x86_64 platforms. So far, its main use has been as a testbed for algorithm development in computer graphics, but there are many other interesting applications.
-Mitsuba comes with a command-line interface as well as a graphical frontend to interactively explore scenes. While navigating, a rough preview is shown that becomes increasingly accurate as soon as all movements are stopped. Once a viewpoint has been chosen, a wide range of rendering techniques can be used to generate images, and their parameters can be tuned from within the program.
+Mitsuba comes with a command-line interface as well as a graphical frontend to interactively explore scenes. While navigating, a rough preview is shown that becomes increasingly accurate as soon as all movements are stopped. Once a viewpoint has been chosen, a wide range of rendering techniques can be used to generate images, and their parameters can be tuned from within the program.
%package devel
Summary: Mitsuba development files
Requires: boost-devel qt4-devel OpenEXR-devel xerces-c-devel python-devel glew-devel collada-dom-devel
@@ -63,6 +63,9 @@ rm -rf $RPM_BUILD_ROOT
/usr/include/*
%changelog
+* Tue Jan 29 2013 Wenzel Jakob 0.4.3%{?dist}
+- Upgrade to version 0.4.3
+
* Wed Oct 31 2012 Wenzel Jakob 0.4.2%{?dist}
- Upgrade to version 0.4.2
diff --git a/doc/format.tex b/doc/format.tex
index d837adde..de82cf4a 100644
--- a/doc/format.tex
+++ b/doc/format.tex
@@ -97,7 +97,7 @@ and one or more emitters. Here is a more complex example:
-
+
@@ -289,7 +289,7 @@ do not explicitly have to be specified.
\subsection{Animated transformations}
Most shapes, emitters, and sensors in Mitsuba can accept both normal transformations
and \emph{animated transformations} as parameters. The latter is useful to
-render scenes involving motion blur. The syntax used to specify these
+render scenes involving motion blur (Figure~\ref{fig:animated-transform}). The syntax used to specify these
is slightly different:
\begin{xml}
@@ -304,6 +304,11 @@ is slightly different:
.. additional transformations (optional) ..
\end{xml}
+\renderings{
+ \fbox{\includegraphics[width=.6\textwidth]{images/animated_transform}}\hfill\,
+ \caption{\label{fig:animated-transform}Beware the dragon: a triangle mesh undergoing linear motion with several keyframes (object courtesy of XYZRGB)}
+}
+
Mitsuba then decomposes each transformation into a scale, translation, and
rotation component and interpolates\footnote{Using linear interpolation
for the scale and translation component and spherical linear quaternion
@@ -311,7 +316,7 @@ interpolation for the rotation component.} these for intermediate
time values.
It is important to specify appropriate shutter open/close times
to the sensor so that the motion is visible.
-
+\newpage
\subsection{References}
Quite often, you will find yourself using an object (such as a material) in many places. To avoid having
to declare it over and over again, which wastes memory, you can make use of references. Here is an example
diff --git a/doc/images/animated_transform.jpg b/doc/images/animated_transform.jpg
new file mode 100644
index 00000000..fd287ab1
Binary files /dev/null and b/doc/images/animated_transform.jpg differ
diff --git a/doc/images/annotation_example.jpg b/doc/images/annotation_example.jpg
new file mode 100644
index 00000000..0420429f
Binary files /dev/null and b/doc/images/annotation_example.jpg differ
diff --git a/doc/images/shape_cube_basic.jpg b/doc/images/shape_cube_basic.jpg
new file mode 100644
index 00000000..d5f26251
Binary files /dev/null and b/doc/images/shape_cube_basic.jpg differ
diff --git a/doc/images/shape_cube_parameterization.jpg b/doc/images/shape_cube_parameterization.jpg
new file mode 100644
index 00000000..d9f34781
Binary files /dev/null and b/doc/images/shape_cube_parameterization.jpg differ
diff --git a/doc/main.tex b/doc/main.tex
index f4b3c7a0..1ed7ad5c 100644
--- a/doc/main.tex
+++ b/doc/main.tex
@@ -27,6 +27,7 @@
\usepackage{ifthen}
\usepackage{longtable}
\usepackage{wrapfig}
+\usepackage{footnote} % savenotes environment
% Make sure that ligatures remain searchable in the PDF
\input glyphtounicode
@@ -39,8 +40,8 @@
\setcounter{secnumdepth}{3}
\setcounter{tocdepth}{3}
-\newcommand{\MitsubaVersion}{0.4.2}
-\newcommand{\MitsubaYear}{2012}
+\newcommand{\MitsubaVersion}{0.4.3}
+\newcommand{\MitsubaYear}{2013}
\typearea[current]{last}
\raggedbottom
diff --git a/include/mitsuba/core/platform.h b/include/mitsuba/core/platform.h
index 88ca7594..9f72838f 100644
--- a/include/mitsuba/core/platform.h
+++ b/include/mitsuba/core/platform.h
@@ -203,13 +203,14 @@ MTS_NAMESPACE_END
#define snprintf _snprintf
#define vsnprintf _vsnprintf
-#define strncasecmp _strnicmp
+namespace mitsuba {
#if defined(__64BIT__)
typedef long long ssize_t;
#else
typedef long ssize_t;
#endif
+};
namespace std {
inline char tolower(char c) {
diff --git a/include/mitsuba/core/util.h b/include/mitsuba/core/util.h
index 7bd67cb6..37b7c8db 100644
--- a/include/mitsuba/core/util.h
+++ b/include/mitsuba/core/util.h
@@ -58,7 +58,7 @@ extern MTS_EXPORT_CORE std::string formatString(const char *pFmt, ...);
extern MTS_EXPORT_CORE std::string timeString(Float time, bool precise = false);
/// Turn a memory size into a human-readable string
-extern MTS_EXPORT_CORE std::string memString(size_t size);
+extern MTS_EXPORT_CORE std::string memString(size_t size, bool precise = false);
/// Return a string representation of a list of objects
template std::string containerToString(const Iterator &start, const Iterator &end) {
diff --git a/include/mitsuba/render/scenehandler.h b/include/mitsuba/render/scenehandler.h
index 268967f8..d878f93a 100644
--- a/include/mitsuba/render/scenehandler.h
+++ b/include/mitsuba/render/scenehandler.h
@@ -68,6 +68,9 @@ private:
# pragma warning( pop )
#endif
+/// Push a cleanup handler to be executed after loading the scene is done
+extern MTS_EXPORT_RENDER void pushSceneCleanupHandler(void (*cleanup)());
+
/**
* \brief XML parser for Mitsuba scene files. To be used with the
* SAX interface of Xerces-C++.
@@ -101,9 +104,6 @@ public:
/// Free the memory taken up by staticInitialization()
static void staticShutdown();
- /// Push a cleanup handler to be executed after loading the scene is done
- static void pushCleanupHandler(void (*cleanup)());
-
// -----------------------------------------------------------------------
// Implementation of the SAX DocumentHandler interface
// -----------------------------------------------------------------------
@@ -136,8 +136,7 @@ protected:
private:
struct ParseContext {
inline ParseContext(ParseContext *_parent)
- : parent(_parent) {
- }
+ : parent(_parent) { }
ParseContext *parent;
Properties properties;
diff --git a/src/bsdfs/coating.cpp b/src/bsdfs/coating.cpp
index 1c4f77c2..ec37de9a 100644
--- a/src/bsdfs/coating.cpp
+++ b/src/bsdfs/coating.cpp
@@ -419,7 +419,8 @@ protected:
class SmoothCoatingShader : public Shader {
public:
SmoothCoatingShader(Renderer *renderer, Float eta, const BSDF *nested,
- const Texture *sigmaA) : Shader(renderer, EBSDFShader), m_nested(nested), m_sigmaA(sigmaA), m_eta(eta) {
+ const Texture *sigmaA) : Shader(renderer, EBSDFShader),
+ m_nested(nested), m_sigmaA(sigmaA), m_eta(eta) {
m_nestedShader = renderer->registerShaderForResource(m_nested.get());
m_sigmaAShader = renderer->registerShaderForResource(m_sigmaA.get());
m_R0 = fresnelDielectricExt(1.0f, eta);
@@ -467,15 +468,15 @@ public:
<< "vec3 " << evalName << "_refract(vec3 wi, out float T) {" << endl
<< " float cosThetaI = cosTheta(wi);" << endl
<< " bool entering = cosThetaI > 0.0;" << endl
- << " float eta = " << evalName << "_eta;" << endl
- << " float sinThetaTSqr = eta * eta * sinTheta2(wi);" << endl
+ << " float invEta = 1.0 / " << evalName << "_eta;" << endl
+ << " float sinThetaTSqr = invEta * invEta * sinTheta2(wi);" << endl
<< " if (sinThetaTSqr >= 1.0) {" << endl
<< " T = 0.0; /* Total internal reflection */" << endl
<< " return vec3(0.0);" << endl
<< " } else {" << endl
<< " float cosThetaT = sqrt(1.0 - sinThetaTSqr);" << endl
<< " T = 1.0 - " << evalName << "_schlick(1.0 - abs(cosThetaI));" << endl
- << " return vec3(eta*wi.x, eta*wi.y, entering ? cosThetaT : -cosThetaT);" << endl
+ << " return vec3(invEta*wi.x, invEta*wi.y, entering ? cosThetaT : -cosThetaT);" << endl
<< " }" << endl
<< "}" << endl
<< endl
@@ -512,10 +513,11 @@ public:
<< " 1/abs(cosTheta(woPrime))));" << endl
<< " if (cosTheta(wi)*cosTheta(wo) > 0) {" << endl
<< " vec3 H = normalize(wi + wo);" << endl
+ << " if (H.z < 0) H = -H;" << endl
<< " float D = " << evalName << "_D(H)" << ";" << endl
<< " float G = " << evalName << "_G(H, wi, wo);" << endl
- << " float F = " << evalName << "_schlick(1-dot(wi, H));" << endl
- << " result += vec3(F * D * G / (4*cosTheta(wi)));" << endl
+ << " float F = " << evalName << "_schlick(1-abs(dot(wi, H)));" << endl
+ << " result += vec3(abs(F * D * G) / abs(4*cosTheta(wi)));" << endl
<< " }" << endl
<< " return result;" << endl
<< "}" << endl
diff --git a/src/bsdfs/microfacet.h b/src/bsdfs/microfacet.h
index 16799e97..9fbf7538 100644
--- a/src/bsdfs/microfacet.h
+++ b/src/bsdfs/microfacet.h
@@ -84,7 +84,11 @@ public:
* (For lower roughness values, please switch to the smooth BSDF variants)
*/
Float transformRoughness(Float value) const {
- value = std::max(value, (Float) 1e-5f);
+ #if defined(SINGLE_PRECISION)
+ value = std::max(value, (Float) 1e-3f);
+ #else
+ value = std::max(value, (Float) 1e-5f);
+ #endif
if (m_type == EPhong || m_type == EAshikhminShirley)
value = std::max(2 / (value * value) - 2, (Float) 0.1f);
return value;
diff --git a/src/bsdfs/plastic.cpp b/src/bsdfs/plastic.cpp
index 4f11f242..5c1999f6 100644
--- a/src/bsdfs/plastic.cpp
+++ b/src/bsdfs/plastic.cpp
@@ -339,7 +339,7 @@ public:
Spectrum diff = m_diffuseReflectance->eval(bRec.its);
if (m_nonlinear)
- diff /= Spectrum(1.0f) - m_fdrInt*diff;
+ diff /= Spectrum(1.0f) - diff*m_fdrInt;
else
diff /= 1 - m_fdrInt;
@@ -357,6 +357,7 @@ public:
bRec.sampledType = EDiffuseReflection;
Spectrum diff = m_diffuseReflectance->eval(bRec.its);
+ diff /= Spectrum(1.0f) - m_fdrInt*diff;
if (m_nonlinear)
diff /= Spectrum(1.0f) - diff*m_fdrInt;
else
@@ -424,14 +425,14 @@ public:
bRec.wo = Warp::squareToCosineHemisphere(sample);
Float Fo = fresnelDielectricExt(Frame::cosTheta(bRec.wo), m_eta);
- pdf = Warp::squareToCosineHemispherePdf(bRec.wo);
-
Spectrum diff = m_diffuseReflectance->eval(bRec.its);
if (m_nonlinear)
diff /= Spectrum(1.0f) - diff*m_fdrInt;
else
diff /= 1 - m_fdrInt;
+ pdf = Warp::squareToCosineHemispherePdf(bRec.wo);
+
return diff * (m_invEta2 * (1-Fi) * (1-Fo));
}
}
diff --git a/src/bsdfs/roughcoating.cpp b/src/bsdfs/roughcoating.cpp
index 0622316d..d11362e9 100644
--- a/src/bsdfs/roughcoating.cpp
+++ b/src/bsdfs/roughcoating.cpp
@@ -554,7 +554,7 @@ public:
<< "vec3 " << evalName << "_refract(vec3 wi, out float T) {" << endl
<< " float cosThetaI = cosTheta(wi);" << endl
<< " bool entering = cosThetaI > 0.0;" << endl
- << " float invEta = " << evalName << "_eta;" << endl
+ << " float invEta = 1.0 / " << evalName << "_eta;" << endl
<< " float sinThetaTSqr = invEta * invEta * sinTheta2(wi);" << endl
<< " if (sinThetaTSqr >= 1.0) {" << endl
<< " T = 0.0; /* Total internal reflection */" << endl
diff --git a/src/films/annotations.h b/src/films/annotations.h
index 6d041e03..3ae47777 100644
--- a/src/films/annotations.h
+++ b/src/films/annotations.h
@@ -75,48 +75,68 @@ void annotate(const Scene *scene, const Properties &properties,
if (!(strt = strchr((char *) value.c_str(), '$')))
break;
- if (strncasecmp(strt, "$rendertime", 11) == 0) {
- value.replace(strt-value.c_str(), 11, timeString(renderTime));
- } else if (strncasecmp(strt, "$memusage", 11) == 0) {
- value.replace(strt-value.c_str(), 11, memString(getPrivateMemoryUsage()));
- } else {
- char *par1, *par2;
- if (!(par1 = strchr(strt, '[')))
- break;
- if (!(par2 = strchr(par1, ']')))
- break;
+ char *par1, *par2;
+ if (!(par1 = strchr(strt, '[')))
+ break;
+ if (!(par2 = strchr(par1, ']')))
+ break;
- std::string propSource = value.substr(strt-value.c_str()+1, par1-strt-1);
- std::string propKey = value.substr(par1-value.c_str()+1, par2-par1-1);
- propSource.erase(std::remove_if(propSource.begin(), propSource.end(), ::isspace), propSource.end());
- propKey.erase(std::remove_if(propKey.begin(), propKey.end(), ::isspace), propKey.end());
+ std::string propSource = value.substr(strt-value.c_str()+1, par1-strt-1);
+ std::string propKey = value.substr(par1-value.c_str()+1, par2-par1-1);
+ propSource.erase(std::remove_if(propSource.begin(), propSource.end(), ::isspace), propSource.end());
+ propKey.erase(std::remove_if(propKey.begin(), propKey.end(), ::isspace), propKey.end());
- if (!boost::starts_with(propKey, "'") || !boost::ends_with(propKey, "'"))
- SLog(EError, "Encountered invalid key '%s'", propKey.c_str());
+ if (!boost::starts_with(propKey, "'") || !boost::ends_with(propKey, "'"))
+ SLog(EError, "Encountered invalid key '%s'", propKey.c_str());
- propKey = propKey.substr(1, propKey.length()-2);
+ propKey = propKey.substr(1, propKey.length()-2);
- const ConfigurableObject *source = NULL;
- if (propSource == "film")
- source = scene->getFilm();
- else if (propSource == "sampler")
- source = scene->getSampler();
- else if (propSource == "sensor")
- source = scene->getSensor();
- else if (propSource == "integrator")
- source = scene->getIntegrator();
- else
- SLog(EError, "Unknown data source '%s' (must be film/sampler/sensor/integrator)", propSource.c_str());
+ const ConfigurableObject *source = NULL;
+ if (propSource == "scene")
+ source = scene;
+ else if (propSource == "film")
+ source = scene->getFilm();
+ else if (propSource == "sampler")
+ source = scene->getSampler();
+ else if (propSource == "sensor")
+ source = scene->getSensor();
+ else if (propSource == "integrator")
+ source = scene->getIntegrator();
+ else
+ SLog(EError, "Unknown data source '%s' (must be film/sampler/sensor/integrator)", propSource.c_str());
- std::string replacement;
+ std::string replacement;
+
+ if (source == scene) {
+ if (propKey == "renderTime") {
+ replacement = timeString(renderTime);
+ } else if (propKey == "renderTimePrecise") {
+ replacement = timeString(renderTime, true);
+ } else if (propKey == "memUsage") {
+ replacement = memString(getPrivateMemoryUsage());
+ } else if (propKey == "memUsagePrecise") {
+ replacement = memString(getPrivateMemoryUsage(), true);
+ } else if (propKey == "coreCount") {
+ replacement = formatString("%i", Scheduler::getInstance()->getCoreCount());
+ } else if (propKey == "blockSize") {
+ replacement = formatString("%i", scene->getBlockSize());
+ } else if (propKey == "sourceFile") {
+ replacement = scene->getSourceFile().string();
+ } else if (propKey == "destFile") {
+ replacement = scene->getDestinationFile().string();
+ }
+ }
+
+ if (replacement.empty()) {
if (propKey == "type")
replacement = source->getProperties().getPluginName();
else
replacement = source->getProperties().getAsString(propKey);
-
- value.replace(strt-value.c_str(), par2-strt+1, replacement);
}
+
+ value.replace(strt-value.c_str(), par2-strt+1, replacement);
}
+
if (labelAnnotation) {
Vector2i size = font->getSize(value);
bitmap->fillRect(offset-Vector2i(4, 4), size + Vector2i(8, 8), Spectrum(0.0f));
diff --git a/src/films/hdrfilm.cpp b/src/films/hdrfilm.cpp
index 8bb01a3c..d8113755 100644
--- a/src/films/hdrfilm.cpp
+++ b/src/films/hdrfilm.cpp
@@ -117,33 +117,89 @@ MTS_NAMESPACE_BEGIN
*
* \end{xml}
*
- * \subsubsection*{Annotations:}
+ * \subsubsection*{Render-time annotations:}
* \label{sec:film-annotations}
- * The \pluginref{ldrfilm} and \pluginref{hdrfilm} plugins support an additional
- * feature referred to as \emph{annotations}, which can be quite useful under
- * certain circumstances.
- *
+ * The \pluginref{ldrfilm} and \pluginref{hdrfilm} plugins support a
+ * feature referred to as \emph{render-time annotations} to facilitate
+ * record keeping.
* Annotations are used to embed useful information inside a rendered image so
* that this information is later available to anyone viewing the image.
* Exemplary uses of this feature might be to store the frame or take number,
- * camera parameters, or other relevant scene information.
- *
- * Annotations can either be created by means of a \emph{tag}, which is an entry
- * in the metadata table of the image file (does not modify the actual image data),
- * or a \emph{text} label which is ``burned'' into the image.
+ * rendering time, memory usage, camera parameters, or other relevant scene
+ * information.
*
+ * Currently, two different types are supported: a \code{metadata} annotation
+ * creates an entry in the metadata table of the image, which is preferable
+ * when the image contents should not be touched. Alternatively, a \code{label}
+ * annotation creates a line of text that is overlaid on top of the image. Note
+ * that this is only visible when opening the output file (i.e. the line is not
+ * shown in the interactive viewer).
* The syntax of this looks as follows:
*
* \begin{xml}
- *
- *
- *
+ *
+ *
+ *
*
*
- *
+ *
*
* \end{xml}
+ *
+ * The \code{value="..."} argument may also include certain keywords that will be
+ * evaluated and substituted when the rendered image is written to disk. A list all available
+ * keywords is provided in Table~\ref{tbl:film-keywords}.
+ *
+ * Apart from querying the render time,
+ * memory usage, and other scene-related information, it is also possible
+ * to `paste' an existing parameter that was provided to another plugin---for instance,the
+ * the camera transform matrix would be obtained as \code{\$sensor['toWorld']}. The name of
+ * the active integrator plugin is given by \code{\$integrator['type']}, and so on.
+ * All of these can be mixed to build larger fragments, as following example demonstrates.
+ * The result of this annotation is shown in Figure~\ref{fig:annotation-example}.
+ * \begin{xml}[mathescape=false]
+ *
+ * \end{xml}
+ * \vspace{1cm}
+ * \renderings{
+ * \fbox{\includegraphics[width=.8\textwidth]{images/annotation_example}}\hfill\,
+ * \caption{\label{fig:annotation-example}A demonstration of the label annotation feature
+ * given the example string shown above.}
+ * }
+ * \vspace{2cm}
+ * \begin{table}[htb]
+ * \centering
+ * \begin{savenotes}
+ * \begin{tabular}{ll}
+ * \toprule
+ * \code{\$scene['renderTime']}& Image render time, use \code{renderTimePrecise} for more digits.\\
+ * \code{\$scene['memUsage']}& Mitsuba memory usage\footnote{The definition of this quantity unfortunately
+ * varies a bit from platform to platform. On Linux and Windows, it denotes the total
+ * amount of allocated RAM and disk-based memory that is private to the process (i.e. not
+ * shared or shareable), which most intuitively captures the amount of memory required for
+ * rendering. On OSX, it denotes the working set size---roughly speaking, this is the
+ * amount of RAM apportioned to the process (i.e. excluding disk-based memory).}.
+ * Use \code{memUsagePrecise} for more digits.\\
+ * \code{\$scene['coreCount']}& Number of local and remote cores working on the rendering job\\
+ * \code{\$scene['blockSize']}& Block size used to parallelize up the rendering workload\\
+ * \code{\$scene['sourceFile']}& Source file name\\
+ * \code{\$scene['destFile']}& Destination file name\\
+ * \code{\$integrator['..']}& Copy a named integrator parameter\\
+ * \code{\$sensor['..']}& Copy a named sensor parameter\\
+ * \code{\$sampler['..']}& Copy a named sampler parameter\\
+ * \code{\$film['..']}& Copy a named film parameter\\
+ * \bottomrule
+ * \end{tabular}
+ * \end{savenotes}
+ * \caption{\label{tbl:film-keywords}A list of all special
+ * keywords supported by the annotation feature}
+ * \end{table}
+ *
*/
+
class HDRFilm : public Film {
public:
HDRFilm(const Properties &props) : Film(props) {
diff --git a/src/integrators/photonmapper/photonmapper.cpp b/src/integrators/photonmapper/photonmapper.cpp
index 91d3ac15..d77c7fbc 100644
--- a/src/integrators/photonmapper/photonmapper.cpp
+++ b/src/integrators/photonmapper/photonmapper.cpp
@@ -435,9 +435,17 @@ public:
return LiSurf * transmittance + LiMedium;
unsigned int bsdfType = bsdf->getType() & BSDF::EAll;
- bool isDiffuse = (bsdfType == BSDF::EDiffuseReflection);
- if (isDiffuse || cacheQuery) {
+ /* Irradiance cachq query -> trat as diffuse */
+ bool isDiffuse = (bsdfType == BSDF::EDiffuseReflection) || cacheQuery;
+
+ bool hasSpecular = bsdfType & BSDF::EDelta;
+
+ /* Exhaustively recurse into all specular lobes? */
+ bool exhaustiveSpecular = rRec.depth < m_maxSpecularDepth && !cacheQuery;
+
+ if (isDiffuse) {
+ /* 1. Diffuse indirect */
int maxDepth = m_maxDepth == -1 ? INT_MAX : (m_maxDepth-rRec.depth);
if (rRec.type & RadianceQueryRecord::EIndirectSurfaceRadiance && m_globalPhotonMap.get())
LiSurf += m_globalPhotonMap->estimateIrradiance(its.p,
@@ -449,53 +457,55 @@ public:
m_causticLookupSize) * bsdf->getDiffuseReflectance(its) * INV_PI;
}
- if ((bsdfType & BSDF::EDelta) && rRec.depth < m_maxSpecularDepth && !cacheQuery) {
- if (rRec.type & RadianceQueryRecord::EIndirectSurfaceRadiance) {
- int compCount = bsdf->getComponentCount();
- RadianceQueryRecord rRec2;
- for (int i=0; igetType(i);
- if (!(type & BSDF::EDelta))
- continue;
- /* Sample the BSDF and recurse */
- BSDFSamplingRecord bRec(its, rRec.sampler, ERadiance);
- bRec.component = i;
- Spectrum bsdfVal = bsdf->sample(bRec, Point2(0.0f));
- if (bsdfVal.isZero())
- continue;
+ if (hasSpecular && exhaustiveSpecular
+ && (rRec.type & RadianceQueryRecord::EIndirectSurfaceRadiance)) {
+ /* 1. Specular indirect */
+ int compCount = bsdf->getComponentCount();
+ RadianceQueryRecord rRec2;
+ for (int i=0; igetType(i);
+ if (!(type & BSDF::EDelta))
+ continue;
+ /* Sample the BSDF and recurse */
+ BSDFSamplingRecord bRec(its, rRec.sampler, ERadiance);
+ bRec.component = i;
+ Spectrum bsdfVal = bsdf->sample(bRec, Point2(0.5f));
+ if (bsdfVal.isZero())
+ continue;
- rRec2.recursiveQuery(rRec, RadianceQueryRecord::ERadiance);
- RayDifferential bsdfRay(its.p, its.toWorld(bRec.wo), ray.time);
- if (its.isMediumTransition())
- rRec2.medium = its.getTargetMedium(bsdfRay.d);
+ rRec2.recursiveQuery(rRec, RadianceQueryRecord::ERadiance);
+ RayDifferential bsdfRay(its.p, its.toWorld(bRec.wo), ray.time);
+ if (its.isMediumTransition())
+ rRec2.medium = its.getTargetMedium(bsdfRay.d);
- LiSurf += bsdfVal * m_parentIntegrator->Li(bsdfRay, rRec2);
- }
+ LiSurf += bsdfVal * m_parentIntegrator->Li(bsdfRay, rRec2);
}
- } else if (rRec.type & RadianceQueryRecord::EDirectSurfaceRadiance) {
- /* Estimate the direct illumination if this is requested */
- Point2 *sampleArray;
- Point2 sample;
- int numEmitterSamples = m_directSamples,
- numBSDFSamples;
+ }
- Float weightLum, weightBSDF;
+ /* Estimate the direct illumination if this is requested */
+ int numEmitterSamples = m_directSamples, numBSDFSamples;
+ Float weightLum, weightBSDF;
+ Point2 *sampleArray;
+ Point2 sample;
- if (rRec.depth > 1 || cacheQuery || adaptiveQuery) {
- /* This integrator is used recursively by another integrator.
- Be less accurate as this sample will not directly be observed. */
- numBSDFSamples = numEmitterSamples = 1;
- weightLum = weightBSDF = 1.0f;
+ if (rRec.depth > 1 || cacheQuery || adaptiveQuery) {
+ /* This integrator is used recursively by another integrator.
+ Be less accurate as this sample will not directly be observed. */
+ numBSDFSamples = numEmitterSamples = 1;
+ weightLum = weightBSDF = 1.0f;
+ } else {
+ if (isDiffuse) {
+ numBSDFSamples = m_directSamples;
+ weightBSDF = weightLum = m_invEmitterSamples;
} else {
- if (isDiffuse) {
- numBSDFSamples = m_directSamples;
- weightBSDF = weightLum = m_invEmitterSamples;
- } else {
- numBSDFSamples = m_glossySamples;
- weightLum = m_invEmitterSamples;
- weightBSDF = m_invGlossySamples;
- }
+ numBSDFSamples = m_glossySamples;
+ weightLum = m_invEmitterSamples;
+ weightBSDF = m_invGlossySamples;
}
+ }
+
+ if ((bsdfType & BSDF::ESmooth) && (rRec.type & RadianceQueryRecord::EDirectSurfaceRadiance)) {
+ DirectSamplingRecord dRec(its);
if (numEmitterSamples > 1) {
sampleArray = rRec.sampler->next2DArray(m_directSamples);
@@ -503,45 +513,62 @@ public:
sample = rRec.nextSample2D(); sampleArray = &sample;
}
- DirectSamplingRecord dRec(its);
- if (bsdf->getType() & BSDF::ESmooth) {
- for (int i=0; isampleAttenuatedEmitterDirect(
- dRec, its, rRec.medium, interactions,
- sampleArray[i], rRec.sampler);
+ for (int i=0; isampleAttenuatedEmitterDirect(
+ dRec, its, rRec.medium, interactions,
+ sampleArray[i], rRec.sampler);
- /* Estimate the direct illumination if this is requested */
- if (!value.isZero()) {
- const Emitter *emitter = static_cast(dRec.object);
+ /* Estimate the direct illumination if this is requested */
+ if (!value.isZero()) {
+ const Emitter *emitter = static_cast(dRec.object);
- /* Allocate a record for querying the BSDF */
- BSDFSamplingRecord bRec(its, its.toLocal(dRec.d));
+ /* Allocate a record for querying the BSDF */
+ BSDFSamplingRecord bRec(its, its.toLocal(dRec.d));
- /* Evaluate BSDF * cos(theta) */
- const Spectrum bsdfVal = bsdf->eval(bRec);
+ /* Evaluate BSDF * cos(theta) */
+ const Spectrum bsdfVal = bsdf->eval(bRec);
- if (!bsdfVal.isZero()) {
- /* Calculate prob. of having sampled that direction
- using BSDF sampling */
- Float bsdfPdf = (emitter->isOnSurface()
- && dRec.measure == ESolidAngle
- && interactions == 0)
- ? bsdf->pdf(bRec) : (Float) 0.0f;
+ if (!bsdfVal.isZero()) {
+ /* Calculate prob. of having sampled that direction
+ using BSDF sampling */
- /* Weight using the power heuristic */
- const Float weight = miWeight(dRec.pdf * numEmitterSamples,
- bsdfPdf * numBSDFSamples) * weightLum;
- LiSurf += value * bsdfVal * weight;
- }
+ if (!hasSpecular || exhaustiveSpecular)
+ bRec.typeMask = BSDF::ESmooth;
+
+ Float bsdfPdf = (emitter->isOnSurface()
+ && dRec.measure == ESolidAngle
+ && interactions == 0)
+ ? bsdf->pdf(bRec) : (Float) 0.0f;
+
+ /* Weight using the power heuristic */
+ const Float weight = miWeight(dRec.pdf * numEmitterSamples,
+ bsdfPdf * numBSDFSamples) * weightLum;
+
+ LiSurf += value * bsdfVal * weight;
}
}
}
+ }
- /* ==================================================================== */
- /* BSDF sampling */
- /* ==================================================================== */
+ /* ==================================================================== */
+ /* BSDF sampling */
+ /* ==================================================================== */
+ /* Sample direct compontent via BSDF sampling if this is generally requested AND
+ the BSDF is smooth, or there is a delta component that was not handled by the
+ exhaustive sampling loop above */
+ bool bsdfSampleDirect = (rRec.type & RadianceQueryRecord::EDirectSurfaceRadiance) &&
+ ((bsdfType & BSDF::ESmooth) || (hasSpecular && !exhaustiveSpecular));
+
+ /* Sample indirect component via BSDF sampling if this is generally requested AND
+ the BSDF is non-diffuse (diffuse is handled by the global photon map)
+ or there is a delta component that was not handled by the exhaustive sampling loop
+ above. */
+ bool bsdfSampleIndirect = (rRec.type & RadianceQueryRecord::EIndirectSurfaceRadiance) &&
+ !isDiffuse && ((bsdfType & BSDF::ESmooth) || (hasSpecular && !exhaustiveSpecular));
+
+ if (bsdfSampleDirect || bsdfSampleIndirect) {
if (numBSDFSamples > 1) {
sampleArray = rRec.sampler->next2DArray(
std::max(m_directSamples, m_glossySamples));
@@ -552,9 +579,13 @@ public:
RadianceQueryRecord rRec2;
Intersection &bsdfIts = rRec2.its;
+ DirectSamplingRecord dRec;
for (int i=0; isample(bRec, bsdfPdf, sampleArray[i]);
if (bsdfVal.isZero())
@@ -567,12 +598,12 @@ public:
bool hitEmitter = false;
if (scene->rayIntersect(bsdfRay, bsdfIts)) {
/* Intersected something - check if it was a luminaire */
- if (bsdfIts.isEmitter()) {
+ if (bsdfIts.isEmitter() && bsdfSampleDirect) {
value = bsdfIts.Le(-bsdfRay.d);
dRec.setQuery(bsdfRay, bsdfIts);
hitEmitter = true;
}
- } else {
+ } else if (bsdfSampleDirect) {
/* Intersected nothing -- perhaps there is an environment map? */
const Emitter *env = scene->getEnvironmentEmitter();
@@ -584,8 +615,7 @@ public:
}
if (hitEmitter) {
- const Float emitterPdf = (!(bRec.sampledType & BSDF::EDelta)) ?
- scene->pdfEmitterDirect(dRec) : 0;
+ const Float emitterPdf = scene->pdfEmitterDirect(dRec);
Spectrum transmittance = rRec2.medium ?
rRec2.medium->evalTransmittance(Ray(bsdfRay, 0, bsdfIts.t)) : Spectrum(1.0f);
@@ -597,7 +627,7 @@ public:
}
/* Recurse */
- if (!isDiffuse && (rRec.type & RadianceQueryRecord::EIndirectSurfaceRadiance) && !cacheQuery) {
+ if (bsdfSampleIndirect) {
rRec2.recursiveQuery(rRec,
RadianceQueryRecord::ERadianceNoEmission);
rRec2.type ^= RadianceQueryRecord::EIntersection;
@@ -608,35 +638,6 @@ public:
LiSurf += bsdfVal * m_parentIntegrator->Li(bsdfRay, rRec2) * weightBSDF;
}
}
- } else if (!isDiffuse && (rRec.type & RadianceQueryRecord::EIndirectSurfaceRadiance) && !cacheQuery) {
- int numBSDFSamples = (rRec.depth > 1 || adaptiveQuery) ? 1 : m_glossySamples;
- Float weightBSDF;
- Point2 *sampleArray;
- Point2 sample;
-
- if (numBSDFSamples > 1) {
- sampleArray = rRec.sampler->next2DArray(
- std::max(m_directSamples, m_glossySamples));
- weightBSDF = m_invGlossySamples;
- } else {
- sample = rRec.nextSample2D(); sampleArray = &sample;
- weightBSDF = 1.0f;
- }
-
- RadianceQueryRecord rRec2;
- for (int i=0; isample(bRec, bsdfPdf, sampleArray[i]);
- if (bsdfVal.isZero())
- continue;
- rRec2.recursiveQuery(rRec,
- RadianceQueryRecord::ERadianceNoEmission);
-
- RayDifferential bsdfRay(its.p, its.toWorld(bRec.wo), ray.time);
- LiSurf += bsdfVal * m_parentIntegrator->Li(bsdfRay, rRec2) * weightBSDF;
- }
}
return LiSurf * transmittance + LiMedium;
diff --git a/src/libcore/sched_remote.cpp b/src/libcore/sched_remote.cpp
index d11e763a..95f737c5 100644
--- a/src/libcore/sched_remote.cpp
+++ b/src/libcore/sched_remote.cpp
@@ -325,14 +325,7 @@ StreamBackend::StreamBackend(const std::string &thrName, Scheduler *scheduler,
m_memStream->setByteOrder(Stream::ENetworkByteOrder);
}
-StreamBackend::~StreamBackend() {
- if (m_stream->getClass()->derivesFrom(MTS_CLASS(SocketStream))) {
- SocketStream *sstream = static_cast(m_stream.get());
- Log(EInfo, "Closing connection to %s - received %i KB / sent %i KB",
- sstream->getPeer().c_str(), (int) (sstream->getReceivedBytes() / 1024),
- (int) (sstream->getSentBytes() / 1024));
- }
-}
+StreamBackend::~StreamBackend() { }
void StreamBackend::run() {
if (m_detach)
@@ -489,6 +482,13 @@ void StreamBackend::run() {
Log(EWarn, "Removing stray resource %i", (*it).first);
m_scheduler->unregisterResource((*it).second);
}
+
+ if (m_stream->getClass()->derivesFrom(MTS_CLASS(SocketStream))) {
+ SocketStream *sstream = static_cast(m_stream.get());
+ Log(EInfo, "Closing connection to %s - received %i KB / sent %i KB",
+ sstream->getPeer().c_str(), (int) (sstream->getReceivedBytes() / 1024),
+ (int) (sstream->getSentBytes() / 1024));
+ }
}
void StreamBackend::sendCancellation(int id, int numLost) {
diff --git a/src/libcore/util.cpp b/src/libcore/util.cpp
index c0cbb270..afe999ac 100644
--- a/src/libcore/util.cpp
+++ b/src/libcore/util.cpp
@@ -123,19 +123,6 @@ std::string indent(const std::string &string, int amount) {
return oss.str();
}
-std::string memString(size_t size) {
- Float value = (Float) size;
- const char *prefixes[] = {
- "B", "KiB", "MiB", "GiB", "TiB", "PiB"
- };
- int prefix = 0;
- while (prefix < 5 && value > 1024.0f) {
- value /= 1024.0f; ++prefix;
- }
- return formatString(prefix == 0 ?
- "%.0f %s" : "%.2f %s", value, prefixes[prefix]);
-}
-
void * __restrict allocAligned(size_t size) {
#if defined(__WINDOWS__)
return _aligned_malloc(size, L1_CACHE_LINE_SIZE);
@@ -809,8 +796,6 @@ Float fresnelDiffuseReflectance(Float eta, bool fast) {
}
std::string timeString(Float time, bool precise) {
- std::ostringstream os;
-
if (std::isnan(time) || std::isinf(time))
return "inf";
@@ -825,12 +810,31 @@ std::string timeString(Float time, bool precise) {
}
}
+ std::ostringstream os;
os << std::setprecision(precise ? 4 : 1)
<< std::fixed << time << suffix;
return os.str();
}
+std::string memString(size_t size, bool precise) {
+ Float value = (Float) size;
+ const char *suffixes[] = {
+ "B", "KiB", "MiB", "GiB", "TiB", "PiB"
+ };
+ int suffix = 0;
+ while (suffix < 5 && value > 1024.0f) {
+ value /= 1024.0f; ++suffix;
+ }
+
+ std::ostringstream os;
+ os << std::setprecision(suffix == 0 ? 0 : (precise ? 4 : 1))
+ << std::fixed << value << suffixes[suffix];
+
+ return os.str();
+}
+
+
Float hypot2(Float a, Float b) {
Float r;
if (std::abs(a) > std::abs(b)) {
diff --git a/src/librender/scenehandler.cpp b/src/librender/scenehandler.cpp
index 7c77e75b..947421d8 100644
--- a/src/librender/scenehandler.cpp
+++ b/src/librender/scenehandler.cpp
@@ -274,7 +274,7 @@ void SceneHandler::startElement(const XMLCh* const xmlName,
m_context.push(context);
}
-void SceneHandler::pushCleanupHandler(void (*cleanup)()) {
+void pushSceneCleanupHandler(void (*cleanup)()) {
__cleanup_tls.get().insert(cleanup);
}
diff --git a/src/medium/materials.h b/src/medium/materials.h
index b31de859..50812f01 100644
--- a/src/medium/materials.h
+++ b/src/medium/materials.h
@@ -161,8 +161,12 @@ static void lookupMaterial(const Properties &props, Spectrum &sigmaS, Spectrum &
sigmaA = sigmaT - sigmaS;
}
- if (props.hasProperty("g"))
- g = Spectrum(props.getFloat("g"));
+ if (props.hasProperty("g")) {
+ if (props.getType("g") == Properties::ESpectrum)
+ g = props.getSpectrum("g");
+ else
+ g = Spectrum(props.getFloat("g"));
+ }
if (g.min() <= -1 || g.max() >= 1)
SLog(EError, "The anisotropy parameter 'g' must be in the range (-1, 1)!");
diff --git a/src/mtsgui/SConscript b/src/mtsgui/SConscript
index 85ec98da..c4c4bc33 100644
--- a/src/mtsgui/SConscript
+++ b/src/mtsgui/SConscript
@@ -72,9 +72,6 @@ if hasQt:
else:
qtSources = [x for x in qtSources if (not isinstance(x, str) or 'cocoa' not in x)]
- if sys.platform == 'win32':
- qtSources += qtEnv.StaticObject('qtmain_win.cpp')
-
mtsgui = qtEnv.Program('mtsgui', qtSources)
if sys.platform == 'darwin':
qtEnv.AddPostAction(mtsgui, 'install_name_tool -change QtGui.framework/Versions/4/QtGui @rpath/QtGui $TARGET')
diff --git a/src/mtsgui/aboutdlg.cpp b/src/mtsgui/aboutdlg.cpp
index 191cfa43..aa541777 100644
--- a/src/mtsgui/aboutdlg.cpp
+++ b/src/mtsgui/aboutdlg.cpp
@@ -82,6 +82,7 @@ AboutDialog::AboutDialog(QWidget *parent) :
SPECTRUM_SAMPLES).c_str();
ui->label->setText(ui->label->text().replace("MTS_VERSION", MTS_VERSION));
+ ui->label->setText(ui->label->text().replace("MTS_YEAR", MTS_YEAR));
ui->label->setText(ui->label->text().replace("CONFIG_FLAGS", configFlags));
#if defined(__OSX__)
diff --git a/src/mtsgui/aboutdlg.ui b/src/mtsgui/aboutdlg.ui
index dc53785f..26fe8301 100644
--- a/src/mtsgui/aboutdlg.ui
+++ b/src/mtsgui/aboutdlg.ui
@@ -81,7 +81,7 @@ p, li { white-space: pre-wrap; }
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">About Mitsuba</span></p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Version MTS_VERSION<br />Configuration flags: <span style=" font-family:'Courier New,courier';">CONFIG_FLAGS</span></p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">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.</p>
-<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Copyright © 2012 Wenzel Jakob <<a href="mailto:wenzel@cs.cornell.edu"><span style=" text-decoration: underline; color:#0000ff;">wenzel@cs.cornell.edu</span></a>></p>
+<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Copyright © MTS_YEAR Wenzel Jakob <<a href="mailto:wenzel@cs.cornell.edu"><span style=" text-decoration: underline; color:#0000ff;">wenzel@cs.cornell.edu</span></a>></p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Licensed under the <a href="http://www.gnu.org/licenses/gpl-3.0.html"><span style=" text-decoration: underline; color:#0000ff;">GNU GPL, Version 3</span></a>.</p></body></html>
diff --git a/src/mtsgui/symlinks_install.c b/src/mtsgui/symlinks_install.c
index 058c8a7c..34e1b039 100644
--- a/src/mtsgui/symlinks_install.c
+++ b/src/mtsgui/symlinks_install.c
@@ -85,11 +85,12 @@ int main(int argc, char **argv) {
install(argv[1], "mtsimport");
installPython(argv[1], "2.6");
installPython(argv[1], "2.7");
- struct passwd *pw = getpwuid(atoi(argv[2]));
- appendShellConfig(pw->pw_dir, ".bashrc", "\nexport LD_LIBRARY_PATH=%s/Contents/Frameworks:$LD_LIBRARY_PATH\n", argv[1]);
- appendShellConfig(pw->pw_dir, ".zshrc", "\nexport LD_LIBRARY_PATH=%s/Contents/Frameworks:$LD_LIBRARY_PATH\n", argv[1]);
- appendShellConfig(pw->pw_dir, ".cshrc", "\nsetenv LD_LIBRARY_PATH %s/Contents/Frameworks:${LD_LIBRARY_PATH}\n", argv[1]);
+ /// this is not required anymore as of Mitsuba 0.4.3
+ //struct passwd *pw = getpwuid(atoi(argv[2]));
+ //appendShellConfig(pw->pw_dir, ".bashrc", "\nexport LD_LIBRARY_PATH=%s/Contents/Frameworks:$LD_LIBRARY_PATH\n", argv[1]);
+ //appendShellConfig(pw->pw_dir, ".zshrc", "\nexport LD_LIBRARY_PATH=%s/Contents/Frameworks:$LD_LIBRARY_PATH\n", argv[1]);
+ //appendShellConfig(pw->pw_dir, ".cshrc", "\nsetenv LD_LIBRARY_PATH %s/Contents/Frameworks:${LD_LIBRARY_PATH}\n", argv[1]);
return 0;
}
diff --git a/src/shapes/CMakeLists.txt b/src/shapes/CMakeLists.txt
index e59f2b84..6c73ab39 100644
--- a/src/shapes/CMakeLists.txt
+++ b/src/shapes/CMakeLists.txt
@@ -15,6 +15,7 @@ add_shape(rectangle rectangle.cpp)
add_shape(disk disk.cpp)
add_shape(sphere sphere.cpp)
add_shape(cylinder cylinder.cpp)
+add_shape(cube cube.cpp)
add_shape(hair hair.h hair.cpp)
add_shape(shapegroup shapegroup.h shapegroup.cpp)
add_shape(instance instance.h instance.cpp)
diff --git a/src/shapes/SConscript b/src/shapes/SConscript
index 0d8a266d..db9f0728 100644
--- a/src/shapes/SConscript
+++ b/src/shapes/SConscript
@@ -11,6 +11,7 @@ plugins += env.SharedLibrary('cylinder', ['cylinder.cpp'])
plugins += env.SharedLibrary('hair', ['hair.cpp'])
plugins += env.SharedLibrary('shapegroup', ['shapegroup.cpp'])
plugins += env.SharedLibrary('instance', ['instance.cpp'])
+plugins += env.SharedLibrary('cube', ['cube.cpp'])
#plugins += env.SharedLibrary('deformable', ['deformable.cpp'])
Export('plugins')
diff --git a/src/shapes/cube.cpp b/src/shapes/cube.cpp
new file mode 100644
index 00000000..19b9841a
--- /dev/null
+++ b/src/shapes/cube.cpp
@@ -0,0 +1,115 @@
+/*
+ This file is part of Mitsuba, a physically based rendering system.
+
+ Copyright (c) 2007-2012 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 .
+*/
+
+#include
+#include
+
+MTS_NAMESPACE_BEGIN
+
+static Float CubeData_vertexPositions[][3] = {{1, 0, 0}, {1, 0, 1}, {0, 0, 1}, {0, 0, 0}, {1, 1, 0}, {0, 1, 0}, {0, 1, 1}, {1, 1, 1}, {1, 0, 0}, {1, 1, 0}, {1, 1, 1}, {1, 0, 1}, {1, 0, 1}, {1, 1, 1}, {0, 1, 1}, {0, 0, 1}, {0, 0, 1}, {0, 1, 1}, {0, 1, 0}, {0, 0, 0}, {1, 1, 0}, {1, 0, 0}, {0, 0, 0}, {0, 1, 0}};
+
+static Float CubeData_vertexNormals[][3] = {{0, -1, 0}, {0, -1, 0}, {0, -1, 0}, {0, -1, 0}, {0, 1, 0}, {0, 1, 0}, {0, 1, 0}, {0, 1, 0}, {1, 0, 0}, {1, 0, 0}, {1, 0, 0}, {1, 0, 0}, {0, 0, 1}, {0, 0, 1}, {0, 0, 1}, {0, 0, 1}, {-1, 0, 0}, {-1, 0, 0}, {-1, 0, 0}, {-1, 0, 0}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}};
+
+static Float CubeData_texcoords[][2] = {{0, 1}, {1, 1}, {1, 0}, {0, 0}, {0, 1}, {1, 1}, {1, 0}, {0, 0}, {0, 1}, {1, 1}, {1, 0}, {0, 0}, {0, 1}, {1, 1}, {1, 0}, {0, 0}, {0, 1}, {1, 1}, {1, 0}, {0, 0}, {0, 1}, {1, 1}, {1, 0}, {0, 0}};
+
+static uint32_t CubeData_triangles[][3] = {{0, 1, 2}, {3, 0, 2}, {4, 5, 6}, {7, 4, 6}, {8, 9, 10}, {11, 8, 10}, {12, 13, 14}, {15, 12, 14}, {16, 17, 18}, {19, 16, 18}, {20, 21, 22}, {23, 20, 22}};
+
+/*!\plugin{cube}{Cube intersection primitive}
+ * \order{0}
+ * \parameters{
+ * \parameter{toWorld}{\Transform\Or\Animation}{
+ * Specifies an optional linear object-to-world transformation.
+ * \default{none (i.e. object space $=$ world space)}
+ * }
+ * \parameter{flipNormals}{\Boolean}{
+ * Is the cube inverted, i.e. should the normal vectors
+ * be flipped? \default{\code{false}, i.e. the normals point outside}
+ * }
+ * }
+ *
+ * \renderings{
+ * \rendering{Basic example, see \lstref{cube-basic}}
+ * {shape_cube_basic}
+ * \rendering{A textured and stretched cube with the default parameterization
+ * (Listing~\ref{lst:cube-example})}
+ * {shape_cube_parameterization}
+ * }
+ *
+ * This shape plugin describes a simple cube/cuboid intersection primitive. By
+ * default, it creates a cube between the world-space positions $(0, 0, 0)$ and $(1,1,1)$.
+ * However, an arbitrary linear transformation may be specified to translate, rotate, scale
+ * or skew it as desired. The parameterization of this shape maps every face onto the
+ * rectangle $[0,1]^2$ in $uv$ space.
+ * \vspace{5mm}
+ * \begin{xml}[caption={Example of a textured and stretched cube}, label=lst:cube-example]
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ * \end{xml}
+ */
+class Cube : public TriMesh {
+public:
+ Cube(const Properties &props) : TriMesh(props) {
+ m_name = props.getID();
+ m_triangleCount = 12;
+ m_vertexCount = 24;
+ m_positions = new Point[m_vertexCount];
+ m_texcoords = new Point2[m_vertexCount];
+ m_normals = new Normal[m_vertexCount];
+ m_triangles = new Triangle[m_triangleCount];
+
+ Transform toWorld = props.getTransform("toWorld", Transform());
+ for (uint32_t i=0; i
-#include
#include
#include
#include
@@ -31,6 +30,9 @@
MTS_NAMESPACE_BEGIN
+/* Avoid having to include scenehandler.h */
+extern MTS_EXPORT_RENDER void pushSceneCleanupHandler(void (*cleanup)());
+
/*!\plugin{serialized}{Serialized mesh loader}
* \order{7}
* \parameters{
@@ -57,7 +59,6 @@ MTS_NAMESPACE_BEGIN
* }
* \parameter{toWorld}{\Transform\Or\Animation}{
* Specifies an optional linear object-to-world transformation.
- * Note that non-uniform scales are not permitted!
* \default{none (i.e. object space $=$ world space)}
* }
* }
@@ -185,7 +186,7 @@ public:
}
if (m_normals) {
for (size_t i=0; i m_fstream;
};
- struct FileStreamCache : LRUCache,
- boost::shared_ptr > {
+ typedef LRUCache,
+ boost::shared_ptr > MeshLoaderCache;
+ class FileStreamCache : MeshLoaderCache {
+ public:
inline boost::shared_ptr get(const fs::path& path) {
bool dummy;
- return LRUCache::get(path, dummy);
+ return MeshLoaderCache::get(path, dummy);
}
- FileStreamCache() : LRUCache(MTS_SERIALIZED_CACHE_SIZE,
- &boost::make_shared) {}
+ FileStreamCache() : MeshLoaderCache(MTS_SERIALIZED_CACHE_SIZE,
+ &FileStreamCache::create) { }
+
+ private:
+ inline static boost::shared_ptr create(const fs::path &path) {
+ return boost::make_shared(path);
+ }
};
/// Release all currently held offset caches / file streams
@@ -281,7 +289,7 @@ private:
if (EXPECT_NOT_TAKEN(cache == NULL)) {
cache = new FileStreamCache();
m_cache.set(cache);
- SceneHandler::pushCleanupHandler(&SerializedMesh::flushCache);
+ mitsuba::pushSceneCleanupHandler(&SerializedMesh::flushCache);
}
boost::shared_ptr meshLoader = cache->get(filePath);