finished the roughdiffuse model, fixed a handedness switch in Transform::lookAt
parent
ac3935fa17
commit
873fe06277
|
@ -5,6 +5,9 @@
|
|||
<!-- Test the smooth diffuse model -->
|
||||
<bsdf type="diffuse"/>
|
||||
|
||||
<!-- Test the rough diffuse model -->
|
||||
<bsdf type="roughdiffuse"/>
|
||||
|
||||
<!-- Test the diffuse transmission model -->
|
||||
<bsdf type="difftrans"/>
|
||||
|
||||
|
|
|
@ -189,11 +189,10 @@ The \texttt{reflectance} intent is used by default, so remember to
|
|||
set it to \texttt{illuminant} when defining the brightness of a
|
||||
light source with the \texttt{<rgb>} tag.
|
||||
|
||||
When spectral power distributions are obtained from measurements
|
||||
When spectral power or reflectance distributions are obtained from measurements
|
||||
(e.g. at 10$nm$ intervals), they are usually quite unwiedy and can clutter
|
||||
the scene description. For this reason, there is yet another way to pass
|
||||
a spectrum by loading it from an external
|
||||
file:
|
||||
a spectrum by loading it from an external file:
|
||||
\begin{xml}
|
||||
<spectrum name="spectrumProperty" filename="measuredSpectrum.spd"/>
|
||||
\end{xml}
|
||||
|
@ -201,7 +200,7 @@ The file should contain a single measurement per line, with the corresponding
|
|||
wavelength in nanometers and the measured value separated by a space. Comments
|
||||
are allowed. Here is an example:
|
||||
\begin{xml}
|
||||
# This file contains a measured spectral power distribution
|
||||
# This file contains a measured spectral power/reflectance distribution
|
||||
406.13 0.703313
|
||||
413.88 0.744563
|
||||
422.03 0.791625
|
||||
|
|
File diff suppressed because one or more lines are too long
Binary file not shown.
After Width: | Height: | Size: 187 KiB |
Binary file not shown.
After Width: | Height: | Size: 186 KiB |
|
@ -37,9 +37,7 @@
|
|||
%\toprule
|
||||
\\[-2.2ex]
|
||||
\textbf{Parameter}&\textbf{Type}&\textbf{Description}\\
|
||||
\otoprule
|
||||
#1
|
||||
%\bottomrule
|
||||
\end{tabular}}
|
||||
\end{figure}
|
||||
\setlength\fboxrule\fboxrulebackup
|
||||
|
@ -60,12 +58,8 @@
|
|||
\newcommand{\smallrendering}[2]{ \subfigure[#1]{\fbox{\includegraphics[width=0.2\textwidth]{images/#2}}}\hfill}
|
||||
|
||||
\newcommand{\parameter}[3]{
|
||||
\small\texttt{#1} & \small #2 & \small #3\\
|
||||
\otoprule
|
||||
}
|
||||
|
||||
\newcommand{\lastparameter}[3]{
|
||||
\small\texttt{#1} & \small #2 & \small #3\\
|
||||
\small\texttt{#1} & \small #2 & \small #3 \\
|
||||
}
|
||||
|
||||
\newcommand{\default}[1]{ (Default: #1)}
|
||||
|
|
|
@ -1,4 +1,16 @@
|
|||
\subsection{Surface scattering models}
|
||||
\begin{figure}[h!]
|
||||
\centering
|
||||
\includegraphics[width=15.5cm]{images/bsdf_overview.pdf}
|
||||
\caption{
|
||||
Schematic overview of the surface scattering models that ship with
|
||||
Mitsuba. The arrows indicate possible outcomes of an
|
||||
interaction with a surface that has the respective model applied to it.
|
||||
\vspace{4mm}
|
||||
}
|
||||
\end{figure}
|
||||
|
||||
|
||||
\label{sec:bsdfs}
|
||||
Surface scattering models describe the manner in which light interacts
|
||||
with surfaces in the scene. They conveniently summarize the mesoscopic
|
||||
|
@ -11,53 +23,11 @@ please refer to Sections~\ref{sec:media} and \ref{sec:subsurface}.
|
|||
This section presents an overview of all surface scattering models that are
|
||||
supported, along with their parameters.
|
||||
|
||||
\subsubsection*{Correctness considerations}
|
||||
\begin{figure}[b!]
|
||||
\centering
|
||||
\vspace{-5mm}
|
||||
\includegraphics[width=15cm]{images/glass_explanation.pdf}
|
||||
\vspace{-5mm}
|
||||
\caption{
|
||||
\label{fig:glass-explanation}
|
||||
Some of the scattering models in Mitsuba need to know
|
||||
the indices of refraction on the exterior and interior-facing
|
||||
side of a surface.
|
||||
It is therefore important to decompose the mesh into meaningful
|
||||
separate surfaces corresponding to each index of refraction change.
|
||||
The example here shows such a decomposition for a water-filled Glass.
|
||||
}
|
||||
\end{figure}
|
||||
|
||||
|
||||
A vital consideration when modeling a scene in a physically-based rendering
|
||||
system is that the used materials do not violate physical properties, and
|
||||
that their arrangement is meaningful. For instance, imagine having designed
|
||||
an architectural interior scene that looks good except for a white desk that
|
||||
seems a bit too dark. A closer inspection reveals that it uses a Lambertian
|
||||
material with a diffuse reflectance of $0.9$.
|
||||
|
||||
In many rendering systems, it would be feasible to increase the
|
||||
reflectance value above $1.0$ in such a situation. But in Mitsuba, even a
|
||||
small surface that reflects a little more light than it receives will
|
||||
likely break the available rendering algorithms, or cause them to produce otherwise
|
||||
unpredictable results. In fact, we should rather change the lighting setup and
|
||||
then \emph{reduce} the material's reflectance, since it is quite unlikely that
|
||||
we could find a real-world desk with a reflectance as high as $0.9$.
|
||||
|
||||
As an example of the necessity for a meaningful material arrangement, consider
|
||||
the glass model illustrated in \figref{glass-explanation}. Here, careful thinking
|
||||
is needed to decompose the object into boundaries that mark index of
|
||||
refraction-changes. If this is done incorrectly and a beam of light can
|
||||
potentially pass through a sequence of incompatible index of refraction changes (e.g. $1.00\to 1.33$
|
||||
followed by $1.50\to1.33$), the output is undefined and will quite likely
|
||||
even contain inaccuracies in parts of the scene that are some distance
|
||||
away from the glass.
|
||||
|
||||
\subsubsection*{BSDFs}
|
||||
To achieve realistic results, Mitsuba comes with a library of both
|
||||
general-purpose surface scattering models (smooth or rough glass, metal,
|
||||
plastic, etc.) and specializations to particular materials (woven cloth,
|
||||
masks, etc.). Some model plugins fit neither category and could be described
|
||||
masks, etc.). Some model plugins fit neither category and can best be described
|
||||
as \emph{modifiers} that are applied on top of one or more scattering models.
|
||||
|
||||
Throughout the documentation and within the scene description
|
||||
|
@ -95,4 +65,45 @@ The following fragment shows an example of both kinds of usages:
|
|||
It is generally more economical to use named BSDFs when they
|
||||
are used in several places, since this reduces Mitsuba's internal
|
||||
memory usage.
|
||||
\subsubsection*{Correctness considerations}
|
||||
\begin{figure}[b!]
|
||||
\centering
|
||||
\vspace{-5mm}
|
||||
\includegraphics[width=15cm]{images/glass_explanation.pdf}
|
||||
\vspace{-5mm}
|
||||
\caption{
|
||||
\label{fig:glass-explanation}
|
||||
Some of the scattering models in Mitsuba need to know
|
||||
the indices of refraction on the exterior and interior-facing
|
||||
side of a surface.
|
||||
It is therefore important to decompose the mesh into meaningful
|
||||
separate surfaces corresponding to each index of refraction change.
|
||||
The example here shows such a decomposition for a water-filled Glass.
|
||||
}
|
||||
\end{figure}
|
||||
|
||||
A vital consideration when modeling a scene in a physically-based rendering
|
||||
system is that the used materials do not violate physical properties, and
|
||||
that their arrangement is meaningful. For instance, imagine having designed
|
||||
an architectural interior scene that looks good except for a white desk that
|
||||
seems a bit too dark. A closer inspection reveals that it uses a Lambertian
|
||||
material with a diffuse reflectance of $0.9$.
|
||||
|
||||
In many rendering systems, it would be feasible to increase the
|
||||
reflectance value above $1.0$ in such a situation. But in Mitsuba, even a
|
||||
small surface that reflects a little more light than it receives will
|
||||
likely break the available rendering algorithms, or cause them to produce otherwise
|
||||
unpredictable results. In fact, we should rather change the lighting setup and
|
||||
then \emph{reduce} the material's reflectance, since it is quite unlikely that
|
||||
we could find a real-world desk with a reflectance as high as $0.9$.
|
||||
|
||||
As an example of the necessity for a meaningful material arrangement, consider
|
||||
the glass model illustrated in \figref{glass-explanation}. Here, careful thinking
|
||||
is needed to decompose the object into boundaries that mark index of
|
||||
refraction-changes. If this is done incorrectly and a beam of light can
|
||||
potentially pass through a sequence of incompatible index of refraction changes (e.g. $1.00\to 1.33$
|
||||
followed by $1.50\to1.33$), the output is undefined and will quite likely
|
||||
even contain inaccuracies in parts of the scene that are some distance
|
||||
away from the glass.
|
||||
|
||||
|
||||
|
|
|
@ -112,6 +112,38 @@ struct Frame {
|
|||
return 1.0f - v.z * v.z;
|
||||
}
|
||||
|
||||
/** \brief Assuming that the given direction is in the local coordinate
|
||||
* system, return the sine of the phi parameter in spherical coordinates */
|
||||
inline static Float sinPhi(const Vector &v) {
|
||||
Float sinTheta = Frame::sinTheta(v);
|
||||
if (sinTheta == 0.0f)
|
||||
return 1.0f;
|
||||
return clamp(v.y / sinTheta, -1.0f, 1.0f);
|
||||
}
|
||||
|
||||
/** \brief Assuming that the given direction is in the local coordinate
|
||||
* system, return the cosine of the phi parameter in spherical coordinates */
|
||||
inline static Float cosPhi(const Vector &v) {
|
||||
Float sinTheta = Frame::sinTheta(v);
|
||||
if (sinTheta == 0.0f)
|
||||
return 1.0f;
|
||||
return clamp(v.x / sinTheta, -1.0f, 1.0f);
|
||||
}
|
||||
|
||||
/** \brief Assuming that the given direction is in the local coordinate
|
||||
* system, return the squared sine of the phi parameter in spherical
|
||||
* coordinates */
|
||||
inline static Float sinPhiSquared(const Vector &v) {
|
||||
return clamp(v.y * v.y / sinTheta2(v), 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
/** \brief Assuming that the given direction is in the local coordinate
|
||||
* system, return the squared cosine of the phi parameter in spherical
|
||||
* coordinates */
|
||||
inline static Float cosPhiSquared(const Vector &v) {
|
||||
return clamp(v.x * v.x / sinTheta2(v), 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
/// Return a string representation of this frame
|
||||
inline std::string toString() const {
|
||||
std::ostringstream oss;
|
||||
|
|
|
@ -32,7 +32,7 @@ MTS_NAMESPACE_BEGIN
|
|||
* \parameter{k}{\Spectrum}{Imaginary part of the material's index of
|
||||
* refraction, also known as absorption coefficient.
|
||||
* \default{based on the value of \texttt{material}}}
|
||||
* \lastparameter{specular\showbreak Reflectance}{\Spectrum\Or\Texture}{
|
||||
* \parameter{specular\showbreak Reflectance}{\Spectrum\Or\Texture}{
|
||||
* Optional factor used to modulate the reflectance component
|
||||
* \default{1.0}}
|
||||
* }
|
||||
|
|
|
@ -31,7 +31,7 @@ MTS_NAMESPACE_BEGIN
|
|||
* numerically or using a known material name. \default{\texttt{air} / 1.000277}}
|
||||
* \parameter{specular\showbreak Reflectance}{\Spectrum\Or\Texture}{Optional
|
||||
* factor used to modulate the reflectance component\default{1.0}}
|
||||
* \lastparameter{specular\showbreak Transmittance}{\Spectrum\Or\Texture}{Optional
|
||||
* \parameter{specular\showbreak Transmittance}{\Spectrum\Or\Texture}{Optional
|
||||
* factor used to modulate the transmittance component\default{1.0}}
|
||||
* }
|
||||
*
|
||||
|
|
|
@ -25,7 +25,7 @@ MTS_NAMESPACE_BEGIN
|
|||
/*! \plugin{difftrans}{Diffuse transmitter}
|
||||
*
|
||||
* \parameters{
|
||||
* \lastparameter{transmittance}{\Spectrum\Or\Texture}{
|
||||
* \parameter{transmittance}{\Spectrum\Or\Texture}{
|
||||
* Specifies the diffuse transmittance of the material
|
||||
* \default{0.5}
|
||||
* }
|
||||
|
|
|
@ -25,17 +25,20 @@ MTS_NAMESPACE_BEGIN
|
|||
/*!\plugin{diffuse}{Smooth diffuse material}
|
||||
* \order{1}
|
||||
* \parameters{
|
||||
* \lastparameter{reflectance}{\Spectrum\Or\Texture}{
|
||||
* Specifies the diffuse reflectance / albedo of the material \linebreak(Default: 0.5)
|
||||
* \parameter{reflectance}{\Spectrum\Or\Texture}{
|
||||
* Specifies the diffuse albedo of the
|
||||
* material \default{0.5}
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* \renderings{
|
||||
* \rendering{Homogeneous reflectance, see \lstref{diffuse-uniform}}{bsdf_diffuse_plain}
|
||||
* \rendering{Textured reflectance, see \lstref{diffuse-textured}}{bsdf_diffuse_textured}
|
||||
* \rendering{Homogeneous reflectance, see \lstref{diffuse-uniform}}
|
||||
* {bsdf_diffuse_plain}
|
||||
* \rendering{Textured reflectance, see \lstref{diffuse-textured}}
|
||||
* {bsdf_diffuse_textured}
|
||||
* }
|
||||
*
|
||||
* The smooth diffuse material (sometimes referred to as ``Lambertian'')
|
||||
* The smooth diffuse material (also referred to as ``Lambertian'')
|
||||
* represents an ideally diffuse material with a user-specified amount of
|
||||
* reflectance. Any received illumination is scattered so that the surface
|
||||
* looks the same independently of the direction of observation.
|
||||
|
@ -51,13 +54,15 @@ MTS_NAMESPACE_BEGIN
|
|||
* consider using the \pluginref{twosided} BRDF adapter plugin.
|
||||
* \vspace{4mm}
|
||||
*
|
||||
* \begin{xml}[caption={A diffuse material, whose reflectance is specified as an sRGB color}, label=lst:diffuse-uniform]
|
||||
* \begin{xml}[caption={A diffuse material, whose reflectance is specified
|
||||
* as an sRGB color}, label=lst:diffuse-uniform]
|
||||
* <bsdf type="diffuse">
|
||||
* <srgb name="reflectance" value="#6d7185"/>
|
||||
* </bsdf>
|
||||
* \end{xml}
|
||||
*
|
||||
* \begin{xml}[caption=A diffuse material with a texture map, label=lst:diffuse-textured]
|
||||
* \begin{xml}[caption=A diffuse material with a texture map,
|
||||
* label=lst:diffuse-textured]
|
||||
* <bsdf type="diffuse">
|
||||
* <texture type="bitmap" name="reflectance">
|
||||
* <string name="filename" value="wood.jpg"/>
|
||||
|
|
|
@ -31,7 +31,7 @@ MTS_NAMESPACE_BEGIN
|
|||
* numerically or using a known material name. \default{\texttt{air} / 1.000277}}
|
||||
* \parameter{specular\showbreak Reflectance}{\Spectrum\Or\Texture}{Optional
|
||||
* factor used to modulate the specular component\default{1.0}}
|
||||
* \lastparameter{diffuse\showbreak Reflectance}{\Spectrum\Or\Texture}{Optional
|
||||
* \parameter{diffuse\showbreak Reflectance}{\Spectrum\Or\Texture}{Optional
|
||||
* factor used to modulate the diffuse component\default{0.5}}
|
||||
* }
|
||||
*
|
||||
|
|
|
@ -62,7 +62,7 @@ MTS_NAMESPACE_BEGIN
|
|||
* \default{0.1}.
|
||||
* }
|
||||
* \parameter{alphaU, alphaV}{\Float\Or\Texture}{
|
||||
* Specifies the anisotropic rougness values along the tangent and
|
||||
* Specifies the anisotropic roughness values along the tangent and
|
||||
* bitangent directions. These parameter are only valid when
|
||||
* \texttt{distribution=as}. \default{0.1}.
|
||||
* }
|
||||
|
@ -73,7 +73,7 @@ MTS_NAMESPACE_BEGIN
|
|||
* \parameter{k}{\Spectrum}{Imaginary part of the material's index of
|
||||
* refraction, also known as absorption coefficient.
|
||||
* \default{based on the value of \texttt{material}}}
|
||||
* \lastparameter{specular\showbreak Reflectance}{\Spectrum\Or\Texture}{Optional
|
||||
* \parameter{specular\showbreak Reflectance}{\Spectrum\Or\Texture}{Optional
|
||||
* factor used to modulate the reflectance component\default{1.0}}
|
||||
* }
|
||||
* This plugin implements a realistic microfacet scattering model for rendering
|
||||
|
@ -117,7 +117,7 @@ MTS_NAMESPACE_BEGIN
|
|||
* a value of $\alpha=0.001-0.01$ corresponds to a material
|
||||
* with slight imperfections on an
|
||||
* otherwise smooth surface finish, $\alpha=0.1$ is relatively rough,
|
||||
* and $\alpha=0.3-0.5$ is \emph{extremely} rough (e.g. an etched or ground
|
||||
* and $\alpha=0.3-0.7$ is \emph{extremely} rough (e.g. an etched or ground
|
||||
* finish).
|
||||
* \vspace{-2mm}
|
||||
* \subsubsection*{Techical details}\vspace{-2mm}
|
||||
|
|
|
@ -59,7 +59,7 @@ MTS_NAMESPACE_BEGIN
|
|||
* \default{0.1}.
|
||||
* }
|
||||
* \parameter{alphaU, alphaV}{\Float\Or\Texture}{
|
||||
* Specifies the anisotropic rougness values along the tangent and
|
||||
* Specifies the anisotropic roughness values along the tangent and
|
||||
* bitangent directions. These parameter are only valid when
|
||||
* \texttt{distribution=as}. \default{0.1}.
|
||||
* }
|
||||
|
@ -69,7 +69,7 @@ MTS_NAMESPACE_BEGIN
|
|||
* numerically or using a known material name. \default{\texttt{air} / 1.000277}}
|
||||
* \parameter{specular\showbreak Reflectance}{\Spectrum\Or\Texture}{Optional
|
||||
* factor used to modulate the reflectance component\default{1.0}}
|
||||
* \lastparameter{specular\showbreak Transmittance}{\Spectrum\Or\Texture}{Optional
|
||||
* \parameter{specular\showbreak Transmittance}{\Spectrum\Or\Texture}{Optional
|
||||
* factor used to modulate the transmittance component\default{1.0}}
|
||||
* }\vspace{4mm}
|
||||
*
|
||||
|
@ -111,7 +111,7 @@ MTS_NAMESPACE_BEGIN
|
|||
* a value of $\alpha=0.001-0.01$ corresponds to a material
|
||||
* with slight imperfections on an
|
||||
* otherwise smooth surface finish, $\alpha=0.1$ is relatively rough,
|
||||
* and $\alpha=0.3-0.5$ is \emph{extremely} rough (e.g. an etched or ground
|
||||
* and $\alpha=0.3-0.7$ is \emph{extremely} rough (e.g. an etched or ground
|
||||
* finish).
|
||||
*
|
||||
* Please note that when using this plugin, it is crucial that the scene contains
|
||||
|
@ -142,7 +142,7 @@ MTS_NAMESPACE_BEGIN
|
|||
* \renderings{
|
||||
* \rendering{Ground glass (GGX, $\alpha$=0.304,
|
||||
* \lstref{roughdielectric-roughglass})}{bsdf_roughdielectric_ggx_0_304.jpg}
|
||||
* \rendering{Textured rougness (\lstref{roughdielectric-textured})}
|
||||
* \rendering{Textured roughness (\lstref{roughdielectric-textured})}
|
||||
* {bsdf_roughdielectric_textured.jpg}
|
||||
* }
|
||||
*
|
||||
|
@ -467,7 +467,7 @@ public:
|
|||
1. Take the Fresnel term with respect to the surface
|
||||
normal to be a good approximation to the microsurface
|
||||
Fresnel term -- this will be less true for higher
|
||||
rougness values. To be safe, clamp it to some
|
||||
roughness values. To be safe, clamp it to some
|
||||
reasonable range.
|
||||
2. Use this approximate term and a random number to
|
||||
choose between reflection and refraction component.
|
||||
|
@ -595,7 +595,7 @@ public:
|
|||
1. Take the Fresnel term with respect to the surface
|
||||
normal to be a good approximation to the microsurface
|
||||
Fresnel term -- this will be less true for higher
|
||||
rougness values. To be safe, clamp it to some
|
||||
roughness values. To be safe, clamp it to some
|
||||
reasonable range.
|
||||
2. Use this approximate term and a random number to
|
||||
choose between reflection and refraction component.
|
||||
|
|
|
@ -21,60 +21,65 @@
|
|||
|
||||
MTS_NAMESPACE_BEGIN
|
||||
|
||||
/*!\plugin{diffuse}{Rough diffuse material}
|
||||
/*!\plugin{roughdiffuse}{Rough diffuse material}
|
||||
* \order{2}
|
||||
* \parameters{
|
||||
* \parameter{reflectance}{\Spectrum\Or\Texture}{
|
||||
* Specifies the reflectance / albedo of the material \linebreak(Default: 0.5)
|
||||
* Specifies the diffuse albedo of the
|
||||
* material. \default{0.5}
|
||||
* }
|
||||
* \lastparameter{alpha}{\Spectrum\Or\Texture}{
|
||||
* Specifies the roughness of the unresolved surface microgeometry.
|
||||
* This parameter is approximately equal to the \emph{root mean square}
|
||||
* (RMS) slope of the microfacets.\default{0.1}
|
||||
* \parameter{alpha}{\Spectrum\Or\Texture}{
|
||||
* Specifies the roughness of the unresolved surface microgeometry
|
||||
* using the \emph{root mean square} (RMS) slope of the
|
||||
* microfacets. \default{0.2}
|
||||
* }
|
||||
* \parameter{useFastApprox}{\Boolean}{
|
||||
* This parameter selects between the full version of the model
|
||||
* or a fast approximation that still retains most qualitative features.
|
||||
* \default{\texttt{false}, i.e. use the high-quality version}
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* \renderings{
|
||||
* \rendering{Homogeneous reflectance, see \lstref{diffuse-uniform}}{bsdf_diffuse_plain}
|
||||
* \rendering{Textured reflectance, see \lstref{diffuse-textured}}{bsdf_diffuse_textured}
|
||||
* \rendering{Smooth diffuse surface ($\alpha=0$)}
|
||||
* {bsdf_roughdiffuse_0}
|
||||
* \rendering{Very rough diffuse surface ($\alpha=0.7$)}
|
||||
* {bsdf_roughdiffuse_0_7}
|
||||
* \vspace{-3mm}
|
||||
* \caption{The effect of switching from smooth to rough diffuse scattering
|
||||
* is fairly subtle on this model---generally, there will be higher
|
||||
* reflectance at grazing angles, as well as an overall reduced contrast.}\vspace{3mm}
|
||||
* }
|
||||
*
|
||||
* This reflectance model describes scattering from a rough diffuse material,
|
||||
* such as plaster, sand, clay, or concrete.
|
||||
* This reflectance model describes the interaction of light with a rough
|
||||
* diffuse material, such as plaster, sand, clay, or concrete.
|
||||
* The underlying theory was developed by Oren and Nayar
|
||||
* \cite{Oren1994Generalization}, who model the microscopic surface structure as
|
||||
* unresolved planar facets arranged in V-shaped grooves, where each facet
|
||||
* is an ideal diffuse reflector. The model takes into account shadowing,
|
||||
* masking, as well as interreflections between the facets.
|
||||
*
|
||||
* Since the original publication in 1994, this approach has been shown to
|
||||
* Since the original publication, this approach has been shown to
|
||||
* be a good match for many real-world materials, particularly compared
|
||||
* to Lambertian scattering, which does not take surface roughness into account.
|
||||
*
|
||||
* The implementation in Mitsuba uses a surface roughness parameter $\alpha$ that
|
||||
* is slighly different from the slope-area variance in the original paper.
|
||||
* is slighly different from the slope-area variance in the original 1994 paper.
|
||||
* The reason for this change is to make the parameter $\alpha$ portable
|
||||
* across different models (i.e. \pluginref{roughglass},
|
||||
* across different models (i.e. \pluginref{roughglass}, \pluginref{roughplastic},
|
||||
* \pluginref{roughconductor}).
|
||||
*
|
||||
* To get an intuition about the effect of the
|
||||
* parameter $\alpha$, consider the following approximate differentiation:
|
||||
* a value of $\alpha=0.001-0.01$ corresponds to a material
|
||||
* with slight imperfections on an otherwise smooth surface (for such small
|
||||
* values, the model will behave almost identically to \pluginref{diffuse}), $\alpha=0.1$
|
||||
* is relatively rough, and $\alpha=0.3-0.5$ is \emph{extremely} rough
|
||||
* values, the model will behave identically to \pluginref{diffuse}), $\alpha=0.1$
|
||||
* is relatively rough, and $\alpha=0.3-0.7$ is \emph{extremely} rough
|
||||
* (e.g. an etched or ground surface).
|
||||
*
|
||||
* Note that this material is one-sided---that is, observed from the
|
||||
* back side, it will be completely black. If this is undesirable,
|
||||
* consider using the \pluginref{twosided} BRDF adapter plugin.
|
||||
* \vspace{4mm}
|
||||
*
|
||||
* \begin{xml}[caption={A diffuse material, whose reflectance is specified as an sRGB color}, label=lst:diffuse-uniform]
|
||||
* <bsdf type="diffuse">
|
||||
* <srgb name="reflectance" value="#6d7185"/>
|
||||
* </bsdf>
|
||||
* \end{xml}
|
||||
*/
|
||||
class RoughDiffuse : public BSDF {
|
||||
public:
|
||||
|
@ -84,9 +89,11 @@ public:
|
|||
'reflectance' and 'diffuseReflectance' as parameter names */
|
||||
m_reflectance = new ConstantSpectrumTexture(props.getSpectrum(
|
||||
props.hasProperty("reflectance") ? "reflectance"
|
||||
: "diffuseReflectance", Spectrum(.5f)));
|
||||
: "diffuseReflectance", Spectrum(0.5f)));
|
||||
|
||||
m_alpha = new ConstantFloatTexture(props.getFloat("alpha", 0.1f));
|
||||
m_useFastApprox = props.getBoolean("useFastApprox", false);
|
||||
|
||||
m_alpha = new ConstantFloatTexture(props.getFloat("alpha", 0.2f));
|
||||
m_components.push_back(EGlossyReflection | EFrontSide);
|
||||
m_usesRayDifferentials = false;
|
||||
}
|
||||
|
@ -95,6 +102,7 @@ public:
|
|||
: BSDF(stream, manager) {
|
||||
m_reflectance = static_cast<Texture *>(manager->getInstance(stream));
|
||||
m_alpha = static_cast<Texture *>(manager->getInstance(stream));
|
||||
m_useFastApprox = stream->readBool();
|
||||
m_components.push_back(EGlossyReflection | EFrontSide);
|
||||
m_usesRayDifferentials = m_reflectance->usesRayDifferentials();
|
||||
}
|
||||
|
@ -124,12 +132,80 @@ public:
|
|||
Float sigma = m_alpha->getValue(bRec.its).average()
|
||||
* conversionFactor;
|
||||
|
||||
Float sigma2 = sigma*sigma;
|
||||
Float A = 10.f - (sigma2 / (2.0f * (sigma2 + 0.33f)));
|
||||
Float B = 0.45f * sigma2 / (sigma2 + 0.09f);
|
||||
const Float sigma2 = sigma*sigma;
|
||||
|
||||
return m_reflectance->getValue(bRec.its)
|
||||
* (INV_PI * Frame::cosTheta(bRec.wo));
|
||||
Float sinThetaI = Frame::sinTheta(bRec.wi),
|
||||
sinThetaO = Frame::sinTheta(bRec.wo);
|
||||
|
||||
Float cosPhiDiff = 0;
|
||||
if (sinThetaI > Epsilon && sinThetaO > Epsilon) {
|
||||
/* Compute cos(phiO-phiI) using the half-angle formulae */
|
||||
Float sinPhiI = Frame::sinPhi(bRec.wi),
|
||||
cosPhiI = Frame::cosPhi(bRec.wi),
|
||||
sinPhiO = Frame::sinPhi(bRec.wo),
|
||||
cosPhiO = Frame::cosPhi(bRec.wo);
|
||||
cosPhiDiff = cosPhiI * cosPhiO + sinPhiI * sinPhiO;
|
||||
}
|
||||
|
||||
if (m_useFastApprox) {
|
||||
Float A = 1.0f - 0.5f * sigma2 / (sigma2 + 0.33f),
|
||||
B = 0.45f * sigma2 / (sigma2 + 0.09f),
|
||||
sinAlpha, tanBeta;
|
||||
|
||||
if (Frame::cosTheta(bRec.wi) > Frame::cosTheta(bRec.wo)) {
|
||||
sinAlpha = sinThetaO;
|
||||
tanBeta = sinThetaI / Frame::cosTheta(bRec.wi);
|
||||
} else {
|
||||
sinAlpha = sinThetaI;
|
||||
tanBeta = sinThetaO / Frame::cosTheta(bRec.wo);
|
||||
}
|
||||
|
||||
return m_reflectance->getValue(bRec.its)
|
||||
* (INV_PI * Frame::cosTheta(bRec.wo) * (A + B
|
||||
* std::max(cosPhiDiff, (Float) 0.0f) * sinAlpha * tanBeta));
|
||||
} else {
|
||||
Float sinThetaI = Frame::sinTheta(bRec.wi),
|
||||
sinThetaO = Frame::sinTheta(bRec.wo),
|
||||
thetaI = std::acos(Frame::cosTheta(bRec.wi)),
|
||||
thetaO = std::acos(Frame::cosTheta(bRec.wo)),
|
||||
alpha = std::max(thetaI, thetaO),
|
||||
beta = std::min(thetaI, thetaO);
|
||||
|
||||
Float sinAlpha, sinBeta, tanBeta;
|
||||
if (Frame::cosTheta(bRec.wi) > Frame::cosTheta(bRec.wo)) {
|
||||
sinAlpha = sinThetaO; sinBeta = sinThetaI;
|
||||
tanBeta = sinThetaI / Frame::cosTheta(bRec.wi);
|
||||
} else {
|
||||
sinAlpha = sinThetaI; sinBeta = sinThetaO;
|
||||
tanBeta = sinThetaO / Frame::cosTheta(bRec.wo);
|
||||
}
|
||||
|
||||
Float tmp = sigma2 / (sigma2 + 0.09f),
|
||||
tmp2 = (4*INV_PI*INV_PI) * alpha * beta,
|
||||
tmp3 = 2*beta*INV_PI;
|
||||
|
||||
Float C1 = 1.0f - 0.5f * sigma2 / (sigma2 + 0.33f),
|
||||
C2 = 0.45f * tmp,
|
||||
C3 = 0.125f * tmp * tmp2 * tmp2,
|
||||
C4 = 0.17f * sigma2 / (sigma2 + 0.13f);
|
||||
|
||||
if (cosPhiDiff > 0)
|
||||
C2 *= sinAlpha;
|
||||
else
|
||||
C2 *= sinAlpha - tmp3*tmp3*tmp3;
|
||||
|
||||
/* Compute tan(0.5 * (alpha+beta)) using the half-angle formulae */
|
||||
Float tanHalf = (sinAlpha + sinBeta) / (
|
||||
std::sqrt(std::max((Float) 0.0f, 1.0f - sinAlpha * sinAlpha)) +
|
||||
std::sqrt(std::max((Float) 0.0f, 1.0f - sinBeta * sinBeta)));
|
||||
|
||||
Spectrum rho = m_reflectance->getValue(bRec.its),
|
||||
snglScat = rho * (C1 + cosPhiDiff * C2 * tanBeta +
|
||||
(1.0f - std::abs(cosPhiDiff)) * C3 * tanHalf),
|
||||
dblScat = rho * rho * (C4 * (1.0f - cosPhiDiff*tmp3*tmp3));
|
||||
|
||||
return (snglScat + dblScat) * (INV_PI * Frame::cosTheta(bRec.wo));
|
||||
}
|
||||
}
|
||||
|
||||
Float pdf(const BSDFQueryRecord &bRec, EMeasure measure) const {
|
||||
|
@ -148,7 +224,8 @@ public:
|
|||
bRec.wo = squareToHemispherePSA(sample);
|
||||
bRec.sampledComponent = 0;
|
||||
bRec.sampledType = EGlossyReflection;
|
||||
return m_reflectance->getValue(bRec.its);
|
||||
return eval(bRec, ESolidAngle) /
|
||||
(Frame::cosTheta(bRec.wo) * INV_PI);
|
||||
}
|
||||
|
||||
Spectrum sample(BSDFQueryRecord &bRec, Float &pdf, const Point2 &sample) const {
|
||||
|
@ -159,8 +236,7 @@ public:
|
|||
bRec.sampledComponent = 0;
|
||||
bRec.sampledType = EGlossyReflection;
|
||||
pdf = Frame::cosTheta(bRec.wo) * INV_PI;
|
||||
return m_reflectance->getValue(bRec.its)
|
||||
* (INV_PI * Frame::cosTheta(bRec.wo));
|
||||
return eval(bRec, ESolidAngle);
|
||||
}
|
||||
|
||||
void addChild(const std::string &name, ConfigurableObject *child) {
|
||||
|
@ -182,6 +258,7 @@ public:
|
|||
|
||||
manager->serialize(stream, m_reflectance.get());
|
||||
manager->serialize(stream, m_alpha.get());
|
||||
stream->writeBool(m_useFastApprox);
|
||||
}
|
||||
|
||||
std::string toString() const {
|
||||
|
@ -189,7 +266,8 @@ public:
|
|||
oss << "RoughDiffuse[" << endl
|
||||
<< " name = \"" << getName() << "\"," << endl
|
||||
<< " reflectance = " << indent(m_reflectance->toString()) << "," << endl
|
||||
<< " alpha = " << indent(m_alpha->toString()) << endl
|
||||
<< " alpha = " << indent(m_alpha->toString()) << "," << endl
|
||||
<< " useFastApprox = " << m_useFastApprox << endl
|
||||
<< "]";
|
||||
return oss.str();
|
||||
}
|
||||
|
@ -200,6 +278,7 @@ public:
|
|||
private:
|
||||
ref<Texture> m_reflectance;
|
||||
ref<Texture> m_alpha;
|
||||
bool m_useFastApprox;
|
||||
};
|
||||
|
||||
// ================ Hardware shader implementation ================
|
||||
|
@ -233,11 +312,27 @@ public:
|
|||
oss << "vec3 " << evalName << "(vec2 uv, vec3 wi, vec3 wo) {" << endl
|
||||
<< " if (cosTheta(wi) < 0.0 || cosTheta(wo) < 0.0)" << endl
|
||||
<< " return vec3(0.0);" << endl
|
||||
<< " return " << depNames[0] << "(uv) * 0.31831 * cosTheta(wo);" << endl
|
||||
<< " float sigma = " << depNames[1] << "(uv)[0] * 0.70711;" << endl
|
||||
<< " float sigma2 = sigma * sigma;" << endl
|
||||
<< " float A = 1.0 - 0.5 * sigma2 / (sigma2 + 0.33);" << endl
|
||||
<< " float B = 0.45 * sigma2 / (sigma2 + 0.09);" << endl
|
||||
<< " float maxCos = max(0.0, cosPhi(wi)*cosPhi(wo)+sinPhi(wi)*sinPhi(wo));" << endl
|
||||
<< " float sinAlpha, tanBeta;" << endl
|
||||
<< " if (cosTheta(wi) > cosTheta(wo)) {" << endl
|
||||
<< " sinAlpha = sinTheta(wo);" << endl
|
||||
<< " tanBeta = sinTheta(wi) / cosTheta(wi);" << endl
|
||||
<< " } else {" << endl
|
||||
<< " sinAlpha = sinTheta(wi);" << endl
|
||||
<< " tanBeta = sinTheta(wo) / cosTheta(wo);" << endl
|
||||
<< " }" << endl
|
||||
<< " float value = A + B * maxCos * sinAlpha * tanBeta;" << endl
|
||||
<< " return " << depNames[0] << "(uv) * 0.31831 * cosTheta(wo) * value;" << endl
|
||||
<< "}" << endl
|
||||
<< endl
|
||||
<< "vec3 " << evalName << "_diffuse(vec2 uv, vec3 wi, vec3 wo) {" << endl
|
||||
<< " return " << evalName << "(uv, wi, wo);" << endl
|
||||
<< " if (cosTheta(wi) < 0.0 || cosTheta(wo) < 0.0)" << endl
|
||||
<< " return vec3(0.0);" << endl
|
||||
<< " return " << depNames[0] << "(uv) * 0.31831 * cosTheta(wo);" << endl
|
||||
<< "}" << endl;
|
||||
}
|
||||
|
||||
|
|
|
@ -1103,7 +1103,7 @@ void loadCamera(ColladaContext &ctx, Transform transform, domCamera &camera) {
|
|||
int xres=768;
|
||||
|
||||
// Cameras in Mitsuba point along the positive Z axis (COLLADA: neg. Z)
|
||||
transform = transform * Transform::scale(Vector(1,1,-1));
|
||||
transform = transform * Transform::scale(Vector(1, 1, -1));
|
||||
|
||||
std::ostringstream matrix;
|
||||
for (int i=0; i<4; ++i)
|
||||
|
@ -1130,14 +1130,8 @@ void loadCamera(ColladaContext &ctx, Transform transform, domCamera &camera) {
|
|||
xres = ctx.cvt->m_xres;
|
||||
aspect = (Float) ctx.cvt->m_xres / (Float) ctx.cvt->m_yres;
|
||||
} else {
|
||||
if (persp->getAspect_ratio().cast() != 0) {
|
||||
if (persp->getAspect_ratio().cast() != 0)
|
||||
aspect = (Float) persp->getAspect_ratio()->getValue();
|
||||
if (std::abs(aspect-0.1) < Epsilon) {
|
||||
SLog(EWarn, "Found the suspicious aspect ratio \"0.1\", which is likely due to a bug in Blender 2.5"
|
||||
" - setting to 1.0. Please use the \"-r\" parameter to override the resolution.");
|
||||
aspect = 1.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
ctx.os << "\t<camera id=\"" << identifier << "\" type=\"perspective\">" << endl;
|
||||
if (persp->getXfov().cast()) {
|
||||
|
|
|
@ -174,16 +174,16 @@ Transform Transform::glOrthographic(Float clipNear, Float clipFar) {
|
|||
Transform Transform::lookAt(const Point &p, const Point &t, const Vector &up) {
|
||||
Matrix4x4 result;
|
||||
|
||||
Vector dirct = normalize(t-p);
|
||||
Vector right = normalize(cross(dirct, up));
|
||||
Vector dir = normalize(t-p);
|
||||
Vector left = normalize(cross(normalize(up), dir));
|
||||
|
||||
/* Generate a new, orthogonalized up vector */
|
||||
Vector newUp = cross(right, dirct);
|
||||
Vector newUp = cross(dir, left);
|
||||
|
||||
/* Store as columns */
|
||||
result.m[0][0] = right.x; result.m[1][0] = right.y; result.m[2][0] = right.z; result.m[3][0] = 0;
|
||||
result.m[0][0] = left.x; result.m[1][0] = left.y; result.m[2][0] = left.z; result.m[3][0] = 0;
|
||||
result.m[0][1] = newUp.x; result.m[1][1] = newUp.y; result.m[2][1] = newUp.z; result.m[3][1] = 0;
|
||||
result.m[0][2] = dirct.x; result.m[1][2] = dirct.y; result.m[2][2] = dirct.z; result.m[3][2] = 0;
|
||||
result.m[0][2] = dir.x; result.m[1][2] = dir.y; result.m[2][2] = dir.z; result.m[3][2] = 0;
|
||||
result.m[0][3] = p.x; result.m[1][3] = p.y; result.m[2][3] = p.z; result.m[3][3] = 1;
|
||||
|
||||
return Transform(result);
|
||||
|
|
|
@ -308,6 +308,7 @@ void VPLShaderManager::setVPL(const VPL &vpl) {
|
|||
case 4: lightViewTrafo = Transform::lookAt(p, p + Vector(0, 0, 1), Vector(0, 1, 0)).inverse(); break;
|
||||
case 5: lightViewTrafo = Transform::lookAt(p, p + Vector(0, 0, -1), Vector(0, 1, 0)).inverse(); break;
|
||||
}
|
||||
lightViewTrafo = Transform::scale(Vector(-1, 1, 1)) * lightViewTrafo;
|
||||
const Matrix4x4 &viewMatrix = lightViewTrafo.getMatrix();
|
||||
m_shadowProgram->setParameter(m_shadowProgramParam_cubeMapTransform[i], lightProjTrafo * lightViewTrafo);
|
||||
m_shadowProgram->setParameter(m_shadowProgramParam_depthVec[i], Vector4(
|
||||
|
@ -331,6 +332,7 @@ void VPLShaderManager::setVPL(const VPL &vpl) {
|
|||
case 4: lightViewTrafo = Transform::lookAt(p, p + Vector(0, 0, 1), Vector(0, 1, 0)).inverse(); break;
|
||||
case 5: lightViewTrafo = Transform::lookAt(p, p + Vector(0, 0, -1), Vector(0, 1, 0)).inverse(); break;
|
||||
}
|
||||
lightViewTrafo = Transform::scale(Vector(-1, 1, 1)) * lightViewTrafo;
|
||||
const Matrix4x4 &viewMatrix = lightViewTrafo.getMatrix();
|
||||
|
||||
m_altShadowProgram->setParameter(m_altShadowProgramParam_cubeMapTransform, lightProjTrafo * lightViewTrafo);
|
||||
|
@ -368,13 +370,6 @@ void VPLShaderManager::configure(const VPL &vpl, const BSDF *bsdf,
|
|||
return;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (bsdfShader->getFlags() & Shader::ETransparent) {
|
||||
m_renderer->setColor(Spectrum(1.0f), 0.3f);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool anisotropic = bsdf->getType() & BSDF::EAnisotropic;
|
||||
|
||||
m_targetConfig = VPLProgramConfiguration(vplShader, bsdfShader,
|
||||
|
@ -495,6 +490,8 @@ void VPLShaderManager::configure(const VPL &vpl, const BSDF *bsdf,
|
|||
<< "float sinTheta2(vec3 v) { return 1.0-v.z*v.z; }" << endl
|
||||
<< "float sinTheta(vec3 v) { float st2 = sinTheta2(v); if (st2 <= 0) return 0.0; else return sqrt(sinTheta2(v)); }" << endl
|
||||
<< "float tanTheta(vec3 v) { return sinTheta(v)/cosTheta(v); }" << endl
|
||||
<< "float sinPhi(vec3 v) { return v.y/sinTheta(v); }" << endl
|
||||
<< "float cosPhi(vec3 v) { return v.x/sinTheta(v); }" << endl
|
||||
<< endl;
|
||||
|
||||
std::string vplEvalName, bsdfEvalName, lumEvalName;
|
||||
|
|
|
@ -237,14 +237,17 @@ void Scene::configure() {
|
|||
Float maxExtents = std::max(extents.x, extents.y);
|
||||
Float distance = maxExtents/(2.0f * std::tan(45 * .5f * M_PI/180));
|
||||
|
||||
props.setTransform("toWorld", Transform::translate(Vector(center.x, center.y, aabb.min.z - distance)));
|
||||
props.setTransform("toWorld", Transform::translate(Vector(center.x,
|
||||
center.y, aabb.min.z - distance)));
|
||||
props.setFloat("fov", 45.0f);
|
||||
|
||||
m_camera = static_cast<Camera *> (PluginManager::getInstance()->createObject(MTS_CLASS(Camera), props));
|
||||
m_camera = static_cast<Camera *> (PluginManager::getInstance()->
|
||||
createObject(MTS_CLASS(Camera), props));
|
||||
m_camera->configure();
|
||||
m_sampler = m_camera->getSampler();
|
||||
} else {
|
||||
Log(EWarn, "Unable to set up a default camera -- does the scene contain anything at all?");
|
||||
Log(EWarn, "Unable to set up a default camera -- does the scene "
|
||||
"contain anything at all?");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -675,7 +675,7 @@ void GLWidget::mouseMoveEvent(QMouseEvent *event) {
|
|||
if (coords.x < 0 || coords.x > M_PI)
|
||||
m_context->up *= -1;
|
||||
|
||||
if (camera->getViewTransform().det3x3() < 0)
|
||||
if (camera->getViewTransform().det3x3() > 0)
|
||||
camera->setInverseViewTransform(Transform::lookAt(p, target, m_context->up));
|
||||
else
|
||||
camera->setInverseViewTransform(
|
||||
|
@ -693,7 +693,7 @@ void GLWidget::mouseMoveEvent(QMouseEvent *event) {
|
|||
* camera->getViewTransform();
|
||||
d = trafo.inverse()(Vector(0,0,1));
|
||||
|
||||
if (camera->getViewTransform().det3x3() < 0)
|
||||
if (camera->getViewTransform().det3x3() > 0)
|
||||
camera->setInverseViewTransform(Transform::lookAt(p, p+d, up));
|
||||
else
|
||||
camera->setInverseViewTransform(
|
||||
|
@ -713,7 +713,7 @@ void GLWidget::mouseMoveEvent(QMouseEvent *event) {
|
|||
Float roll = rel.x() * m_mouseSensitivity * .02f;
|
||||
Float fovChange = rel.y() * m_mouseSensitivity * .03f;
|
||||
|
||||
if (camera->getViewTransform().det3x3() < 0) {
|
||||
if (camera->getViewTransform().det3x3() > 0) {
|
||||
m_context->up = Transform::rotate(d, roll)(up);
|
||||
camera->setInverseViewTransform(Transform::lookAt(p, p+d, m_context->up));
|
||||
} else {
|
||||
|
@ -743,7 +743,7 @@ void GLWidget::mouseMoveEvent(QMouseEvent *event) {
|
|||
Vector d = Vector(camera->getImagePlaneNormal());
|
||||
p = p + (oldFocusDepth - focusDepth) * d;
|
||||
|
||||
if (camera->getViewTransform().det3x3() < 0)
|
||||
if (camera->getViewTransform().det3x3() > 0)
|
||||
camera->setInverseViewTransform(Transform::lookAt(p, p+d, up));
|
||||
else
|
||||
camera->setInverseViewTransform(
|
||||
|
@ -809,8 +809,13 @@ void GLWidget::wheelEvent(QWheelEvent *event) {
|
|||
Vector d = Vector(camera->getImagePlaneNormal());
|
||||
Point o = camera->getPosition() + (oldFocusDepth - focusDepth) * d;
|
||||
|
||||
camera->setInverseViewTransform(
|
||||
Transform::lookAt(o, o+d, up));
|
||||
if (camera->getViewTransform().det3x3() > 0)
|
||||
camera->setInverseViewTransform(Transform::lookAt(o, o+d, up));
|
||||
else
|
||||
camera->setInverseViewTransform(
|
||||
Transform::lookAt(o, o+d, up) *
|
||||
Transform::scale(Vector(-1,1,1))
|
||||
);
|
||||
|
||||
m_wheelTimer->reset();
|
||||
if (!m_movementTimer->isActive())
|
||||
|
|
|
@ -165,7 +165,7 @@ void saveScene(QWidget *parent, SceneContext *ctx, const QString &targetFile) {
|
|||
u = ctx->up;
|
||||
Point t, p = sceneCamera->getInverseViewTransform()(Point(0,0,0));
|
||||
|
||||
if (sceneCamera->getViewTransform().det3x3() > 0) {
|
||||
if (sceneCamera->getViewTransform().det3x3() < 0) {
|
||||
QDomElement scale = doc.createElement("scale");
|
||||
scale.setAttribute("x", "-1");
|
||||
cameraTransform.insertBefore(scale, lookAt);
|
||||
|
|
Loading…
Reference in New Issue