From bc16235f6fa149d7af97d341c9b847a225ecb11d Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Sat, 13 Aug 2011 12:04:28 -0400 Subject: [PATCH] renamed the mixture BSDF, added support for reparameterizing the HK & SSBRDF plugins in terms of albedo --- data/schema/upgrade_0.3.0.xsl | 2 +- include/mitsuba/hw/basicshader.h | 153 +++++++++++++++++++ src/bsdfs/SConscript | 2 +- src/bsdfs/difftrans.cpp | 7 +- src/bsdfs/dipolebrdf.cpp | 24 ++- src/bsdfs/hk.cpp | 41 +++++- src/bsdfs/{mixture.cpp => mixturebsdf.cpp} | 4 +- src/bsdfs/sssbrdf.cpp | 10 +- src/libhw/basicshader.cpp | 162 +++++++++++++++++++++ src/medium/materials.h | 39 +++-- 10 files changed, 417 insertions(+), 27 deletions(-) rename src/bsdfs/{mixture.cpp => mixturebsdf.cpp} (99%) diff --git a/data/schema/upgrade_0.3.0.xsl b/data/schema/upgrade_0.3.0.xsl index 6c54066b..cec202a8 100644 --- a/data/schema/upgrade_0.3.0.xsl +++ b/data/schema/upgrade_0.3.0.xsl @@ -205,7 +205,7 @@ - mixture + mixturebsdf diff --git a/include/mitsuba/hw/basicshader.h b/include/mitsuba/hw/basicshader.h index 62653cca..35b0145c 100644 --- a/include/mitsuba/hw/basicshader.h +++ b/include/mitsuba/hw/basicshader.h @@ -126,6 +126,159 @@ protected: Float m_value; }; +/** + * \brief Componentwise addition of two textures + * + * Includes a \ref Shader implementation for hardware rendering + */ +class MTS_EXPORT_HW SpectrumAdditionTexture : public Texture { +public: + inline SpectrumAdditionTexture(const Texture *a, const Texture *b) + : Texture(Properties()), m_a(a), m_b(b) { } + + SpectrumAdditionTexture(Stream *stream, InstanceManager *manager); + + inline Spectrum getValue(const Intersection &its) const { + return m_a->getValue(its) + m_b->getValue(its); + } + + inline Spectrum getAverage() const { + return m_a->getAverage() + m_b->getAverage(); + } + + inline Spectrum getMaximum() const { + SLog(EError, "SpectrumAdditionTexture::getMaximum() -- information unavailable!"); + return Spectrum(0.0f); + } + + inline bool isConstant() const { + return m_a->isConstant() && m_b->isConstant(); + } + + inline std::string toString() const { + std::ostringstream oss; + oss << "SpectrumAdditionTexture[" << endl + << " a = " << indent(m_a->toString()) << "," << endl + << " b = " << indent(m_a->toString()) << endl + << "]"; + return oss.str(); + } + + inline bool usesRayDifferentials() const { + return m_a->usesRayDifferentials() || m_b->usesRayDifferentials(); + } + + Shader *createShader(Renderer *renderer) const; + + void serialize(Stream *stream, InstanceManager *manager) const; + + MTS_DECLARE_CLASS() +protected: + ref m_a, m_b; +}; + +/** + * \brief Componentwise subtraction of two textures + * + * Includes a \ref Shader implementation for hardware rendering + */ +class MTS_EXPORT_HW SpectrumSubtractionTexture : public Texture { +public: + inline SpectrumSubtractionTexture(const Texture *a, const Texture *b) + : Texture(Properties()), m_a(a), m_b(b) { } + + SpectrumSubtractionTexture(Stream *stream, InstanceManager *manager); + + inline Spectrum getValue(const Intersection &its) const { + return m_a->getValue(its) - m_b->getValue(its); + } + + inline Spectrum getAverage() const { + return m_a->getAverage() - m_b->getAverage(); + } + + inline Spectrum getMaximum() const { + SLog(EError, "SpectrumSubtractionTexture::getMaximum() -- information unavailable!"); + return Spectrum(0.0f); + } + + inline bool isConstant() const { + return m_a->isConstant() && m_b->isConstant(); + } + + inline std::string toString() const { + std::ostringstream oss; + oss << "SpectrumSubtractionTexture[" << endl + << " a = " << indent(m_a->toString()) << "," << endl + << " b = " << indent(m_b->toString()) << endl + << "]"; + return oss.str(); + } + + inline bool usesRayDifferentials() const { + return m_a->usesRayDifferentials() || m_b->usesRayDifferentials(); + } + + Shader *createShader(Renderer *renderer) const; + + void serialize(Stream *stream, InstanceManager *manager) const; + + MTS_DECLARE_CLASS() +protected: + ref m_a, m_b; +}; + +/** + * \brief Componentwise product of two textures + * + * Includes a \ref Shader implementation for hardware rendering + */ +class MTS_EXPORT_HW SpectrumProductTexture : public Texture { +public: + inline SpectrumProductTexture(const Texture *a, const Texture *b) + : Texture(Properties()), m_a(a), m_b(b) { } + + SpectrumProductTexture(Stream *stream, InstanceManager *manager); + + inline Spectrum getValue(const Intersection &its) const { + return m_a->getValue(its) * m_b->getValue(its); + } + + inline Spectrum getAverage() const { + SLog(EError, "SpectrumProductTexture::getAverage() -- information unavailable!"); + return Spectrum(0.0f); + } + + inline Spectrum getMaximum() const { + return m_a->getMaximum() * m_b->getMaximum(); + } + + inline bool isConstant() const { + return m_a->isConstant() && m_b->isConstant(); + } + + inline std::string toString() const { + std::ostringstream oss; + oss << "SpectrumProductTexture[" << endl + << " a = " << indent(m_a->toString()) << "," << endl + << " b = " << indent(m_b->toString()) << endl + << "]"; + return oss.str(); + } + + inline bool usesRayDifferentials() const { + return m_a->usesRayDifferentials() || m_b->usesRayDifferentials(); + } + + Shader *createShader(Renderer *renderer) const; + + void serialize(Stream *stream, InstanceManager *manager) const; + + MTS_DECLARE_CLASS() +protected: + ref m_a, m_b; +}; + MTS_NAMESPACE_END #endif /* __BASIC_SHADER_H */ diff --git a/src/bsdfs/SConscript b/src/bsdfs/SConscript index 2716f587..147283db 100644 --- a/src/bsdfs/SConscript +++ b/src/bsdfs/SConscript @@ -13,7 +13,7 @@ plugins += env.SharedLibrary('roughplastic', ['roughplastic.cpp']) # Materials that act as modifiers plugins += env.SharedLibrary('twosided', ['twosided.cpp']) plugins += env.SharedLibrary('mask', ['mask.cpp']) -plugins += env.SharedLibrary('mixture', ['mixture.cpp']) +plugins += env.SharedLibrary('mixturebsdf', ['mixturebsdf.cpp']) plugins += env.SharedLibrary('coating', ['coating.cpp']) plugins += env.SharedLibrary('bump', ['bump.cpp']) diff --git a/src/bsdfs/difftrans.cpp b/src/bsdfs/difftrans.cpp index 5d2e0864..98ad058f 100644 --- a/src/bsdfs/difftrans.cpp +++ b/src/bsdfs/difftrans.cpp @@ -38,9 +38,10 @@ MTS_NAMESPACE_BEGIN * * This BSDF models a non-reflective material, where any entering light loses * its directionality and is diffusely scattered from the other side. This - * model can be combined\footnote{For instance using the \pluginref{mixture} - * plugin.} with a surface reflection model to describe translucent substances - * that have internal multiple scattering processes (e.g. plant leaves). + * model can be combined\footnote{For instance using the + * \pluginref{mixturebsdf} plugin.} with a surface reflection model to + * describe translucent substances that have internal multiple scattering + * processes (e.g. plant leaves). */ class DiffuseTransmitter : public BSDF { public: diff --git a/src/bsdfs/dipolebrdf.cpp b/src/bsdfs/dipolebrdf.cpp index a7716d1d..9013c633 100644 --- a/src/bsdfs/dipolebrdf.cpp +++ b/src/bsdfs/dipolebrdf.cpp @@ -33,7 +33,7 @@ public: : BSDF(props) { Spectrum sigmaS, sigmaA; - Float eta; + Float eta = 1.33f; lookupMaterial(props, sigmaS, sigmaA, &eta, false); /* Specifies the internal index of refraction at the interface */ @@ -85,10 +85,23 @@ public: } void configure() { + if (m_sigmaT != NULL || m_albedo != NULL) { + /* Support for the alternative scattering/absorption + * coefficient parameter passing convention */ + if (m_sigmaT == NULL || m_albedo == NULL) + SLog(EError, "Please provide *both* sigmaT & albedo!"); + + m_sigmaS = new SpectrumProductTexture(m_sigmaT, m_albedo); + m_sigmaA = new SpectrumSubtractionTexture(m_sigmaT, m_sigmaS); + m_sigmaT = NULL; + m_albedo = NULL; + } + m_components.clear(); m_components.push_back(EDiffuseReflection | EFrontSide | (m_sigmaS->isConstant() && m_sigmaA->isConstant() ? 0 : ESpatiallyVarying)); - m_usesRayDifferentials = m_sigmaS->usesRayDifferentials() || m_sigmaA->usesRayDifferentials(); + m_usesRayDifferentials = m_sigmaS->usesRayDifferentials() + || m_sigmaA->usesRayDifferentials(); if ((m_sigmaS->getMaximum()+m_sigmaA->getMaximum()).isZero()) Log(EError, "Please specify nonzero sigmaS/sigmaA-values!"); @@ -176,6 +189,10 @@ public: m_sigmaS = static_cast(child); else if (name == "sigmaA") m_sigmaA = static_cast(child); + else if (name == "sigmaT") + m_sigmaT = static_cast(child); + else if (name == "albedo") + m_albedo = static_cast(child); else BSDF::addChild(name, child); } else { @@ -212,6 +229,9 @@ public: private: Float m_intIOR, m_extIOR, m_g, m_A; ref m_sigmaS, m_sigmaA; + /* Temporary fields */ + ref m_sigmaT; + ref m_albedo; }; // ================ Hardware shader implementation ================ diff --git a/src/bsdfs/hk.cpp b/src/bsdfs/hk.cpp index e32c1baf..b02c3517 100644 --- a/src/bsdfs/hk.cpp +++ b/src/bsdfs/hk.cpp @@ -36,6 +36,12 @@ MTS_NAMESPACE_BEGIN * of the internal layer. \default{based on \code{material}}} * \parameter{sigmaA}{\Spectrum\Or\Texture}{Specifies the absorption coefficient * of the internal layer. \default{based on \code{material}}} + * \parameter{sigmaT \& albedo}{\Spectrum\Or\Texture}{ + * Optional: Alternatively, the scattering and absorption coefficients may also be + * specified using the extinction coefficient \code{sigmaT} and the + * single-scattering albedo. Note that only one of the parameter passing + * conventions can be used at a time (i.e. use either \code{sigmaS\&sigmaA} + * \emph{or} \code{sigmaT\&albedo})} * \parameter{thickness}{\Float}{Denotes the thickness of the layer. * (should be specified in inverse units of \code{sigmaA} and \code{sigmaS})\default{1}} * \parameter{\Unnamed}{\Phase}{A nested phase function instance that represents @@ -45,12 +51,11 @@ MTS_NAMESPACE_BEGIN * \renderings{ * \rendering{An index-matched scattering layer with parameters $\sigma_s=2$, $\sigma_a=0.1$, thickness$=0.1$}{bsdf_hk_1} * \rendering{Example of the HK model with a dielectric coating (and the \code{ketchup} material preset, see \lstref{hk-coated})}{bsdf_hk_2} - * \vspace{-3mm} * \caption{ * \label{fig:hk-example} * Renderings using the uncoated and coated form of the Hanrahan-Krueger model. * } - * \vspace{1mm} + * \vspace{3mm} * } * * This plugin provides an implementation of the Hanrahan-Krueger BSDF @@ -62,7 +67,7 @@ MTS_NAMESPACE_BEGIN * This BSDF requires a phase function to model scattering interactions within the * random medium. When no phase function is explicitly specified, it uses an * isotropic one ($g=0$) by default. A sample usage for instantiating the - * plugin is given below: + * plugin is given on the next page:\newpage * \begin{xml} * * @@ -123,7 +128,6 @@ public: /* Slab thickness in inverse units of sigmaS and sigmaA */ m_thickness = props.getFloat("thickness", 1); - } HanrahanKrueger(Stream *stream, InstanceManager *manager) @@ -140,13 +144,29 @@ public: m_phase = static_cast (PluginManager::getInstance()-> createObject(MTS_CLASS(PhaseFunction), Properties("isotropic"))); + if (m_sigmaT != NULL || m_albedo != NULL) { + /* Support for the alternative scattering/absorption + * coefficient parameter passing convention */ + if (m_sigmaT == NULL || m_albedo == NULL) + SLog(EError, "Please provide *both* sigmaT & albedo!"); + + m_sigmaS = new SpectrumProductTexture(m_sigmaT, m_albedo); + m_sigmaA = new SpectrumSubtractionTexture(m_sigmaT, m_sigmaS); + m_sigmaT = NULL; + m_albedo = NULL; + } + if ((m_sigmaS->getMaximum()+m_sigmaA->getMaximum()).isZero()) Log(EError, "Please specify nonzero sigmaS/sigmaA-values!"); + int extraFlags = m_sigmaS->isConstant() && m_sigmaA->isConstant() ? 0 : ESpatiallyVarying; m_components.clear(); - m_components.push_back(EGlossyReflection | EFrontSide | EBackSide | ECanUseSampler); - m_components.push_back(EGlossyTransmission | EFrontSide | EBackSide | ECanUseSampler); - m_components.push_back(EDeltaTransmission | EFrontSide | EBackSide | ECanUseSampler); + m_components.push_back(EGlossyReflection | EFrontSide | EBackSide | ECanUseSampler | extraFlags); + m_components.push_back(EGlossyTransmission | EFrontSide | EBackSide | ECanUseSampler | extraFlags); + m_components.push_back(EDeltaTransmission | EFrontSide | EBackSide | ECanUseSampler | extraFlags); + + m_usesRayDifferentials = m_sigmaS->usesRayDifferentials() + || m_sigmaA->usesRayDifferentials(); BSDF::configure(); } @@ -369,6 +389,10 @@ public: m_sigmaS = static_cast(child); else if (name == "sigmaA") m_sigmaA = static_cast(child); + else if (name == "sigmaT") + m_sigmaT = static_cast(child); + else if (name == "albedo") + m_albedo = static_cast(child); else BSDF::addChild(name, child); } else { @@ -395,6 +419,9 @@ private: ref m_sigmaS; ref m_sigmaA; Float m_thickness; + /* Temporary fields */ + ref m_sigmaT; + ref m_albedo; }; diff --git a/src/bsdfs/mixture.cpp b/src/bsdfs/mixturebsdf.cpp similarity index 99% rename from src/bsdfs/mixture.cpp rename to src/bsdfs/mixturebsdf.cpp index 36f00960..80b38850 100644 --- a/src/bsdfs/mixture.cpp +++ b/src/bsdfs/mixturebsdf.cpp @@ -22,7 +22,7 @@ MTS_NAMESPACE_BEGIN -/*! \plugin{mixture}{Mixture material} +/*! \plugin{mixturebsdf}{Mixture material} * * \parameters{ * \parameter{weights}{\String}{A comma-separated list of BSDF weights} @@ -46,7 +46,7 @@ MTS_NAMESPACE_BEGIN * \begin{xml}[caption={A material definition for a mixture of 70% smooth * chromium, 20% of a greenish rough diffuse material (and 10% absorption)}, * label=lst:mixture-example] - * + * * * * diff --git a/src/bsdfs/sssbrdf.cpp b/src/bsdfs/sssbrdf.cpp index afc67f8e..a1e4b2a0 100644 --- a/src/bsdfs/sssbrdf.cpp +++ b/src/bsdfs/sssbrdf.cpp @@ -34,6 +34,12 @@ MTS_NAMESPACE_BEGIN * of the layer. \default{based on \code{material}}} * \parameter{sigmaA}{\Spectrum\Or\Texture}{Specifies the absorption coefficient * of the layer. \default{based on \code{material}}} + * \parameter{sigmaT \& albedo}{\Spectrum\Or\Texture}{ + * Optional: Alternatively, the scattering and absorption coefficients may also be + * specified using the extinction coefficient \code{sigmaT} and the + * single-scattering albedo. Note that only one of the parameter passing + * conventions can be used at a time (i.e. use either \code{sigmaS\&sigmaA} + * \emph{or} \code{sigmaT\&albedo})} * \parameter{intIOR}{\Float\Or\String}{Interior index of refraction specified * numerically or using a known material name. \default{based on \code{material}}} * \parameter{extIOR}{\Float\Or\String}{Exterior index of refraction specified @@ -97,7 +103,7 @@ public: m_dipole = static_cast (PluginManager::getInstance()-> createObject(MTS_CLASS(BSDF), dipoleProps)); - Properties mixtureProps("mixture"); + Properties mixtureProps("mixturebsdf"); mixtureProps.setString("weights", "1.0, 1.0"); mixtureProps.setBoolean("ensureEnergyConservation", false); m_mixture = static_cast (PluginManager::getInstance()-> @@ -106,6 +112,8 @@ public: props.markQueried("material"); props.markQueried("sigmaS"); props.markQueried("sigmaA"); + props.markQueried("coating"); + props.markQueried("sigmaT"); props.markQueried("intIOR"); props.markQueried("extIOR"); } diff --git a/src/libhw/basicshader.cpp b/src/libhw/basicshader.cpp index 7d0cc886..4bb966b1 100644 --- a/src/libhw/basicshader.cpp +++ b/src/libhw/basicshader.cpp @@ -41,6 +41,42 @@ void ConstantFloatTexture::serialize(Stream *stream, InstanceManager *manager) c stream->writeFloat(m_value); } +SpectrumProductTexture::SpectrumProductTexture(Stream *stream, InstanceManager *manager) + : Texture(stream, manager) { + m_a = static_cast(manager->getInstance(stream)); + m_b = static_cast(manager->getInstance(stream)); +} + +void SpectrumProductTexture::serialize(Stream *stream, InstanceManager *manager) const { + Texture::serialize(stream, manager); + manager->serialize(stream, m_a.get()); + manager->serialize(stream, m_b.get()); +} + +SpectrumAdditionTexture::SpectrumAdditionTexture(Stream *stream, InstanceManager *manager) + : Texture(stream, manager) { + m_a = static_cast(manager->getInstance(stream)); + m_b = static_cast(manager->getInstance(stream)); +} + +void SpectrumAdditionTexture::serialize(Stream *stream, InstanceManager *manager) const { + Texture::serialize(stream, manager); + manager->serialize(stream, m_a.get()); + manager->serialize(stream, m_b.get()); +} + +SpectrumSubtractionTexture::SpectrumSubtractionTexture(Stream *stream, InstanceManager *manager) + : Texture(stream, manager) { + m_a = static_cast(manager->getInstance(stream)); + m_b = static_cast(manager->getInstance(stream)); +} + +void SpectrumSubtractionTexture::serialize(Stream *stream, InstanceManager *manager) const { + Texture::serialize(stream, manager); + manager->serialize(stream, m_a.get()); + manager->serialize(stream, m_b.get()); +} + class ConstantSpectrumTextureShader : public Shader { public: ConstantSpectrumTextureShader(Renderer *renderer, const Spectrum &value) @@ -99,6 +135,114 @@ private: Float m_value; }; +class SpectrumProductTextureShader : public Shader { +public: + SpectrumProductTextureShader(Renderer *renderer, const Texture *a, const Texture *b) + : Shader(renderer, ETextureShader), m_a(a), m_b(b) { + m_aShader = renderer->registerShaderForResource(m_a.get()); + m_bShader = renderer->registerShaderForResource(m_b.get()); + } + + bool isComplete() const { + return m_a.get() != NULL && m_b.get() != NULL; + } + + void cleanup(Renderer *renderer) { + renderer->unregisterShaderForResource(m_a.get()); + renderer->unregisterShaderForResource(m_b.get()); + } + + void putDependencies(std::vector &deps) { + deps.push_back(m_aShader.get()); + deps.push_back(m_bShader.get()); + } + + void generateCode(std::ostringstream &oss, + const std::string &evalName, + const std::vector &depNames) const { + oss << "vec3 " << evalName << "(vec2 uv) {" << endl + << " return " << depNames[0] << "(uv) * " << depNames[1] << "(uv);" << endl + << "}" << endl; + } + + MTS_DECLARE_CLASS() +private: + ref m_a, m_b; + ref m_aShader, m_bShader; +}; + +class SpectrumAdditionTextureShader : public Shader { +public: + SpectrumAdditionTextureShader(Renderer *renderer, const Texture *a, const Texture *b) + : Shader(renderer, ETextureShader), m_a(a), m_b(b) { + m_aShader = renderer->registerShaderForResource(m_a.get()); + m_bShader = renderer->registerShaderForResource(m_b.get()); + } + + bool isComplete() const { + return m_a.get() != NULL && m_b.get() != NULL; + } + + void cleanup(Renderer *renderer) { + renderer->unregisterShaderForResource(m_a.get()); + renderer->unregisterShaderForResource(m_b.get()); + } + + void putDependencies(std::vector &deps) { + deps.push_back(m_aShader.get()); + deps.push_back(m_bShader.get()); + } + + void generateCode(std::ostringstream &oss, + const std::string &evalName, + const std::vector &depNames) const { + oss << "vec3 " << evalName << "(vec2 uv) {" << endl + << " return " << depNames[0] << "(uv) + " << depNames[1] << "(uv);" << endl + << "}" << endl; + } + + MTS_DECLARE_CLASS() +private: + ref m_a, m_b; + ref m_aShader, m_bShader; +}; + +class SpectrumSubtractionTextureShader : public Shader { +public: + SpectrumSubtractionTextureShader(Renderer *renderer, const Texture *a, const Texture *b) + : Shader(renderer, ETextureShader), m_a(a), m_b(b) { + m_aShader = renderer->registerShaderForResource(m_a.get()); + m_bShader = renderer->registerShaderForResource(m_b.get()); + } + + bool isComplete() const { + return m_a.get() != NULL && m_b.get() != NULL; + } + + void cleanup(Renderer *renderer) { + renderer->unregisterShaderForResource(m_a.get()); + renderer->unregisterShaderForResource(m_b.get()); + } + + void putDependencies(std::vector &deps) { + deps.push_back(m_aShader.get()); + deps.push_back(m_bShader.get()); + } + + void generateCode(std::ostringstream &oss, + const std::string &evalName, + const std::vector &depNames) const { + oss << "vec3 " << evalName << "(vec2 uv) {" << endl + << " return " << depNames[0] << "(uv) - " << depNames[1] << "(uv);" << endl + << "}" << endl; + } + + MTS_DECLARE_CLASS() +private: + ref m_a, m_b; + ref m_aShader, m_bShader; +}; + Shader *ConstantSpectrumTexture::createShader(Renderer *renderer) const { return new ConstantSpectrumTextureShader(renderer, m_value); } @@ -107,8 +251,26 @@ Shader *ConstantFloatTexture::createShader(Renderer *renderer) const { return new ConstantFloatTextureShader(renderer, m_value); } +Shader *SpectrumProductTexture::createShader(Renderer *renderer) const { + return new SpectrumProductTextureShader(renderer, m_a.get(), m_b.get()); +} + +Shader *SpectrumAdditionTexture::createShader(Renderer *renderer) const { + return new SpectrumAdditionTextureShader(renderer, m_a.get(), m_b.get()); +} + +Shader *SpectrumSubtractionTexture::createShader(Renderer *renderer) const { + return new SpectrumSubtractionTextureShader(renderer, m_a.get(), m_b.get()); +} + MTS_IMPLEMENT_CLASS_S(ConstantSpectrumTexture, false, Texture) MTS_IMPLEMENT_CLASS(ConstantSpectrumTextureShader, false, Shader) MTS_IMPLEMENT_CLASS_S(ConstantFloatTexture, false, Texture) MTS_IMPLEMENT_CLASS(ConstantFloatTextureShader, false, Shader) +MTS_IMPLEMENT_CLASS_S(SpectrumProductTexture, false, Texture) +MTS_IMPLEMENT_CLASS(SpectrumProductTextureShader, false, Shader) +MTS_IMPLEMENT_CLASS_S(SpectrumAdditionTexture, false, Texture) +MTS_IMPLEMENT_CLASS(SpectrumAdditionTextureShader, false, Shader) +MTS_IMPLEMENT_CLASS_S(SpectrumSubtractionTexture, false, Texture) +MTS_IMPLEMENT_CLASS(SpectrumSubtractionTextureShader, false, Shader) MTS_NAMESPACE_END diff --git a/src/medium/materials.h b/src/medium/materials.h index 36a9ce7f..75d5c8d9 100644 --- a/src/medium/materials.h +++ b/src/medium/materials.h @@ -49,12 +49,14 @@ static MaterialEntry materialData[] = { }; static void lookupMaterial(const Properties &props, Spectrum &sigmaS, Spectrum &sigmaA, Float *eta = NULL, bool requireValues = true) { - bool manual = (props.hasProperty("sigmaS") || props.hasProperty("sigmaA")); - bool preset = props.hasProperty("material"); + bool hasSigmaAS = props.hasProperty("sigmaS") || props.hasProperty("sigmaA"), + hasSigmaTAlbedo = props.hasProperty("sigmaT") || props.hasProperty("albedo"), + manual = hasSigmaAS || hasSigmaTAlbedo, + hasPreset = props.hasProperty("material"); - if (manual && preset) - SLog(EError, "Please specify either a preset material, or " - "sigmaS & sigmaA (you provided both!)"); + if (manual && hasPreset) + SLog(EError, "Please specify either a preset material or " + "scattering coefficients (you provided both!)"); SAssertEx(!props.hasProperty("sizeMultiplier"), "The sizeMultiplier property was deprecated!"); @@ -62,12 +64,29 @@ static void lookupMaterial(const Properties &props, Spectrum &sigmaS, Spectrum & Float densityMultiplier = props.getFloat("densityMultiplier", 1.0f); if (manual) { - if (requireValues) { - sigmaS = props.getSpectrum("sigmaS") * densityMultiplier; - sigmaA = props.getSpectrum("sigmaA") * densityMultiplier; + if (hasSigmaAS && hasSigmaTAlbedo) { + SLog(EError, "You can either specify sigmaS & sigmaA *or* " + "sigmaT & albedo, but no other combinations!"); + } + if (hasSigmaAS) { + if (requireValues) { + sigmaS = props.getSpectrum("sigmaS") * densityMultiplier; + sigmaA = props.getSpectrum("sigmaA") * densityMultiplier; + } else { + sigmaS = props.getSpectrum("sigmaS", Spectrum(0.0f)) * densityMultiplier; + sigmaA = props.getSpectrum("sigmaA", Spectrum(0.0f)) * densityMultiplier; + } } else { - sigmaS = props.getSpectrum("sigmaS", Spectrum(0.0f)) * densityMultiplier; - sigmaA = props.getSpectrum("sigmaA", Spectrum(0.0f)) * densityMultiplier; + Spectrum albedo, sigmaT; + if (requireValues) { + albedo = props.getSpectrum("albedo"); + sigmaT = props.getSpectrum("sigmaT") * densityMultiplier; + } else { + albedo = props.getSpectrum("albedo", Spectrum(0.0f)); + sigmaT = props.getSpectrum("sigmaT", Spectrum(0.0f)) * densityMultiplier; + } + sigmaS = albedo * sigmaT; + sigmaA = sigmaT - sigmaS; } if (eta) *eta = props.getFloat("eta", 1.3f);