twosided plugin now supports having a different BRDF on each side

metadata
Wenzel Jakob 2012-04-14 13:39:39 -04:00
parent 6089c1d52c
commit 8f623c7fc6
1 changed files with 91 additions and 33 deletions

View File

@ -25,7 +25,8 @@ MTS_NAMESPACE_BEGIN
/*!\plugin{twosided}{Two-sided BRDF adapter}
* \parameters{
* \parameter{\Unnamed}{\BSDF}{A nested BRDF that should
* be turned into a two-sided scattering model.}
* be turned into a two-sided scattering model. If two BRDFs
* are specified, they will be placed on the front and back side, respectively.}
* }
*
* \renderings{
@ -47,7 +48,9 @@ MTS_NAMESPACE_BEGIN
* bothersome. In that case, this plugin can be used to turn
* one-sided scattering models into proper two-sided versions of
* themselves. The plugin has no parameters other than a required
* nested BSDF specification.
* nested BSDF specification. It is also possible to supply two
* different BRDFs that should be placed on the front and back
* side, respectively.
* \vspace{4mm}
*
* \begin{xml}[caption=A two-sided diffuse material]
@ -65,23 +68,36 @@ public:
TwoSidedBRDF(Stream *stream, InstanceManager *manager)
: BSDF(stream, manager) {
m_nestedBRDF = static_cast<BSDF *>(manager->getInstance(stream));
m_nestedBRDF[0] = static_cast<BSDF *>(manager->getInstance(stream));
m_nestedBRDF[1] = static_cast<BSDF *>(manager->getInstance(stream));
configure();
}
void serialize(Stream *stream, InstanceManager *manager) const {
BSDF::serialize(stream, manager);
manager->serialize(stream, m_nestedBRDF.get());
manager->serialize(stream, m_nestedBRDF[0].get());
manager->serialize(stream, m_nestedBRDF[1].get());
}
void configure() {
if (!m_nestedBRDF)
if (!m_nestedBRDF[0])
Log(EError, "A nested one-sided material is required!");
m_usesRayDifferentials = m_nestedBRDF->usesRayDifferentials();
if (!m_nestedBRDF[1])
m_nestedBRDF[1] = m_nestedBRDF[0];
m_usesRayDifferentials = m_nestedBRDF[0]->usesRayDifferentials()
|| m_nestedBRDF[1]->usesRayDifferentials();
m_components.clear();
for (int i=0; i<m_nestedBRDF->getComponentCount(); ++i)
m_components.push_back(m_nestedBRDF->getType(i) | EFrontSide | EBackSide);
for (int i=0; i<m_nestedBRDF[0]->getComponentCount(); ++i)
m_components.push_back((m_nestedBRDF[0]->getType(i) & ~EBackSide) | EFrontSide);
for (int i=0; i<m_nestedBRDF[1]->getComponentCount(); ++i)
m_components.push_back((m_nestedBRDF[1]->getType(i) & ~EFrontSide) | EBackSide);
BSDF::configure();
if (m_combinedType & BSDF::ETransmission)
Log(EError, "Only materials without "
@ -90,36 +106,54 @@ public:
Spectrum eval(const BSDFQueryRecord &bRec, EMeasure measure) const {
BSDFQueryRecord b(bRec);
if (Frame::cosTheta(b.wi) < 0) {
if (Frame::cosTheta(b.wi) > 0) {
return m_nestedBRDF[0]->eval(b, measure);
} else {
if (b.component != -1)
b.component -= m_nestedBRDF[0]->getComponentCount();
b.wi.z *= -1;
b.wo.z *= -1;
return m_nestedBRDF[1]->eval(b, measure);
}
return m_nestedBRDF->eval(b, measure);
}
Float pdf(const BSDFQueryRecord &bRec, EMeasure measure) const {
BSDFQueryRecord b(bRec);
if (b.wi.z < 0) {
if (b.wi.z > 0) {
return m_nestedBRDF[0]->pdf(b, measure);
} else {
if (b.component != -1)
b.component -= m_nestedBRDF[0]->getComponentCount();
b.wi.z *= -1;
b.wo.z *= -1;
return m_nestedBRDF[1]->pdf(b, measure);
}
return m_nestedBRDF->pdf(b, measure);
}
Spectrum sample(BSDFQueryRecord &bRec, const Point2 &sample) const {
bool flipped = false;
if (Frame::cosTheta(bRec.wi) < 0) {
bRec.wi.z *= -1;
flipped = true;
if (bRec.component != -1)
bRec.component -= m_nestedBRDF[0]->getComponentCount();
}
Spectrum result = m_nestedBRDF->sample(bRec, sample);
Spectrum result = m_nestedBRDF[flipped ? 1 : 0]->sample(bRec, sample);
if (flipped) {
bRec.wi.z *= -1;
if (!result.isZero())
if (bRec.component != -1)
bRec.component += m_nestedBRDF[0]->getComponentCount();
if (!result.isZero()) {
bRec.wo.z *= -1;
bRec.sampledComponent += m_nestedBRDF[0]->getComponentCount();
}
}
return result;
}
@ -128,24 +162,33 @@ public:
if (Frame::cosTheta(bRec.wi) < 0) {
bRec.wi.z *= -1;
flipped = true;
if (bRec.component != -1)
bRec.component -= m_nestedBRDF[0]->getComponentCount();
}
Spectrum result = m_nestedBRDF->sample(bRec, pdf, sample);
Spectrum result = m_nestedBRDF[flipped ? 1 : 0]->sample(bRec, pdf, sample);
if (flipped) {
bRec.wi.z *= -1;
if (!result.isZero() && pdf != 0)
if (bRec.component != -1)
bRec.component += m_nestedBRDF[0]->getComponentCount();
if (!result.isZero() && pdf != 0) {
bRec.wo.z *= -1;
bRec.sampledComponent += m_nestedBRDF[0]->getComponentCount();
}
}
return result;
}
void addChild(const std::string &name, ConfigurableObject *child) {
if (child->getClass()->derivesFrom(BSDF::m_theClass)) {
if (m_nestedBRDF != NULL)
Log(EError, "Only a single nested BRDF can be added!");
m_nestedBRDF = static_cast<BSDF *>(child);
if (m_nestedBRDF[0] == NULL)
m_nestedBRDF[0] = static_cast<BSDF *>(child);
else if (m_nestedBRDF[1] == NULL)
m_nestedBRDF[1] = static_cast<BSDF *>(child);
else
Log(EError, "No more than two nested BRDFs can be added!");
} else {
BSDF::addChild(name, child);
}
@ -154,7 +197,8 @@ public:
std::string toString() const {
std::ostringstream oss;
oss << "TwoSided[" << endl
<< " nestedBRDF = " << indent(m_nestedBRDF->toString()) << endl
<< " nestedBRDF[0] = " << indent(m_nestedBRDF[0]->toString()) << "," << endl
<< " nestedBRDF[1] = " << indent(m_nestedBRDF[1]->toString()) << endl
<< "]";
return oss.str();
}
@ -163,7 +207,7 @@ public:
MTS_DECLARE_CLASS()
protected:
ref<BSDF> m_nestedBRDF;
ref<BSDF> m_nestedBRDF[2];
};
@ -172,21 +216,32 @@ protected:
class TwoSidedShader : public Shader {
public:
TwoSidedShader(Renderer *renderer,
const BSDF *nestedBRDF) : Shader(renderer, EBSDFShader),
m_nestedBRDF(nestedBRDF) {
m_nestedBRDFShader = renderer->registerShaderForResource(nestedBRDF);
const ref<BSDF> *nestedBRDF) : Shader(renderer, EBSDFShader) {
m_nestedBRDF[0] = nestedBRDF[0].get();
m_nestedBRDF[1] = nestedBRDF[1].get();
m_nestedBRDFShader[0] = renderer->registerShaderForResource(m_nestedBRDF[0]);
if (m_nestedBRDF[0] != m_nestedBRDF[1])
m_nestedBRDFShader[1] = renderer->registerShaderForResource(m_nestedBRDF[1]);
else
m_nestedBRDFShader[1] = NULL;
}
bool isComplete() const {
return m_nestedBRDFShader.get() != NULL;
return m_nestedBRDFShader[0].get() != NULL &&
(m_nestedBRDF[0] == m_nestedBRDF[1] || m_nestedBRDFShader[1].get() != NULL);
}
void putDependencies(std::vector<Shader *> &deps) {
deps.push_back(m_nestedBRDFShader.get());
deps.push_back(m_nestedBRDFShader[0].get());
if (m_nestedBRDF[0] != m_nestedBRDF[1])
deps.push_back(m_nestedBRDFShader[1].get());
}
void cleanup(Renderer *renderer) {
renderer->unregisterShaderForResource(m_nestedBRDF);
renderer->unregisterShaderForResource(m_nestedBRDF[0]);
if (m_nestedBRDF[0] != m_nestedBRDF[1])
renderer->unregisterShaderForResource(m_nestedBRDF[1]);
}
void generateCode(std::ostringstream &oss,
@ -195,26 +250,29 @@ public:
oss << "vec3 " << evalName << "(vec2 uv, vec3 wi, vec3 wo) {" << endl
<< " if (cosTheta(wi) <= 0.0) {" << endl
<< " wi.z *= -1; wo.z *= -1;" << endl
<< " return " << (depNames.size() == 2 ? depNames[1] : depNames[0]) << "(uv, wi, wo);" << endl
<< " } else {" << endl
<< " return " << depNames[0] << "(uv, wi, wo);" << endl
<< " }" << endl
<< " return " << depNames[0] << "(uv, wi, wo);" << endl
<< "}" << endl
<< "vec3 " << evalName << "_diffuse(vec2 uv, vec3 wi, vec3 wo) {" << endl
<< " if (cosTheta(wi) <= 0.0) {" << endl
<< " wi.z *= -1; wo.z *= -1;" << endl
<< " return " << (depNames.size() == 2 ? depNames[1] : depNames[0]) << "_diffuse(uv, wi, wo);" << endl
<< " } else {" << endl
<< " return " << depNames[0] << "_diffuse(uv, wi, wo);" << endl
<< " }" << endl
<< " return " << depNames[0] << "_diffuse(uv, wi, wo);" << endl
<< "}" << endl;
}
MTS_DECLARE_CLASS()
private:
const BSDF *m_nestedBRDF;
ref<Shader> m_nestedBRDFShader;
bool m_complete;
const BSDF *m_nestedBRDF[2];
ref<Shader> m_nestedBRDFShader[2];
};
Shader *TwoSidedBRDF::createShader(Renderer *renderer) const {
return new TwoSidedShader(renderer, m_nestedBRDF.get());
return new TwoSidedShader(renderer, m_nestedBRDF);
}
MTS_IMPLEMENT_CLASS(TwoSidedShader, false, Shader)