From 736a8e686682167c7975d7b50e6c65e6e235a95e Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Thu, 7 Jul 2011 17:49:21 +0200 Subject: [PATCH] improved interface for ensuring energy conservation --- data/tests/test_bsdf.xml | 49 +++++++--- include/mitsuba/render/bsdf.h | 14 +++ include/mitsuba/render/consttexture.h | 109 ---------------------- include/mitsuba/render/texture.h | 128 ++++++++++++++++++++++++++ src/bsdfs/coating.cpp | 2 +- src/bsdfs/conductor.cpp | 9 +- src/bsdfs/dielectric.cpp | 11 ++- src/bsdfs/difftrans.cpp | 10 +- src/bsdfs/diffuse.cpp | 14 ++- src/bsdfs/microfacet.h | 18 +--- src/bsdfs/phong.cpp | 8 +- src/bsdfs/roughdielectric.cpp | 30 ++++-- src/bsdfs/twosided.cpp | 2 +- src/bsdfs/ward.cpp | 8 +- src/librender/bsdf.cpp | 29 ++++++ src/librender/texture.cpp | 64 ++++++++++++- src/luminaires/envmap.cpp | 2 +- src/luminaires/spot.cpp | 2 +- 18 files changed, 345 insertions(+), 164 deletions(-) delete mode 100644 include/mitsuba/render/consttexture.h diff --git a/data/tests/test_bsdf.xml b/data/tests/test_bsdf.xml index e5affc8e..a0add420 100644 --- a/data/tests/test_bsdf.xml +++ b/data/tests/test_bsdf.xml @@ -2,8 +2,7 @@ to be tested for consistency. This is done using the testcase 'test_chisquare' --> - - @@ -19,15 +18,6 @@ - - - - - - - - @@ -49,4 +39,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/include/mitsuba/render/bsdf.h b/include/mitsuba/render/bsdf.h index 3395786b..8fcc8a96 100644 --- a/include/mitsuba/render/bsdf.h +++ b/include/mitsuba/render/bsdf.h @@ -422,12 +422,26 @@ protected: /// Unserialize a BSDF instance BSDF(Stream *stream, InstanceManager *manager); + /** + * \brief Convenience function to ensure energy conservation + * + * This function determines the component-wise maximum of the + * texture \c tex and checks if it is below \c max. If yes, + * it returns the texture unmodified. Otherwise, it wraps + * the texture into a \ref ScaleTexture instance (with a + * scaling factor chosen so that the desired maximum \c max + * is abided) and prints a warning. + */ + Texture *ensureEnergyConservation(Texture *tex, + const std::string ¶mName, Float max) const; + /// Virtual destructor virtual ~BSDF(); protected: std::vector m_components; unsigned int m_combinedType; bool m_usesRayDifferentials; + bool m_ensureEnergyConservation; std::string m_name; }; diff --git a/include/mitsuba/render/consttexture.h b/include/mitsuba/render/consttexture.h deleted file mode 100644 index b5af4776..00000000 --- a/include/mitsuba/render/consttexture.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - This file is part of Mitsuba, a physically based rendering system. - - Copyright (c) 2007-2011 by Wenzel Jakob and others. - - Mitsuba is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License Version 3 - as published by the Free Software Foundation. - - Mitsuba is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#if !defined(__CONST_TEXTURE_H) -#define __CONST_TEXTURE_H - -#include -#include - -MTS_NAMESPACE_BEGIN - -class MTS_EXPORT_RENDER ConstantSpectrumTexture : public Texture { -public: - inline ConstantSpectrumTexture(const Spectrum &value) - : Texture(Properties()), m_value(value) { - } - - ConstantSpectrumTexture(Stream *stream, InstanceManager *manager); - - inline Spectrum getValue(const Intersection &its) const { - return m_value; - } - - inline Spectrum getAverage() const { - return m_value; - } - - inline Spectrum getMaximum() const { - return m_value; - } - - inline std::string toString() const { - std::ostringstream oss; - oss << "ConstantSpectrumTexture[value=" << m_value.toString() << "]"; - return oss.str(); - } - - inline bool usesRayDifferentials() const { - return false; - } - - Shader *createShader(Renderer *renderer) const; - - void serialize(Stream *stream, InstanceManager *manager) const; - - MTS_DECLARE_CLASS() -protected: - Spectrum m_value; -}; - -class MTS_EXPORT_RENDER ConstantFloatTexture : public Texture { -public: - inline ConstantFloatTexture(const Float &value) - : Texture(Properties()), m_value(value) { - } - - ConstantFloatTexture(Stream *stream, InstanceManager *manager); - - - inline Spectrum getValue(const Intersection &its) const { - return Spectrum(m_value); - } - - inline Spectrum getAverage() const { - return Spectrum(m_value); - } - - inline Spectrum getMaximum() const { - return Spectrum(m_value); - } - - inline std::string toString() const { - std::ostringstream oss; - oss << "ConstantFloatTexture[value=" << m_value << "]"; - return oss.str(); - } - - inline bool usesRayDifferentials() const { - return false; - } - - Shader *createShader(Renderer *renderer) const; - - void serialize(Stream *stream, InstanceManager *manager) const; - - MTS_DECLARE_CLASS() -protected: - Float m_value; -}; - - -MTS_NAMESPACE_END - -#endif /* __CONST_TEXTURE_H */ diff --git a/include/mitsuba/render/texture.h b/include/mitsuba/render/texture.h index 7fd8f008..4e6f154c 100644 --- a/include/mitsuba/render/texture.h +++ b/include/mitsuba/render/texture.h @@ -20,6 +20,7 @@ #define __TEXTURE_H #include +#include #include MTS_NAMESPACE_BEGIN @@ -85,6 +86,133 @@ protected: Vector2 m_uvScale; }; +/* ============================================================ */ +/* Some vary basic texture definitions */ +/* ============================================================ */ + +class MTS_EXPORT_RENDER ConstantSpectrumTexture : public Texture { +public: + inline ConstantSpectrumTexture(const Spectrum &value) + : Texture(Properties()), m_value(value) { + } + + ConstantSpectrumTexture(Stream *stream, InstanceManager *manager); + + inline Spectrum getValue(const Intersection &its) const { + return m_value; + } + + inline Spectrum getAverage() const { + return m_value; + } + + inline Spectrum getMaximum() const { + return m_value; + } + + inline std::string toString() const { + std::ostringstream oss; + oss << "ConstantSpectrumTexture[value=" << m_value.toString() << "]"; + return oss.str(); + } + + inline bool usesRayDifferentials() const { + return false; + } + + Shader *createShader(Renderer *renderer) const; + + void serialize(Stream *stream, InstanceManager *manager) const; + + MTS_DECLARE_CLASS() +protected: + Spectrum m_value; +}; + +class MTS_EXPORT_RENDER ConstantFloatTexture : public Texture { +public: + inline ConstantFloatTexture(const Float &value) + : Texture(Properties()), m_value(value) { + } + + ConstantFloatTexture(Stream *stream, InstanceManager *manager); + + + inline Spectrum getValue(const Intersection &its) const { + return Spectrum(m_value); + } + + inline Spectrum getAverage() const { + return Spectrum(m_value); + } + + inline Spectrum getMaximum() const { + return Spectrum(m_value); + } + + inline std::string toString() const { + std::ostringstream oss; + oss << "ConstantFloatTexture[value=" << m_value << "]"; + return oss.str(); + } + + inline bool usesRayDifferentials() const { + return false; + } + + Shader *createShader(Renderer *renderer) const; + + void serialize(Stream *stream, InstanceManager *manager) const; + + MTS_DECLARE_CLASS() +protected: + Float m_value; +}; + +class MTS_EXPORT_RENDER ScaleTexture : public Texture { +public: + inline ScaleTexture(const Texture *nested, const Float &scale) + : Texture(Properties()), m_nested(nested), m_scale(scale) { + } + + ScaleTexture(Stream *stream, InstanceManager *manager); + + + inline Spectrum getValue(const Intersection &its) const { + return m_nested->getValue(its) * m_scale; + } + + inline Spectrum getAverage() const { + return m_nested->getAverage() * m_scale; + } + + inline Spectrum getMaximum() const { + return m_nested->getMaximum() * m_scale; + } + + inline std::string toString() const { + std::ostringstream oss; + oss << "ScaleTexture[" << endl + << " nested = " << indent(m_nested->toString()) << "," << endl + << " scale = " << m_scale << endl + << "]"; + return oss.str(); + } + + inline bool usesRayDifferentials() const { + return m_nested->usesRayDifferentials(); + } + + Shader *createShader(Renderer *renderer) const; + + void serialize(Stream *stream, InstanceManager *manager) const; + + MTS_DECLARE_CLASS() +protected: + ref m_nested; + Float m_scale; +}; + MTS_NAMESPACE_END #endif /* __TEXTURE_H */ diff --git a/src/bsdfs/coating.cpp b/src/bsdfs/coating.cpp index 33d7ee14..615faec6 100644 --- a/src/bsdfs/coating.cpp +++ b/src/bsdfs/coating.cpp @@ -17,7 +17,7 @@ */ #include -#include +#include MTS_NAMESPACE_BEGIN diff --git a/src/bsdfs/conductor.cpp b/src/bsdfs/conductor.cpp index 6448f2a1..8ed4f6a9 100644 --- a/src/bsdfs/conductor.cpp +++ b/src/bsdfs/conductor.cpp @@ -17,7 +17,7 @@ */ #include -#include +#include #include MTS_NAMESPACE_BEGIN @@ -180,6 +180,13 @@ public: } } + void configure() { + BSDF::configure(); + /* Verify the input parameter and fix them if necessary */ + m_specularReflectance = ensureEnergyConservation( + m_specularReflectance, "specularReflectance", 1.0f); + } + /// Reflection in local coordinates inline Vector reflect(const Vector &wi) const { return Vector(-wi.x, -wi.y, wi.z); diff --git a/src/bsdfs/dielectric.cpp b/src/bsdfs/dielectric.cpp index 3e4ad269..45fcc263 100644 --- a/src/bsdfs/dielectric.cpp +++ b/src/bsdfs/dielectric.cpp @@ -17,7 +17,7 @@ */ #include -#include +#include #include "ior.h" MTS_NAMESPACE_BEGIN @@ -186,6 +186,15 @@ public: } } + void configure() { + BSDF::configure(); + /* Verify the input parameter and fix them if necessary */ + m_specularReflectance = ensureEnergyConservation( + m_specularReflectance, "specularReflectance", 1.0f); + m_specularTransmittance = ensureEnergyConservation( + m_specularTransmittance, "specularTransmittance", 1.0f); + } + /// Reflection in local coordinates inline Vector reflect(const Vector &wi) const { return Vector(-wi.x, -wi.y, wi.z); diff --git a/src/bsdfs/difftrans.cpp b/src/bsdfs/difftrans.cpp index eddd9a2e..b334d6df 100644 --- a/src/bsdfs/difftrans.cpp +++ b/src/bsdfs/difftrans.cpp @@ -17,12 +17,11 @@ */ #include -#include +#include #include MTS_NAMESPACE_BEGIN - /*! \plugin{difftrans}{Diffuse transmitter} * * \parameters{ @@ -42,7 +41,6 @@ MTS_NAMESPACE_BEGIN * 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: DiffuseTransmitter(const Properties &props) @@ -65,6 +63,12 @@ public: virtual ~DiffuseTransmitter() { } + void configure() { + BSDF::configure(); + /* Verify the input parameter and fix them if necessary */ + m_transmittance = ensureEnergyConservation(m_transmittance, "transmittance", 1.0f); + } + Spectrum eval(const BSDFQueryRecord &bRec, EMeasure measure) const { if (!(bRec.typeMask & EDiffuseTransmission) || measure != ESolidAngle || Frame::cosTheta(bRec.wi) * Frame::cosTheta(bRec.wo) >= 0) diff --git a/src/bsdfs/diffuse.cpp b/src/bsdfs/diffuse.cpp index a8de30da..f01edeb3 100644 --- a/src/bsdfs/diffuse.cpp +++ b/src/bsdfs/diffuse.cpp @@ -17,8 +17,7 @@ */ #include -#include -#include +#include #include MTS_NAMESPACE_BEGIN @@ -87,6 +86,16 @@ public: virtual ~SmoothDiffuse() { } + void configure() { + BSDF::configure(); + /* Verify the input parameter and fix them if necessary */ + m_reflectance = ensureEnergyConservation(m_reflectance, "reflectance", 1.0f); + } + + Spectrum getDiffuseReflectance(const Intersection &its) const { + return m_reflectance->getValue(its); + } + Spectrum eval(const BSDFQueryRecord &bRec, EMeasure measure) const { if (!(bRec.typeMask & EDiffuseReflection) || measure != ESolidAngle || Frame::cosTheta(bRec.wi) <= 0 @@ -147,6 +156,7 @@ public: std::string toString() const { std::ostringstream oss; oss << "SmoothDiffuse[" << endl + << " name = \"" << getName() << "\"," << endl << " reflectance = " << indent(m_reflectance->toString()) << endl << "]"; return oss.str(); diff --git a/src/bsdfs/microfacet.h b/src/bsdfs/microfacet.h index c5b90dc4..4a84a333 100644 --- a/src/bsdfs/microfacet.h +++ b/src/bsdfs/microfacet.h @@ -106,7 +106,7 @@ public: case EPhong: { /* Phong distribution function */ - result = (alphaU + 1) * INV_TWOPI + result = (alphaU + 2) * INV_TWOPI * std::pow(Frame::cosTheta(m), alphaU); } break; @@ -315,20 +315,8 @@ public: * \param alpha The surface roughness */ Float G(const Vector &wi, const Vector &wo, const Vector &m, Float alphaU, Float alphaV) const { - if (EXPECT_TAKEN(m_type != EAshikhminShirley)) { - return smithG1(wi, m, alphaU) * smithG1(wo, m, alphaV); - } else { - /* Infinite groove shadowing/masking */ - const Float nDotM = std::abs(Frame::cosTheta(m)), - nDotWo = std::abs(Frame::cosTheta(wo)), - nDotWi = std::abs(Frame::cosTheta(wi)), - woDotM = absDot(wo, m), - wiDotM = absDot(wi, m); - - return std::max((Float) 0, std::min((Float) 1, - std::min(2 * nDotM * nDotWo / woDotM, - 2 * nDotM * nDotWi / wiDotM))); - } + Float alpha = std::max(alphaU, alphaV); + return smithG1(wi, m, alpha) * smithG1(wo, m, alpha); } std::string toString() const { diff --git a/src/bsdfs/phong.cpp b/src/bsdfs/phong.cpp index af37febc..2877bf40 100644 --- a/src/bsdfs/phong.cpp +++ b/src/bsdfs/phong.cpp @@ -41,7 +41,7 @@ public: m_exponent = props.getFloat("exponent", 10.0f); - m_verifyEnergyConservation = props.getBoolean("verifyEnergyConservation", true); + m_ensureEnergyConservation = props.getBoolean("ensureEnergyConservation", true); m_specularSamplingWeight = props.getFloat("specularSamplingWeight", -1); m_componentCount = 2; @@ -78,14 +78,14 @@ public: void configure() { BSDF::configure(); - if (m_verifyEnergyConservation && (m_kd * m_diffuseReflectance->getMaximum().max() + if (m_ensureEnergyConservation && (m_kd * m_diffuseReflectance->getMaximum().max() + m_ks * m_specularReflectance->getMaximum().max() > 1.0f)) { Log(EWarn, "Material \"%s\": Energy conservation is potentially violated!", getName().c_str()); Log(EWarn, "Max. diffuse reflectance = %f * %f = %f", m_kd, m_diffuseReflectance->getMaximum().max(), m_kd*m_diffuseReflectance->getMaximum().max()); Log(EWarn, "Max. specular reflectance = %f * %f = %f", m_ks, m_specularReflectance->getMaximum().max(), m_ks*m_specularReflectance->getMaximum().max()); Float normalization = 1/(m_kd * m_diffuseReflectance->getMaximum().max() + m_ks * m_specularReflectance->getMaximum().max()); Log(EWarn, "Reducing the albedo to %.1f%% of the original value to be on the safe side. " - "Specify verifyEnergyConservation=false to prevent this.", normalization * 100); + "Specify ensureEnergyConservation=false to prevent this.", normalization * 100); m_kd *= normalization; m_ks *= normalization; } @@ -275,7 +275,7 @@ private: Float m_kd, m_ks; Float m_specularSamplingWeight; Float m_diffuseSamplingWeight; - bool m_verifyEnergyConservation; + bool m_ensureEnergyConservation; }; // ================ Hardware shader implementation ================ diff --git a/src/bsdfs/roughdielectric.cpp b/src/bsdfs/roughdielectric.cpp index 4df4b24a..17ca8463 100644 --- a/src/bsdfs/roughdielectric.cpp +++ b/src/bsdfs/roughdielectric.cpp @@ -18,8 +18,9 @@ #include #include -#include +#include #include "microfacet.h" +#include "ior.h" MTS_NAMESPACE_BEGIN @@ -123,8 +124,8 @@ MTS_NAMESPACE_BEGIN * \begin{xml}[caption=A texture can be attached to the roughness parameter, label=lst:roughdielectric-textured] * * - * - * + * + * * * * @@ -141,8 +142,11 @@ public: m_specularTransmittance = new ConstantSpectrumTexture( props.getSpectrum("specularTransmittance", Spectrum(1.0f))); - m_intIOR = props.getFloat("intIOR", 1.5046f); - m_extIOR = props.getFloat("extIOR", 1.0f); + /* Specifies the internal index of refraction at the interface */ + m_intIOR = lookupIOR(props, "intIOR", "bk7"); + + /* Specifies the external index of refraction at the interface */ + m_extIOR = lookupIOR(props, "extIOR", "air"); if (m_intIOR < 0 || m_extIOR < 0 || m_intIOR == m_extIOR) Log(EError, "The interior and exterior indices of " @@ -208,6 +212,12 @@ public: m_components.push_back( EGlossyTransmission | EFrontSide | EBackSide | ECanUseSampler | extraFlags); + /* Verify the input parameter and fix them if necessary */ + m_specularReflectance = ensureEnergyConservation( + m_specularReflectance, "specularReflectance", 1.0f); + m_specularTransmittance = ensureEnergyConservation( + m_specularTransmittance, "specularTransmittance", 1.0f); + BSDF::configure(); } @@ -303,7 +313,8 @@ public: } else { /* Calculate the total amount of transmission */ Float sqrtDenom = etaI * dot(bRec.wi, H) + etaT * dot(bRec.wo, H); - Float value = ((1 - F) * D * G * etaT * etaT * dot(bRec.wi, H)*dot(bRec.wo, H)) / + Float value = ((1 - F) * D * G * etaT * etaT + * dot(bRec.wi, H) * dot(bRec.wo, H)) / (Frame::cosTheta(bRec.wi) * sqrtDenom * sqrtDenom); /* Missing term in the original paper: account for the solid angle @@ -380,6 +391,7 @@ public: std::abs(Frame::cosTheta(bRec.wi)))); alphaU *= factor; alphaV *= factor; #endif + /* Microsurface normal sampling density */ Float prob = m_distribution.pdf(H, alphaU, alphaV); @@ -512,7 +524,8 @@ public: return Spectrum(0.0f); result = m_specularTransmittance->getValue(bRec.its) - * ((bRec.quantity == ERadiance) ? ((etaI*etaI) / (etaT*etaT)) : (Float) 1); + * ((bRec.quantity == ERadiance) ? + ((etaI*etaI) / (etaT*etaT)) : (Float) 1); } Float numerator = m_distribution.eval(m, alphaU, alphaV) @@ -603,7 +616,8 @@ public: #endif /* Sample M, the microsurface normal */ - const Normal m = m_distribution.sample(sample, sampleAlphaU, sampleAlphaV); + const Normal m = m_distribution.sample(sample, + sampleAlphaU, sampleAlphaV); if (sampleExactFresnelTerm) { Float sampleF = fresnel(dot(bRec.wi, m), m_extIOR, m_intIOR); diff --git a/src/bsdfs/twosided.cpp b/src/bsdfs/twosided.cpp index a5210c4f..5e13f315 100644 --- a/src/bsdfs/twosided.cpp +++ b/src/bsdfs/twosided.cpp @@ -17,7 +17,7 @@ */ #include -#include +#include #include MTS_NAMESPACE_BEGIN diff --git a/src/bsdfs/ward.cpp b/src/bsdfs/ward.cpp index 663ec4f1..d54ee44c 100644 --- a/src/bsdfs/ward.cpp +++ b/src/bsdfs/ward.cpp @@ -72,7 +72,7 @@ public: Log(EError, "Specified an invalid model type \"%s\", must be " "\"ward\", \"ward-duer\", or \"balanced\"!", type.c_str()); - m_verifyEnergyConservation = props.getBoolean("verifyEnergyConservation", true); + m_ensureEnergyConservation = props.getBoolean("ensureEnergyConservation", true); m_specularSamplingWeight = props.getFloat("specularSamplingWeight", -1); m_alphaX = props.getFloat("alphaX", .1f); @@ -116,14 +116,14 @@ public: } void configure() { - if (m_verifyEnergyConservation && (m_kd * m_diffuseReflectance->getMaximum().max() + if (m_ensureEnergyConservation && (m_kd * m_diffuseReflectance->getMaximum().max() + m_ks * m_specularReflectance->getMaximum().max() > 1.0f)) { Log(EWarn, "Material \"%s\": Energy conservation is potentially violated!", getName().c_str()); Log(EWarn, "Max. diffuse reflectance = %f * %f = %f", m_kd, m_diffuseReflectance->getMaximum().max(), m_kd*m_diffuseReflectance->getMaximum().max()); Log(EWarn, "Max. specular reflectance = %f * %f = %f", m_ks, m_specularReflectance->getMaximum().max(), m_ks*m_specularReflectance->getMaximum().max()); Float normalization = 1/(m_kd * m_diffuseReflectance->getMaximum().max() + m_ks * m_specularReflectance->getMaximum().max()); Log(EWarn, "Reducing the albedo to %.1f%% of the original value to be on the safe side. " - "Specify verifyEnergyConservation=false to prevent this.", normalization * 100); + "Specify ensureEnergyConservation=false to prevent this.", normalization * 100); m_kd *= normalization; m_ks *= normalization; } @@ -340,7 +340,7 @@ private: Float m_kd, m_ks; Float m_specularSamplingWeight; Float m_diffuseSamplingWeight; - bool m_verifyEnergyConservation; + bool m_ensureEnergyConservation; }; // ================ Hardware shader implementation ================ diff --git a/src/librender/bsdf.cpp b/src/librender/bsdf.cpp index 2b3737e7..b1128d10 100644 --- a/src/librender/bsdf.cpp +++ b/src/librender/bsdf.cpp @@ -23,11 +23,17 @@ MTS_NAMESPACE_BEGIN BSDF::BSDF(const Properties &props) : ConfigurableObject(props), m_name(props.getID()) { + /* By default, verify whether energy conservation holds + for the user-specified parameter values. This step + is completely up to the particular BSDF implementations */ + m_ensureEnergyConservation = props.getBoolean( + "ensureEnergyConservation", true); } BSDF::BSDF(Stream *stream, InstanceManager *manager) : ConfigurableObject(stream, manager) { m_name = stream->readString(); + m_ensureEnergyConservation = stream->readBool(); } BSDF::~BSDF() { } @@ -35,6 +41,7 @@ BSDF::~BSDF() { } void BSDF::serialize(Stream *stream, InstanceManager *manager) const { ConfigurableObject::serialize(stream, manager); stream->writeString(m_name); + stream->writeBool(m_ensureEnergyConservation); } void BSDF::setParent(ConfigurableObject *parent) { @@ -58,6 +65,28 @@ Spectrum BSDF::getDiffuseReflectance(const Intersection &its) const { return eval(bRec) * M_PI; } +Texture *BSDF::ensureEnergyConservation(Texture *texture, + const std::string ¶mName, Float max) const { + if (!m_ensureEnergyConservation) + return texture; + + Float actualMax = texture->getMaximum().max(); + if (actualMax > max) { + std::ostringstream oss; + Float scale = 0.99f * (max / actualMax); + oss << "The BSDF" << endl << toString() << endl + << "violates energy conservation! The parameter \"" << paramName << "\" " + << "has a component-wise maximum of "<< actualMax << " (which is > " << max << "!) " + << "and will therefore be scaled by " << scale << " to prevent " + << "issues. Specify the parameter ensureEnergyConservation=false " + << "to the BSDF to prevent this from happening."; + Log(EWarn, "%s", oss.str().c_str()); + return new ScaleTexture(texture, scale); + } + return texture; +} + + static std::string typeMaskToString(unsigned int typeMask) { std::ostringstream oss; oss << "{ "; diff --git a/src/librender/texture.cpp b/src/librender/texture.cpp index fa8aff2a..618cb1e4 100644 --- a/src/librender/texture.cpp +++ b/src/librender/texture.cpp @@ -16,7 +16,7 @@ along with this program. If not, see . */ -#include +#include #include MTS_NAMESPACE_BEGIN @@ -102,6 +102,18 @@ void ConstantFloatTexture::serialize(Stream *stream, InstanceManager *manager) c stream->writeFloat(m_value); } +ScaleTexture::ScaleTexture(Stream *stream, InstanceManager *manager) + : Texture(stream, manager) { + m_nested = static_cast(manager->getInstance(stream)); + m_scale = stream->readFloat(); +} + +void ScaleTexture::serialize(Stream *stream, InstanceManager *manager) const { + Texture::serialize(stream, manager); + manager->serialize(stream, m_nested.get()); + stream->writeFloat(m_scale); +} + class ConstantSpectrumTextureShader : public Shader { public: ConstantSpectrumTextureShader(Renderer *renderer, const Spectrum &value) @@ -160,6 +172,50 @@ private: Float m_value; }; +class ScaleTextureShader : public Shader { +public: + ScaleTextureShader(Renderer *renderer, const Texture *nested, const Float &scale) + : Shader(renderer, ETextureShader), m_nested(nested), m_scale(scale) { + m_nestedShader = renderer->registerShaderForResource(m_nested.get()); + } + + bool isComplete() const { + return m_nestedShader.get() != NULL; + } + + void cleanup(Renderer *renderer) { + renderer->unregisterShaderForResource(m_nested.get()); + } + + void putDependencies(std::vector &deps) { + deps.push_back(m_nestedShader.get()); + } + + void generateCode(std::ostringstream &oss, + const std::string &evalName, + const std::vector &depNames) const { + oss << "uniform float " << evalName << "_scale;" << endl + << endl + << "vec3 " << evalName << "(vec2 uv) {" << endl + << " return " << depNames[0] << "(uv) * " << evalName << "_scale;" << endl + << "}" << endl; + } + + void resolve(const GPUProgram *program, const std::string &evalName, std::vector ¶meterIDs) const { + parameterIDs.push_back(program->getParameterID(evalName + "_scale")); + } + + void bind(GPUProgram *program, const std::vector ¶meterIDs, int &nestedUnitOffset) const { + program->setParameter(parameterIDs[0], m_scale); + } + + MTS_DECLARE_CLASS() +private: + ref m_nested; + ref m_nestedShader; + Float m_scale; +}; + Shader *ConstantSpectrumTexture::createShader(Renderer *renderer) const { return new ConstantSpectrumTextureShader(renderer, m_value); } @@ -168,7 +224,9 @@ Shader *ConstantFloatTexture::createShader(Renderer *renderer) const { return new ConstantFloatTextureShader(renderer, m_value); } - +Shader *ScaleTexture::createShader(Renderer *renderer) const { + return new ScaleTextureShader(renderer, m_nested.get(), m_scale); +} MTS_IMPLEMENT_CLASS(Texture, true, ConfigurableObject) MTS_IMPLEMENT_CLASS(Texture2D, true, Texture) @@ -176,4 +234,6 @@ 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(ScaleTexture, false, Texture) +MTS_IMPLEMENT_CLASS(ScaleTextureShader, false, Shader) MTS_NAMESPACE_END diff --git a/src/luminaires/envmap.cpp b/src/luminaires/envmap.cpp index d5a9b4e2..36dab570 100644 --- a/src/luminaires/envmap.cpp +++ b/src/luminaires/envmap.cpp @@ -390,7 +390,7 @@ public: // into doing correct texture filtering across the u=0 to u=1 seam. << " if (u < 0.1)" << endl << " return texture2D(" << evalName << "_texture, vec2(u+1.0, v)).rgb * " << evalName << "_intensityScale;" << endl - << " else" + << " else" << endl << " return texture2D(" << evalName << "_texture, vec2(u, v)).rgb * " << evalName << "_intensityScale;" << endl << "}" << endl; } diff --git a/src/luminaires/spot.cpp b/src/luminaires/spot.cpp index add70d93..a74bca49 100644 --- a/src/luminaires/spot.cpp +++ b/src/luminaires/spot.cpp @@ -17,7 +17,7 @@ */ #include -#include +#include #include MTS_NAMESPACE_BEGIN