diff --git a/doc/basics.tex b/doc/basics.tex index 317ee923..d95057bd 100644 --- a/doc/basics.tex +++ b/doc/basics.tex @@ -86,7 +86,7 @@ $\texttt{\$}$ mitsuba -c machine1;machine2;... path-to/my-scene.xml 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 +another machine (\code{mtssrv} is the Mitsuba server process). From 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. diff --git a/doc/compiling.tex b/doc/compiling.tex index 067db386..0a4b96c0 100644 --- a/doc/compiling.tex +++ b/doc/compiling.tex @@ -48,7 +48,7 @@ Visual Studio 2010 for legacy 32 bit builds. Versions XE 2012 and 2013 are known to work. \end{description} \paragraph{Mac OS:} -On Mac OS, builds can either be performed using the the XCode 4 \code{llvm-gcc} toolchain or Intel XE Composer. +On Mac OS, builds can either be performed using the XCode 4 \code{llvm-gcc} toolchain or Intel XE Composer. It is possible to target MacOS 10.6 (Snow Leopard) or 10.7 (Lion) as the oldest supported operating system release. In both cases, XCode must be installed along with the supplementary command line tools. \begin{description} @@ -57,7 +57,7 @@ In both cases, XCode must be installed along with the supplementary command line Versions XE 2012 and 2013 are known to work. \end{description} Note that the configuration files assume that XCode was -installed in the \code{/Applications} folder. They must be be manually updated +installed in the \code{/Applications} folder. They must be manually updated when this is not the case. \subsubsection{Selecting a configuration} Having chosen a configuration, copy it to the main directory and rename it to \code{config.py}, e.g.: diff --git a/doc/development.tex b/doc/development.tex index 0bb711e7..ffd9ec51 100644 --- a/doc/development.tex +++ b/doc/development.tex @@ -1,8 +1,8 @@ \part{Development guide} \label{sec:development} This chapter and the subsequent ones will provide an overview -of the the coding conventions and general architecture of Mitsuba. -You should only read them if if you wish to interface with the API +of the coding conventions and general architecture of Mitsuba. +You should only read them if you wish to interface with the API in some way (e.g. by developing your own plugins). The coding style section is only relevant if you plan to submit patches that are meant to become part of the main codebase. diff --git a/doc/integrator.tex b/doc/integrator.tex index b2742dfc..ab29ae06 100644 --- a/doc/integrator.tex +++ b/doc/integrator.tex @@ -7,7 +7,7 @@ The framework distinguishes between \emph{sampling-based} integrators and \emph{generic} ones. A sampling-based integrator is able to generate (usually unbiased) estimates of the incident radiance along a specified rays, and this is done a large number of times to render a scene. A generic integrator -is more like a black box, where no assumptions are made on how the the image is +is more like a black box, where no assumptions are made on how the image is created. For instance, the VPL renderer uses OpenGL to rasterize the scene using hardware acceleration, which certainly doesn't fit into the sampling-based pattern. For that reason, it must be implemented as a generic integrator. @@ -261,7 +261,7 @@ As you can see, we did something slightly different in the distance renderer fragment above (we called \code{RadianceQueryRecord::rayIntersect()} on the supplied parameter \code{rRec}), and the reason for this is \emph{nesting}. \subsection{Nesting} -The idea of of nesting is that sampling-based rendering techniques can be +The idea of nesting is that sampling-based rendering techniques can be embedded within each other for added flexibility: for instance, one might concoct a 1-bounce indirect rendering technique complete with irradiance caching and adaptive integration simply by writing the following diff --git a/doc/main.tex b/doc/main.tex index 1cc4419f..a53bb232 100644 --- a/doc/main.tex +++ b/doc/main.tex @@ -51,8 +51,8 @@ \ofoot[]{} \cfoot[]{} \automark[subsection]{section} -\ihead{\sc\leftmark} -\ohead{\sc\rightmark} +\ihead{\normalfont\scshape\leftmark} +\ohead{\normalfont\scshape\rightmark} \chead{} \setheadsepline{.2pt} \setkomafont{pagenumber}{\normalfont} diff --git a/doc/python.tex b/doc/python.tex index fd1beedd..d7482387 100644 --- a/doc/python.tex +++ b/doc/python.tex @@ -545,7 +545,7 @@ command-line executable. \subsubsection{Simultaneously rendering multiple versions of a scene} Sometimes it is useful to be able to submit multiple scenes to the rendering scheduler at the same time, e.g. when rendering on a big cluster, where one image is not enough to keep all -cores on all machines busy. This is is quite easy to do by simply launching multiple \code{RenderJob} +cores on all machines busy. This is quite easy to do by simply launching multiple \code{RenderJob} instances before issuing the \code{queue.waitLeft} call. However, things go wrong when rendering multiple versions of the \emph{same} scene simultaneously (for instance @@ -753,7 +753,7 @@ As before, some changes will be necessary to get this to run on PySide. When using this snippet, please be wary of threading-related issues; the key thing to remember is that in Qt, only the main thread is allowed to modify Qt widgets. On the other hand, rendering and logging-related callbacks will be invoked from different Mitsuba-internal threads---this means that it's not possible to e.g. -directly update the status bar message from the callback \code{finishJobEvent}. To do this, we must use +directly update the status bar message from the callback \code{finishJobEvent}. To do this, we must use Qt's \code{QueuedConnection} to communicate this event to the main thread via signals and slots. See the code that updates the status and progress bar for more detail. \begin{python} diff --git a/doc/section_rfilters.tex b/doc/section_rfilters.tex index ecdcfb3c..7c93750d 100644 --- a/doc/section_rfilters.tex +++ b/doc/section_rfilters.tex @@ -31,7 +31,8 @@ this is a windowed Gaussian filter with configurable standard deviation. It produces pleasing results and never suffers from ringing, but may occasionally introduce too much blurring. When no reconstruction filter is explicitly requested, this is the default -choice in Mitsuba. +choice in Mitsuba. Takes a standard deviation parameter (\code{stddev}) +which is set to 0.5 pixels by default. \item[Mitchell-Netravali filter (\code{mitchell}):] Separable cubic spline reconstruction filter by Mitchell and Netravali \cite{Mitchell:1988:Reconstruction} diff --git a/src/bsdfs/blendbsdf.cpp b/src/bsdfs/blendbsdf.cpp index 3d7f6617..887cf38c 100644 --- a/src/bsdfs/blendbsdf.cpp +++ b/src/bsdfs/blendbsdf.cpp @@ -24,7 +24,7 @@ MTS_NAMESPACE_BEGIN /*! \plugin{blendbsdf}{Blended material} - * \order{16} + * \order{17} * \parameters{ * \parameter{weight}{\Float\Or\Texture}{A floating point value or texture * with values between zero and one. The extreme values zero and one activate the diff --git a/src/bsdfs/bumpmap.cpp b/src/bsdfs/bumpmap.cpp index 8de46dc6..0dab142a 100644 --- a/src/bsdfs/bumpmap.cpp +++ b/src/bsdfs/bumpmap.cpp @@ -113,6 +113,11 @@ public: } else if (child->getClass()->derivesFrom(MTS_CLASS(Texture))) { if (m_displacement != NULL) Log(EError, "Only a single displacement texture can be specified!"); + const Properties &props = child->getProperties(); + if (props.getPluginName() == "bitmap" && !props.hasProperty("gamma")) + Log(EError, "When using a bitmap texture as a bump map, please explicitly specify " + "the 'gamma' parameter of the bitmap plugin. In most cases the following is the correct choice: " + ""); m_displacement = static_cast(child); } else { BSDF::addChild(name, child); diff --git a/src/bsdfs/mask.cpp b/src/bsdfs/mask.cpp index 0a426f7b..d34e368a 100644 --- a/src/bsdfs/mask.cpp +++ b/src/bsdfs/mask.cpp @@ -22,7 +22,7 @@ MTS_NAMESPACE_BEGIN /*!\plugin{mask}{Opacity mask} - * \order{17} + * \order{18} * \parameters{ * \parameter{opacity}{\Spectrum\Or\Texture}{ * Specifies the per-channel opacity (where $1=$ completely opaque)\default{0.5}. diff --git a/src/bsdfs/mixturebsdf.cpp b/src/bsdfs/mixturebsdf.cpp index 533d5371..7baad5ab 100644 --- a/src/bsdfs/mixturebsdf.cpp +++ b/src/bsdfs/mixturebsdf.cpp @@ -23,7 +23,7 @@ MTS_NAMESPACE_BEGIN /*! \plugin{mixturebsdf}{Mixture material} - * \order{15} + * \order{16} * \parameters{ * \parameter{weights}{\String}{A comma-separated list of BSDF weights} * \parameter{\Unnamed}{\BSDF}{Multiple BSDF instances that should be diff --git a/src/bsdfs/normalmap.cpp b/src/bsdfs/normalmap.cpp index 4b46f0ab..ec131050 100644 --- a/src/bsdfs/normalmap.cpp +++ b/src/bsdfs/normalmap.cpp @@ -21,6 +21,29 @@ MTS_NAMESPACE_BEGIN +/*! \plugin{normalmap}{Normal map modifier} + * \order{13} + * \icon{bsdf_bumpmap} + * + * \parameters{ + * \parameter{\Unnamed}{\Texture}{ + * The color values of this texture specify the perturbed + * normals relative in the local surface coordinate system. + * } + * \parameter{\Unnamed}{\BSDF}{A BSDF model that should + * be affected by the normal map} + * } + * + * This plugin is conceptually similar to the \pluginref{bump} map plugin + * but uses a normal map instead of a bump map. A normal map is a RGB texture, whose color channels + * encode the XYZ coordinates of the desired surface normals. + * These are specified \emph{relative} to the local shading frame, + * which means that a normal map with a value of $(0,0,1)$ everywhere + * causes no changes to the surface. + * To turn the 3D normal directions into (nonnegative) color values + * suitable for this plugin, the + * mapping $x \mapsto (x+1)/2$ must be applied to each component. + */ class NormalMap : public BSDF { public: NormalMap(const Properties &props) : BSDF(props) { } @@ -61,7 +84,12 @@ public: m_nested = static_cast(child); } else if (child->getClass()->derivesFrom(MTS_CLASS(Texture))) { if (m_normals != NULL) - Log(EError, "Only a single normals texture can be specified!"); + Log(EError, "Only a single normal texture can be specified!"); + const Properties &props = child->getProperties(); + if (props.getPluginName() == "bitmap" && !props.hasProperty("gamma")) + Log(EError, "When using a bitmap texture as a normal map, please explicitly specify " + "the 'gamma' parameter of the bitmap plugin. In most cases the following is the correct choice: " + ""); m_normals = static_cast(child); } else { BSDF::addChild(name, child); @@ -192,7 +220,7 @@ protected: // ================ Hardware shader implementation ================ /** - * This is a quite approximate version of the bump map model -- it likely + * This is a quite approximate version of the normal map model -- it likely * won't match the reference exactly, but it should be good enough for * preview purposes */ diff --git a/src/bsdfs/phong.cpp b/src/bsdfs/phong.cpp index 8130d600..6b029940 100644 --- a/src/bsdfs/phong.cpp +++ b/src/bsdfs/phong.cpp @@ -23,7 +23,7 @@ MTS_NAMESPACE_BEGIN /*!\plugin{phong}{Modified Phong BRDF} - * \order{13} + * \order{14} * \parameters{ * \parameter{exponent}{\Float\Or\Texture}{ * Specifies the Phong exponent \default{30}. diff --git a/src/bsdfs/plastic.cpp b/src/bsdfs/plastic.cpp index b5083021..5e99fe6b 100644 --- a/src/bsdfs/plastic.cpp +++ b/src/bsdfs/plastic.cpp @@ -96,7 +96,7 @@ MTS_NAMESPACE_BEGIN * Internally, this is model simulates the interaction of light with a diffuse * base surface coated by a thin dielectric layer. This is a convenient * abstraction rather than a restriction. In other words, there are many - * materials that can be rendered with this model, even if they might not not + * materials that can be rendered with this model, even if they might not * fit this description perfectly well. * * \begin{figure}[h] diff --git a/src/bsdfs/roughplastic.cpp b/src/bsdfs/roughplastic.cpp index cc8f933d..4f48180d 100644 --- a/src/bsdfs/roughplastic.cpp +++ b/src/bsdfs/roughplastic.cpp @@ -103,13 +103,13 @@ MTS_NAMESPACE_BEGIN * interaction of light with a diffuse base surface coated by a thin dielectric * layer (where the coating layer is now \emph{rough}). This is a convenient * abstraction rather than a restriction. In other words, there are many - * materials that can be rendered with this model, even if they might not not + * materials that can be rendered with this model, even if they might not * fit this description perfectly well. * * The simplicity of this setup makes it possible to account for interesting * nonlinear effects due to internal scattering, which is controlled by * the \texttt{nonlinear} parameter. For more details, please refer to the description - * of this parameter given in the the \pluginref{plastic} plugin section + * of this parameter given in the \pluginref{plastic} plugin section * on \pluginpage{plastic}. * * diff --git a/src/bsdfs/twosided.cpp b/src/bsdfs/twosided.cpp index 8593741e..6fa51d04 100644 --- a/src/bsdfs/twosided.cpp +++ b/src/bsdfs/twosided.cpp @@ -23,7 +23,7 @@ MTS_NAMESPACE_BEGIN /*!\plugin{twosided}{Two-sided BRDF adapter} - * \order{18} + * \order{19} * \parameters{ * \parameter{\Unnamed}{\BSDF}{A nested BRDF that should * be turned into a two-sided scattering model. If two BRDFs diff --git a/src/bsdfs/ward.cpp b/src/bsdfs/ward.cpp index 596419ff..9e2cde9c 100644 --- a/src/bsdfs/ward.cpp +++ b/src/bsdfs/ward.cpp @@ -24,7 +24,7 @@ MTS_NAMESPACE_BEGIN /*!\plugin{ward}{Anisotropic Ward BRDF} - * \order{14} + * \order{15} * \parameters{ * \parameter{variant}{\String}{ * Determines the variant of the Ward model to use: diff --git a/src/emitters/envmap.cpp b/src/emitters/envmap.cpp index e2374052..f76cd905 100644 --- a/src/emitters/envmap.cpp +++ b/src/emitters/envmap.cpp @@ -80,7 +80,7 @@ MTS_NAMESPACE_BEGIN * * The implementation loads a captured illumination environment from a image in * latitude-longitude format and turns it into an infinitely distant emitter. - * The image could either be be a processed photograph or a rendering made using the + * The image could either be a processed photograph or a rendering made using the * \pluginref{spherical} sensor. The direction conventions of this transformation * are shown in (b). * The plugin can work with all types of images that are natively supported by Mitsuba diff --git a/src/emitters/sky.cpp b/src/emitters/sky.cpp index 4b15f110..28b26583 100644 --- a/src/emitters/sky.cpp +++ b/src/emitters/sky.cpp @@ -64,7 +64,7 @@ MTS_NAMESPACE_BEGIN * \parameter{resolution}{\Integer}{Specifies the horizontal resolution of the precomputed * image that is used to represent the sun environment map \default{512, i.e. 512$\times$256}} * \parameter{scale}{\Float}{ - * This parameter can be used to scale the the amount of illumination + * This parameter can be used to scale the amount of illumination * emitted by the sky emitter. \default{1} * } * \parameter{samplingWeight}{\Float}{ @@ -160,7 +160,7 @@ MTS_NAMESPACE_BEGIN * (512$\times$ 256) of the entire sky that is then forwarded to the * \pluginref{envmap} plugin---this dramatically improves rendering * performance. This resolution is generally plenty since the sky radiance - * distribution is so smooth, but it it can be adjusted manually if + * distribution is so smooth, but it can be adjusted manually if * necessary using the \code{resolution} parameter. * * Note that while the model encompasses sunrise and sunset configurations, @@ -212,7 +212,7 @@ MTS_NAMESPACE_BEGIN * \medrendering{\code{albedo}=100%}{emitter_sky_albedo_1} * \medrendering{\code{albedo}=20% green}{emitter_sky_albedo_green} * \caption{\label{fig:sky_groundalbedo}Influence - * of the ground albedo on the apperance of the sky} + * of the ground albedo on the appearance of the sky} * } */ class SkyEmitter : public Emitter { diff --git a/src/emitters/sun.cpp b/src/emitters/sun.cpp index 89222785..615dcb1c 100644 --- a/src/emitters/sun.cpp +++ b/src/emitters/sun.cpp @@ -62,7 +62,7 @@ MTS_NAMESPACE_BEGIN * \parameter{resolution}{\Integer}{Specifies the horizontal resolution of the precomputed * image that is used to represent the sun environment map \default{512, i.e. 512$\times$256}} * \parameter{scale}{\Float}{ - * This parameter can be used to scale the the amount of illumination + * This parameter can be used to scale the amount of illumination * emitted by the sun emitter. \default{1} * } * \parameter{sunRadiusScale}{\Float}{ diff --git a/src/emitters/sunsky.cpp b/src/emitters/sunsky.cpp index 37a3c35b..5def0f09 100644 --- a/src/emitters/sunsky.cpp +++ b/src/emitters/sunsky.cpp @@ -67,11 +67,11 @@ MTS_NAMESPACE_BEGIN * \parameter{resolution}{\Integer}{Specifies the horizontal resolution of the precomputed * image that is used to represent the sun environment map \default{512, i.e. 512$\times$256}} * \parameter{sunScale}{\Float}{ - * This parameter can be used to separately scale the the amount of illumination + * This parameter can be used to separately scale the amount of illumination * emitted by the sun. \default{1} * } * \parameter{skyScale}{\Float}{ - * This parameter can be used to separately scale the the amount of illumination + * This parameter can be used to separately scale the amount of illumination * emitted by the sky.\default{1} * } * \parameter{sunRadiusScale}{\Float}{ diff --git a/src/films/hdrfilm.cpp b/src/films/hdrfilm.cpp index de5bd024..6ecb20c0 100644 --- a/src/films/hdrfilm.cpp +++ b/src/films/hdrfilm.cpp @@ -155,7 +155,7 @@ MTS_NAMESPACE_BEGIN * * 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 + * to `paste' an existing parameter that was provided to another plugin---for instance, * 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. diff --git a/src/films/ldrfilm.cpp b/src/films/ldrfilm.cpp index 3333af57..bf7fdfc4 100644 --- a/src/films/ldrfilm.cpp +++ b/src/films/ldrfilm.cpp @@ -48,7 +48,7 @@ MTS_NAMESPACE_BEGIN * \begin{enumerate}[(i)] * \item \code{gamma}: Exposure and gamma correction (default) * \vspace{-1mm} - * \item \code{reinhard}: Apply the the + * \item \code{reinhard}: Apply the * tonemapping technique by Reinhard et al. \cite{Reinhard2002Photographic} * followd by gamma correction. * \vspace{-4mm} diff --git a/src/integrators/bdpt/bdpt.cpp b/src/integrators/bdpt/bdpt.cpp index efba837d..6c3f6480 100644 --- a/src/integrators/bdpt/bdpt.cpp +++ b/src/integrators/bdpt/bdpt.cpp @@ -56,7 +56,7 @@ MTS_NAMESPACE_BEGIN * paths starting at the emitters and the sensor and connecting them in every possible way. * This works particularly well in closed scenes as the one shown above. Here, the unidirectional * path tracer has severe difficulties finding some of the indirect illumination paths. - * Modeled after after a scene by Eric Veach. + * Modeled after a scene by Eric Veach. * } * } * \renderings{ diff --git a/src/integrators/photonmapper/photonmapper.cpp b/src/integrators/photonmapper/photonmapper.cpp index 9b205b67..77fd07d9 100644 --- a/src/integrators/photonmapper/photonmapper.cpp +++ b/src/integrators/photonmapper/photonmapper.cpp @@ -437,7 +437,7 @@ public: unsigned int bsdfType = bsdf->getType() & BSDF::EAll; - /* Irradiance cachq query -> trat as diffuse */ + /* Irradiance cache query -> treat as diffuse */ bool isDiffuse = (bsdfType == BSDF::EDiffuseReflection) || cacheQuery; bool hasSpecular = bsdfType & BSDF::EDelta; diff --git a/src/integrators/photonmapper/ppm.cpp b/src/integrators/photonmapper/ppm.cpp index d4e2963a..6bcd66ef 100644 --- a/src/integrators/photonmapper/ppm.cpp +++ b/src/integrators/photonmapper/ppm.cpp @@ -65,7 +65,7 @@ MTS_NAMESPACE_BEGIN * * \remarks{ * \item Due to the data dependencies of this algorithm, the parallelization is - * limited to to the local machine (i.e. cluster-wide renderings are not implemented) + * limited to the local machine (i.e. cluster-wide renderings are not implemented) * \item This integrator does not handle participating media * \item This integrator does not currently work with subsurface scattering * models. diff --git a/src/integrators/photonmapper/sppm.cpp b/src/integrators/photonmapper/sppm.cpp index 95d22f32..8b820ff3 100644 --- a/src/integrators/photonmapper/sppm.cpp +++ b/src/integrators/photonmapper/sppm.cpp @@ -63,7 +63,7 @@ MTS_NAMESPACE_BEGIN * * \remarks{ * \item Due to the data dependencies of this algorithm, the parallelization is - * limited to to the local machine (i.e. cluster-wide renderings are not implemented) + * limited to the local machine (i.e. cluster-wide renderings are not implemented) * \item This integrator does not handle participating media * \item This integrator does not currently work with subsurface scattering * models. diff --git a/src/integrators/ptracer/ptracer.cpp b/src/integrators/ptracer/ptracer.cpp index 264b2ca5..a6aa7af5 100644 --- a/src/integrators/ptracer/ptracer.cpp +++ b/src/integrators/ptracer/ptracer.cpp @@ -34,7 +34,7 @@ MTS_NAMESPACE_BEGIN * path termination criterion. \default{\code{5}} * } * \parameter{granularity}{\Integer}{ - * Specifies the work unit granularity used to parallize the the particle + * Specifies the work unit granularity used to parallize the particle * tracing task. This should be set high enough so that accumulating * partially exposed images (and potentially sending them over the network) * is not the bottleneck. diff --git a/src/libcore/bitmap.cpp b/src/libcore/bitmap.cpp index 42eb3c9b..b2d89105 100644 --- a/src/libcore/bitmap.cpp +++ b/src/libcore/bitmap.cpp @@ -2815,7 +2815,8 @@ void Bitmap::writeOpenEXR(Stream *stream) const { Imf::ChannelList &channels = header.channels(); if (!m_channelNames.empty()) { if (m_channelNames.size() != (size_t) m_channelCount) - Log(EError, "writeOpenEXR(): 'channelNames' has the wrong number of entries!"); + Log(EError, "writeOpenEXR(): 'channelNames' has the wrong number of entries (%i, expected %i)!", + (int) m_channelNames.size(), (int) m_channelCount); for (size_t i=0; iunregisterGeometry(shape)) continue; - m_renderer->unregisterShaderForResource(shape->getBSDF()); + const BSDF *bsdf = shape->getBSDF(); + if (!bsdf) + bsdf = const_cast(shape)->createTriMesh()->getBSDF(); + m_renderer->unregisterShaderForResource(bsdf); } } else { + const BSDF *bsdf = shape->getBSDF(); + if (!bsdf) + bsdf = const_cast(shape)->createTriMesh()->getBSDF(); + if (!m_renderer->unregisterGeometry(shape)) continue; - m_renderer->unregisterShaderForResource(shape->getBSDF()); + m_renderer->unregisterShaderForResource(bsdf); } } @@ -168,9 +175,13 @@ void VPLShaderManager::setScene(const Scene *scene) { if (!gpuGeo) continue; - Shader *shader = m_renderer->registerShaderForResource(shape->getBSDF()); + const BSDF *bsdf = shape->getBSDF(); + if (!bsdf) + bsdf = gpuGeo->getTriMesh()->getBSDF(); + + Shader *shader = m_renderer->registerShaderForResource(bsdf); if (shader && !shader->isComplete()) { - m_renderer->unregisterShaderForResource(shape->getBSDF()); + m_renderer->unregisterShaderForResource(bsdf); shader = NULL; } @@ -192,13 +203,14 @@ void VPLShaderManager::setScene(const Scene *scene) { GPUGeometry *gpuGeo = m_renderer->registerGeometry(shape); if (!gpuGeo) continue; - - Shader *shader = m_renderer->registerShaderForResource(shape->getBSDF()); + const BSDF *bsdf = shape->getBSDF(); + if (!bsdf) + bsdf = gpuGeo->getTriMesh()->getBSDF(); + Shader *shader = m_renderer->registerShaderForResource(bsdf); if (shader && !shader->isComplete()) { - m_renderer->unregisterShaderForResource(shape->getBSDF()); + m_renderer->unregisterShaderForResource(bsdf); shader = NULL; } - gpuGeo->setShader(shader); m_geometry.push_back(std::make_pair(gpuGeo, identityTrafo)); diff --git a/src/samplers/hammersley.cpp b/src/samplers/hammersley.cpp index ec44b226..cd8b9490 100644 --- a/src/samplers/hammersley.cpp +++ b/src/samplers/hammersley.cpp @@ -70,7 +70,7 @@ MTS_NAMESPACE_BEGIN * The Hammerlsey sequence is closely related to the Halton sequence and yields a very * high quality point set that is slightly more regular (and has lower discrepancy), * especially in the first few dimensions. As is the case with the Halton sequence, - * the points should be scrambled to reduce patterns that manifest due due to correlations + * the points should be scrambled to reduce patterns that manifest due to correlations * in higher dimensions. Please refer to the \pluginref{halton} page for more information * on how this works. * diff --git a/src/shapes/hair.cpp b/src/shapes/hair.cpp index 39e3bce4..3bb01207 100644 --- a/src/shapes/hair.cpp +++ b/src/shapes/hair.cpp @@ -65,7 +65,7 @@ MTS_NAMESPACE_BEGIN * \fbox{\includegraphics[width=6cm]{images/shape_hair}}\hspace{4.5cm} * \caption{A close-up of the hair shape rendered with a diffuse * scattering model (an actual hair scattering model will - * be needed for realistic apperance)} + * be needed for realistic appearance)} * } * The plugin implements a space-efficient acceleration structure for * hairs made from many straight cylindrical hair segments with miter diff --git a/src/shapes/obj.cpp b/src/shapes/obj.cpp index 7de49f44..5b681a3c 100644 --- a/src/shapes/obj.cpp +++ b/src/shapes/obj.cpp @@ -39,7 +39,7 @@ MTS_NAMESPACE_BEGIN * \parameter{faceNormals}{\Boolean}{ * When set to \code{true}, any existing or computed vertex normals are * discarded and \emph{face normals} will instead be used during rendering. - * This gives the rendered object a faceted apperance.\default{\code{false}} + * This gives the rendered object a faceted appearance.\default{\code{false}} * } * \parameter{maxSmoothAngle}{\Float}{ * When specified, Mitsuba will discard all vertex normals in the input mesh and rebuild @@ -52,15 +52,21 @@ MTS_NAMESPACE_BEGIN * } * \parameter{flipTexCoords}{\Boolean}{ * Treat the vertical component of the texture as inverted? Most OBJ files use - * this convention. \default{\code{true}, i.e. flip them to get the - * correct coordinates}. + * this convention. \default{\code{true}} * } * \parameter{toWorld}{\Transform\Or\Animation}{ * Specifies an optional linear object-to-world transformation. * \default{none (i.e. object space $=$ world space)} * } + * \parameter{shapeIndex}{\Integer}{ + * When the file contains multiple meshes, this parameter can + * be used to select a single one. \default{\code{-1}, \mbox{i.e. load all}} + * } * \parameter{collapse}{\Boolean}{ - * Collapse all contained meshes into a single object \default{\code{false}} + * Collapse all meshes into a single shape \default{\code{false}} + * } + * \parameter{loadMaterials}{\Boolean}{ + * \mbox{Import materials from a \code{mtl} file, if it exists?\default{\code{true}}} * } * } * \renderings{ @@ -134,7 +140,6 @@ MTS_NAMESPACE_BEGIN * valid vertex normals). * * \remarks{ - * \item The plugin currently only supports loading meshes constructed from triangles and quadrilaterals. * \item Importing geometry via OBJ files should only be used as an absolutely * last resort. Due to inherent limitations of this format, the files tend to be unreasonably * large, and parsing them requires significant amounts of memory and processing power. What's worse @@ -205,9 +210,15 @@ public: /* Causes all texture coordinates to be vertically flipped */ bool flipTexCoords = props.getBoolean("flipTexCoords", true); + /// When the file contains multiple meshes, this index specifies which one to load + int shapeIndex = props.getInteger("shapeIndex", -1); + /* Object-space -> World-space transformation */ Transform objectToWorld = props.getTransform("toWorld", Transform()); + /* Import materials from a MTL file, if any? */ + bool loadMaterials = props.getBoolean("loadMaterials", true); + /* Load the geometry */ Log(EInfo, "Loading geometry from \"%s\" ..", path.filename().string().c_str()); fs::ifstream is(path); @@ -226,7 +237,7 @@ public: std::set geomNames; std::vector vertexBuffer; fs::path materialLibrary; - int geomIdx = 0; + int geomIndex = 0; bool nameBeforeGeometry = false; std::string materialName; @@ -260,10 +271,12 @@ public: if (triangles.size() > 0) { /// make sure that we have unique names if (geomNames.find(targetName) != geomNames.end()) - targetName = formatString("%s_%i", targetName.c_str(), geomIdx++); + targetName = formatString("%s_%i", targetName.c_str(), geomIndex); + geomIndex += 1; geomNames.insert(targetName); - createMesh(targetName, vertices, normals, texcoords, - triangles, materialName, objectToWorld, vertexBuffer); + if (shapeIndex < 0 || geomIndex-1 == shapeIndex) + createMesh(targetName, vertices, normals, texcoords, + triangles, materialName, objectToWorld, vertexBuffer); triangles.clear(); } else { nameBeforeGeometry = true; @@ -271,13 +284,15 @@ public: name = newName; } else if (buf == "usemtl") { /* Flush if necessary */ - if (triangles.size() > 0) { + if (triangles.size() > 0 && !m_collapse) { /// make sure that we have unique names if (geomNames.find(name) != geomNames.end()) - name = formatString("%s_%i", name.c_str(), geomIdx++); + name = formatString("%s_%i", name.c_str(), geomIndex); + geomIndex += 1; geomNames.insert(name); - createMesh(name, vertices, normals, texcoords, - triangles, materialName, objectToWorld, vertexBuffer); + if (shapeIndex < 0 || geomIndex-1 == shapeIndex) + createMesh(name, vertices, normals, texcoords, + triangles, materialName, objectToWorld, vertexBuffer); triangles.clear(); name = m_name; } @@ -298,27 +313,25 @@ public: iss >> tmp; parse(t, 1, tmp); iss >> tmp; parse(t, 2, tmp); triangles.push_back(t); - if (iss >> tmp) { - t.p[1] = t.p[0]; - t.uv[1] = t.uv[0]; - t.n[1] = t.n[0]; - parse(t, 0, tmp); - + /* Handle n-gons assuming a convex shape */ + while (iss >> tmp) { + t.p[1] = t.p[2]; + t.uv[1] = t.uv[2]; + t.n[1] = t.n[2]; + parse(t, 2, tmp); triangles.push_back(t); } - if (iss >> tmp) - Log(EError, "Encountered an n-gon (with n>4)! Only " - "triangles and quads are supported by the OBJ loader."); } else { /* Ignore */ } } if (geomNames.find(name) != geomNames.end()) /// make sure that we have unique names - name = formatString("%s_%i", m_name.c_str(), geomIdx); + name = formatString("%s_%i", m_name.c_str(), geomIndex); - createMesh(name, vertices, normals, texcoords, - triangles, materialName, objectToWorld, vertexBuffer); + if (shapeIndex < 0 || geomIndex-1 == shapeIndex) + createMesh(name, vertices, normals, texcoords, + triangles, materialName, objectToWorld, vertexBuffer); if (props.hasProperty("maxSmoothAngle")) { if (m_faceNormals) @@ -329,7 +342,7 @@ public: m_meshes[i]->rebuildTopology(maxSmoothAngle); } - if (!materialLibrary.empty()) + if (!materialLibrary.empty() && loadMaterials) loadMaterialLibrary(fileResolver, materialLibrary); Log(EInfo, "Done with \"%s\" (took %i ms)", path.filename().string().c_str(), timer->getMilliseconds()); @@ -401,6 +414,7 @@ public: } Properties props("bitmap"); props.setString("filename", path.string()); + props.setFloat("gamma", 1.0f); ref texture = static_cast (PluginManager::getInstance()-> createObject(MTS_CLASS(Texture), props)); texture->configure(); @@ -535,7 +549,7 @@ public: bsdf->configure(); if (bump) { - props = Properties("bump"); + props = Properties("bumpmap"); ref bumpBSDF = static_cast (PluginManager::getInstance()-> createObject(MTS_CLASS(BSDF), props)); diff --git a/src/shapes/ply.cpp b/src/shapes/ply.cpp index 5edf6f3a..0ed17629 100644 --- a/src/shapes/ply.cpp +++ b/src/shapes/ply.cpp @@ -51,7 +51,7 @@ MTS_NAMESPACE_BEGIN * } * \parameter{faceNormals}{\Boolean}{ * When set to \code{true}, Mitsuba will use face normals when rendering - * the object, which will give it a faceted apperance. \default{\code{false}} + * the object, which will give it a faceted appearance. \default{\code{false}} * } * \parameter{maxSmoothAngle}{\Float}{ * When specified, Mitsuba will discard all vertex normals in the input mesh and rebuild diff --git a/src/shapes/serialized.cpp b/src/shapes/serialized.cpp index 74b15bde..5f4e6285 100644 --- a/src/shapes/serialized.cpp +++ b/src/shapes/serialized.cpp @@ -46,7 +46,7 @@ extern MTS_EXPORT_RENDER void pushSceneCleanupHandler(void (*cleanup)()); * \parameter{faceNormals}{\Boolean}{ * When set to \code{true}, any existing or computed vertex normals are * discarded and \emph{face normals} will instead be used during rendering. - * This gives the rendered object a faceted apperance.\default{\code{false}} + * This gives the rendered object a faceted appearance.\default{\code{false}} * } * \parameter{maxSmoothAngle}{\Float}{ * When specified, Mitsuba will discard all vertex normals in the input mesh and rebuild diff --git a/src/textures/wireframe.cpp b/src/textures/wireframe.cpp index 944b26ad..c6867b89 100644 --- a/src/textures/wireframe.cpp +++ b/src/textures/wireframe.cpp @@ -39,7 +39,7 @@ MTS_NAMESPACE_BEGIN * \default{automatic} * } * \parameter{stepWidth}{\Float}{ - * Controls the width of of step function used for the + * Controls the width of the step function used for the * color transition. It is specified as a value between zero * and one (relative to the \code{lineWidth} parameter) * \default{0.5}