finished the roughdiffuse model, fixed a handedness switch in Transform::lookAt
parent
ac3935fa17
commit
873fe06277
|
@ -5,6 +5,9 @@
|
||||||
<!-- Test the smooth diffuse model -->
|
<!-- Test the smooth diffuse model -->
|
||||||
<bsdf type="diffuse"/>
|
<bsdf type="diffuse"/>
|
||||||
|
|
||||||
|
<!-- Test the rough diffuse model -->
|
||||||
|
<bsdf type="roughdiffuse"/>
|
||||||
|
|
||||||
<!-- Test the diffuse transmission model -->
|
<!-- Test the diffuse transmission model -->
|
||||||
<bsdf type="difftrans"/>
|
<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
|
set it to \texttt{illuminant} when defining the brightness of a
|
||||||
light source with the \texttt{<rgb>} tag.
|
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
|
(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
|
the scene description. For this reason, there is yet another way to pass
|
||||||
a spectrum by loading it from an external
|
a spectrum by loading it from an external file:
|
||||||
file:
|
|
||||||
\begin{xml}
|
\begin{xml}
|
||||||
<spectrum name="spectrumProperty" filename="measuredSpectrum.spd"/>
|
<spectrum name="spectrumProperty" filename="measuredSpectrum.spd"/>
|
||||||
\end{xml}
|
\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
|
wavelength in nanometers and the measured value separated by a space. Comments
|
||||||
are allowed. Here is an example:
|
are allowed. Here is an example:
|
||||||
\begin{xml}
|
\begin{xml}
|
||||||
# This file contains a measured spectral power distribution
|
# This file contains a measured spectral power/reflectance distribution
|
||||||
406.13 0.703313
|
406.13 0.703313
|
||||||
413.88 0.744563
|
413.88 0.744563
|
||||||
422.03 0.791625
|
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
|
%\toprule
|
||||||
\\[-2.2ex]
|
\\[-2.2ex]
|
||||||
\textbf{Parameter}&\textbf{Type}&\textbf{Description}\\
|
\textbf{Parameter}&\textbf{Type}&\textbf{Description}\\
|
||||||
\otoprule
|
|
||||||
#1
|
#1
|
||||||
%\bottomrule
|
|
||||||
\end{tabular}}
|
\end{tabular}}
|
||||||
\end{figure}
|
\end{figure}
|
||||||
\setlength\fboxrule\fboxrulebackup
|
\setlength\fboxrule\fboxrulebackup
|
||||||
|
@ -60,12 +58,8 @@
|
||||||
\newcommand{\smallrendering}[2]{ \subfigure[#1]{\fbox{\includegraphics[width=0.2\textwidth]{images/#2}}}\hfill}
|
\newcommand{\smallrendering}[2]{ \subfigure[#1]{\fbox{\includegraphics[width=0.2\textwidth]{images/#2}}}\hfill}
|
||||||
|
|
||||||
\newcommand{\parameter}[3]{
|
\newcommand{\parameter}[3]{
|
||||||
\small\texttt{#1} & \small #2 & \small #3\\
|
|
||||||
\otoprule
|
\otoprule
|
||||||
|
\small\texttt{#1} & \small #2 & \small #3 \\
|
||||||
}
|
}
|
||||||
|
|
||||||
\newcommand{\lastparameter}[3]{
|
|
||||||
\small\texttt{#1} & \small #2 & \small #3\\
|
|
||||||
}
|
|
||||||
|
|
||||||
\newcommand{\default}[1]{ (Default: #1)}
|
\newcommand{\default}[1]{ (Default: #1)}
|
||||||
|
|
|
@ -1,4 +1,16 @@
|
||||||
\subsection{Surface scattering models}
|
\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}
|
\label{sec:bsdfs}
|
||||||
Surface scattering models describe the manner in which light interacts
|
Surface scattering models describe the manner in which light interacts
|
||||||
with surfaces in the scene. They conveniently summarize the mesoscopic
|
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
|
This section presents an overview of all surface scattering models that are
|
||||||
supported, along with their parameters.
|
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}
|
\subsubsection*{BSDFs}
|
||||||
To achieve realistic results, Mitsuba comes with a library of both
|
To achieve realistic results, Mitsuba comes with a library of both
|
||||||
general-purpose surface scattering models (smooth or rough glass, metal,
|
general-purpose surface scattering models (smooth or rough glass, metal,
|
||||||
plastic, etc.) and specializations to particular materials (woven cloth,
|
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.
|
as \emph{modifiers} that are applied on top of one or more scattering models.
|
||||||
|
|
||||||
Throughout the documentation and within the scene description
|
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
|
It is generally more economical to use named BSDFs when they
|
||||||
are used in several places, since this reduces Mitsuba's internal
|
are used in several places, since this reduces Mitsuba's internal
|
||||||
memory usage.
|
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;
|
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
|
/// Return a string representation of this frame
|
||||||
inline std::string toString() const {
|
inline std::string toString() const {
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
|
|
|
@ -32,7 +32,7 @@ MTS_NAMESPACE_BEGIN
|
||||||
* \parameter{k}{\Spectrum}{Imaginary part of the material's index of
|
* \parameter{k}{\Spectrum}{Imaginary part of the material's index of
|
||||||
* refraction, also known as absorption coefficient.
|
* refraction, also known as absorption coefficient.
|
||||||
* \default{based on the value of \texttt{material}}}
|
* \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
|
* Optional factor used to modulate the reflectance component
|
||||||
* \default{1.0}}
|
* \default{1.0}}
|
||||||
* }
|
* }
|
||||||
|
|
|
@ -31,7 +31,7 @@ MTS_NAMESPACE_BEGIN
|
||||||
* numerically or using a known material name. \default{\texttt{air} / 1.000277}}
|
* numerically or using a known material name. \default{\texttt{air} / 1.000277}}
|
||||||
* \parameter{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}}
|
* 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}}
|
* factor used to modulate the transmittance component\default{1.0}}
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
|
|
|
@ -25,7 +25,7 @@ MTS_NAMESPACE_BEGIN
|
||||||
/*! \plugin{difftrans}{Diffuse transmitter}
|
/*! \plugin{difftrans}{Diffuse transmitter}
|
||||||
*
|
*
|
||||||
* \parameters{
|
* \parameters{
|
||||||
* \lastparameter{transmittance}{\Spectrum\Or\Texture}{
|
* \parameter{transmittance}{\Spectrum\Or\Texture}{
|
||||||
* Specifies the diffuse transmittance of the material
|
* Specifies the diffuse transmittance of the material
|
||||||
* \default{0.5}
|
* \default{0.5}
|
||||||
* }
|
* }
|
||||||
|
|
|
@ -25,17 +25,20 @@ MTS_NAMESPACE_BEGIN
|
||||||
/*!\plugin{diffuse}{Smooth diffuse material}
|
/*!\plugin{diffuse}{Smooth diffuse material}
|
||||||
* \order{1}
|
* \order{1}
|
||||||
* \parameters{
|
* \parameters{
|
||||||
* \lastparameter{reflectance}{\Spectrum\Or\Texture}{
|
* \parameter{reflectance}{\Spectrum\Or\Texture}{
|
||||||
* Specifies the diffuse reflectance / albedo of the material \linebreak(Default: 0.5)
|
* Specifies the diffuse albedo of the
|
||||||
|
* material \default{0.5}
|
||||||
* }
|
* }
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
* \renderings{
|
* \renderings{
|
||||||
* \rendering{Homogeneous reflectance, see \lstref{diffuse-uniform}}{bsdf_diffuse_plain}
|
* \rendering{Homogeneous reflectance, see \lstref{diffuse-uniform}}
|
||||||
* \rendering{Textured reflectance, see \lstref{diffuse-textured}}{bsdf_diffuse_textured}
|
* {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
|
* represents an ideally diffuse material with a user-specified amount of
|
||||||
* reflectance. Any received illumination is scattered so that the surface
|
* reflectance. Any received illumination is scattered so that the surface
|
||||||
* looks the same independently of the direction of observation.
|
* looks the same independently of the direction of observation.
|
||||||
|
@ -51,13 +54,15 @@ MTS_NAMESPACE_BEGIN
|
||||||
* consider using the \pluginref{twosided} BRDF adapter plugin.
|
* consider using the \pluginref{twosided} BRDF adapter plugin.
|
||||||
* \vspace{4mm}
|
* \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">
|
* <bsdf type="diffuse">
|
||||||
* <srgb name="reflectance" value="#6d7185"/>
|
* <srgb name="reflectance" value="#6d7185"/>
|
||||||
* </bsdf>
|
* </bsdf>
|
||||||
* \end{xml}
|
* \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">
|
* <bsdf type="diffuse">
|
||||||
* <texture type="bitmap" name="reflectance">
|
* <texture type="bitmap" name="reflectance">
|
||||||
* <string name="filename" value="wood.jpg"/>
|
* <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}}
|
* numerically or using a known material name. \default{\texttt{air} / 1.000277}}
|
||||||
* \parameter{specular\showbreak Reflectance}{\Spectrum\Or\Texture}{Optional
|
* \parameter{specular\showbreak Reflectance}{\Spectrum\Or\Texture}{Optional
|
||||||
* factor used to modulate the specular component\default{1.0}}
|
* 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}}
|
* factor used to modulate the diffuse component\default{0.5}}
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
|
|
|
@ -62,7 +62,7 @@ MTS_NAMESPACE_BEGIN
|
||||||
* \default{0.1}.
|
* \default{0.1}.
|
||||||
* }
|
* }
|
||||||
* \parameter{alphaU, alphaV}{\Float\Or\Texture}{
|
* \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
|
* bitangent directions. These parameter are only valid when
|
||||||
* \texttt{distribution=as}. \default{0.1}.
|
* \texttt{distribution=as}. \default{0.1}.
|
||||||
* }
|
* }
|
||||||
|
@ -73,7 +73,7 @@ MTS_NAMESPACE_BEGIN
|
||||||
* \parameter{k}{\Spectrum}{Imaginary part of the material's index of
|
* \parameter{k}{\Spectrum}{Imaginary part of the material's index of
|
||||||
* refraction, also known as absorption coefficient.
|
* refraction, also known as absorption coefficient.
|
||||||
* \default{based on the value of \texttt{material}}}
|
* \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}}
|
* factor used to modulate the reflectance component\default{1.0}}
|
||||||
* }
|
* }
|
||||||
* This plugin implements a realistic microfacet scattering model for rendering
|
* 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
|
* a value of $\alpha=0.001-0.01$ corresponds to a material
|
||||||
* with slight imperfections on an
|
* with slight imperfections on an
|
||||||
* otherwise smooth surface finish, $\alpha=0.1$ is relatively rough,
|
* 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).
|
* finish).
|
||||||
* \vspace{-2mm}
|
* \vspace{-2mm}
|
||||||
* \subsubsection*{Techical details}\vspace{-2mm}
|
* \subsubsection*{Techical details}\vspace{-2mm}
|
||||||
|
|
|
@ -59,7 +59,7 @@ MTS_NAMESPACE_BEGIN
|
||||||
* \default{0.1}.
|
* \default{0.1}.
|
||||||
* }
|
* }
|
||||||
* \parameter{alphaU, alphaV}{\Float\Or\Texture}{
|
* \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
|
* bitangent directions. These parameter are only valid when
|
||||||
* \texttt{distribution=as}. \default{0.1}.
|
* \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}}
|
* numerically or using a known material name. \default{\texttt{air} / 1.000277}}
|
||||||
* \parameter{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}}
|
* 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}}
|
* factor used to modulate the transmittance component\default{1.0}}
|
||||||
* }\vspace{4mm}
|
* }\vspace{4mm}
|
||||||
*
|
*
|
||||||
|
@ -111,7 +111,7 @@ MTS_NAMESPACE_BEGIN
|
||||||
* a value of $\alpha=0.001-0.01$ corresponds to a material
|
* a value of $\alpha=0.001-0.01$ corresponds to a material
|
||||||
* with slight imperfections on an
|
* with slight imperfections on an
|
||||||
* otherwise smooth surface finish, $\alpha=0.1$ is relatively rough,
|
* 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).
|
* finish).
|
||||||
*
|
*
|
||||||
* Please note that when using this plugin, it is crucial that the scene contains
|
* Please note that when using this plugin, it is crucial that the scene contains
|
||||||
|
@ -142,7 +142,7 @@ MTS_NAMESPACE_BEGIN
|
||||||
* \renderings{
|
* \renderings{
|
||||||
* \rendering{Ground glass (GGX, $\alpha$=0.304,
|
* \rendering{Ground glass (GGX, $\alpha$=0.304,
|
||||||
* \lstref{roughdielectric-roughglass})}{bsdf_roughdielectric_ggx_0_304.jpg}
|
* \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}
|
* {bsdf_roughdielectric_textured.jpg}
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
|
@ -467,7 +467,7 @@ public:
|
||||||
1. Take the Fresnel term with respect to the surface
|
1. Take the Fresnel term with respect to the surface
|
||||||
normal to be a good approximation to the microsurface
|
normal to be a good approximation to the microsurface
|
||||||
Fresnel term -- this will be less true for higher
|
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.
|
reasonable range.
|
||||||
2. Use this approximate term and a random number to
|
2. Use this approximate term and a random number to
|
||||||
choose between reflection and refraction component.
|
choose between reflection and refraction component.
|
||||||
|
@ -595,7 +595,7 @@ public:
|
||||||
1. Take the Fresnel term with respect to the surface
|
1. Take the Fresnel term with respect to the surface
|
||||||
normal to be a good approximation to the microsurface
|
normal to be a good approximation to the microsurface
|
||||||
Fresnel term -- this will be less true for higher
|
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.
|
reasonable range.
|
||||||
2. Use this approximate term and a random number to
|
2. Use this approximate term and a random number to
|
||||||
choose between reflection and refraction component.
|
choose between reflection and refraction component.
|
||||||
|
|
|
@ -21,60 +21,65 @@
|
||||||
|
|
||||||
MTS_NAMESPACE_BEGIN
|
MTS_NAMESPACE_BEGIN
|
||||||
|
|
||||||
/*!\plugin{diffuse}{Rough diffuse material}
|
/*!\plugin{roughdiffuse}{Rough diffuse material}
|
||||||
* \order{2}
|
* \order{2}
|
||||||
* \parameters{
|
* \parameters{
|
||||||
* \parameter{reflectance}{\Spectrum\Or\Texture}{
|
* \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}{
|
* \parameter{alpha}{\Spectrum\Or\Texture}{
|
||||||
* Specifies the roughness of the unresolved surface microgeometry.
|
* Specifies the roughness of the unresolved surface microgeometry
|
||||||
* This parameter is approximately equal to the \emph{root mean square}
|
* using the \emph{root mean square} (RMS) slope of the
|
||||||
* (RMS) slope of the microfacets.\default{0.1}
|
* 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{
|
* \renderings{
|
||||||
* \rendering{Homogeneous reflectance, see \lstref{diffuse-uniform}}{bsdf_diffuse_plain}
|
* \rendering{Smooth diffuse surface ($\alpha=0$)}
|
||||||
* \rendering{Textured reflectance, see \lstref{diffuse-textured}}{bsdf_diffuse_textured}
|
* {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,
|
* This reflectance model describes the interaction of light with a rough
|
||||||
* such as plaster, sand, clay, or concrete.
|
* diffuse material, such as plaster, sand, clay, or concrete.
|
||||||
* The underlying theory was developed by Oren and Nayar
|
* The underlying theory was developed by Oren and Nayar
|
||||||
* \cite{Oren1994Generalization}, who model the microscopic surface structure as
|
* \cite{Oren1994Generalization}, who model the microscopic surface structure as
|
||||||
* unresolved planar facets arranged in V-shaped grooves, where each facet
|
* unresolved planar facets arranged in V-shaped grooves, where each facet
|
||||||
* is an ideal diffuse reflector. The model takes into account shadowing,
|
* is an ideal diffuse reflector. The model takes into account shadowing,
|
||||||
* masking, as well as interreflections between the facets.
|
* 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
|
* be a good match for many real-world materials, particularly compared
|
||||||
* to Lambertian scattering, which does not take surface roughness into account.
|
* to Lambertian scattering, which does not take surface roughness into account.
|
||||||
*
|
*
|
||||||
* The implementation in Mitsuba uses a surface roughness parameter $\alpha$ that
|
* 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
|
* 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}).
|
* \pluginref{roughconductor}).
|
||||||
*
|
*
|
||||||
* To get an intuition about the effect of the
|
* To get an intuition about the effect of the
|
||||||
* parameter $\alpha$, consider the following approximate differentiation:
|
* parameter $\alpha$, consider the following approximate differentiation:
|
||||||
* a value of $\alpha=0.001-0.01$ corresponds to a material
|
* a value of $\alpha=0.001-0.01$ corresponds to a material
|
||||||
* with slight imperfections on an otherwise smooth surface (for such small
|
* with slight imperfections on an otherwise smooth surface (for such small
|
||||||
* values, the model will behave almost identically to \pluginref{diffuse}), $\alpha=0.1$
|
* values, the model will behave identically to \pluginref{diffuse}), $\alpha=0.1$
|
||||||
* is relatively rough, and $\alpha=0.3-0.5$ is \emph{extremely} rough
|
* is relatively rough, and $\alpha=0.3-0.7$ is \emph{extremely} rough
|
||||||
* (e.g. an etched or ground surface).
|
* (e.g. an etched or ground surface).
|
||||||
*
|
*
|
||||||
* Note that this material is one-sided---that is, observed from the
|
* Note that this material is one-sided---that is, observed from the
|
||||||
* back side, it will be completely black. If this is undesirable,
|
* back side, it will be completely black. If this is undesirable,
|
||||||
* consider using the \pluginref{twosided} BRDF adapter plugin.
|
* 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 {
|
class RoughDiffuse : public BSDF {
|
||||||
public:
|
public:
|
||||||
|
@ -84,9 +89,11 @@ public:
|
||||||
'reflectance' and 'diffuseReflectance' as parameter names */
|
'reflectance' and 'diffuseReflectance' as parameter names */
|
||||||
m_reflectance = new ConstantSpectrumTexture(props.getSpectrum(
|
m_reflectance = new ConstantSpectrumTexture(props.getSpectrum(
|
||||||
props.hasProperty("reflectance") ? "reflectance"
|
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_components.push_back(EGlossyReflection | EFrontSide);
|
||||||
m_usesRayDifferentials = false;
|
m_usesRayDifferentials = false;
|
||||||
}
|
}
|
||||||
|
@ -95,6 +102,7 @@ public:
|
||||||
: BSDF(stream, manager) {
|
: BSDF(stream, manager) {
|
||||||
m_reflectance = static_cast<Texture *>(manager->getInstance(stream));
|
m_reflectance = static_cast<Texture *>(manager->getInstance(stream));
|
||||||
m_alpha = 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_components.push_back(EGlossyReflection | EFrontSide);
|
||||||
m_usesRayDifferentials = m_reflectance->usesRayDifferentials();
|
m_usesRayDifferentials = m_reflectance->usesRayDifferentials();
|
||||||
}
|
}
|
||||||
|
@ -110,7 +118,7 @@ public:
|
||||||
|
|
||||||
Spectrum eval(const BSDFQueryRecord &bRec, EMeasure measure) const {
|
Spectrum eval(const BSDFQueryRecord &bRec, EMeasure measure) const {
|
||||||
if (!(bRec.typeMask & EGlossyReflection) || measure != ESolidAngle
|
if (!(bRec.typeMask & EGlossyReflection) || measure != ESolidAngle
|
||||||
|| Frame::cosTheta(bRec.wi) <= 0
|
|| Frame::cosTheta(bRec.wi) <= 0
|
||||||
|| Frame::cosTheta(bRec.wo) <= 0)
|
|| Frame::cosTheta(bRec.wo) <= 0)
|
||||||
return Spectrum(0.0f);
|
return Spectrum(0.0f);
|
||||||
|
|
||||||
|
@ -124,12 +132,80 @@ public:
|
||||||
Float sigma = m_alpha->getValue(bRec.its).average()
|
Float sigma = m_alpha->getValue(bRec.its).average()
|
||||||
* conversionFactor;
|
* conversionFactor;
|
||||||
|
|
||||||
Float sigma2 = sigma*sigma;
|
const Float sigma2 = sigma*sigma;
|
||||||
Float A = 10.f - (sigma2 / (2.0f * (sigma2 + 0.33f)));
|
|
||||||
Float B = 0.45f * sigma2 / (sigma2 + 0.09f);
|
|
||||||
|
|
||||||
return m_reflectance->getValue(bRec.its)
|
Float sinThetaI = Frame::sinTheta(bRec.wi),
|
||||||
* (INV_PI * Frame::cosTheta(bRec.wo));
|
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 {
|
Float pdf(const BSDFQueryRecord &bRec, EMeasure measure) const {
|
||||||
|
@ -148,7 +224,8 @@ public:
|
||||||
bRec.wo = squareToHemispherePSA(sample);
|
bRec.wo = squareToHemispherePSA(sample);
|
||||||
bRec.sampledComponent = 0;
|
bRec.sampledComponent = 0;
|
||||||
bRec.sampledType = EGlossyReflection;
|
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 {
|
Spectrum sample(BSDFQueryRecord &bRec, Float &pdf, const Point2 &sample) const {
|
||||||
|
@ -159,8 +236,7 @@ public:
|
||||||
bRec.sampledComponent = 0;
|
bRec.sampledComponent = 0;
|
||||||
bRec.sampledType = EGlossyReflection;
|
bRec.sampledType = EGlossyReflection;
|
||||||
pdf = Frame::cosTheta(bRec.wo) * INV_PI;
|
pdf = Frame::cosTheta(bRec.wo) * INV_PI;
|
||||||
return m_reflectance->getValue(bRec.its)
|
return eval(bRec, ESolidAngle);
|
||||||
* (INV_PI * Frame::cosTheta(bRec.wo));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void addChild(const std::string &name, ConfigurableObject *child) {
|
void addChild(const std::string &name, ConfigurableObject *child) {
|
||||||
|
@ -182,6 +258,7 @@ public:
|
||||||
|
|
||||||
manager->serialize(stream, m_reflectance.get());
|
manager->serialize(stream, m_reflectance.get());
|
||||||
manager->serialize(stream, m_alpha.get());
|
manager->serialize(stream, m_alpha.get());
|
||||||
|
stream->writeBool(m_useFastApprox);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string toString() const {
|
std::string toString() const {
|
||||||
|
@ -189,7 +266,8 @@ public:
|
||||||
oss << "RoughDiffuse[" << endl
|
oss << "RoughDiffuse[" << endl
|
||||||
<< " name = \"" << getName() << "\"," << endl
|
<< " name = \"" << getName() << "\"," << endl
|
||||||
<< " reflectance = " << indent(m_reflectance->toString()) << "," << 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();
|
return oss.str();
|
||||||
}
|
}
|
||||||
|
@ -200,6 +278,7 @@ public:
|
||||||
private:
|
private:
|
||||||
ref<Texture> m_reflectance;
|
ref<Texture> m_reflectance;
|
||||||
ref<Texture> m_alpha;
|
ref<Texture> m_alpha;
|
||||||
|
bool m_useFastApprox;
|
||||||
};
|
};
|
||||||
|
|
||||||
// ================ Hardware shader implementation ================
|
// ================ Hardware shader implementation ================
|
||||||
|
@ -233,11 +312,27 @@ public:
|
||||||
oss << "vec3 " << evalName << "(vec2 uv, vec3 wi, vec3 wo) {" << endl
|
oss << "vec3 " << evalName << "(vec2 uv, vec3 wi, vec3 wo) {" << endl
|
||||||
<< " if (cosTheta(wi) < 0.0 || cosTheta(wo) < 0.0)" << endl
|
<< " if (cosTheta(wi) < 0.0 || cosTheta(wo) < 0.0)" << endl
|
||||||
<< " return vec3(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
|
||||||
<< endl
|
<< endl
|
||||||
<< "vec3 " << evalName << "_diffuse(vec2 uv, vec3 wi, vec3 wo) {" << 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;
|
<< "}" << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1103,7 +1103,7 @@ void loadCamera(ColladaContext &ctx, Transform transform, domCamera &camera) {
|
||||||
int xres=768;
|
int xres=768;
|
||||||
|
|
||||||
// Cameras in Mitsuba point along the positive Z axis (COLLADA: neg. Z)
|
// 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;
|
std::ostringstream matrix;
|
||||||
for (int i=0; i<4; ++i)
|
for (int i=0; i<4; ++i)
|
||||||
|
@ -1130,14 +1130,8 @@ void loadCamera(ColladaContext &ctx, Transform transform, domCamera &camera) {
|
||||||
xres = ctx.cvt->m_xres;
|
xres = ctx.cvt->m_xres;
|
||||||
aspect = (Float) ctx.cvt->m_xres / (Float) ctx.cvt->m_yres;
|
aspect = (Float) ctx.cvt->m_xres / (Float) ctx.cvt->m_yres;
|
||||||
} else {
|
} else {
|
||||||
if (persp->getAspect_ratio().cast() != 0) {
|
if (persp->getAspect_ratio().cast() != 0)
|
||||||
aspect = (Float) persp->getAspect_ratio()->getValue();
|
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;
|
ctx.os << "\t<camera id=\"" << identifier << "\" type=\"perspective\">" << endl;
|
||||||
if (persp->getXfov().cast()) {
|
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) {
|
Transform Transform::lookAt(const Point &p, const Point &t, const Vector &up) {
|
||||||
Matrix4x4 result;
|
Matrix4x4 result;
|
||||||
|
|
||||||
Vector dirct = normalize(t-p);
|
Vector dir = normalize(t-p);
|
||||||
Vector right = normalize(cross(dirct, up));
|
Vector left = normalize(cross(normalize(up), dir));
|
||||||
|
|
||||||
/* Generate a new, orthogonalized up vector */
|
/* Generate a new, orthogonalized up vector */
|
||||||
Vector newUp = cross(right, dirct);
|
Vector newUp = cross(dir, left);
|
||||||
|
|
||||||
/* Store as columns */
|
/* 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][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;
|
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);
|
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 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;
|
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();
|
const Matrix4x4 &viewMatrix = lightViewTrafo.getMatrix();
|
||||||
m_shadowProgram->setParameter(m_shadowProgramParam_cubeMapTransform[i], lightProjTrafo * lightViewTrafo);
|
m_shadowProgram->setParameter(m_shadowProgramParam_cubeMapTransform[i], lightProjTrafo * lightViewTrafo);
|
||||||
m_shadowProgram->setParameter(m_shadowProgramParam_depthVec[i], Vector4(
|
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 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;
|
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();
|
const Matrix4x4 &viewMatrix = lightViewTrafo.getMatrix();
|
||||||
|
|
||||||
m_altShadowProgram->setParameter(m_altShadowProgramParam_cubeMapTransform, lightProjTrafo * lightViewTrafo);
|
m_altShadowProgram->setParameter(m_altShadowProgramParam_cubeMapTransform, lightProjTrafo * lightViewTrafo);
|
||||||
|
@ -368,13 +370,6 @@ void VPLShaderManager::configure(const VPL &vpl, const BSDF *bsdf,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
if (bsdfShader->getFlags() & Shader::ETransparent) {
|
|
||||||
m_renderer->setColor(Spectrum(1.0f), 0.3f);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
bool anisotropic = bsdf->getType() & BSDF::EAnisotropic;
|
bool anisotropic = bsdf->getType() & BSDF::EAnisotropic;
|
||||||
|
|
||||||
m_targetConfig = VPLProgramConfiguration(vplShader, bsdfShader,
|
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 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 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 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;
|
<< endl;
|
||||||
|
|
||||||
std::string vplEvalName, bsdfEvalName, lumEvalName;
|
std::string vplEvalName, bsdfEvalName, lumEvalName;
|
||||||
|
|
|
@ -237,14 +237,17 @@ void Scene::configure() {
|
||||||
Float maxExtents = std::max(extents.x, extents.y);
|
Float maxExtents = std::max(extents.x, extents.y);
|
||||||
Float distance = maxExtents/(2.0f * std::tan(45 * .5f * M_PI/180));
|
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);
|
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_camera->configure();
|
||||||
m_sampler = m_camera->getSampler();
|
m_sampler = m_camera->getSampler();
|
||||||
} else {
|
} 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)
|
if (coords.x < 0 || coords.x > M_PI)
|
||||||
m_context->up *= -1;
|
m_context->up *= -1;
|
||||||
|
|
||||||
if (camera->getViewTransform().det3x3() < 0)
|
if (camera->getViewTransform().det3x3() > 0)
|
||||||
camera->setInverseViewTransform(Transform::lookAt(p, target, m_context->up));
|
camera->setInverseViewTransform(Transform::lookAt(p, target, m_context->up));
|
||||||
else
|
else
|
||||||
camera->setInverseViewTransform(
|
camera->setInverseViewTransform(
|
||||||
|
@ -693,7 +693,7 @@ void GLWidget::mouseMoveEvent(QMouseEvent *event) {
|
||||||
* camera->getViewTransform();
|
* camera->getViewTransform();
|
||||||
d = trafo.inverse()(Vector(0,0,1));
|
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));
|
camera->setInverseViewTransform(Transform::lookAt(p, p+d, up));
|
||||||
else
|
else
|
||||||
camera->setInverseViewTransform(
|
camera->setInverseViewTransform(
|
||||||
|
@ -713,7 +713,7 @@ void GLWidget::mouseMoveEvent(QMouseEvent *event) {
|
||||||
Float roll = rel.x() * m_mouseSensitivity * .02f;
|
Float roll = rel.x() * m_mouseSensitivity * .02f;
|
||||||
Float fovChange = rel.y() * m_mouseSensitivity * .03f;
|
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);
|
m_context->up = Transform::rotate(d, roll)(up);
|
||||||
camera->setInverseViewTransform(Transform::lookAt(p, p+d, m_context->up));
|
camera->setInverseViewTransform(Transform::lookAt(p, p+d, m_context->up));
|
||||||
} else {
|
} else {
|
||||||
|
@ -743,7 +743,7 @@ void GLWidget::mouseMoveEvent(QMouseEvent *event) {
|
||||||
Vector d = Vector(camera->getImagePlaneNormal());
|
Vector d = Vector(camera->getImagePlaneNormal());
|
||||||
p = p + (oldFocusDepth - focusDepth) * d;
|
p = p + (oldFocusDepth - focusDepth) * d;
|
||||||
|
|
||||||
if (camera->getViewTransform().det3x3() < 0)
|
if (camera->getViewTransform().det3x3() > 0)
|
||||||
camera->setInverseViewTransform(Transform::lookAt(p, p+d, up));
|
camera->setInverseViewTransform(Transform::lookAt(p, p+d, up));
|
||||||
else
|
else
|
||||||
camera->setInverseViewTransform(
|
camera->setInverseViewTransform(
|
||||||
|
@ -809,8 +809,13 @@ void GLWidget::wheelEvent(QWheelEvent *event) {
|
||||||
Vector d = Vector(camera->getImagePlaneNormal());
|
Vector d = Vector(camera->getImagePlaneNormal());
|
||||||
Point o = camera->getPosition() + (oldFocusDepth - focusDepth) * d;
|
Point o = camera->getPosition() + (oldFocusDepth - focusDepth) * d;
|
||||||
|
|
||||||
camera->setInverseViewTransform(
|
if (camera->getViewTransform().det3x3() > 0)
|
||||||
Transform::lookAt(o, o+d, up));
|
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();
|
m_wheelTimer->reset();
|
||||||
if (!m_movementTimer->isActive())
|
if (!m_movementTimer->isActive())
|
||||||
|
|
|
@ -165,7 +165,7 @@ void saveScene(QWidget *parent, SceneContext *ctx, const QString &targetFile) {
|
||||||
u = ctx->up;
|
u = ctx->up;
|
||||||
Point t, p = sceneCamera->getInverseViewTransform()(Point(0,0,0));
|
Point t, p = sceneCamera->getInverseViewTransform()(Point(0,0,0));
|
||||||
|
|
||||||
if (sceneCamera->getViewTransform().det3x3() > 0) {
|
if (sceneCamera->getViewTransform().det3x3() < 0) {
|
||||||
QDomElement scale = doc.createElement("scale");
|
QDomElement scale = doc.createElement("scale");
|
||||||
scale.setAttribute("x", "-1");
|
scale.setAttribute("x", "-1");
|
||||||
cameraTransform.insertBefore(scale, lookAt);
|
cameraTransform.insertBefore(scale, lookAt);
|
||||||
|
|
Loading…
Reference in New Issue