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