diff --git a/data/ior/Cu.eta.spd b/data/ior/Cu.eta.spd index 6765da4b..75686a6a 100644 --- a/data/ior/Cu.eta.spd +++ b/data/ior/Cu.eta.spd @@ -2,6 +2,7 @@ # ; Optical constants for Cu # ; # ; Lambda (A) n k +# ;----------------------------------------- 302.400421 1.380000 306.133759 1.358438 309.960449 1.340000 diff --git a/data/ior/Cu.k.spd b/data/ior/Cu.k.spd index e087d4a0..5ecd7a36 100644 --- a/data/ior/Cu.k.spd +++ b/data/ior/Cu.k.spd @@ -3,7 +3,6 @@ # ; # ; Lambda (A) n k # ;----------------------------------------- -298.757050 1.662125 302.400421 1.687000 306.133759 1.703313 309.960449 1.720000 diff --git a/data/tests/test_bsdf.xml b/data/tests/test_bsdf.xml index f87239e2..13cc8203 100644 --- a/data/tests/test_bsdf.xml +++ b/data/tests/test_bsdf.xml @@ -24,4 +24,7 @@ + + + diff --git a/doc/format.tex b/doc/format.tex index 2fd444f8..09d1f5e8 100644 --- a/doc/format.tex +++ b/doc/format.tex @@ -127,6 +127,7 @@ Passing strings is straightforward: \end{xml} \subsubsection{Color spectra} +\label{sec:format-spectra} Depending on the compilation flags of Mitsuba (see \secref{compiling-flags} for details), the renderer internally either represents colors using discretized color spectra (when \texttt{SPECTRUM\_SAMPLES} is set to a value other than 3), or it diff --git a/doc/images/bsdf_conductor_copper.jpg b/doc/images/bsdf_conductor_copper.jpg new file mode 100644 index 00000000..c5a91ad0 Binary files /dev/null and b/doc/images/bsdf_conductor_copper.jpg differ diff --git a/doc/images/bsdf_conductor_gold.jpg b/doc/images/bsdf_conductor_gold.jpg new file mode 100644 index 00000000..928005f1 Binary files /dev/null and b/doc/images/bsdf_conductor_gold.jpg differ diff --git a/doc/images/bsdf_difftrans.jpg b/doc/images/bsdf_difftrans.jpg new file mode 100644 index 00000000..b028704e Binary files /dev/null and b/doc/images/bsdf_difftrans.jpg differ diff --git a/doc/macros.sty b/doc/macros.sty index 5a569956..298bd7af 100644 --- a/doc/macros.sty +++ b/doc/macros.sty @@ -3,6 +3,7 @@ \newcommand{\figref}[1]{\mbox{Figure~\ref{fig:#1}}} \newcommand{\secref}[1]{\mbox{Section~\ref{sec:#1}}} \newcommand{\lstref}[1]{\mbox{Listing~\ref{lst:#1}}} +\newcommand{\tblref}[1]{\mbox{Table~\ref{tbl:#1}}} \newcommand{\code}[1]{\texttt{#1}} % Macros that are used in the plugin documentation diff --git a/doc/main.bib b/doc/main.bib index 684f447d..55bf548b 100644 --- a/doc/main.bib +++ b/doc/main.bib @@ -21,3 +21,10 @@ year = {2005}, publisher = {AK Peters, Ltd.} } + +@book{Palik1998Handbook, + title = {Handbook of optical constants of solids}, + author = {Palik, E.D. and Ghosh, G.}, + year = {1998}, + publisher = {Academic press} +} diff --git a/include/mitsuba/core/util.h b/include/mitsuba/core/util.h index 3f181310..bd24e8db 100644 --- a/include/mitsuba/core/util.h +++ b/include/mitsuba/core/util.h @@ -453,14 +453,14 @@ extern MTS_EXPORT_CORE Float fresnel(Float cosThetaI, Float etaExt, * Calculates the unpolarized fresnel reflection coefficient on * an interface to a conductor. * - * \param cosTheta + * \param cosThetaI * Cosine of the angle between the normal and the incident ray * \param eta - * Relative refractive index (per wavelength) + * Real refractive index (wavelength-dependent) * \param k - * Absorption coefficient (per wavelength) + * Imaginary refractive index (wavelength-dependent) */ -extern MTS_EXPORT_CORE Spectrum fresnelConductor(Float cosTheta, +extern MTS_EXPORT_CORE Spectrum fresnelConductor(Float cosThetaI, const Spectrum &eta, const Spectrum &k); /*! @} */ diff --git a/src/bsdfs/SConscript b/src/bsdfs/SConscript index 3611a22f..28cf464d 100644 --- a/src/bsdfs/SConscript +++ b/src/bsdfs/SConscript @@ -6,7 +6,7 @@ plugins += env.SharedLibrary('conductor', ['conductor.cpp']) plugins += env.SharedLibrary('diffuse', ['diffuse.cpp']) #plugins += env.SharedLibrary('plastic', ['plastic.cpp']) -#plugins += env.SharedLibrary('roughdielectric', ['roughdielectric.cpp']) +plugins += env.SharedLibrary('roughdielectric', ['roughdielectric.cpp']) #plugins += env.SharedLibrary('roughconductor', ['roughconductor.cpp']) #plugins += env.SharedLibrary('roughdiffuse', ['roughdiffuse.cpp']) #plugins += env.SharedLibrary('roughplastic', ['roughplastic.cpp']) diff --git a/src/bsdfs/coating.cpp b/src/bsdfs/coating.cpp index 97d40ce0..33d7ee14 100644 --- a/src/bsdfs/coating.cpp +++ b/src/bsdfs/coating.cpp @@ -21,7 +21,7 @@ MTS_NAMESPACE_BEGIN -/*! \plugin{varnish}{Smooth varnish layer} +/*! \plugin{coating}{Smooth coating layer} * * \parameters{ * \parameter{intIOR}{\Float}{Interior index of refraction \default{1.5046}} diff --git a/src/bsdfs/conductor.cpp b/src/bsdfs/conductor.cpp index c684976c..81b4c3a3 100644 --- a/src/bsdfs/conductor.cpp +++ b/src/bsdfs/conductor.cpp @@ -18,13 +18,75 @@ #include #include -#include "ior.h" +#include MTS_NAMESPACE_BEGIN /*! \plugin{conductor}{Smooth conductor} + * \parameters{ + * \parameter{preset}{\String}{Name of a material preset, see \tblref{conductor-iors}.\!\default{\texttt{Cu} / copper}} + * \parameter{eta}{\Spectrum}{Real part of the material's index of refraction \default{based on the value of \texttt{preset}}} + * \parameter{k}{\Spectrum}{Imaginary part of the material's index of refraction, also known as absorption coefficient. + * \default{based on the value of \texttt{preset}}} + * \lastparameter{specular\showbreak Reflectance}{\Spectrum\Or\Texture}{Optional + * factor used to modulate the reflectance component\default{1.0}} + * } + * \renderings{ + * \rendering{Measured copper material (the default)}{bsdf_conductor_copper.jpg} + * \rendering{Measured gold material (\lstref{conductor-gold})}{bsdf_conductor_gold.jpg} + * } + + * This plugin implements a perfectly smooth interface to a conducting material, + * such as a metal. For a similar model that instead describes a rough surface + * microstructure, take a look at the seperately available + * \pluginref{roughconductor} plugin. + + * In contrast to dielectric materials, conductors do not transmit + * any light. Their index of refraction is complex-valued and tends to undergo + * considerable changes throughout the visible color spectrum. + * + * To faciliate the tedious task of specifying spectrally-varying index of + * refraction information, Mitsuba ships with a set of measured data for a + * several materials, where visible-spectrum information was publicly available\footnote{ + * These index of refraction values are identical to the data distributed with PBRT. + * They are originally from the Luxpop database (\url{www.luxpop.com}) and + * are based on data by Palik et al. \cite{Palik1998Handbook} and measurements + * of atomic scattering factors made by the Center For X-Ray Optics (CXRO) + * at Berkeley and the Lawrence Livermore National Laboratory (LLNL). + * }. + * + * Note that \tblref{conductor-iors} also includes several popular optical coatings, which are + * not actually conductors. These materials can also be used with this plugin, + * though note that the plugin will ignore any refraction component that the actual + * material might have had. + * The table also contains a few birefingent materials, which are split into + * separate measurements correponding to their two indices of + * refraction (named ``ordinary'' and ``extraordinary ray''). * - * \begin{table} + * When using this plugin, you should compile Mitsuba with support for spectral + * renderings to get the most accurate results. While it also works in RGB mode, + * the computations will be much more approximate in this case. + * + * \begin{xml}[caption=Material configuration for a smooth conductor with measured gold data, label=lst:conductor-gold] + * + * + * + * + * + * \end{xml} + * \vspace{5mm} + * It is also possible to load spectrally varying index of refraction data from + * two external files (see \secref{format-spectra} for details on the file format): + * \begin{xml}[caption=Rendering a smooth conductor with custom data] + * + * + * + * + * + * + * \end{xml} + * \vspace{1.5cm} + * \begin{table}[hb!] * \centering * \scriptsize * \begin{tabular}{>{\ttfamily}llp{1mm}>{\ttfamily}ll} @@ -55,24 +117,33 @@ MTS_NAMESPACE_BEGIN * \bottomrule * \end{tabular} * \caption{ - * \label{tbl:dielectric-iors} + * \label{tbl:conductor-iors} * This table lists all supported material names that can be passed into the - * \pluginref{conductor} plugin. In most cases, there are two separate - * measurements of the same material made using different approaches. + * \pluginref{conductor} plugin. Note that some of them are not actually + * conductors---this is not a problem, they can be used regardless (though only + * the reflection component and no transmission will be simulated). + * In most cases, there are multiple entries for each material, which + * represent different measurements. * } * \end{table} - ** */ class SmoothConductor : public BSDF { public: SmoothConductor(const Properties &props) : BSDF(props) { + ref fResolver = Thread::getThread()->getFileResolver(); + m_specularReflectance = new ConstantSpectrumTexture( props.getSpectrum("specularReflectance", Spectrum(1.0f))); std::string preset = props.getString("preset", "Cu"); + Spectrum presetEta, presetK; + presetEta.fromContinuousSpectrum(InterpolatedSpectrum( + fResolver->resolve("data/ior/" + preset + ".eta.spd"))); + presetK.fromContinuousSpectrum(InterpolatedSpectrum( + fResolver->resolve("data/ior/" + preset + ".k.spd"))); - //m_eta = props.getSpectrum("eta", presetEta); -// m_k = props.getSpectrum("k", presetK); + m_eta = props.getSpectrum("eta", presetEta); + m_k = props.getSpectrum("k", presetK); m_components.push_back(EDeltaReflection | EFrontSide); m_usesRayDifferentials = false; @@ -106,20 +177,63 @@ public: } } - Spectrum sample(BSDFQueryRecord &bRec, const Point2 &sample) const { - return Spectrum(0.0f); + /// Reflection in local coordinates + inline Vector reflect(const Vector &wi) const { + return Vector(-wi.x, -wi.y, wi.z); } Spectrum eval(const BSDFQueryRecord &bRec, EMeasure measure) const { - return Spectrum(0.0f); - } + bool sampleReflection = (bRec.typeMask & EDeltaReflection) + && (bRec.component == -1 || bRec.component == 0); - Spectrum sample(BSDFQueryRecord &bRec, Float &pdf, const Point2 &sample) const { - return Spectrum(0.0f); + if (!sampleReflection || measure != EDiscrete || + Frame::cosTheta(bRec.wi) <= 0 || + Frame::cosTheta(bRec.wo) <= 0) + return Spectrum(0.0f); + + return m_specularReflectance->getValue(bRec.its) * + fresnelConductor(Frame::cosTheta(bRec.wi), m_eta, m_k); } Float pdf(const BSDFQueryRecord &bRec, EMeasure measure) const { - return 0.0f; + bool sampleReflection = (bRec.typeMask & EDeltaReflection) + && (bRec.component == -1 || bRec.component == 0); + if (!sampleReflection || measure != EDiscrete || + Frame::cosTheta(bRec.wi) <= 0 || + Frame::cosTheta(bRec.wo) <= 0) + return 0.0f; + return 1.0f; + } + + Spectrum sample(BSDFQueryRecord &bRec, const Point2 &sample) const { + bool sampleReflection = (bRec.typeMask & EDeltaReflection) + && (bRec.component == -1 || bRec.component == 0); + + if (!sampleReflection || Frame::cosTheta(bRec.wi) <= 0) + return Spectrum(0.0f); + + bRec.sampledComponent = 0; + bRec.sampledType = EDeltaReflection; + bRec.wo = reflect(bRec.wi); + + return m_specularReflectance->getValue(bRec.its) * + fresnelConductor(Frame::cosTheta(bRec.wi), m_eta, m_k); + } + + Spectrum sample(BSDFQueryRecord &bRec, Float &pdf, const Point2 &sample) const { + bool sampleReflection = (bRec.typeMask & EDeltaReflection) + && (bRec.component == -1 || bRec.component == 0); + + if (!sampleReflection || Frame::cosTheta(bRec.wi) <= 0) + return Spectrum(0.0f); + + bRec.sampledComponent = 0; + bRec.sampledType = EDeltaReflection; + bRec.wo = reflect(bRec.wi); + pdf = 1; + + return m_specularReflectance->getValue(bRec.its) * + fresnelConductor(Frame::cosTheta(bRec.wi), m_eta, m_k); } std::string toString() const { diff --git a/src/bsdfs/dielectric.cpp b/src/bsdfs/dielectric.cpp index 853bfcf5..3e4ad269 100644 --- a/src/bsdfs/dielectric.cpp +++ b/src/bsdfs/dielectric.cpp @@ -196,6 +196,54 @@ public: return Vector(-eta*wi.x, -eta*wi.y, cosThetaT); } + Spectrum eval(const BSDFQueryRecord &bRec, EMeasure measure) const { + bool sampleReflection = (bRec.typeMask & EDeltaReflection) + && (bRec.component == -1 || bRec.component == 0); + bool sampleTransmission = (bRec.typeMask & EDeltaTransmission) + && (bRec.component == -1 || bRec.component == 1); + bool reflection = Frame::cosTheta(bRec.wo) * Frame::cosTheta(bRec.wi) > 0; + + if ((reflection && !sampleReflection) || + (!reflection && !sampleTransmission) || measure != EDiscrete) + return Spectrum(0.0f); + + Float fr = fresnel(Frame::cosTheta(bRec.wi), m_extIOR, m_intIOR); + + if (reflection) { + return m_specularReflectance->getValue(bRec.its) * fr; + } else { + Float etaI = m_extIOR, etaT = m_intIOR; + bool entering = Frame::cosTheta(bRec.wi) > 0.0f; + if (!entering) + std::swap(etaI, etaT); + + Float factor = (bRec.quantity == ERadiance) + ? (etaI*etaI) / (etaT*etaT) : 1.0f; + + return m_specularTransmittance->getValue(bRec.its) * factor * (1 - fr); + } + } + + Float pdf(const BSDFQueryRecord &bRec, EMeasure measure) const { + bool sampleReflection = (bRec.typeMask & EDeltaReflection) + && (bRec.component == -1 || bRec.component == 0); + bool sampleTransmission = (bRec.typeMask & EDeltaTransmission) + && (bRec.component == -1 || bRec.component == 1); + bool reflection = Frame::cosTheta(bRec.wo) + * Frame::cosTheta(bRec.wi) > 0; + + if ((reflection && !sampleReflection) || + (!reflection && !sampleTransmission) || measure != EDiscrete) + return 0.0f; + + if (sampleTransmission && sampleReflection) { + Float Fr = fresnel(Frame::cosTheta(bRec.wi), m_extIOR, m_intIOR); + return reflection ? Fr : (1 - Fr); + } else { + return 1.0f; + } + } + Spectrum sample(BSDFQueryRecord &bRec, const Point2 &sample) const { bool sampleReflection = (bRec.typeMask & EDeltaReflection) && (bRec.component == -1 || bRec.component == 0); @@ -278,54 +326,6 @@ public: } } - Spectrum eval(const BSDFQueryRecord &bRec, EMeasure measure) const { - bool sampleReflection = (bRec.typeMask & EDeltaReflection) - && (bRec.component == -1 || bRec.component == 0); - bool sampleTransmission = (bRec.typeMask & EDeltaTransmission) - && (bRec.component == -1 || bRec.component == 1); - bool reflection = Frame::cosTheta(bRec.wo) * Frame::cosTheta(bRec.wi) > 0; - - if ((reflection && !sampleReflection) || - (!reflection && !sampleTransmission) || measure != EDiscrete) - return Spectrum(0.0f); - - Float fr = fresnel(Frame::cosTheta(bRec.wi), m_extIOR, m_intIOR); - - if (reflection) { - return m_specularReflectance->getValue(bRec.its) * fr; - } else { - Float etaI = m_extIOR, etaT = m_intIOR; - bool entering = Frame::cosTheta(bRec.wi) > 0.0f; - if (!entering) - std::swap(etaI, etaT); - - Float factor = (bRec.quantity == ERadiance) - ? (etaI*etaI) / (etaT*etaT) : 1.0f; - - return m_specularTransmittance->getValue(bRec.its) * factor * (1 - fr); - } - } - - Float pdf(const BSDFQueryRecord &bRec, EMeasure measure) const { - bool sampleReflection = (bRec.typeMask & EDeltaReflection) - && (bRec.component == -1 || bRec.component == 0); - bool sampleTransmission = (bRec.typeMask & EDeltaTransmission) - && (bRec.component == -1 || bRec.component == 1); - bool reflection = Frame::cosTheta(bRec.wo) - * Frame::cosTheta(bRec.wi) > 0; - - if ((reflection && !sampleReflection) || - (!reflection && !sampleTransmission) || measure != EDiscrete) - return 0.0f; - - if (sampleTransmission && sampleReflection) { - Float Fr = fresnel(Frame::cosTheta(bRec.wi), m_extIOR, m_intIOR); - return reflection ? Fr : (1 - Fr); - } else { - return 1.0f; - } - } - Spectrum sample(BSDFQueryRecord &bRec, Float &pdf, const Point2 &sample) const { bool sampleReflection = (bRec.typeMask & EDeltaReflection) && (bRec.component == -1 || bRec.component == 0); diff --git a/src/bsdfs/microfacet.h b/src/bsdfs/microfacet.h index 267847be..314cb89d 100644 --- a/src/bsdfs/microfacet.h +++ b/src/bsdfs/microfacet.h @@ -50,8 +50,7 @@ public: * (ggx/phong/beckmann) */ MicrofacetDistribution(const std::string &name) { - std::string distr = - boost::to_lower_copy(props.getString("distribution", "beckmann")); + std::string distr = boost::to_lower_copy(name); if (distr == "beckmann") m_type = EBeckmann; @@ -171,8 +170,8 @@ public: * \brief Smith's shadow-masking function G1 for each * of the supported microfacet distributions * - * \param m The microsurface normal * \param v An arbitrary direction + * \param m The microsurface normal * \param alpha The surface roughness */ Float smithG1(const Vector &v, const Vector &m, Float alpha) const { @@ -218,9 +217,22 @@ public: return 0.0f; } } + + /** + * \brief Smith's shadow-masking function G1 for each + * of the supported microfacet distributions + * + * \param wi The incident direction + * \param wo The exitant direction + * \param m The microsurface normal + * \param alpha The surface roughness + */ + Float smithG(const Vector &wi, const Vector &wo, const Vector &m, Float alpha) const { + return smithG1(wi, m, alpha) * smithG1(wo, m, alpha); + } std::string toString() const { - switch (m_distribution) { + switch (m_type) { case EBeckmann: return "beckmann"; break; case EPhong: return "phong"; break; case EGGX: return "ggx"; break; @@ -230,7 +242,7 @@ public: } } private: - EType type; + EType m_type; }; MTS_NAMESPACE_END diff --git a/src/bsdfs/roughdielectric.cpp b/src/bsdfs/roughdielectric.cpp index 4bca5728..529a225b 100644 --- a/src/bsdfs/roughdielectric.cpp +++ b/src/bsdfs/roughdielectric.cpp @@ -127,15 +127,6 @@ public: m_specularTransmittance = new ConstantSpectrumTexture( props.getSpectrum("specularTransmittance", Spectrum(1.0f))); - Float alpha; - if (props.hasProperty("alphaB")) { - Log(EWarn, "Deprecation warning: the 'alphaB' parameter " - "has been renamed to 'alpha'"); - - alpha = props.getFloat("alphaB"); - } else { - alpha = props.getFloat("alpha", 0.1f); - } m_intIOR = props.getFloat("intIOR", 1.5046f); m_extIOR = props.getFloat("extIOR", 1.0f); @@ -145,10 +136,11 @@ public: "refraction must be positive and differ!"); m_distribution = MicrofacetDistribution( - m_props.getString("distribution", "beckmann") + props.getString("distribution", "beckmann") ); - m_alpha = new ConstantFloatTexture(alpha); + m_alpha = new ConstantFloatTexture( + props.getFloat("alpha", 0.1f)); m_components.push_back( EGlossyReflection | EFrontSide | EBackSide | ECanUseSampler); @@ -184,7 +176,10 @@ public: return (value < 0) ? -1.0f : 1.0f; } - Spectrum eval(const BSDFQueryRecord &bRec) const { + Spectrum eval(const BSDFQueryRecord &bRec, EMeasure measure) const { + if (measure != ESolidAngle) + return Spectrum(0.0f); + /* Determine the type of interaction */ bool reflect = Frame::cosTheta(bRec.wi) * Frame::cosTheta(bRec.wo) > 0; @@ -219,7 +214,7 @@ public: } /* Evaluate the roughness */ - Float alpha = m_distribution.transform( + Float alpha = m_distribution.transformRoughness( m_alpha->getValue(bRec.its).average()); /* Microsurface normal distribution */ @@ -231,7 +226,7 @@ public: const Float F = fresnel(dot(bRec.wi, H), m_extIOR, m_intIOR); /* Smith's shadow-masking function */ - const Float G = smithG1(bRec.wi, H, alpha) * smithG1(bRec.wo, H, alpha); + const Float G = m_distribution.smithG(bRec.wi, bRec.wo, H, alpha); if (reflect) { /* Calculate the total amount of reflection */ @@ -255,7 +250,10 @@ public: } } - Float pdf(const BSDFQueryRecord &bRec) const { + Float pdf(const BSDFQueryRecord &bRec, EMeasure measure) const { + if (measure != ESolidAngle) + return 0.0f; + /* Determine the type of interaction */ bool sampleReflection = ((bRec.component == -1 || bRec.component == 0) && (bRec.typeMask & EGlossyReflection)), @@ -303,7 +301,7 @@ public: } /* Evaluate the roughness */ - Float alpha = m_distribution.transform( + Float alpha = m_distribution.transformRoughness( m_alpha->getValue(bRec.its).average()); /* Suggestion by Bruce Walter: sample using a slightly different @@ -386,7 +384,7 @@ public: } /* Evaluate the roughness */ - Float alpha = m_distribution.transform( + Float alpha = m_distribution.transformRoughness( m_alpha->getValue(bRec.its).average()); /* Suggestion by Bruce Walter: sample using a slightly different @@ -396,7 +394,7 @@ public: std::abs(Frame::cosTheta(bRec.wi)))); /* Sample M, the microsurface normal */ - const Normal m = sampleD(sample, sampleAlpha); + const Normal m = m_distribution.sampleD(sample, sampleAlpha); if (sampleExactFresnelTerm) { sampleF = fresnel(dot(bRec.wi, m), m_extIOR, m_intIOR); @@ -438,8 +436,7 @@ public: } Float numerator = m_distribution.eval(m, alpha) - * m_distribution.smithG1(bRec.wi, m, alpha) - * m_distribution.smithG1(bRec.wo, m, alpha) + * m_distribution.smithG(bRec.wi, bRec.wo, m, alpha) * dot(bRec.wi, m); Float denominator = m_distribution.eval(m, sampleAlpha) @@ -508,7 +505,7 @@ public: } /* Evaluate the roughness */ - Float alpha = m_distribution.transform( + Float alpha = m_distribution.transformRoughness( m_alpha->getValue(bRec.its).average()); /* Suggestion by Bruce Walter: sample using a slightly different @@ -518,7 +515,7 @@ public: std::abs(Frame::cosTheta(bRec.wi)))); /* Sample M, the microsurface normal */ - const Normal m = sampleD(sample, sampleAlpha); + const Normal m = m_distribution.sampleD(sample, sampleAlpha); if (sampleExactFresnelTerm) { Float sampleF = fresnel(dot(bRec.wi, m), m_extIOR, m_intIOR); diff --git a/src/libcore/spectrum.cpp b/src/libcore/spectrum.cpp index bc5f112b..fdeb1e24 100644 --- a/src/libcore/spectrum.cpp +++ b/src/libcore/spectrum.cpp @@ -96,6 +96,8 @@ Float Spectrum::m_wavelengths[SPECTRUM_SAMPLES + 1]; void Spectrum::staticInitialization() { #if SPECTRUM_SAMPLES != 3 std::ostringstream oss; + oss << std::fixed; + oss.precision(2); Float stepSize = SPECTRUM_RANGE / (Float) SPECTRUM_SAMPLES; for (int i=0; i " << s[i]; + << m_wavelengths[i+1] << "nm => "; + oss.precision(3); + oss << s[i]; #endif if (i < SPECTRUM_SAMPLES - 1) oss << ", "; @@ -607,9 +613,13 @@ Float InterpolatedSpectrum::eval(Float lambda) const { std::string InterpolatedSpectrum::toString() const { std::ostringstream oss; + oss << std::fixed; oss << "InterpolatedSpectrum[" << endl; for (size_t i=0; i " << m_values[i]; + oss.precision(1); + oss << " " << m_wavelengths[i] << " nm => "; + oss.precision(3); + oss << m_values[i]; if (i+1 < m_wavelengths.size()) oss << ","; oss << endl; diff --git a/src/libcore/util.cpp b/src/libcore/util.cpp index de483653..31a84e45 100644 --- a/src/libcore/util.cpp +++ b/src/libcore/util.cpp @@ -687,16 +687,16 @@ Float fresnelDielectric(Float cosThetaI, Float cosThetaT, return (Rs * Rs + Rp * Rp) / 2.0f; } -Spectrum fresnelConductor(Float cosTheta, const Spectrum &eta, const Spectrum &k) { - Spectrum tmp = (eta*eta + k*k) * (cosTheta * cosTheta); +Spectrum fresnelConductor(Float cosThetaI, const Spectrum &eta, const Spectrum &k) { + Spectrum tmp = (eta*eta + k*k) * (cosThetaI * cosThetaI); - Spectrum rParl2 = (tmp - (eta * (2.0f * cosTheta)) + Spectrum(1.0f)) - / (tmp + (eta * (2.0f * cosTheta)) + Spectrum(1.0f)); + Spectrum rParl2 = (tmp - (eta * (2.0f * cosThetaI)) + Spectrum(1.0f)) + / (tmp + (eta * (2.0f * cosThetaI)) + Spectrum(1.0f)); Spectrum tmpF = eta*eta + k*k; - Spectrum rPerp2 = (tmpF - (eta * (2.0f * cosTheta)) + Spectrum(cosTheta*cosTheta)) / - (tmpF + (eta * (2.0f * cosTheta)) + Spectrum(cosTheta*cosTheta)); + Spectrum rPerp2 = (tmpF - (eta * (2.0f * cosThetaI)) + Spectrum(cosThetaI*cosThetaI)) / + (tmpF + (eta * (2.0f * cosThetaI)) + Spectrum(cosThetaI*cosThetaI)); return (rParl2 + rPerp2) / 2.0f; }