twosided plugin now supports having a different BRDF on each side
parent
6089c1d52c
commit
8f623c7fc6
|
@ -25,7 +25,8 @@ MTS_NAMESPACE_BEGIN
|
||||||
/*!\plugin{twosided}{Two-sided BRDF adapter}
|
/*!\plugin{twosided}{Two-sided BRDF adapter}
|
||||||
* \parameters{
|
* \parameters{
|
||||||
* \parameter{\Unnamed}{\BSDF}{A nested BRDF that should
|
* \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{
|
* \renderings{
|
||||||
|
@ -47,7 +48,9 @@ MTS_NAMESPACE_BEGIN
|
||||||
* bothersome. In that case, this plugin can be used to turn
|
* bothersome. In that case, this plugin can be used to turn
|
||||||
* one-sided scattering models into proper two-sided versions of
|
* one-sided scattering models into proper two-sided versions of
|
||||||
* themselves. The plugin has no parameters other than a required
|
* 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}
|
* \vspace{4mm}
|
||||||
*
|
*
|
||||||
* \begin{xml}[caption=A two-sided diffuse material]
|
* \begin{xml}[caption=A two-sided diffuse material]
|
||||||
|
@ -65,23 +68,36 @@ public:
|
||||||
|
|
||||||
TwoSidedBRDF(Stream *stream, InstanceManager *manager)
|
TwoSidedBRDF(Stream *stream, InstanceManager *manager)
|
||||||
: BSDF(stream, 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();
|
configure();
|
||||||
}
|
}
|
||||||
|
|
||||||
void serialize(Stream *stream, InstanceManager *manager) const {
|
void serialize(Stream *stream, InstanceManager *manager) const {
|
||||||
BSDF::serialize(stream, manager);
|
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() {
|
void configure() {
|
||||||
if (!m_nestedBRDF)
|
if (!m_nestedBRDF[0])
|
||||||
Log(EError, "A nested one-sided material is required!");
|
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();
|
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();
|
BSDF::configure();
|
||||||
if (m_combinedType & BSDF::ETransmission)
|
if (m_combinedType & BSDF::ETransmission)
|
||||||
Log(EError, "Only materials without "
|
Log(EError, "Only materials without "
|
||||||
|
@ -90,36 +106,54 @@ public:
|
||||||
|
|
||||||
Spectrum eval(const BSDFQueryRecord &bRec, EMeasure measure) const {
|
Spectrum eval(const BSDFQueryRecord &bRec, EMeasure measure) const {
|
||||||
BSDFQueryRecord b(bRec);
|
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.wi.z *= -1;
|
||||||
b.wo.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 {
|
Float pdf(const BSDFQueryRecord &bRec, EMeasure measure) const {
|
||||||
BSDFQueryRecord b(bRec);
|
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.wi.z *= -1;
|
||||||
b.wo.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 {
|
Spectrum sample(BSDFQueryRecord &bRec, const Point2 &sample) const {
|
||||||
bool flipped = false;
|
bool flipped = false;
|
||||||
|
|
||||||
if (Frame::cosTheta(bRec.wi) < 0) {
|
if (Frame::cosTheta(bRec.wi) < 0) {
|
||||||
bRec.wi.z *= -1;
|
bRec.wi.z *= -1;
|
||||||
flipped = true;
|
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) {
|
if (flipped) {
|
||||||
bRec.wi.z *= -1;
|
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.wo.z *= -1;
|
||||||
|
bRec.sampledComponent += m_nestedBRDF[0]->getComponentCount();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,24 +162,33 @@ public:
|
||||||
if (Frame::cosTheta(bRec.wi) < 0) {
|
if (Frame::cosTheta(bRec.wi) < 0) {
|
||||||
bRec.wi.z *= -1;
|
bRec.wi.z *= -1;
|
||||||
flipped = true;
|
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) {
|
if (flipped) {
|
||||||
bRec.wi.z *= -1;
|
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.wo.z *= -1;
|
||||||
|
bRec.sampledComponent += m_nestedBRDF[0]->getComponentCount();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void addChild(const std::string &name, ConfigurableObject *child) {
|
void addChild(const std::string &name, ConfigurableObject *child) {
|
||||||
if (child->getClass()->derivesFrom(BSDF::m_theClass)) {
|
if (child->getClass()->derivesFrom(BSDF::m_theClass)) {
|
||||||
if (m_nestedBRDF != NULL)
|
if (m_nestedBRDF[0] == NULL)
|
||||||
Log(EError, "Only a single nested BRDF can be added!");
|
m_nestedBRDF[0] = static_cast<BSDF *>(child);
|
||||||
m_nestedBRDF = 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 {
|
} else {
|
||||||
BSDF::addChild(name, child);
|
BSDF::addChild(name, child);
|
||||||
}
|
}
|
||||||
|
@ -154,7 +197,8 @@ public:
|
||||||
std::string toString() const {
|
std::string toString() const {
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << "TwoSided[" << endl
|
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();
|
return oss.str();
|
||||||
}
|
}
|
||||||
|
@ -163,7 +207,7 @@ public:
|
||||||
|
|
||||||
MTS_DECLARE_CLASS()
|
MTS_DECLARE_CLASS()
|
||||||
protected:
|
protected:
|
||||||
ref<BSDF> m_nestedBRDF;
|
ref<BSDF> m_nestedBRDF[2];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -172,21 +216,32 @@ protected:
|
||||||
class TwoSidedShader : public Shader {
|
class TwoSidedShader : public Shader {
|
||||||
public:
|
public:
|
||||||
TwoSidedShader(Renderer *renderer,
|
TwoSidedShader(Renderer *renderer,
|
||||||
const BSDF *nestedBRDF) : Shader(renderer, EBSDFShader),
|
const ref<BSDF> *nestedBRDF) : Shader(renderer, EBSDFShader) {
|
||||||
m_nestedBRDF(nestedBRDF) {
|
m_nestedBRDF[0] = nestedBRDF[0].get();
|
||||||
m_nestedBRDFShader = renderer->registerShaderForResource(nestedBRDF);
|
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 {
|
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) {
|
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) {
|
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,
|
void generateCode(std::ostringstream &oss,
|
||||||
|
@ -195,26 +250,29 @@ public:
|
||||||
oss << "vec3 " << evalName << "(vec2 uv, vec3 wi, vec3 wo) {" << endl
|
oss << "vec3 " << evalName << "(vec2 uv, vec3 wi, vec3 wo) {" << endl
|
||||||
<< " if (cosTheta(wi) <= 0.0) {" << endl
|
<< " if (cosTheta(wi) <= 0.0) {" << endl
|
||||||
<< " wi.z *= -1; wo.z *= -1;" << 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
|
<< " }" << endl
|
||||||
<< " return " << depNames[0] << "(uv, wi, wo);" << endl
|
|
||||||
<< "}" << endl
|
<< "}" << endl
|
||||||
<< "vec3 " << evalName << "_diffuse(vec2 uv, vec3 wi, vec3 wo) {" << endl
|
<< "vec3 " << evalName << "_diffuse(vec2 uv, vec3 wi, vec3 wo) {" << endl
|
||||||
<< " if (cosTheta(wi) <= 0.0) {" << endl
|
<< " if (cosTheta(wi) <= 0.0) {" << endl
|
||||||
<< " wi.z *= -1; wo.z *= -1;" << 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
|
<< " }" << endl
|
||||||
<< " return " << depNames[0] << "_diffuse(uv, wi, wo);" << endl
|
|
||||||
<< "}" << endl;
|
<< "}" << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
MTS_DECLARE_CLASS()
|
MTS_DECLARE_CLASS()
|
||||||
private:
|
private:
|
||||||
const BSDF *m_nestedBRDF;
|
const BSDF *m_nestedBRDF[2];
|
||||||
ref<Shader> m_nestedBRDFShader;
|
ref<Shader> m_nestedBRDFShader[2];
|
||||||
bool m_complete;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Shader *TwoSidedBRDF::createShader(Renderer *renderer) const {
|
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)
|
MTS_IMPLEMENT_CLASS(TwoSidedShader, false, Shader)
|
||||||
|
|
Loading…
Reference in New Issue