improved interface for ensuring energy conservation
parent
8dbb6327f4
commit
736a8e6866
|
@ -2,8 +2,7 @@
|
|||
to be tested for consistency. This is done
|
||||
using the testcase 'test_chisquare' -->
|
||||
<scene>
|
||||
|
||||
<!-- Test the rough glass model with the
|
||||
<!-- Test the rough dielectric model with the anisotropic
|
||||
Ashikhmin-Shirley microfacet distribution -->
|
||||
<bsdf type="roughdielectric">
|
||||
<string name="distribution" value="as"/>
|
||||
|
@ -19,15 +18,6 @@
|
|||
<string name="extIOR" value="air"/>
|
||||
</bsdf>
|
||||
|
||||
<!-- Test the rough glass model with the
|
||||
Beckmann microfacet distribution -->
|
||||
<bsdf type="roughdielectric">
|
||||
<string name="distribution" value="beckmann"/>
|
||||
<float name="alpha" value=".3"/>
|
||||
<float name="intIOR" value="1.5"/>
|
||||
<float name="extIOR" value="1.0"/>
|
||||
</bsdf>
|
||||
|
||||
<!-- Test the diffuse model -->
|
||||
<bsdf type="diffuse"/>
|
||||
|
||||
|
@ -49,4 +39,41 @@
|
|||
|
||||
<!-- Test the conductor model -->
|
||||
<bsdf type="conductor"/>
|
||||
|
||||
<!-- Test the rough glass model with the
|
||||
Beckmann microfacet distribution -->
|
||||
<bsdf type="roughdielectric">
|
||||
<string name="distribution" value="beckmann"/>
|
||||
<float name="alpha" value=".3"/>
|
||||
<float name="intIOR" value="1.5"/>
|
||||
<float name="extIOR" value="1.0"/>
|
||||
</bsdf>
|
||||
|
||||
<!-- Test the rough glass model with the
|
||||
Phong microfacet distribution -->
|
||||
<bsdf type="roughdielectric">
|
||||
<string name="distribution" value="phong"/>
|
||||
<float name="alpha" value=".3"/>
|
||||
<float name="intIOR" value="1.5"/>
|
||||
<float name="extIOR" value="1.0"/>
|
||||
</bsdf>
|
||||
|
||||
<!-- Test the rough glass model with the
|
||||
GGX microfacet distribution -->
|
||||
<bsdf type="roughdielectric">
|
||||
<string name="distribution" value="ggx"/>
|
||||
<float name="alpha" value=".3"/>
|
||||
<float name="intIOR" value="1.5"/>
|
||||
<float name="extIOR" value="1.0"/>
|
||||
</bsdf>
|
||||
|
||||
<!-- Test the rough dielectric model with the anisotropic
|
||||
Ashikhmin-Shirley microfacet distribution -->
|
||||
<bsdf type="roughdielectric">
|
||||
<string name="distribution" value="as"/>
|
||||
<float name="alphaU" value=".1"/>
|
||||
<float name="alphaV" value=".3"/>
|
||||
<float name="intIOR" value="1.5"/>
|
||||
<float name="extIOR" value="1.0"/>
|
||||
</bsdf>
|
||||
</scene>
|
||||
|
|
|
@ -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<unsigned int> m_components;
|
||||
unsigned int m_combinedType;
|
||||
bool m_usesRayDifferentials;
|
||||
bool m_ensureEnergyConservation;
|
||||
std::string m_name;
|
||||
};
|
||||
|
||||
|
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if !defined(__CONST_TEXTURE_H)
|
||||
#define __CONST_TEXTURE_H
|
||||
|
||||
#include <mitsuba/core/properties.h>
|
||||
#include <mitsuba/render/texture.h>
|
||||
|
||||
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 */
|
|
@ -20,6 +20,7 @@
|
|||
#define __TEXTURE_H
|
||||
|
||||
#include <mitsuba/core/cobject.h>
|
||||
#include <mitsuba/core/properties.h>
|
||||
#include <mitsuba/render/shader.h>
|
||||
|
||||
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<const Texture> m_nested;
|
||||
Float m_scale;
|
||||
};
|
||||
|
||||
MTS_NAMESPACE_END
|
||||
|
||||
#endif /* __TEXTURE_H */
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
*/
|
||||
|
||||
#include <mitsuba/render/bsdf.h>
|
||||
#include <mitsuba/render/consttexture.h>
|
||||
#include <mitsuba/render/texture.h>
|
||||
|
||||
MTS_NAMESPACE_BEGIN
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
*/
|
||||
|
||||
#include <mitsuba/render/bsdf.h>
|
||||
#include <mitsuba/render/consttexture.h>
|
||||
#include <mitsuba/render/texture.h>
|
||||
#include <mitsuba/core/fresolver.h>
|
||||
|
||||
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);
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
*/
|
||||
|
||||
#include <mitsuba/render/bsdf.h>
|
||||
#include <mitsuba/render/consttexture.h>
|
||||
#include <mitsuba/render/texture.h>
|
||||
#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);
|
||||
|
|
|
@ -17,12 +17,11 @@
|
|||
*/
|
||||
|
||||
#include <mitsuba/render/bsdf.h>
|
||||
#include <mitsuba/render/consttexture.h>
|
||||
#include <mitsuba/render/texture.h>
|
||||
#include <mitsuba/hw/renderer.h>
|
||||
|
||||
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)
|
||||
|
|
|
@ -17,8 +17,7 @@
|
|||
*/
|
||||
|
||||
#include <mitsuba/render/bsdf.h>
|
||||
#include <mitsuba/render/consttexture.h>
|
||||
#include <mitsuba/core/properties.h>
|
||||
#include <mitsuba/render/texture.h>
|
||||
#include <mitsuba/hw/renderer.h>
|
||||
|
||||
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();
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 ================
|
||||
|
|
|
@ -18,8 +18,9 @@
|
|||
|
||||
#include <mitsuba/render/bsdf.h>
|
||||
#include <mitsuba/render/sampler.h>
|
||||
#include <mitsuba/render/consttexture.h>
|
||||
#include <mitsuba/render/texture.h>
|
||||
#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]
|
||||
* <bsdf type="roughdielectric">
|
||||
* <string name="distribution" value="beckmann"/>
|
||||
* <float name="intIOR" value="1.5046"/>
|
||||
* <float name="extIOR" value="1.0"/>
|
||||
* <string name="intIOR" value="bk7"/>
|
||||
* <string name="extIOR" value="air"/>
|
||||
*
|
||||
* <texture name="alpha" type="bitmap">
|
||||
* <string name="filename" value="roughness.exr"/>
|
||||
|
@ -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);
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
*/
|
||||
|
||||
#include <mitsuba/render/bsdf.h>
|
||||
#include <mitsuba/render/consttexture.h>
|
||||
#include <mitsuba/render/texture.h>
|
||||
#include <mitsuba/hw/gpuprogram.h>
|
||||
|
||||
MTS_NAMESPACE_BEGIN
|
||||
|
|
|
@ -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 ================
|
||||
|
|
|
@ -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 << "{ ";
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <mitsuba/render/consttexture.h>
|
||||
#include <mitsuba/render/texture.h>
|
||||
#include <mitsuba/hw/gpuprogram.h>
|
||||
|
||||
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<Texture *>(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<Shader *> &deps) {
|
||||
deps.push_back(m_nestedShader.get());
|
||||
}
|
||||
|
||||
void generateCode(std::ostringstream &oss,
|
||||
const std::string &evalName,
|
||||
const std::vector<std::string> &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<int> ¶meterIDs) const {
|
||||
parameterIDs.push_back(program->getParameterID(evalName + "_scale"));
|
||||
}
|
||||
|
||||
void bind(GPUProgram *program, const std::vector<int> ¶meterIDs, int &nestedUnitOffset) const {
|
||||
program->setParameter(parameterIDs[0], m_scale);
|
||||
}
|
||||
|
||||
MTS_DECLARE_CLASS()
|
||||
private:
|
||||
ref<const Texture> m_nested;
|
||||
ref<Shader> 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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
*/
|
||||
|
||||
#include <mitsuba/render/scene.h>
|
||||
#include <mitsuba/render/consttexture.h>
|
||||
#include <mitsuba/render/texture.h>
|
||||
#include <mitsuba/hw/gpuprogram.h>
|
||||
|
||||
MTS_NAMESPACE_BEGIN
|
||||
|
|
Loading…
Reference in New Issue