got the coating to work; more documentation
|
@ -2,12 +2,20 @@
|
||||||
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>
|
||||||
|
<!-- Test a smooth coating over a diffuse base material -->
|
||||||
<bsdf type="coating">
|
<bsdf type="coating">
|
||||||
<float name="intIOR" value="1.5"/>
|
<float name="intIOR" value="1.5"/>
|
||||||
<float name="extIOR" value="1"/>
|
<float name="extIOR" value="1"/>
|
||||||
<bsdf type="diffuse"/>
|
<bsdf type="diffuse"/>
|
||||||
</bsdf>
|
</bsdf>
|
||||||
|
|
||||||
|
<!-- Test a smooth coating over a rough metal material -->
|
||||||
|
<bsdf type="coating">
|
||||||
|
<float name="intIOR" value="1.5"/>
|
||||||
|
<float name="extIOR" value="1"/>
|
||||||
|
<bsdf type="roughconductor"/>
|
||||||
|
</bsdf>
|
||||||
|
|
||||||
<!-- Test the smooth diffuse model -->
|
<!-- Test the smooth diffuse model -->
|
||||||
<bsdf type="diffuse"/>
|
<bsdf type="diffuse"/>
|
||||||
|
|
||||||
|
@ -106,7 +114,7 @@
|
||||||
<!-- Test the rough dielectric model with the anisotropic
|
<!-- Test the rough dielectric model with the anisotropic
|
||||||
Ashikhmin-Shirley microfacet distribution -->
|
Ashikhmin-Shirley microfacet distribution -->
|
||||||
<bsdf type="roughconductor">
|
<bsdf type="roughconductor">
|
||||||
<string name="preset" value="Au"/>
|
<string name="material" value="Au"/>
|
||||||
<string name="distribution" value="as"/>
|
<string name="distribution" value="as"/>
|
||||||
<float name="alphaU" value="0.1"/>
|
<float name="alphaU" value="0.1"/>
|
||||||
<float name="alphaV" value="0.3"/>
|
<float name="alphaV" value="0.3"/>
|
||||||
|
|
After Width: | Height: | Size: 154 KiB |
After Width: | Height: | Size: 186 KiB |
After Width: | Height: | Size: 151 KiB |
Before Width: | Height: | Size: 202 KiB After Width: | Height: | Size: 191 KiB |
Before Width: | Height: | Size: 168 KiB After Width: | Height: | Size: 160 KiB |
Before Width: | Height: | Size: 184 KiB After Width: | Height: | Size: 175 KiB |
Before Width: | Height: | Size: 187 KiB After Width: | Height: | Size: 175 KiB |
Before Width: | Height: | Size: 186 KiB After Width: | Height: | Size: 174 KiB |
Before Width: | Height: | Size: 172 KiB After Width: | Height: | Size: 162 KiB |
Before Width: | Height: | Size: 185 KiB After Width: | Height: | Size: 176 KiB |
Before Width: | Height: | Size: 188 KiB After Width: | Height: | Size: 176 KiB |
Before Width: | Height: | Size: 182 KiB After Width: | Height: | Size: 172 KiB |
Before Width: | Height: | Size: 202 KiB After Width: | Height: | Size: 190 KiB |
|
@ -30,10 +30,45 @@ MTS_NAMESPACE_BEGIN
|
||||||
* numerically or using a known material name. \default{\texttt{bk7} / 1.5046}}
|
* numerically or using a known material name. \default{\texttt{bk7} / 1.5046}}
|
||||||
* \parameter{extIOR}{\Float\Or\String}{Exterior index of refraction specified
|
* \parameter{extIOR}{\Float\Or\String}{Exterior index of refraction specified
|
||||||
* numerically or using a known material name. \default{\texttt{air} / 1.000277}}
|
* numerically or using a known material name. \default{\texttt{air} / 1.000277}}
|
||||||
|
* \parameter{sigmaA}{\Spectrum\Or\Texture}{Absorption coefficient within the layer. \default{0}}
|
||||||
|
* \parameter{thickness}{\Float}{Thickness of the absorbing layer (given in inverse units of \code{sigmaA})\default{1}}
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
* This class implements a smooth dielectric coating in the style of
|
* \renderings{
|
||||||
* Weidlich and Wilkie \cite{Weidlich2007Arbitrarily}.
|
* \rendering{Coated rough copper (lower exposure, \lstref{coating-roughcopper})}
|
||||||
|
* {bsdf_coating_roughconductor}
|
||||||
|
* \rendering{Coated rough plastic}
|
||||||
|
* {bsdf_coating_roughplastic}
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* This plugin implements a smooth dielectric coating in the style of the
|
||||||
|
* paper ``Arbitrarily Layered Micro-Facet Surfaces'' by Weidlich and
|
||||||
|
* Wilkie \cite{Weidlich2007Arbitrarily}. Any non-transmissive model can
|
||||||
|
* be coated, and multiple layers can be applied in sequence. This allows
|
||||||
|
* designing custom materials like car paint.
|
||||||
|
*
|
||||||
|
* The coating layer can optionally be filled with an absorbing medium,
|
||||||
|
* in which case this model also accounts for the directionally dependent
|
||||||
|
* extinction within the layer.
|
||||||
|
*
|
||||||
|
* Evaluating the internal component of this model entails refracting the
|
||||||
|
* incident and exitant rays through the dielectric interface, followed by
|
||||||
|
* querying the nested material with this modified direction pair. The result
|
||||||
|
* is attenuated by the two Fresnel transmittances. Note that this model does
|
||||||
|
* not attempt to handle illumination that is reflected by the interior of the
|
||||||
|
* coating---this energy is essentially lost.
|
||||||
|
*
|
||||||
|
* \vspace{4mm}
|
||||||
|
*
|
||||||
|
* \begin{xml}[caption=Rough copper coated with a transparent layer of lacquer, label=lst:coating-roughcopper]
|
||||||
|
* <bsdf type="coating">
|
||||||
|
* <float name="intIOR" value="1.7"/>
|
||||||
|
* <bsdf type="roughconductor">
|
||||||
|
* <string name="material" value="Cu"/>
|
||||||
|
* <float name="alpha" value="0.1"/>
|
||||||
|
* </bsdf>
|
||||||
|
* </bsdf>
|
||||||
|
* \end{xml}
|
||||||
*/
|
*/
|
||||||
class SmoothCoating : public BSDF {
|
class SmoothCoating : public BSDF {
|
||||||
public:
|
public:
|
||||||
|
@ -45,12 +80,12 @@ public:
|
||||||
/* Specifies the external index of refraction at the interface */
|
/* Specifies the external index of refraction at the interface */
|
||||||
m_extIOR = lookupIOR(props, "extIOR", "air");
|
m_extIOR = lookupIOR(props, "extIOR", "air");
|
||||||
|
|
||||||
/* Specifies the layer's thickness using the inverse units of sigmaT */
|
/* Specifies the absorption within the layer */
|
||||||
m_thickness = props.getFloat("thickness", 1);
|
m_sigmaA = new ConstantSpectrumTexture(
|
||||||
|
props.getSpectrum("sigmaA", Spectrum(0.0f)));
|
||||||
|
|
||||||
/* Specifies the attenuation within the varnish layer */
|
/* Specifies the layer's thickness using the inverse units of sigmaA */
|
||||||
m_sigmaT = new ConstantSpectrumTexture(
|
m_thickness = props.getFloat("thickness", 1);
|
||||||
props.getSpectrum("sigmaT", Spectrum(0.0f)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SmoothCoating(Stream *stream, InstanceManager *manager)
|
SmoothCoating(Stream *stream, InstanceManager *manager)
|
||||||
|
@ -59,7 +94,7 @@ public:
|
||||||
m_extIOR = stream->readFloat();
|
m_extIOR = stream->readFloat();
|
||||||
m_thickness = stream->readFloat();
|
m_thickness = stream->readFloat();
|
||||||
m_nested = static_cast<BSDF *>(manager->getInstance(stream));
|
m_nested = static_cast<BSDF *>(manager->getInstance(stream));
|
||||||
m_sigmaT = static_cast<Texture *>(manager->getInstance(stream));
|
m_sigmaA = static_cast<Texture *>(manager->getInstance(stream));
|
||||||
configure();
|
configure();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,7 +111,7 @@ public:
|
||||||
m_components.push_back(EDeltaReflection | EFrontSide);
|
m_components.push_back(EDeltaReflection | EFrontSide);
|
||||||
|
|
||||||
m_usesRayDifferentials = m_nested->usesRayDifferentials()
|
m_usesRayDifferentials = m_nested->usesRayDifferentials()
|
||||||
|| m_sigmaT->usesRayDifferentials();
|
|| m_sigmaA->usesRayDifferentials();
|
||||||
|
|
||||||
BSDF::configure();
|
BSDF::configure();
|
||||||
}
|
}
|
||||||
|
@ -88,7 +123,7 @@ public:
|
||||||
stream->writeFloat(m_extIOR);
|
stream->writeFloat(m_extIOR);
|
||||||
stream->writeFloat(m_thickness);
|
stream->writeFloat(m_thickness);
|
||||||
manager->serialize(stream, m_nested.get());
|
manager->serialize(stream, m_nested.get());
|
||||||
manager->serialize(stream, m_sigmaT.get());
|
manager->serialize(stream, m_sigmaA.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
void addChild(const std::string &name, ConfigurableObject *child) {
|
void addChild(const std::string &name, ConfigurableObject *child) {
|
||||||
|
@ -118,8 +153,7 @@ public:
|
||||||
/// Refraction in local coordinates (full version)
|
/// Refraction in local coordinates (full version)
|
||||||
inline Vector refract(const Vector &wi, Float &F) 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;
|
|
||||||
|
|
||||||
bool entering = cosThetaI > 0.0f;
|
bool entering = cosThetaI > 0.0f;
|
||||||
|
|
||||||
|
@ -132,14 +166,13 @@ 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 */
|
||||||
F = 1.0f;
|
F = 1.0f;
|
||||||
|
|
||||||
return Vector(0.0f);
|
return Vector(0.0f);
|
||||||
} else {
|
} else {
|
||||||
cosThetaT = std::sqrt(1.0f - sinThetaTSqr);
|
Float cosThetaT = std::sqrt(1.0f - sinThetaTSqr);
|
||||||
|
|
||||||
/* Compute the Fresnel transmittance */
|
/* Compute the Fresnel transmittance */
|
||||||
F = fresnelDielectric(std::abs(Frame::cosTheta(wi)),
|
F = fresnelDielectric(std::abs(Frame::cosTheta(wi)),
|
||||||
|
@ -169,8 +202,6 @@ public:
|
||||||
BSDFQueryRecord bRec2(bRec);
|
BSDFQueryRecord bRec2(bRec);
|
||||||
bRec2.wi = -refract(bRec.wi, R12);
|
bRec2.wi = -refract(bRec.wi, R12);
|
||||||
bRec2.wo = -refract(bRec.wo, R21);
|
bRec2.wo = -refract(bRec.wo, R21);
|
||||||
Assert(bRec2.wi.z >= 0);
|
|
||||||
Assert(bRec2.wo.z >= 0);
|
|
||||||
|
|
||||||
if (R12 == 1 || R21 == 1) /* Total internal reflection */
|
if (R12 == 1 || R21 == 1) /* Total internal reflection */
|
||||||
return Spectrum(0.0f);
|
return Spectrum(0.0f);
|
||||||
|
@ -178,15 +209,18 @@ public:
|
||||||
Spectrum result = m_nested->eval(bRec2, measure)
|
Spectrum result = m_nested->eval(bRec2, measure)
|
||||||
* ((1-R12) * (1-R21));
|
* ((1-R12) * (1-R21));
|
||||||
|
|
||||||
Spectrum sigmaT = m_sigmaT->getValue(bRec.its) * m_thickness;
|
Spectrum sigmaA = m_sigmaA->getValue(bRec.its) * m_thickness;
|
||||||
if (!sigmaT.isZero())
|
if (!sigmaA.isZero())
|
||||||
result *= (-sigmaT *
|
result *= (-sigmaA *
|
||||||
(1/std::abs(Frame::cosTheta(bRec2.wi)) +
|
(1/std::abs(Frame::cosTheta(bRec2.wi)) +
|
||||||
1/std::abs(Frame::cosTheta(bRec2.wo)))).exp();
|
1/std::abs(Frame::cosTheta(bRec2.wo)))).exp();
|
||||||
|
|
||||||
if (measure == ESolidAngle)
|
if (measure == ESolidAngle)
|
||||||
result *= Frame::cosTheta(bRec2.wo);
|
result *= Frame::cosTheta(bRec2.wo);
|
||||||
|
|
||||||
|
Float eta = m_extIOR / m_intIOR;
|
||||||
|
result *= eta * eta;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,11 +250,12 @@ public:
|
||||||
if (R12 == 1 || R21 == 1) /* Total internal reflection */
|
if (R12 == 1 || R21 == 1) /* Total internal reflection */
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
|
|
||||||
Float pdf = m_nested->pdf(bRec2, measure);
|
Float pdf = m_nested->pdf(bRec2, measure)
|
||||||
if (measure == ESolidAngle) {
|
* Frame::cosTheta(bRec.wo)
|
||||||
Float eta = m_extIOR / m_intIOR;
|
/ Frame::cosTheta(bRec2.wo);
|
||||||
pdf /= eta * eta;
|
|
||||||
}
|
Float eta = m_extIOR / m_intIOR;
|
||||||
|
pdf *= eta * eta;
|
||||||
|
|
||||||
return sampleSpecular ? (pdf * (1-R12)) : pdf;
|
return sampleSpecular ? (pdf * (1-R12)) : pdf;
|
||||||
} else {
|
} else {
|
||||||
|
@ -234,7 +269,7 @@ public:
|
||||||
bool sampleNested = (bRec.typeMask & m_nested->getType() & BSDF::EAll)
|
bool sampleNested = (bRec.typeMask & m_nested->getType() & BSDF::EAll)
|
||||||
&& (bRec.component == -1 || bRec.component < (int) m_components.size()-1);
|
&& (bRec.component == -1 || bRec.component < (int) m_components.size()-1);
|
||||||
|
|
||||||
if ((!sampleNested && !sampleNested) || Frame::cosTheta(bRec.wi) < 0)
|
if ((!sampleSpecular && !sampleNested) || Frame::cosTheta(bRec.wi) <= 0)
|
||||||
return Spectrum(0.0f);
|
return Spectrum(0.0f);
|
||||||
|
|
||||||
/* Refract the incident direction and compute the Fresnel reflectance */
|
/* Refract the incident direction and compute the Fresnel reflectance */
|
||||||
|
@ -250,54 +285,52 @@ public:
|
||||||
-cosThetaT, m_extIOR, m_intIOR);
|
-cosThetaT, m_extIOR, m_intIOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool choseSpecular = sampleSpecular;
|
||||||
|
|
||||||
Point2 sample(_sample);
|
Point2 sample(_sample);
|
||||||
if (sampleNested && sampleNested) {
|
if (sampleSpecular && sampleNested) {
|
||||||
if (sample.x <= R12) {
|
if (sample.x > R12) {
|
||||||
bRec.sampledComponent = m_components.size()-1;
|
|
||||||
bRec.sampledType = EDeltaReflection;
|
|
||||||
bRec.wo = reflect(bRec.wi);
|
|
||||||
pdf = R12;
|
|
||||||
return Spectrum(R12);
|
|
||||||
} else {
|
|
||||||
Vector wiBackup = bRec.wi;
|
|
||||||
// bRec.wi = -refract(bRec.wi, eta, cosThetaT);
|
|
||||||
bRec.wi = -refract(bRec.wi, R12);
|
|
||||||
sample.x = (sample.x - R12) / (1 - R12);
|
sample.x = (sample.x - R12) / (1 - R12);
|
||||||
|
choseSpecular = false;
|
||||||
Spectrum result = m_nested->sample(bRec, pdf, sample);
|
|
||||||
if (result.isZero())
|
|
||||||
return Spectrum(0.0f);
|
|
||||||
|
|
||||||
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 R21, cosThetaWoPrime = Frame::cosTheta(bRec.wo);
|
|
||||||
bRec.wi = wiBackup;
|
|
||||||
bRec.wo = refract(-bRec.wo, R21);
|
|
||||||
|
|
||||||
if (R21 == 1.0f) /* Total internal reflection */
|
|
||||||
return Spectrum(0.0f);
|
|
||||||
|
|
||||||
pdf *= 1 - R12;
|
|
||||||
if (BSDF::getMeasure(bRec.sampledType) == ESolidAngle)
|
|
||||||
pdf /= eta * eta;
|
|
||||||
|
|
||||||
result *= (1 - R12) * (1 - R21) * cosThetaWoPrime;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
} else if (sampleSpecular) {
|
}
|
||||||
bRec.sampledComponent = 0;
|
|
||||||
|
if (choseSpecular) {
|
||||||
|
bRec.sampledComponent = m_components.size()-1;
|
||||||
bRec.sampledType = EDeltaReflection;
|
bRec.sampledType = EDeltaReflection;
|
||||||
bRec.wo = reflect(bRec.wi);
|
bRec.wo = reflect(bRec.wi);
|
||||||
pdf = 1.0f;
|
pdf = sampleNested ? R12 : 1.0f;
|
||||||
return Spectrum(R12);
|
return Spectrum(R12);
|
||||||
} else {
|
} else {
|
||||||
// XXX not implemented
|
if (R12 == 1.0f) /* Total internal reflection */
|
||||||
return Spectrum(0.0f);
|
return Spectrum(0.0f);
|
||||||
|
|
||||||
|
Vector wiBackup = bRec.wi;
|
||||||
|
bRec.wi = -refract(bRec.wi, eta, cosThetaT);
|
||||||
|
|
||||||
|
Spectrum result = m_nested->sample(bRec, pdf, sample);
|
||||||
|
if (result.isZero())
|
||||||
|
return Spectrum(0.0f);
|
||||||
|
|
||||||
|
Spectrum sigmaA = m_sigmaA->getValue(bRec.its) * m_thickness;
|
||||||
|
if (!sigmaA.isZero())
|
||||||
|
result *= (-sigmaA *
|
||||||
|
(1/std::abs(Frame::cosTheta(bRec.wi)) +
|
||||||
|
1/std::abs(Frame::cosTheta(bRec.wo)))).exp();
|
||||||
|
|
||||||
|
Float R21, cosThetaWoPrime = Frame::cosTheta(bRec.wo);
|
||||||
|
bRec.wo = refract(-bRec.wo, R21);
|
||||||
|
bRec.wi = wiBackup;
|
||||||
|
|
||||||
|
if (R21 == 1.0f) /* Total internal reflection */
|
||||||
|
return Spectrum(0.0f);
|
||||||
|
|
||||||
|
pdf *= (sampleSpecular ? (1 - R12) : 1.0f) * eta * eta *
|
||||||
|
Frame::cosTheta(bRec.wo) / cosThetaWoPrime;
|
||||||
|
|
||||||
|
result *= (1 - R12) * (1 - R21) * cosThetaWoPrime * eta * eta;
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -317,7 +350,7 @@ public:
|
||||||
<< " name = \"" << getName() << "\"," << 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
|
<< " sigmaA = " << indent(m_sigmaA->toString()) << "," << endl
|
||||||
<< " thickness = " << m_thickness << "," << endl
|
<< " thickness = " << m_thickness << "," << endl
|
||||||
<< " nested = " << indent(m_nested->toString()) << endl
|
<< " nested = " << indent(m_nested->toString()) << endl
|
||||||
<< "]";
|
<< "]";
|
||||||
|
@ -327,11 +360,11 @@ public:
|
||||||
MTS_DECLARE_CLASS()
|
MTS_DECLARE_CLASS()
|
||||||
private:
|
private:
|
||||||
Float m_intIOR, m_extIOR;
|
Float m_intIOR, m_extIOR;
|
||||||
ref<Texture> m_sigmaT;
|
ref<Texture> m_sigmaA;
|
||||||
ref<BSDF> m_nested;
|
ref<BSDF> m_nested;
|
||||||
Float m_thickness;
|
Float m_thickness;
|
||||||
};
|
};
|
||||||
|
|
||||||
MTS_IMPLEMENT_CLASS_S(SmoothCoating, false, BSDF)
|
MTS_IMPLEMENT_CLASS_S(SmoothCoating, false, BSDF)
|
||||||
MTS_EXPORT_PLUGIN(SmoothCoating, "Smooth varnish layer");
|
MTS_EXPORT_PLUGIN(SmoothCoating, "Smooth dielectric coating");
|
||||||
MTS_NAMESPACE_END
|
MTS_NAMESPACE_END
|
||||||
|
|
|
@ -212,8 +212,7 @@ public:
|
||||||
/// Refraction in local coordinates (full version)
|
/// Refraction in local coordinates (full version)
|
||||||
inline Vector refract(const Vector &wi) const {
|
inline Vector refract(const Vector &wi) const {
|
||||||
Float cosThetaI = Frame::cosTheta(wi),
|
Float cosThetaI = Frame::cosTheta(wi),
|
||||||
etaI = m_extIOR,
|
etaI = m_extIOR, etaT = m_intIOR;
|
||||||
etaT = m_intIOR;
|
|
||||||
|
|
||||||
bool entering = cosThetaI > 0.0f;
|
bool entering = cosThetaI > 0.0f;
|
||||||
|
|
||||||
|
|
|
@ -72,7 +72,6 @@ MTS_NAMESPACE_BEGIN
|
||||||
* \unframedmedrendering{Silk shantung}{bsdf_irawan_shantung}
|
* \unframedmedrendering{Silk shantung}{bsdf_irawan_shantung}
|
||||||
* \unframedmedrendering{Cotton twill}{bsdf_irawan_twill}
|
* \unframedmedrendering{Cotton twill}{bsdf_irawan_twill}
|
||||||
* }
|
* }
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
class IrawanClothBRDF : public BSDF {
|
class IrawanClothBRDF : public BSDF {
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -22,10 +22,43 @@
|
||||||
|
|
||||||
MTS_NAMESPACE_BEGIN
|
MTS_NAMESPACE_BEGIN
|
||||||
|
|
||||||
/**
|
/*! \plugin{mixture}{Mixture material}
|
||||||
* Mixture material, represents a linear combination of
|
*
|
||||||
* one or more BRDFs.
|
* \parameters{
|
||||||
|
* \parameter{weights}{\String}{A comma-separated list of BSDF weights}
|
||||||
|
* }
|
||||||
|
* \renderings{
|
||||||
|
* \rendering{An exemplary combination of BSDFs
|
||||||
|
* (\lstref{mixture-example})}{bsdf_mixture_test}
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* This plugin implements a ``mixture'' material, which represents
|
||||||
|
* linear combinations of multiple BSDF instances. Any surface scattering
|
||||||
|
* model in Mitsuba (be it smooth, rough, reflecting, or transmitting) can
|
||||||
|
* be mixed with others in this manner to synthesize new models. There
|
||||||
|
* is no limit on how many models can be mixed, but their combination
|
||||||
|
* weights must be nonnegative and sum to less than one to ensure
|
||||||
|
* energy balance.
|
||||||
|
*
|
||||||
|
* \vspace{4mm}
|
||||||
|
* \begin{xml}[caption={A material definition for a mixture of 70% smooth
|
||||||
|
* chromium, 20% of a greenish rough diffuse material (and 10% absorption)},
|
||||||
|
* label=lst:mixture-example]
|
||||||
|
* <bsdf type="mixture">
|
||||||
|
* <string name="weights" value="0.7, 0.2"/>
|
||||||
|
*
|
||||||
|
* <bsdf type="conductor">
|
||||||
|
* <string name="material" value="Cr"/>
|
||||||
|
* </bsdf>
|
||||||
|
*
|
||||||
|
* <bsdf type="roughdiffuse">
|
||||||
|
* <rgb name="reflectance" value=".7 1 .7"/>
|
||||||
|
* <float name="alpha" value="0.4"/>
|
||||||
|
* </bsdf>
|
||||||
|
* </bsdf>
|
||||||
|
* \end{xml}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class MixtureBSDF : public BSDF {
|
class MixtureBSDF : public BSDF {
|
||||||
public:
|
public:
|
||||||
MixtureBSDF(const Properties &props)
|
MixtureBSDF(const Properties &props)
|
||||||
|
|