various cleanups, started working on the smooth dielectric coating
parent
aa1a9a1881
commit
42b92dac8f
|
@ -2,6 +2,12 @@
|
||||||
to be tested for consistency. This is done
|
to be tested for consistency. This is done
|
||||||
using the testcase 'test_chisquare' -->
|
using the testcase 'test_chisquare' -->
|
||||||
<scene>
|
<scene>
|
||||||
|
<bsdf type="coating">
|
||||||
|
<float name="intIOR" value="1.5"/>
|
||||||
|
<float name="extIOR" value="1"/>
|
||||||
|
<bsdf type="diffuse"/>
|
||||||
|
</bsdf>
|
||||||
|
|
||||||
<!-- Test the smooth diffuse model -->
|
<!-- Test the smooth diffuse model -->
|
||||||
<bsdf type="diffuse"/>
|
<bsdf type="diffuse"/>
|
||||||
|
|
||||||
|
@ -130,6 +136,6 @@
|
||||||
|
|
||||||
<!-- Test the mask model -->
|
<!-- Test the mask model -->
|
||||||
<bsdf type="mask">
|
<bsdf type="mask">
|
||||||
<bsdf type="lambertian"/>
|
<bsdf type="diffuse"/>
|
||||||
</bsdf>
|
</bsdf>
|
||||||
</scene>
|
</scene>
|
||||||
|
|
|
@ -11,15 +11,14 @@ plugins += env.SharedLibrary('roughconductor', ['roughconductor.cpp'])
|
||||||
plugins += env.SharedLibrary('roughplastic', ['roughplastic.cpp'])
|
plugins += env.SharedLibrary('roughplastic', ['roughplastic.cpp'])
|
||||||
|
|
||||||
# Materials that act as modifiers
|
# Materials that act as modifiers
|
||||||
#plugins += env.SharedLibrary('coating', ['coating.cpp'])
|
|
||||||
plugins += env.SharedLibrary('twosided', ['twosided.cpp'])
|
plugins += env.SharedLibrary('twosided', ['twosided.cpp'])
|
||||||
plugins += env.SharedLibrary('mask', ['mask.cpp'])
|
plugins += env.SharedLibrary('mask', ['mask.cpp'])
|
||||||
plugins += env.SharedLibrary('mixture', ['mixture.cpp'])
|
plugins += env.SharedLibrary('mixture', ['mixture.cpp'])
|
||||||
|
plugins += env.SharedLibrary('coating', ['coating.cpp'])
|
||||||
|
|
||||||
# Other materials
|
# Other materials
|
||||||
plugins += env.SharedLibrary('phong', ['phong.cpp'])
|
|
||||||
plugins += env.SharedLibrary('ward', ['ward.cpp'])
|
plugins += env.SharedLibrary('ward', ['ward.cpp'])
|
||||||
|
plugins += env.SharedLibrary('phong', ['phong.cpp'])
|
||||||
plugins += env.SharedLibrary('irawan', ['irawan.cpp'])
|
plugins += env.SharedLibrary('irawan', ['irawan.cpp'])
|
||||||
plugins += env.SharedLibrary('difftrans', ['difftrans.cpp'])
|
plugins += env.SharedLibrary('difftrans', ['difftrans.cpp'])
|
||||||
|
|
||||||
|
|
|
@ -17,39 +17,43 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <mitsuba/render/bsdf.h>
|
#include <mitsuba/render/bsdf.h>
|
||||||
#include <mitsuba/render/texture.h>
|
#include <mitsuba/hw/basicshader.h>
|
||||||
|
#include "ior.h"
|
||||||
|
|
||||||
MTS_NAMESPACE_BEGIN
|
MTS_NAMESPACE_BEGIN
|
||||||
|
|
||||||
/*! \plugin{coating}{Smooth dieletric coating}
|
/*! \plugin{coating}{Smooth dielectric coating}
|
||||||
* \order{9}
|
* \order{9}
|
||||||
*
|
*
|
||||||
* \parameters{
|
* \parameters{
|
||||||
* \parameter{intIOR}{\Float}{Interior index of refraction \default{1.5046}}
|
* \parameter{intIOR}{\Float\Or\String}{Interior index of refraction specified
|
||||||
* \parameter{extIOR}{\Float}{Exterior index of refraction \default{1.0}}
|
* 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}}
|
||||||
* }
|
* }
|
||||||
* This class implements a smooth dielectric coating in the style of \cite{Weidlich2007Arbitrarily}.
|
|
||||||
*
|
*
|
||||||
* XXX cancel out cosine factors?
|
* This class implements a smooth dielectric coating in the style of
|
||||||
* XXX did I get the measure conversion terms right?
|
* Weidlich and Wilkie \cite{Weidlich2007Arbitrarily}.
|
||||||
* XXX allow testing interface to verify delta components
|
|
||||||
*/
|
*/
|
||||||
class SmoothVarnish : public BSDF {
|
class SmoothCoating : public BSDF {
|
||||||
public:
|
public:
|
||||||
SmoothVarnish(const Properties &props)
|
SmoothCoating(const Properties &props)
|
||||||
: BSDF(props) {
|
: BSDF(props) {
|
||||||
/* Specifies the internal index of refraction at the interface */
|
/* Specifies the internal index of refraction at the interface */
|
||||||
m_intIOR = props.getFloat("intIOR", 1.5046f);
|
m_intIOR = lookupIOR(props, "intIOR", "bk7");
|
||||||
|
|
||||||
/* Specifies the external index of refraction at the interface */
|
/* Specifies the external index of refraction at the interface */
|
||||||
m_extIOR = props.getFloat("extIOR", 1);
|
m_extIOR = lookupIOR(props, "extIOR", "air");
|
||||||
|
|
||||||
/* Specifies the layer's thickness using the inverse units of sigmaT */
|
/* Specifies the layer's thickness using the inverse units of sigmaT */
|
||||||
m_thickness = props.getFloat("thickness", 1);
|
m_thickness = props.getFloat("thickness", 1);
|
||||||
|
|
||||||
/* Specifies the attenuation within the varnish layer */
|
/* Specifies the attenuation within the varnish layer */
|
||||||
m_sigmaT = new ConstantSpectrumTexture(
|
m_sigmaT = new ConstantSpectrumTexture(
|
||||||
props.getSpectrum("sigmaT", Spectrum(0.0f)));
|
props.getSpectrum("sigmaT", Spectrum(0.0f)));
|
||||||
}
|
}
|
||||||
|
|
||||||
SmoothVarnish(Stream *stream, InstanceManager *manager)
|
SmoothCoating(Stream *stream, InstanceManager *manager)
|
||||||
: BSDF(stream, manager) {
|
: BSDF(stream, manager) {
|
||||||
m_intIOR = stream->readFloat();
|
m_intIOR = stream->readFloat();
|
||||||
m_extIOR = stream->readFloat();
|
m_extIOR = stream->readFloat();
|
||||||
|
@ -59,32 +63,22 @@ public:
|
||||||
configure();
|
configure();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~SmoothVarnish() {
|
|
||||||
delete[] m_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
void configure() {
|
void configure() {
|
||||||
if (!m_nested)
|
if (!m_nested)
|
||||||
Log(EError, "A child BSDF instance is required");
|
Log(EError, "A child BSDF instance is required");
|
||||||
if (m_nested->getType() & BSDF::ETransmission)
|
if (m_nested->getType() & BSDF::ETransmission)
|
||||||
Log(EError, "Tried to put a smooth varnish layer on top of a BSDF "
|
Log(EError, "Tried to put a smooth coating layer on top of a BSDF "
|
||||||
"with a transmission component -- this is currently not allowed!");
|
"with a transmission component -- this is currently not allowed!");
|
||||||
if (m_nested->getType() & BSDF::EDelta)
|
|
||||||
Log(EError, "Tried to put a smooth varnish layer on top of a material with a "
|
|
||||||
"Dirac delta distribution -- this is currently not allowed!");
|
|
||||||
if (m_type)
|
|
||||||
delete[] m_type;
|
|
||||||
|
|
||||||
m_componentCount = 1 + m_nested->getComponentCount();
|
m_components.clear();
|
||||||
m_type = new unsigned int[m_componentCount];
|
for (int i=0; i<m_nested->getComponentCount(); ++i)
|
||||||
m_type[0] = EDeltaReflection | EFrontSide;
|
m_components.push_back(m_nested->getType(i));
|
||||||
m_combinedType = m_type[0];
|
m_components.push_back(EDeltaReflection | EFrontSide);
|
||||||
for (int i=0; i<m_nested->getComponentCount(); ++i) {
|
|
||||||
m_type[i+1] = m_nested->getType(i);
|
|
||||||
m_combinedType |= m_type[i+1];
|
|
||||||
}
|
|
||||||
m_usesRayDifferentials = m_nested->usesRayDifferentials()
|
m_usesRayDifferentials = m_nested->usesRayDifferentials()
|
||||||
|| m_sigmaT->usesRayDifferentials();
|
|| m_sigmaT->usesRayDifferentials();
|
||||||
|
|
||||||
|
BSDF::configure();
|
||||||
}
|
}
|
||||||
|
|
||||||
void serialize(Stream *stream, InstanceManager *manager) const {
|
void serialize(Stream *stream, InstanceManager *manager) const {
|
||||||
|
@ -121,8 +115,8 @@ public:
|
||||||
return Vector(-eta*wi.x, -eta*wi.y, cosThetaT);
|
return Vector(-eta*wi.x, -eta*wi.y, cosThetaT);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fully complete local coordinate refraction routine
|
/// Refraction in local coordinates (full version)
|
||||||
inline Vector refract(const Vector &wi, Float &Fr) const {
|
inline Vector refract(const Vector &wi, Float &F) const {
|
||||||
Float cosThetaI = Frame::cosTheta(wi),
|
Float cosThetaI = Frame::cosTheta(wi),
|
||||||
etaI = m_extIOR,
|
etaI = m_extIOR,
|
||||||
etaT = m_intIOR;
|
etaT = m_intIOR;
|
||||||
|
@ -141,72 +135,138 @@ public:
|
||||||
Float cosThetaT = 0;
|
Float cosThetaT = 0;
|
||||||
if (sinThetaTSqr >= 1.0f) {
|
if (sinThetaTSqr >= 1.0f) {
|
||||||
/* Total internal reflection */
|
/* Total internal reflection */
|
||||||
Fr = 1.0f;
|
F = 1.0f;
|
||||||
|
|
||||||
return Vector(0.0f);
|
return Vector(0.0f);
|
||||||
} else {
|
} else {
|
||||||
cosThetaT = std::sqrt(1.0f - sinThetaTSqr);
|
cosThetaT = std::sqrt(1.0f - sinThetaTSqr);
|
||||||
|
|
||||||
/* Compute the Fresnel refletance */
|
/* Compute the Fresnel transmittance */
|
||||||
Fr = fresnelDielectric(std::abs(cosThetaI),
|
F = fresnelDielectric(std::abs(Frame::cosTheta(wi)),
|
||||||
cosThetaT, etaI, etaT);
|
cosThetaT, m_extIOR, m_intIOR);
|
||||||
|
|
||||||
if (entering)
|
return Vector(-eta*wi.x, -eta*wi.y,
|
||||||
cosThetaT = -cosThetaT;
|
entering ? -cosThetaT : cosThetaT);
|
||||||
return Vector(-eta*wi.x, -eta*wi.y, cosThetaT);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Spectrum eval(const BSDFQueryRecord &bRec, EMeasure measure) const {
|
||||||
|
if (Frame::cosTheta(bRec.wi) <= 0 ||
|
||||||
|
Frame::cosTheta(bRec.wo) <= 0)
|
||||||
|
return Spectrum(0.0f);
|
||||||
|
|
||||||
|
bool sampleSpecular = (bRec.typeMask & EDeltaReflection)
|
||||||
|
&& (bRec.component == -1 || bRec.component == (int) m_components.size()-1);
|
||||||
|
bool sampleNested = (bRec.typeMask & m_nested->getType() & BSDF::EAll)
|
||||||
|
&& (bRec.component == -1 || bRec.component < (int) m_components.size()-1);
|
||||||
|
|
||||||
|
if (measure == EDiscrete && sampleSpecular &&
|
||||||
|
std::abs(1-dot(reflect(bRec.wi), bRec.wo)) < Epsilon) {
|
||||||
|
return Spectrum(fresnel(
|
||||||
|
Frame::cosTheta(bRec.wi), m_extIOR, m_intIOR));
|
||||||
|
} else if (sampleNested) {
|
||||||
|
Float R12, R21;
|
||||||
|
BSDFQueryRecord bRec2(bRec);
|
||||||
|
bRec2.wi = -refract(bRec.wi, R12);
|
||||||
|
bRec2.wo = -refract(bRec.wo, R21);
|
||||||
|
Assert(bRec2.wi.z >= 0);
|
||||||
|
Assert(bRec2.wo.z >= 0);
|
||||||
|
|
||||||
|
if (R12 == 1 || R21 == 1) /* Total internal reflection */
|
||||||
|
return Spectrum(0.0f);
|
||||||
|
|
||||||
|
Spectrum result = m_nested->eval(bRec2, measure)
|
||||||
|
* ((1-R12) * (1-R21));
|
||||||
|
|
||||||
|
Spectrum sigmaT = m_sigmaT->getValue(bRec.its) * m_thickness;
|
||||||
|
if (!sigmaT.isZero())
|
||||||
|
result *= (-sigmaT *
|
||||||
|
(1/std::abs(Frame::cosTheta(bRec2.wi)) +
|
||||||
|
1/std::abs(Frame::cosTheta(bRec2.wo)))).exp();
|
||||||
|
|
||||||
|
if (measure == ESolidAngle)
|
||||||
|
result *= Frame::cosTheta(bRec2.wo);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Spectrum(0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
Float pdf(const BSDFQueryRecord &bRec, EMeasure measure) const {
|
||||||
|
if (Frame::cosTheta(bRec.wi) <= 0 ||
|
||||||
|
Frame::cosTheta(bRec.wo) <= 0)
|
||||||
|
return 0.0f;
|
||||||
|
|
||||||
|
bool sampleSpecular = (bRec.typeMask & EDeltaReflection)
|
||||||
|
&& (bRec.component == -1 || bRec.component == (int) m_components.size()-1);
|
||||||
|
bool sampleNested = (bRec.typeMask & m_nested->getType() & BSDF::EAll)
|
||||||
|
&& (bRec.component == -1 || bRec.component < (int) m_components.size()-1);
|
||||||
|
|
||||||
|
if (measure == EDiscrete && sampleSpecular &&
|
||||||
|
std::abs(1-dot(reflect(bRec.wi), bRec.wo)) < Epsilon) {
|
||||||
|
return sampleNested ? fresnel(
|
||||||
|
Frame::cosTheta(bRec.wi), m_extIOR, m_intIOR) : 1.0f;
|
||||||
|
} else if (sampleNested) {
|
||||||
|
Float R12, R21;
|
||||||
|
BSDFQueryRecord bRec2(bRec);
|
||||||
|
bRec2.wi = -refract(bRec.wi, R12);
|
||||||
|
bRec2.wo = -refract(bRec.wo, R21);
|
||||||
|
|
||||||
|
if (R12 == 1 || R21 == 1) /* Total internal reflection */
|
||||||
|
return 0.0f;
|
||||||
|
|
||||||
|
Float pdf = m_nested->pdf(bRec2, measure);
|
||||||
|
if (measure == ESolidAngle) {
|
||||||
|
Float eta = m_extIOR / m_intIOR;
|
||||||
|
pdf /= eta * eta;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sampleSpecular ? (pdf * (1-R12)) : pdf;
|
||||||
|
} else {
|
||||||
|
return 0.0f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Spectrum sample(BSDFQueryRecord &bRec, Float &pdf, const Point2 &_sample) const {
|
Spectrum sample(BSDFQueryRecord &bRec, Float &pdf, const Point2 &_sample) const {
|
||||||
bool sampleReflection = (bRec.typeMask & EDeltaReflection)
|
bool sampleSpecular = (bRec.typeMask & EDeltaReflection)
|
||||||
&& (bRec.component == -1 || bRec.component == 0);
|
&& (bRec.component == -1 || bRec.component == (int) m_components.size()-1);
|
||||||
bool sampleNested = (bRec.typeMask & m_nested->getType() & BSDF::EAll)
|
bool sampleNested = (bRec.typeMask & m_nested->getType() & BSDF::EAll)
|
||||||
&& (bRec.component == -1 || (bRec.component > 0
|
&& (bRec.component == -1 || bRec.component < (int) m_components.size()-1);
|
||||||
&& bRec.component < m_nested->getComponentCount() + 1));
|
|
||||||
|
|
||||||
if ((!sampleNested && !sampleReflection) || Frame::cosTheta(bRec.wi) < 0)
|
if ((!sampleNested && !sampleNested) || Frame::cosTheta(bRec.wi) < 0)
|
||||||
return Spectrum(0.0f);
|
return Spectrum(0.0f);
|
||||||
|
|
||||||
Float cosThetaI = Frame::cosTheta(bRec.wi),
|
/* Refract the incident direction and compute the Fresnel reflectance */
|
||||||
etaI = m_extIOR,
|
Float eta = m_extIOR / m_intIOR,
|
||||||
etaT = m_intIOR;
|
sinThetaTSqr = eta*eta * Frame::sinTheta2(bRec.wi),
|
||||||
|
R12, cosThetaT = 0;
|
||||||
|
|
||||||
/* Using Snell's law, calculate the squared sine of the
|
|
||||||
angle between the normal and the transmitted ray */
|
|
||||||
Float eta = etaI / etaT,
|
|
||||||
sinThetaTSqr = eta*eta * Frame::sinTheta2(bRec.wi);
|
|
||||||
|
|
||||||
Float Fr, FrOut, cosThetaT = 0;
|
|
||||||
if (sinThetaTSqr >= 1.0f) {
|
if (sinThetaTSqr >= 1.0f) {
|
||||||
/* Total internal reflection */
|
R12 = 1.0f; /* Total internal reflection */
|
||||||
Fr = 1.0f;
|
|
||||||
} else {
|
} else {
|
||||||
cosThetaT = std::sqrt(1.0f - sinThetaTSqr);
|
cosThetaT = -std::sqrt(1.0f - sinThetaTSqr);
|
||||||
|
R12 = fresnelDielectric(Frame::cosTheta(bRec.wi),
|
||||||
/* Compute the Fresnel refletance */
|
-cosThetaT, m_extIOR, m_intIOR);
|
||||||
Fr = fresnelDielectric(cosThetaI,
|
|
||||||
cosThetaT, etaI, etaT);
|
|
||||||
|
|
||||||
cosThetaT = -cosThetaT;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Point2 sample(_sample);
|
Point2 sample(_sample);
|
||||||
if (sampleNested && sampleReflection) {
|
if (sampleNested && sampleNested) {
|
||||||
if (sample.x <= Fr) {
|
if (sample.x <= R12) {
|
||||||
bRec.sampledComponent = 0;
|
bRec.sampledComponent = m_components.size()-1;
|
||||||
bRec.sampledType = EDeltaReflection;
|
bRec.sampledType = EDeltaReflection;
|
||||||
bRec.wo = reflect(bRec.wi);
|
bRec.wo = reflect(bRec.wi);
|
||||||
|
pdf = R12;
|
||||||
pdf = Fr * std::abs(Frame::cosTheta(bRec.wo));
|
return Spectrum(R12);
|
||||||
return Spectrum(Fr);
|
|
||||||
} else {
|
} else {
|
||||||
Vector wiBackup = bRec.wi;
|
Vector wiBackup = bRec.wi;
|
||||||
bRec.wi = -refract(bRec.wi, eta, cosThetaT);
|
// bRec.wi = -refract(bRec.wi, eta, cosThetaT);
|
||||||
sample.x = (sample.x - Fr) / (1 - Fr);
|
bRec.wi = -refract(bRec.wi, R12);
|
||||||
|
sample.x = (sample.x - R12) / (1 - R12);
|
||||||
|
|
||||||
Spectrum result = m_nested->sample(bRec, pdf, sample);
|
Spectrum result = m_nested->sample(bRec, pdf, sample);
|
||||||
if (result.isZero())
|
if (result.isZero())
|
||||||
return Spectrum(0.0f);
|
return Spectrum(0.0f);
|
||||||
bRec.sampledComponent++;
|
|
||||||
|
|
||||||
Spectrum sigmaT = m_sigmaT->getValue(bRec.its) * m_thickness;
|
Spectrum sigmaT = m_sigmaT->getValue(bRec.its) * m_thickness;
|
||||||
if (!sigmaT.isZero())
|
if (!sigmaT.isZero())
|
||||||
|
@ -214,148 +274,47 @@ public:
|
||||||
(1/std::abs(Frame::cosTheta(bRec.wi)) +
|
(1/std::abs(Frame::cosTheta(bRec.wi)) +
|
||||||
1/std::abs(Frame::cosTheta(bRec.wo)))).exp();
|
1/std::abs(Frame::cosTheta(bRec.wo)))).exp();
|
||||||
|
|
||||||
Float cosThetaWoPrime = Frame::cosTheta(bRec.wo);
|
Float R21, cosThetaWoPrime = Frame::cosTheta(bRec.wo);
|
||||||
bRec.wi = wiBackup;
|
bRec.wi = wiBackup;
|
||||||
bRec.wo = refract(-bRec.wo, FrOut);
|
bRec.wo = refract(-bRec.wo, R21);
|
||||||
|
|
||||||
if (FrOut == 1)
|
if (R21 == 1.0f) /* Total internal reflection */
|
||||||
return Spectrum(0.0f);
|
return Spectrum(0.0f);
|
||||||
|
|
||||||
pdf *= (1 - Fr) * eta * eta;
|
pdf *= 1 - R12;
|
||||||
|
if (BSDF::getMeasure(bRec.sampledType) == ESolidAngle)
|
||||||
|
pdf /= eta * eta;
|
||||||
|
|
||||||
|
result *= (1 - R12) * (1 - R21) * cosThetaWoPrime;
|
||||||
|
|
||||||
result *=
|
|
||||||
(1 - Fr) * (1 - FrOut)
|
|
||||||
* std::abs(cosThetaWoPrime *
|
|
||||||
/ Frame::cosTheta(bRec.wo));
|
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
}
|
}
|
||||||
} else if (sampleReflection) {
|
} else if (sampleSpecular) {
|
||||||
bRec.sampledComponent = 0;
|
bRec.sampledComponent = 0;
|
||||||
bRec.sampledType = EDeltaReflection;
|
bRec.sampledType = EDeltaReflection;
|
||||||
bRec.wo = reflect(bRec.wi);
|
bRec.wo = reflect(bRec.wi);
|
||||||
pdf = std::abs(Frame::cosTheta(bRec.wo));
|
pdf = 1.0f;
|
||||||
return Spectrum(Fr);
|
return Spectrum(R12);
|
||||||
} else {
|
} else {
|
||||||
if (Fr == 1.0f) /* Total internal reflection */
|
// XXX not implemented
|
||||||
return Spectrum(0.0f);
|
return Spectrum(0.0f);
|
||||||
|
|
||||||
Vector wiBackup = bRec.wi;
|
|
||||||
bRec.wi = -refract(bRec.wi, eta, cosThetaT);
|
|
||||||
sample.x = (sample.x - Fr) / (1 - Fr);
|
|
||||||
|
|
||||||
Spectrum result = m_nested->sample(bRec, pdf, sample);
|
|
||||||
if (result.isZero())
|
|
||||||
return Spectrum(0.0f);
|
|
||||||
bRec.sampledComponent++;
|
|
||||||
|
|
||||||
Spectrum sigmaT = m_sigmaT->getValue(bRec.its) * m_thickness;
|
|
||||||
if (!sigmaT.isZero())
|
|
||||||
result *= (-sigmaT *
|
|
||||||
(1/std::abs(Frame::cosTheta(bRec.wi)) +
|
|
||||||
1/std::abs(Frame::cosTheta(bRec.wo)))).exp();
|
|
||||||
|
|
||||||
Float cosThetaWoPrime = Frame::cosTheta(bRec.wo);
|
|
||||||
bRec.wi = wiBackup;
|
|
||||||
bRec.wo = refract(-bRec.wo, FrOut);
|
|
||||||
|
|
||||||
if (FrOut == 1)
|
|
||||||
return Spectrum(0.0f);
|
|
||||||
|
|
||||||
pdf *= (1 - Fr) * eta * eta;
|
|
||||||
|
|
||||||
result *=
|
|
||||||
(1 - Fr) * (1 - FrOut)
|
|
||||||
* std::abs(cosThetaWoPrime *
|
|
||||||
/ Frame::cosTheta(bRec.wo));
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Float pdfDelta(const BSDFQueryRecord &bRec) const {
|
Spectrum sample(BSDFQueryRecord &bRec, const Point2 &sample) const {
|
||||||
bool sampleSpecular = (bRec.typeMask & EDeltaReflection)
|
Float pdf;
|
||||||
&& (bRec.component == -1 || bRec.component == 0);
|
Spectrum result = SmoothCoating::sample(bRec, pdf, sample);
|
||||||
|
|
||||||
if (Frame::cosTheta(bRec.wi) <= 0 ||
|
if (result.isZero())
|
||||||
Frame::cosTheta(bRec.wo) <= 0 || !sampleSpecular)
|
|
||||||
return 0.0f;
|
|
||||||
|
|
||||||
bool sampleNested = (bRec.typeMask & m_nested->getType() & BSDF::EAll)
|
|
||||||
&& (bRec.component == -1 || (bRec.component > 0
|
|
||||||
&& bRec.component < m_nested->getComponentCount() + 1));
|
|
||||||
|
|
||||||
Float pdf = std::abs(Frame::cosTheta(bRec.wo));
|
|
||||||
if (sampleNested)
|
|
||||||
pdf *= fresnel(Frame::cosTheta(bRec.wi), m_extIOR, m_intIOR);
|
|
||||||
|
|
||||||
return pdf;
|
|
||||||
}
|
|
||||||
|
|
||||||
Spectrum fDelta(const BSDFQueryRecord &bRec) const {
|
|
||||||
bool sampleSpecular = (bRec.typeMask & EDeltaReflection)
|
|
||||||
&& (bRec.component == -1 || bRec.component == 0);
|
|
||||||
|
|
||||||
if (Frame::cosTheta(bRec.wi) <= 0 ||
|
|
||||||
Frame::cosTheta(bRec.wo) <= 0 || !sampleSpecular)
|
|
||||||
return Spectrum(0.0f);
|
return Spectrum(0.0f);
|
||||||
|
else
|
||||||
return Spectrum(fresnel(Frame::cosTheta(bRec.wi), m_extIOR, m_intIOR));
|
return result / pdf;
|
||||||
}
|
|
||||||
|
|
||||||
Float pdf(const BSDFQueryRecord &bRec) const {
|
|
||||||
bool sampleNested = (bRec.typeMask & m_nested->getType() & BSDF::EAll)
|
|
||||||
&& (bRec.component == -1 || (bRec.component > 0
|
|
||||||
&& bRec.component < m_nested->getComponentCount() + 1));
|
|
||||||
|
|
||||||
if (Frame::cosTheta(bRec.wi) <= 0 ||
|
|
||||||
Frame::cosTheta(bRec.wo) <= 0 || !sampleNested)
|
|
||||||
return 0.0f;
|
|
||||||
|
|
||||||
Float T12, T21;
|
|
||||||
Vector wiPrime = -refract(bRec.wi, T12);
|
|
||||||
Vector woPrime = -refract(bRec.wo, T21);
|
|
||||||
|
|
||||||
if (T12 == 1 || T21 == 1) /* Total internal reflection */
|
|
||||||
return 0.0f;
|
|
||||||
|
|
||||||
BSDFQueryRecord bRec2(bRec);
|
|
||||||
if (bRec2.component != -1)
|
|
||||||
bRec2.component++;
|
|
||||||
bRec2.wi = wiPrime;
|
|
||||||
bRec2.wo = woPrime;
|
|
||||||
|
|
||||||
Float eta = m_extIOR / m_intIOR;
|
|
||||||
return m_nested->pdf(bRec2) * T12 * eta * eta;
|
|
||||||
}
|
|
||||||
|
|
||||||
Spectrum f(const BSDFQueryRecord &bRec) const {
|
|
||||||
bool sampleNested = (bRec.typeMask & m_nested->getType() & BSDF::EAll)
|
|
||||||
&& (bRec.component == -1 || (bRec.component > 0
|
|
||||||
&& bRec.component < m_nested->getComponentCount() + 1));
|
|
||||||
|
|
||||||
if (Frame::cosTheta(bRec.wi) <= 0 ||
|
|
||||||
Frame::cosTheta(bRec.wo) <= 0 || !sampleNested)
|
|
||||||
return Spectrum(0.0f);
|
|
||||||
|
|
||||||
Float T12, T21;
|
|
||||||
Vector wiPrime = -refract(bRec.wi, T12);
|
|
||||||
Vector woPrime = -refract(bRec.wo, T21);
|
|
||||||
|
|
||||||
if (T12 == 1 || T21 == 1) /* Total internal reflection */
|
|
||||||
return Spectrum(0.0f);
|
|
||||||
|
|
||||||
BSDFQueryRecord bRec2(bRec);
|
|
||||||
if (bRec2.component != -1)
|
|
||||||
bRec2.component++;
|
|
||||||
bRec2.wi = wiPrime;
|
|
||||||
bRec2.wo = woPrime;
|
|
||||||
return m_nested->f(bRec2) * T12 * T21;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string toString() const {
|
std::string toString() const {
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << "SmoothVarnish[" << endl
|
oss << "SmoothCoating[" << endl
|
||||||
|
<< " name = \"" << getName() << "\"," << endl
|
||||||
<< " intIOR = " << m_intIOR << "," << endl
|
<< " intIOR = " << m_intIOR << "," << endl
|
||||||
<< " extIOR = " << m_extIOR << "," << endl
|
<< " extIOR = " << m_extIOR << "," << endl
|
||||||
<< " sigmaT = " << indent(m_sigmaT->toString()) << "," << endl
|
<< " sigmaT = " << indent(m_sigmaT->toString()) << "," << endl
|
||||||
|
@ -368,11 +327,11 @@ public:
|
||||||
MTS_DECLARE_CLASS()
|
MTS_DECLARE_CLASS()
|
||||||
private:
|
private:
|
||||||
Float m_intIOR, m_extIOR;
|
Float m_intIOR, m_extIOR;
|
||||||
ref<BSDF> m_nested;
|
|
||||||
ref<Texture> m_sigmaT;
|
ref<Texture> m_sigmaT;
|
||||||
|
ref<BSDF> m_nested;
|
||||||
Float m_thickness;
|
Float m_thickness;
|
||||||
};
|
};
|
||||||
|
|
||||||
MTS_IMPLEMENT_CLASS_S(SmoothVarnish, false, BSDF)
|
MTS_IMPLEMENT_CLASS_S(SmoothCoating, false, BSDF)
|
||||||
MTS_EXPORT_PLUGIN(SmoothVarnish, "Smooth varnish layer");
|
MTS_EXPORT_PLUGIN(SmoothCoating, "Smooth varnish layer");
|
||||||
MTS_NAMESPACE_END
|
MTS_NAMESPACE_END
|
||||||
|
|
|
@ -172,8 +172,6 @@ public:
|
||||||
configure();
|
configure();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~SmoothConductor() { }
|
|
||||||
|
|
||||||
void configure() {
|
void configure() {
|
||||||
/* Verify the input parameters and fix them if necessary */
|
/* Verify the input parameters and fix them if necessary */
|
||||||
m_specularReflectance = ensureEnergyConservation(
|
m_specularReflectance = ensureEnergyConservation(
|
||||||
|
|
|
@ -159,8 +159,6 @@ public:
|
||||||
m_specularTransmittance = static_cast<Texture *>(manager->getInstance(stream));
|
m_specularTransmittance = static_cast<Texture *>(manager->getInstance(stream));
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~SmoothDielectric() { }
|
|
||||||
|
|
||||||
void serialize(Stream *stream, InstanceManager *manager) const {
|
void serialize(Stream *stream, InstanceManager *manager) const {
|
||||||
BSDF::serialize(stream, manager);
|
BSDF::serialize(stream, manager);
|
||||||
|
|
||||||
|
@ -228,18 +226,15 @@ public:
|
||||||
Float eta = etaI / etaT,
|
Float eta = etaI / etaT,
|
||||||
sinThetaTSqr = eta*eta * Frame::sinTheta2(wi);
|
sinThetaTSqr = eta*eta * Frame::sinTheta2(wi);
|
||||||
|
|
||||||
Float cosThetaT = 0;
|
|
||||||
if (sinThetaTSqr >= 1.0f) {
|
if (sinThetaTSqr >= 1.0f) {
|
||||||
/* Total internal reflection */
|
/* Total internal reflection */
|
||||||
return Vector(0.0f);
|
return Vector(0.0f);
|
||||||
} else {
|
} else {
|
||||||
cosThetaT = std::sqrt(1.0f - sinThetaTSqr);
|
Float cosThetaT = std::sqrt(1.0f - sinThetaTSqr);
|
||||||
|
|
||||||
if (entering)
|
return Vector(-eta*wi.x, -eta*wi.y,
|
||||||
cosThetaT = -cosThetaT;
|
entering ? -cosThetaT : cosThetaT);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Vector(-eta*wi.x, -eta*wi.y, cosThetaT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Spectrum eval(const BSDFQueryRecord &bRec, EMeasure measure) const {
|
Spectrum eval(const BSDFQueryRecord &bRec, EMeasure measure) const {
|
||||||
|
|
|
@ -50,24 +50,22 @@ public:
|
||||||
m_transmittance = new ConstantSpectrumTexture(props.getSpectrum(
|
m_transmittance = new ConstantSpectrumTexture(props.getSpectrum(
|
||||||
props.hasProperty("transmittance") ? "transmittance"
|
props.hasProperty("transmittance") ? "transmittance"
|
||||||
: "diffuseTransmittance", Spectrum(.5f)));
|
: "diffuseTransmittance", Spectrum(.5f)));
|
||||||
m_components.push_back(EDiffuseTransmission | EFrontSide | EBackSide);
|
|
||||||
m_usesRayDifferentials = false;
|
m_usesRayDifferentials = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
DiffuseTransmitter(Stream *stream, InstanceManager *manager)
|
DiffuseTransmitter(Stream *stream, InstanceManager *manager)
|
||||||
: BSDF(stream, manager) {
|
: BSDF(stream, manager) {
|
||||||
m_transmittance = static_cast<Texture *>(manager->getInstance(stream));
|
m_transmittance = static_cast<Texture *>(manager->getInstance(stream));
|
||||||
m_components.push_back(EDiffuseTransmission | EFrontSide | EBackSide);
|
|
||||||
m_usesRayDifferentials = m_transmittance->usesRayDifferentials();
|
m_usesRayDifferentials = m_transmittance->usesRayDifferentials();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~DiffuseTransmitter() { }
|
|
||||||
|
|
||||||
void configure() {
|
void configure() {
|
||||||
BSDF::configure();
|
|
||||||
|
|
||||||
/* Verify the input parameters and fix them if necessary */
|
/* Verify the input parameters and fix them if necessary */
|
||||||
m_transmittance = ensureEnergyConservation(m_transmittance, "transmittance", 1.0f);
|
m_transmittance = ensureEnergyConservation(m_transmittance, "transmittance", 1.0f);
|
||||||
|
|
||||||
|
m_components.clear();
|
||||||
|
m_components.push_back(EDiffuseTransmission | EFrontSide | EBackSide);
|
||||||
|
BSDF::configure();
|
||||||
}
|
}
|
||||||
|
|
||||||
Spectrum eval(const BSDFQueryRecord &bRec, EMeasure measure) const {
|
Spectrum eval(const BSDFQueryRecord &bRec, EMeasure measure) const {
|
||||||
|
|
|
@ -88,8 +88,6 @@ public:
|
||||||
configure();
|
configure();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~SmoothDiffuse() { }
|
|
||||||
|
|
||||||
void configure() {
|
void configure() {
|
||||||
/* Verify the input parameter and fix them if necessary */
|
/* Verify the input parameter and fix them if necessary */
|
||||||
m_reflectance = ensureEnergyConservation(m_reflectance, "reflectance", 1.0f);
|
m_reflectance = ensureEnergyConservation(m_reflectance, "reflectance", 1.0f);
|
||||||
|
|
|
@ -121,8 +121,6 @@ public:
|
||||||
m_ksMultiplier = stream->readFloat();
|
m_ksMultiplier = stream->readFloat();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~IrawanClothBRDF() { }
|
|
||||||
|
|
||||||
void configure() {
|
void configure() {
|
||||||
m_components.clear();
|
m_components.clear();
|
||||||
m_components.push_back(EGlossyReflection | EAnisotropic | EFrontSide);
|
m_components.push_back(EGlossyReflection | EAnisotropic | EFrontSide);
|
||||||
|
|
|
@ -31,13 +31,14 @@ MTS_NAMESPACE_BEGIN
|
||||||
* \rendering{Rendering without an opacity mask}
|
* \rendering{Rendering without an opacity mask}
|
||||||
* {bsdf_mask_before.jpg}
|
* {bsdf_mask_before.jpg}
|
||||||
* \rendering{Rendering \emph{with} an opacity mask (\lstref{mask-leaf})}
|
* \rendering{Rendering \emph{with} an opacity mask (\lstref{mask-leaf})}
|
||||||
* {bsdf_mask_before.jpg}
|
* {bsdf_mask_after.jpg}
|
||||||
* }
|
* }
|
||||||
* This plugin applies an opacity mask to add nested BSDF instance. It interpolates
|
* This plugin applies an opacity mask to add nested BSDF instance. It interpolates
|
||||||
* between perfectly transparent and completely opaque based on the \code{opacity}
|
* between perfectly transparent and completely opaque based on the \code{opacity}
|
||||||
* parameter.
|
* parameter.
|
||||||
*
|
*
|
||||||
* The transparency is implemented as a forward-facing Diract delta distribution.
|
* The transparency is implemented as a forward-facing Diract delta distribution.
|
||||||
|
* \vspace{5mm}
|
||||||
*
|
*
|
||||||
* \begin{xml}[caption=Material configuration for a transparent leaf,
|
* \begin{xml}[caption=Material configuration for a transparent leaf,
|
||||||
* label=lst:mask-leaf]
|
* label=lst:mask-leaf]
|
||||||
|
@ -72,8 +73,6 @@ public:
|
||||||
configure();
|
configure();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~Mask() { }
|
|
||||||
|
|
||||||
void serialize(Stream *stream, InstanceManager *manager) const {
|
void serialize(Stream *stream, InstanceManager *manager) const {
|
||||||
BSDF::serialize(stream, manager);
|
BSDF::serialize(stream, manager);
|
||||||
|
|
||||||
|
@ -84,6 +83,7 @@ public:
|
||||||
void configure() {
|
void configure() {
|
||||||
if (!m_nestedBSDF)
|
if (!m_nestedBSDF)
|
||||||
Log(EError, "A child BSDF is required");
|
Log(EError, "A child BSDF is required");
|
||||||
|
m_components.clear();
|
||||||
for (int i=0; i<m_nestedBSDF->getComponentCount(); ++i)
|
for (int i=0; i<m_nestedBSDF->getComponentCount(); ++i)
|
||||||
m_components.push_back(m_nestedBSDF->getType(i));
|
m_components.push_back(m_nestedBSDF->getType(i));
|
||||||
m_components.push_back(EDeltaTransmission | EFrontSide | EBackSide);
|
m_components.push_back(EDeltaTransmission | EFrontSide | EBackSide);
|
||||||
|
|
|
@ -51,8 +51,8 @@ MTS_NAMESPACE_BEGIN
|
||||||
*
|
*
|
||||||
* When using this plugin, note that the diffuse and specular reflectance
|
* When using this plugin, note that the diffuse and specular reflectance
|
||||||
* components should add up to a value less than or equal to one (for each
|
* components should add up to a value less than or equal to one (for each
|
||||||
* color channel). Otherwise, they will be scaled appropriately to ensure
|
* color channel). Otherwise, they will automatically be scaled appropriately
|
||||||
* energy conservation.
|
* to ensure energy conservation.
|
||||||
*/
|
*/
|
||||||
class Phong : public BSDF {
|
class Phong : public BSDF {
|
||||||
public:
|
public:
|
||||||
|
@ -75,8 +75,6 @@ public:
|
||||||
configure();
|
configure();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~Phong() { }
|
|
||||||
|
|
||||||
void configure() {
|
void configure() {
|
||||||
m_components.clear();
|
m_components.clear();
|
||||||
m_components.push_back(EGlossyReflection | EFrontSide);
|
m_components.push_back(EGlossyReflection | EFrontSide);
|
||||||
|
|
|
@ -85,8 +85,6 @@ public:
|
||||||
configure();
|
configure();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~SmoothPlastic() { }
|
|
||||||
|
|
||||||
void configure() {
|
void configure() {
|
||||||
/* Verify the input parameters and fix them if necessary */
|
/* Verify the input parameters and fix them if necessary */
|
||||||
m_specularReflectance = ensureEnergyConservation(
|
m_specularReflectance = ensureEnergyConservation(
|
||||||
|
|
|
@ -222,8 +222,6 @@ public:
|
||||||
BSDF::configure();
|
BSDF::configure();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~RoughConductor() { }
|
|
||||||
|
|
||||||
/// Helper function: reflect \c wi with respect to a given surface normal
|
/// Helper function: reflect \c wi with respect to a given surface normal
|
||||||
inline Vector reflect(const Vector &wi, const Normal &m) const {
|
inline Vector reflect(const Vector &wi, const Normal &m) const {
|
||||||
return 2 * dot(wi, m) * Vector(m) - wi;
|
return 2 * dot(wi, m) * Vector(m) - wi;
|
||||||
|
|
|
@ -248,8 +248,6 @@ public:
|
||||||
BSDF::configure();
|
BSDF::configure();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~RoughDielectric() { }
|
|
||||||
|
|
||||||
inline Float signum(Float value) const {
|
inline Float signum(Float value) const {
|
||||||
return (value < 0) ? -1.0f : 1.0f;
|
return (value < 0) ? -1.0f : 1.0f;
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,8 +104,6 @@ public:
|
||||||
configure();
|
configure();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~RoughDiffuse() { }
|
|
||||||
|
|
||||||
void configure() {
|
void configure() {
|
||||||
/* Verify the input parameter and fix them if necessary */
|
/* Verify the input parameter and fix them if necessary */
|
||||||
m_reflectance = ensureEnergyConservation(m_reflectance, "reflectance", 1.0f);
|
m_reflectance = ensureEnergyConservation(m_reflectance, "reflectance", 1.0f);
|
||||||
|
|
|
@ -202,8 +202,6 @@ public:
|
||||||
BSDF::configure();
|
BSDF::configure();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~RoughPlastic() { }
|
|
||||||
|
|
||||||
Spectrum getDiffuseReflectance(const Intersection &its) const {
|
Spectrum getDiffuseReflectance(const Intersection &its) const {
|
||||||
return m_diffuseReflectance->getValue(its);
|
return m_diffuseReflectance->getValue(its);
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,8 +64,6 @@ public:
|
||||||
configure();
|
configure();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~TwoSidedBRDF() { }
|
|
||||||
|
|
||||||
void serialize(Stream *stream, InstanceManager *manager) const {
|
void serialize(Stream *stream, InstanceManager *manager) const {
|
||||||
BSDF::serialize(stream, manager);
|
BSDF::serialize(stream, manager);
|
||||||
|
|
||||||
|
|
|
@ -58,7 +58,7 @@ MTS_NAMESPACE_BEGIN
|
||||||
* \begin{enumerate}[(i)]
|
* \begin{enumerate}[(i)]
|
||||||
* \item ``Measuring and Modeling Anisotropic Reflection''
|
* \item ``Measuring and Modeling Anisotropic Reflection''
|
||||||
* by Greg Ward \cite{Ward1992Measuring}
|
* by Greg Ward \cite{Ward1992Measuring}
|
||||||
* \item ``Notes on the Ward BRDF'' by Bruce Walter\cite{Walter2005Notes}
|
* \item ``Notes on the Ward BRDF'' by Bruce Walter \cite{Walter2005Notes}
|
||||||
* \item ``An Improved Normalization for the Ward Reflectance Model''
|
* \item ``An Improved Normalization for the Ward Reflectance Model''
|
||||||
* by Arne D\"ur \cite{Dur2006Improved}
|
* by Arne D\"ur \cite{Dur2006Improved}
|
||||||
* \item ``A New Ward BRDF Model with Bounded Albedo'' by
|
* \item ``A New Ward BRDF Model with Bounded Albedo'' by
|
||||||
|
@ -78,8 +78,8 @@ MTS_NAMESPACE_BEGIN
|
||||||
*
|
*
|
||||||
* When using this plugin, note that the diffuse and specular reflectance
|
* When using this plugin, note that the diffuse and specular reflectance
|
||||||
* components should add up to a value less than or equal to one (for each
|
* components should add up to a value less than or equal to one (for each
|
||||||
* color channel). Otherwise, they will be scaled appropriately to ensure
|
* color channel). Otherwise, they will automatically be scaled appropriately
|
||||||
* energy conservation.
|
* to ensure energy conservation.
|
||||||
*/
|
*/
|
||||||
class Ward : public BSDF {
|
class Ward : public BSDF {
|
||||||
public:
|
public:
|
||||||
|
@ -134,8 +134,6 @@ public:
|
||||||
configure();
|
configure();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~Ward() { }
|
|
||||||
|
|
||||||
void configure() {
|
void configure() {
|
||||||
unsigned int extraFlags = 0;
|
unsigned int extraFlags = 0;
|
||||||
if (m_alphaU != m_alphaV)
|
if (m_alphaU != m_alphaV)
|
||||||
|
|
|
@ -849,11 +849,11 @@ double normalQuantile(double p) {
|
||||||
Float hypot2(Float a, Float b) {
|
Float hypot2(Float a, Float b) {
|
||||||
Float r;
|
Float r;
|
||||||
if (std::abs(a) > std::abs(b)) {
|
if (std::abs(a) > std::abs(b)) {
|
||||||
r = b/a;
|
r = b / a;
|
||||||
r = std::abs(a)*std::sqrt(1+r*r);
|
r = std::abs(a) * std::sqrt(1 + r*r);
|
||||||
} else if (b != 0) {
|
} else if (b != 0) {
|
||||||
r = a/b;
|
r = a / b;
|
||||||
r = std::abs(b)*std::sqrt(1+r*r);
|
r = std::abs(b) * std::sqrt(1 + r*r);
|
||||||
} else {
|
} else {
|
||||||
r = 0;
|
r = 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue