finished the roughdiffuse model, fixed a handedness switch in Transform::lookAt

metadata
Wenzel Jakob 2011-07-11 01:34:17 +02:00
parent ac3935fa17
commit 873fe06277
22 changed files with 1133 additions and 140 deletions

View File

@ -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"/>

View File

@ -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

View File

@ -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)}

View File

@ -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.

View File

@ -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;

View File

@ -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}}
* }

View File

@ -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}}
* }
*

View File

@ -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}
* }

View File

@ -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"/>

View File

@ -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}}
* }
*

View File

@ -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}

View File

@ -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.

View File

@ -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;
}

View File

@ -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()) {

View File

@ -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);

View File

@ -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;

View File

@ -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?");
}
}

View File

@ -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())

View File

@ -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);