diff --git a/data/tests/test_bsdf.xml b/data/tests/test_bsdf.xml index 94df5b3c..2abd7c4f 100644 --- a/data/tests/test_bsdf.xml +++ b/data/tests/test_bsdf.xml @@ -6,6 +6,8 @@ + + diff --git a/doc/images/bsdf_coating_roughconductor.jpg b/doc/images/bsdf_coating_roughconductor.jpg index 4a2b4f98..2fc9b633 100644 Binary files a/doc/images/bsdf_coating_roughconductor.jpg and b/doc/images/bsdf_coating_roughconductor.jpg differ diff --git a/doc/images/bsdf_roughconductor_copper.jpg b/doc/images/bsdf_roughconductor_copper.jpg index 2472f5f7..38d45582 100644 Binary files a/doc/images/bsdf_roughconductor_copper.jpg and b/doc/images/bsdf_roughconductor_copper.jpg differ diff --git a/include/mitsuba/hw/basicshader.h b/include/mitsuba/hw/basicshader.h index e8cff643..3c2d5e62 100644 --- a/include/mitsuba/hw/basicshader.h +++ b/include/mitsuba/hw/basicshader.h @@ -55,6 +55,10 @@ public: return m_value; } + inline bool isConstant() const { + return true; + } + inline std::string toString() const { std::ostringstream oss; oss << "ConstantSpectrumTexture[value=" << m_value.toString() << "]"; @@ -99,6 +103,10 @@ public: return Spectrum(m_value); } + inline bool isConstant() const { + return true; + } + inline std::string toString() const { std::ostringstream oss; oss << "ConstantFloatTexture[value=" << m_value << "]"; diff --git a/include/mitsuba/render/bsdf.h b/include/mitsuba/render/bsdf.h index 721e444e..11cd5860 100644 --- a/include/mitsuba/render/bsdf.h +++ b/include/mitsuba/render/bsdf.h @@ -225,10 +225,12 @@ public: // ============================================================= /// The lobe is not invariant to rotation around the normal EAnisotropic = 0x01000, + /// The BSDF depends on the UV coordinates + ESpatiallyVarying = 0x02000, /// Supports interactions on the front-facing side - EFrontSide = 0x02000, + EFrontSide = 0x04000, /// Supports interactions on the back-facing side - EBackSide = 0x04000, + EBackSide = 0x08000, /// Can use an extra sampler instance to improve the sampling method ECanUseSampler = 0x10000 //! @} @@ -276,7 +278,7 @@ public: inline unsigned int getType(int component) const { return m_components[component]; } - + /** * \brief Return the measure corresponding to a particular * component type diff --git a/include/mitsuba/render/texture.h b/include/mitsuba/render/texture.h index f10f052a..a2a7e519 100644 --- a/include/mitsuba/render/texture.h +++ b/include/mitsuba/render/texture.h @@ -43,6 +43,9 @@ public: /// Return the resolution in pixels, if applicable virtual Vector3i getResolution() const; + /// Return whether the texture takes on a single constant value + virtual bool isConstant() const = 0; + /** * \brief Does this texture do pre-filtering when ray * differentials are available? diff --git a/src/bsdfs/coating.cpp b/src/bsdfs/coating.cpp index d9b9414b..94494da5 100644 --- a/src/bsdfs/coating.cpp +++ b/src/bsdfs/coating.cpp @@ -30,37 +30,44 @@ MTS_NAMESPACE_BEGIN * numerically or using a known material name. \default{\texttt{bk7} / 1.5046}} * \parameter{extIOR}{\Float\Or\String}{Exterior index of refraction specified * numerically or using a known material name. \default{\texttt{air} / 1.000277}} - * \parameter{sigmaA}{\Spectrum\Or\Texture}{Absorption coefficient within the layer. \default{0}} - * \parameter{thickness}{\Float}{Thickness of the absorbing layer (given in inverse units of \code{sigmaA})\default{1}} + * \parameter{thickness}{\Float}{Denotes the thickness of the absorbing layer (given in inverse units of \code{sigmaA})\default{1}} + * \parameter{sigmaA}{\Spectrum\Or\Texture}{The absorption coefficient of the coating layer. \default{0, i.e. there is no absorption}} * } * * \renderings{ - * \rendering{Coated rough copper (lower exposure, \lstref{coating-roughcopper})} + * \rendering{Rough copper} + * {bsdf_roughconductor_copper} + * \rendering{The same material coated with a single layer of clear varnish (see \lstref{coating-roughcopper})} * {bsdf_coating_roughconductor} - * \rendering{Coated rough plastic} - * {bsdf_coating_roughplastic} * } * - * This plugin implements a smooth dielectric coating in the style of the - * paper ``Arbitrarily Layered Micro-Facet Surfaces'' by Weidlich and - * Wilkie \cite{Weidlich2007Arbitrarily}. Any non-transmissive model can - * be coated, and multiple layers can be applied in sequence. This allows - * designing custom materials like car paint. + * This plugin implements a smooth dielectric coating (e.g. a layer of varnish) + * in the style of the paper ``Arbitrarily Layered Micro-Facet Surfaces'' by + * Weidlich and Wilkie \cite{Weidlich2007Arbitrarily}. Any non-transmissive + * BSDF in Mitsuba can be coated using this plugin, and multiple coating layers + * can be applied in sequence. This allows designing interesting custom materials + * like car paint or glazed metal foil. The coating layer can optionally be + * tinted (i.e. filled with an absorbing medium), in which case this model also + * accounts for the directionally dependent absorption within the layer. * - * The coating layer can optionally be filled with an absorbing medium, - * in which case this model also accounts for the directionally dependent - * extinction within the layer. + * Note that the plugin discards illumination that undergoes internal + * reflection within the coating. This can lead to a noticeable energy + * loss for materials that reflect much of their energy near or below the critical + * angle (i.e. diffuse or very rough materials). + * Therefore, users are discouraged to use this plugin to coat smooth + * diffuse materials, since there is a separately available plugin + * named \pluginref{smoothplastic}, which covers the same case and does not + * suffer from energy loss. * * Evaluating the internal component of this model entails refracting the * incident and exitant rays through the dielectric interface, followed by * querying the nested material with this modified direction pair. The result - * is attenuated by the two Fresnel transmittances. Note that this model does - * not attempt to handle illumination that is reflected by the interior of the - * coating---this energy is essentially lost. + * is attenuated by the two Fresnel transmittances and the absorption, if any. * * \vspace{4mm} * - * \begin{xml}[caption=Rough copper coated with a transparent layer of lacquer, label=lst:coating-roughcopper] + * \begin{xml}[caption=Rough copper coated with a transparent layer of + * varnish, label=lst:coating-roughcopper] * * * @@ -79,13 +86,13 @@ public: /* Specifies the external index of refraction at the interface */ m_extIOR = lookupIOR(props, "extIOR", "air"); - - /* Specifies the absorption within the layer */ - m_sigmaA = new ConstantSpectrumTexture( - props.getSpectrum("sigmaA", Spectrum(0.0f))); /* Specifies the layer's thickness using the inverse units of sigmaA */ m_thickness = props.getFloat("thickness", 1); + + /* Specifies the absorption within the layer */ + m_sigmaA = new ConstantSpectrumTexture( + props.getSpectrum("sigmaA", Spectrum(0.0f))); } SmoothCoating(Stream *stream, InstanceManager *manager) @@ -105,11 +112,26 @@ public: Log(EError, "Tried to put a smooth coating layer on top of a BSDF " "with a transmission component -- this is currently not allowed!"); +#if COMPENSATE + if (m_nested->getClass()->getName() == "SmoothDiffuse") { + /* For an ideally diffuse material, it is known how much + energy will be lost to total internal reflection */ + m_compensation = (m_intIOR*m_intIOR) / (m_extIOR * m_extIOR); + } else { + /* Otherwise, give up (for now) */ + m_compensation = 1.0f; + } +#endif + unsigned int extraFlags = 0; + if (!m_sigmaA->isConstant()) + extraFlags |= ESpatiallyVarying; + m_components.clear(); for (int i=0; igetComponentCount(); ++i) - m_components.push_back(m_nested->getType(i)); + m_components.push_back(m_nested->getType(i) | extraFlags); + m_components.push_back(EDeltaReflection | EFrontSide); - + m_usesRayDifferentials = m_nested->usesRayDifferentials() || m_sigmaA->usesRayDifferentials(); @@ -206,9 +228,10 @@ public: if (R12 == 1 || R21 == 1) /* Total internal reflection */ return Spectrum(0.0f); + Float eta = m_extIOR / m_intIOR; Spectrum result = m_nested->eval(bRec2, measure) - * ((1-R12) * (1-R21)); - + * ((1-R12) * (1-R21) * eta * eta); + Spectrum sigmaA = m_sigmaA->getValue(bRec.its) * m_thickness; if (!sigmaA.isZero()) result *= (-sigmaA * @@ -216,10 +239,12 @@ public: 1/std::abs(Frame::cosTheta(bRec2.wo)))).exp(); if (measure == ESolidAngle) - result *= Frame::cosTheta(bRec2.wo); + result *= Frame::cosTheta(bRec.wo) + / Frame::cosTheta(bRec2.wo); - Float eta = m_extIOR / m_intIOR; - result *= eta * eta; +#ifdef COMPENSATE + result *= m_compensation; +#endif return result; } @@ -250,9 +275,11 @@ public: if (R12 == 1 || R21 == 1) /* Total internal reflection */ return 0.0f; - Float pdf = m_nested->pdf(bRec2, measure) - * Frame::cosTheta(bRec.wo) - / Frame::cosTheta(bRec2.wo); + Float pdf = m_nested->pdf(bRec2, measure); + + if (measure == ESolidAngle) + pdf *= Frame::cosTheta(bRec.wo) + / Frame::cosTheta(bRec2.wo); Float eta = m_extIOR / m_intIOR; pdf *= eta * eta; @@ -324,11 +351,16 @@ public: if (R21 == 1.0f) /* Total internal reflection */ return Spectrum(0.0f); + bool sampledSA = (BSDF::getMeasure(bRec.sampledType) == ESolidAngle); + Float cosRatio = Frame::cosTheta(bRec.wo) / cosThetaWoPrime, + commonTerms = (sampledSA ? cosRatio : 1.0f)* eta * eta; - pdf *= (sampleSpecular ? (1 - R12) : 1.0f) * eta * eta * - Frame::cosTheta(bRec.wo) / cosThetaWoPrime; + pdf *= (sampleSpecular ? (1 - R12) : 1.0f) * commonTerms; + result *= (1 - R12) * (1 - R21) * commonTerms; - result *= (1 - R12) * (1 - R21) * cosThetaWoPrime * eta * eta; +#ifdef COMPENSATE + result *= m_compensation; +#endif return result; } @@ -358,11 +390,14 @@ public: } MTS_DECLARE_CLASS() -private: +protected: Float m_intIOR, m_extIOR; ref m_sigmaA; ref m_nested; Float m_thickness; +#ifdef COMPENSATE + Float m_compensation; +#endif }; MTS_IMPLEMENT_CLASS_S(SmoothCoating, false, BSDF) diff --git a/src/bsdfs/conductor.cpp b/src/bsdfs/conductor.cpp index 75247472..7c4e30e6 100644 --- a/src/bsdfs/conductor.cpp +++ b/src/bsdfs/conductor.cpp @@ -181,8 +181,9 @@ public: m_specularReflectance->usesRayDifferentials(); m_components.clear(); - m_components.push_back(EDeltaReflection | EFrontSide); - + m_components.push_back(EDeltaReflection | EFrontSide + | (m_specularReflectance->isConstant() ? 0 : ESpatiallyVarying)); + BSDF::configure(); } diff --git a/src/bsdfs/dielectric.cpp b/src/bsdfs/dielectric.cpp index 6f185b31..3fbd4cda 100644 --- a/src/bsdfs/dielectric.cpp +++ b/src/bsdfs/dielectric.cpp @@ -176,8 +176,10 @@ public: m_specularTransmittance, "specularTransmittance", 1.0f); m_components.clear(); - m_components.push_back(EDeltaReflection | EFrontSide | EBackSide); - m_components.push_back(EDeltaTransmission | EFrontSide | EBackSide); + m_components.push_back(EDeltaReflection | EFrontSide | EBackSide + | (m_specularReflectance->isConstant() ? 0 : ESpatiallyVarying)); + m_components.push_back(EDeltaTransmission | EFrontSide | EBackSide + | (m_specularTransmittance->isConstant() ? 0 : ESpatiallyVarying)); m_usesRayDifferentials = m_specularReflectance->usesRayDifferentials() || diff --git a/src/bsdfs/difftrans.cpp b/src/bsdfs/difftrans.cpp index 96bc4722..60fd8707 100644 --- a/src/bsdfs/difftrans.cpp +++ b/src/bsdfs/difftrans.cpp @@ -64,7 +64,8 @@ public: m_transmittance = ensureEnergyConservation(m_transmittance, "transmittance", 1.0f); m_components.clear(); - m_components.push_back(EDiffuseTransmission | EFrontSide | EBackSide); + m_components.push_back(EDiffuseTransmission | EFrontSide | EBackSide + | (m_transmittance->isConstant() ? 0 : ESpatiallyVarying)); BSDF::configure(); } diff --git a/src/bsdfs/diffuse.cpp b/src/bsdfs/diffuse.cpp index 39c3ddf4..deb9f790 100644 --- a/src/bsdfs/diffuse.cpp +++ b/src/bsdfs/diffuse.cpp @@ -93,7 +93,8 @@ public: m_reflectance = ensureEnergyConservation(m_reflectance, "reflectance", 1.0f); m_components.clear(); - m_components.push_back(EDiffuseReflection | EFrontSide); + m_components.push_back(EDiffuseReflection | EFrontSide + | (m_reflectance->isConstant() ? 0 : ESpatiallyVarying)); m_usesRayDifferentials = m_reflectance->usesRayDifferentials(); BSDF::configure(); diff --git a/src/bsdfs/irawan.cpp b/src/bsdfs/irawan.cpp index 5e048f4c..6f42fb89 100644 --- a/src/bsdfs/irawan.cpp +++ b/src/bsdfs/irawan.cpp @@ -122,8 +122,10 @@ public: void configure() { m_components.clear(); - m_components.push_back(EGlossyReflection | EAnisotropic | EFrontSide); - m_components.push_back(EDiffuseReflection | EFrontSide); + m_components.push_back(EGlossyReflection | EFrontSide + | EAnisotropic | ESpatiallyVarying); + m_components.push_back(EDiffuseReflection | EFrontSide + | ESpatiallyVarying); BSDF::configure(); } diff --git a/src/bsdfs/mask.cpp b/src/bsdfs/mask.cpp index af0cff2a..8a7c3392 100644 --- a/src/bsdfs/mask.cpp +++ b/src/bsdfs/mask.cpp @@ -83,10 +83,17 @@ public: void configure() { if (!m_nestedBSDF) Log(EError, "A child BSDF is required"); + + unsigned int extraFlags = 0; + if (!m_opacity->isConstant()) + extraFlags |= ESpatiallyVarying; + m_components.clear(); for (int i=0; igetComponentCount(); ++i) - m_components.push_back(m_nestedBSDF->getType(i)); - m_components.push_back(EDeltaTransmission | EFrontSide | EBackSide); + m_components.push_back(m_nestedBSDF->getType(i) | extraFlags); + m_components.push_back(EDeltaTransmission | EFrontSide + | EBackSide | extraFlags); + m_usesRayDifferentials = m_nestedBSDF->usesRayDifferentials(); m_opacity = ensureEnergyConservation(m_opacity, "opacity", 1.0f); BSDF::configure(); diff --git a/src/bsdfs/mixture.cpp b/src/bsdfs/mixture.cpp index 4a090b5f..ce88404c 100644 --- a/src/bsdfs/mixture.cpp +++ b/src/bsdfs/mixture.cpp @@ -28,8 +28,8 @@ MTS_NAMESPACE_BEGIN * \parameter{weights}{\String}{A comma-separated list of BSDF weights} * } * \renderings{ - * \rendering{An exemplary combination of BSDFs - * (\lstref{mixture-example})}{bsdf_mixture_test} + * \rendering{An admittedly not particularly realistic linear combination of + * diffuse and specular BSDFs (\lstref{mixture-example})}{bsdf_mixture_test} * } * * This plugin implements a ``mixture'' material, which represents diff --git a/src/bsdfs/phong.cpp b/src/bsdfs/phong.cpp index 97729071..8ef18259 100644 --- a/src/bsdfs/phong.cpp +++ b/src/bsdfs/phong.cpp @@ -77,8 +77,11 @@ public: void configure() { m_components.clear(); - m_components.push_back(EGlossyReflection | EFrontSide); - m_components.push_back(EDiffuseReflection | EFrontSide); + m_components.push_back(EGlossyReflection | EFrontSide | + ((!m_specularReflectance->isConstant() + || !m_exponent->isConstant()) ? ESpatiallyVarying : 0)); + m_components.push_back(EDiffuseReflection | EFrontSide + | (m_diffuseReflectance->isConstant() ? 0 : ESpatiallyVarying)); /* Verify the input parameters and fix them if necessary */ std::pair result = ensureEnergyConservation( @@ -230,7 +233,7 @@ public: } Spectrum sample(BSDFQueryRecord &bRec, const Point2 &sample) const { - Float pdf; + Float pdf = 0; Spectrum result = Phong::sample(bRec, pdf, sample); if (result.isZero()) diff --git a/src/bsdfs/plastic.cpp b/src/bsdfs/plastic.cpp index ee1c2133..c2fc9522 100644 --- a/src/bsdfs/plastic.cpp +++ b/src/bsdfs/plastic.cpp @@ -103,8 +103,10 @@ public: m_diffuseReflectance->usesRayDifferentials(); m_components.clear(); - m_components.push_back(EDeltaReflection | EFrontSide); - m_components.push_back(EDiffuseReflection | EFrontSide); + m_components.push_back(EDeltaReflection | EFrontSide + | (m_specularReflectance->isConstant() ? 0 : ESpatiallyVarying)); + m_components.push_back(EDiffuseReflection | EFrontSide + | (m_diffuseReflectance->isConstant() ? 0 : ESpatiallyVarying)); BSDF::configure(); } diff --git a/src/bsdfs/roughconductor.cpp b/src/bsdfs/roughconductor.cpp index 74eb5f61..cf75d9fe 100644 --- a/src/bsdfs/roughconductor.cpp +++ b/src/bsdfs/roughconductor.cpp @@ -205,10 +205,12 @@ public: "anisotropic Ashikhmin-Shirley microfacet distribution " "(named \"as\")"); } + if (!m_alphaU->isConstant() || !m_alphaV->isConstant() || + !m_specularReflectance->isConstant()) + extraFlags |= ESpatiallyVarying; m_components.clear(); - m_components.push_back( - EGlossyReflection | EFrontSide | extraFlags); + m_components.push_back(EGlossyReflection | EFrontSide | extraFlags); /* Verify the input parameters and fix them if necessary */ m_specularReflectance = ensureEnergyConservation( diff --git a/src/bsdfs/roughdielectric.cpp b/src/bsdfs/roughdielectric.cpp index 156fac94..981ce8bc 100644 --- a/src/bsdfs/roughdielectric.cpp +++ b/src/bsdfs/roughdielectric.cpp @@ -227,11 +227,16 @@ public: "(named \"as\")"); } + if (!m_alphaU->isConstant() || !m_alphaV->isConstant()) + extraFlags |= ESpatiallyVarying; + m_components.clear(); - m_components.push_back( - EGlossyReflection | EFrontSide | EBackSide | ECanUseSampler | extraFlags); - m_components.push_back( - EGlossyTransmission | EFrontSide | EBackSide | ECanUseSampler | extraFlags); + m_components.push_back(EGlossyReflection | EFrontSide + | EBackSide | ECanUseSampler | extraFlags + | (m_specularReflectance->isConstant() ? 0 : ESpatiallyVarying)); + m_components.push_back(EGlossyTransmission | EFrontSide + | EBackSide | ECanUseSampler | extraFlags + | (m_specularTransmittance->isConstant() ? 0 : ESpatiallyVarying)); /* Verify the input parameters and fix them if necessary */ m_specularReflectance = ensureEnergyConservation( diff --git a/src/bsdfs/roughdiffuse.cpp b/src/bsdfs/roughdiffuse.cpp index c3e311ae..f10de621 100644 --- a/src/bsdfs/roughdiffuse.cpp +++ b/src/bsdfs/roughdiffuse.cpp @@ -107,9 +107,12 @@ public: void configure() { /* Verify the input parameter and fix them if necessary */ m_reflectance = ensureEnergyConservation(m_reflectance, "reflectance", 1.0f); - + m_components.clear(); - m_components.push_back(EGlossyReflection | EFrontSide); + m_components.push_back(EGlossyReflection | EFrontSide + | ((!m_reflectance->isConstant() || !m_alpha->isConstant()) + ? ESpatiallyVarying : 0)); + m_usesRayDifferentials = m_reflectance->usesRayDifferentials() || m_alpha->usesRayDifferentials(); diff --git a/src/bsdfs/roughplastic.cpp b/src/bsdfs/roughplastic.cpp index c107f6e5..23da5be8 100644 --- a/src/bsdfs/roughplastic.cpp +++ b/src/bsdfs/roughplastic.cpp @@ -176,8 +176,11 @@ public: void configure() { m_components.clear(); - m_components.push_back(EGlossyReflection | EFrontSide); - m_components.push_back(EDiffuseReflection | EFrontSide); + + m_components.push_back(EGlossyReflection | EFrontSide + | (m_specularReflectance->isConstant() ? 0 : ESpatiallyVarying)); + m_components.push_back(EDiffuseReflection | EFrontSide + | (m_diffuseReflectance->isConstant() ? 0 : ESpatiallyVarying)); /* Verify the input parameters and fix them if necessary */ m_specularReflectance = ensureEnergyConservation( @@ -357,7 +360,7 @@ public: } Spectrum sample(BSDFQueryRecord &bRec, const Point2 &sample) const { - Float pdf; + Float pdf = 0; Spectrum result = RoughPlastic::sample(bRec, pdf, sample); if (result.isZero()) diff --git a/src/bsdfs/ward.cpp b/src/bsdfs/ward.cpp index 471041c9..66ed9abc 100644 --- a/src/bsdfs/ward.cpp +++ b/src/bsdfs/ward.cpp @@ -140,8 +140,11 @@ public: extraFlags |= EAnisotropic; m_components.clear(); - m_components.push_back(EGlossyReflection | EFrontSide | extraFlags); - m_components.push_back(EDiffuseReflection | EFrontSide | extraFlags); + m_components.push_back(EGlossyReflection | EFrontSide | extraFlags + | ((!m_specularReflectance->isConstant() || !m_alphaU->isConstant() + || !m_alphaV->isConstant()) ? ESpatiallyVarying : 0)); + m_components.push_back(EDiffuseReflection | EFrontSide | extraFlags + | (m_diffuseReflectance->isConstant() ? 0 : ESpatiallyVarying)); /* Verify the input parameters and fix them if necessary */ std::pair result = ensureEnergyConservation( diff --git a/src/librender/texture.cpp b/src/librender/texture.cpp index 01efc62b..de504110 100644 --- a/src/librender/texture.cpp +++ b/src/librender/texture.cpp @@ -31,7 +31,7 @@ Texture::Texture(Stream *stream, InstanceManager *manager) Vector3i Texture::getResolution() const { return Vector3i(0); } - + Texture::~Texture() { } diff --git a/src/textures/bitmap.cpp b/src/textures/bitmap.cpp index 88843042..cddeb6f4 100644 --- a/src/textures/bitmap.cpp +++ b/src/textures/bitmap.cpp @@ -256,6 +256,10 @@ public: return m_maximum; } + bool isConstant() const { + return false; + } + bool usesRayDifferentials() const { return true; } @@ -353,7 +357,7 @@ public: void unbind() const { m_gpuTexture->unbind(); } - + MTS_DECLARE_CLASS() private: ref m_gpuTexture; diff --git a/src/textures/checkerboard.cpp b/src/textures/checkerboard.cpp index 98f13435..46925746 100644 --- a/src/textures/checkerboard.cpp +++ b/src/textures/checkerboard.cpp @@ -71,6 +71,10 @@ public: return m_brightColor; } + bool isConstant() const { + return false; + } + std::string toString() const { return "Checkerboard[]"; } @@ -128,7 +132,7 @@ public: program->setParameter(parameterIDs[2], m_uvOffset); program->setParameter(parameterIDs[3], m_uvScale); } - + MTS_DECLARE_CLASS() private: Spectrum m_brightColor; diff --git a/src/textures/gridtexture.cpp b/src/textures/gridtexture.cpp index d45f7898..cdd417ff 100644 --- a/src/textures/gridtexture.cpp +++ b/src/textures/gridtexture.cpp @@ -79,6 +79,10 @@ public: Spectrum getAverage() const { return m_brightColor; // that's not quite right } + + bool isConstant() const { + return false; + } std::string toString() const { return "GridTexture[]"; diff --git a/src/textures/scale.cpp b/src/textures/scale.cpp index 69522b69..bcb9ecf0 100644 --- a/src/textures/scale.cpp +++ b/src/textures/scale.cpp @@ -68,6 +68,10 @@ public: return m_nested->getMaximum() * m_scale; } + bool isConstant() const { + return m_nested->isConstant(); + } + std::string toString() const { std::ostringstream oss; oss << "ScalingTexture[" << endl diff --git a/src/textures/vertexcolors.cpp b/src/textures/vertexcolors.cpp index 3a5b0e00..79fa0c68 100644 --- a/src/textures/vertexcolors.cpp +++ b/src/textures/vertexcolors.cpp @@ -54,6 +54,10 @@ public: return Spectrum(1.0f); } + bool isConstant() const { + return false; + } + std::string toString() const { return "VertexColors[]"; }