added a linear blend BSDF that can handle textures
parent
63e629c106
commit
47ad782273
|
@ -14,6 +14,7 @@ plugins += env.SharedLibrary('roughplastic', ['roughplastic.cpp'])
|
|||
plugins += env.SharedLibrary('twosided', ['twosided.cpp'])
|
||||
plugins += env.SharedLibrary('mask', ['mask.cpp'])
|
||||
plugins += env.SharedLibrary('mixturebsdf', ['mixturebsdf.cpp'])
|
||||
plugins += env.SharedLibrary('blendbsdf', ['blendbsdf.cpp'])
|
||||
plugins += env.SharedLibrary('coating', ['coating.cpp'])
|
||||
plugins += env.SharedLibrary('roughcoating', ['roughcoating.cpp'])
|
||||
plugins += env.SharedLibrary('bump', ['bump.cpp'])
|
||||
|
|
|
@ -0,0 +1,276 @@
|
|||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#include <mitsuba/render/bsdf.h>
|
||||
#include <mitsuba/render/texture.h>
|
||||
#include <mitsuba/hw/gpuprogram.h>
|
||||
#include <mitsuba/hw/basicshader.h>
|
||||
|
||||
MTS_NAMESPACE_BEGIN
|
||||
|
||||
/*! \plugin{blendbsdf}{Blended material}
|
||||
*
|
||||
* \parameters{
|
||||
* \parameter{weight}{\Float\Or\Texture}{A floating point value or texture
|
||||
* with values between zero and one. The extreme values zero and one activate the
|
||||
* first and second nested BSDF respectively, and inbetween values
|
||||
* interpolate accordingly. \default{0.5}}
|
||||
* \parameter{\Unnamed}{\BSDF}{Two nested BSDF instances that should be
|
||||
* mixed according to the specified blending weight}
|
||||
* }
|
||||
*
|
||||
* This plugin implements a ``blend'' material, which represents
|
||||
* linear combinations of two BSDF instances. It is conceptually very similar
|
||||
* to the \pluginref{mixture} plugin. The main difference is that
|
||||
* \pluginref{blendbsdf} can interpolate based on a texture.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
class BlendBSDF : public BSDF {
|
||||
public:
|
||||
BlendBSDF(const Properties &props)
|
||||
: BSDF(props) {
|
||||
m_weight = new ConstantFloatTexture(props.getFloat("weight", 0.5f));
|
||||
}
|
||||
|
||||
BlendBSDF(Stream *stream, InstanceManager *manager)
|
||||
: BSDF(stream, manager) {
|
||||
m_weight = static_cast<Texture *>(manager->getInstance(stream));
|
||||
m_bsdfs.push_back(static_cast<BSDF *>(manager->getInstance(stream)));
|
||||
m_bsdfs.push_back(static_cast<BSDF *>(manager->getInstance(stream)));
|
||||
configure();
|
||||
}
|
||||
|
||||
virtual ~BlendBSDF() {
|
||||
for (size_t i=0; i<m_bsdfs.size(); ++i)
|
||||
m_bsdfs[i]->decRef();
|
||||
}
|
||||
|
||||
void serialize(Stream *stream, InstanceManager *manager) const {
|
||||
BSDF::serialize(stream, manager);
|
||||
|
||||
Assert(m_bsdfs.size() == 2);
|
||||
manager->serialize(stream, m_weight.get());
|
||||
manager->serialize(stream, m_bsdfs[0]);
|
||||
manager->serialize(stream, m_bsdfs[1]);
|
||||
}
|
||||
|
||||
void configure() {
|
||||
m_usesRayDifferentials = false;
|
||||
size_t componentCount = 0;
|
||||
|
||||
if (m_bsdfs.size() != 2)
|
||||
Log(EError, "BSDF count mismatch: expected two nested BSDF instances!");
|
||||
|
||||
for (size_t i=0; i<m_bsdfs.size(); ++i)
|
||||
componentCount += m_bsdfs[i]->getComponentCount();
|
||||
|
||||
m_components.reserve(componentCount);
|
||||
m_components.clear();
|
||||
m_indices.reserve(componentCount);
|
||||
m_indices.clear();
|
||||
m_offsets.reserve(m_bsdfs.size());
|
||||
m_offsets.clear();
|
||||
|
||||
int offset = 0;
|
||||
for (size_t i=0; i<m_bsdfs.size(); ++i) {
|
||||
const BSDF *bsdf = m_bsdfs[i];
|
||||
m_offsets.push_back(offset);
|
||||
|
||||
for (int j=0; j<bsdf->getComponentCount(); ++j) {
|
||||
int componentType = bsdf->getType(j);
|
||||
m_components.push_back(componentType);
|
||||
m_indices.push_back(std::make_pair((int) i, j));
|
||||
}
|
||||
|
||||
offset += bsdf->getComponentCount();
|
||||
m_usesRayDifferentials |= bsdf->usesRayDifferentials();
|
||||
}
|
||||
BSDF::configure();
|
||||
}
|
||||
|
||||
Spectrum eval(const BSDFQueryRecord &bRec, EMeasure measure) const {
|
||||
Float weight = std::min(1.0f, std::max(0.0f,
|
||||
m_weight->getValue(bRec.its).average()));
|
||||
|
||||
if (bRec.component == -1) {
|
||||
return
|
||||
m_bsdfs[0]->eval(bRec, measure) * (1-weight) +
|
||||
m_bsdfs[1]->eval(bRec, measure) * weight;
|
||||
} else {
|
||||
/* Pick out an individual component */
|
||||
int idx = m_indices[bRec.component].first;
|
||||
if (idx == 0)
|
||||
weight = 1-weight;
|
||||
BSDFQueryRecord bRec2(bRec);
|
||||
bRec2.component = m_indices[bRec.component].second;
|
||||
return m_bsdfs[idx]->eval(bRec2, measure) * weight;
|
||||
}
|
||||
}
|
||||
|
||||
Float pdf(const BSDFQueryRecord &bRec, EMeasure measure) const {
|
||||
Spectrum result;
|
||||
|
||||
Float weight = std::min(1.0f, std::max(0.0f,
|
||||
m_weight->getValue(bRec.its).average()));
|
||||
|
||||
if (bRec.component == -1) {
|
||||
return
|
||||
m_bsdfs[0]->pdf(bRec, measure) * (1-weight) +
|
||||
m_bsdfs[1]->pdf(bRec, measure) * weight;
|
||||
} else {
|
||||
/* Pick out an individual component */
|
||||
int idx = m_indices[bRec.component].first;
|
||||
if (idx == 0)
|
||||
weight = 1-weight;
|
||||
BSDFQueryRecord bRec2(bRec);
|
||||
bRec2.component = m_indices[bRec.component].second;
|
||||
return m_bsdfs[idx]->pdf(bRec2, measure) * weight;
|
||||
}
|
||||
}
|
||||
|
||||
Spectrum sample(BSDFQueryRecord &bRec, const Point2 &_sample) const {
|
||||
Point2 sample(_sample);
|
||||
|
||||
Float weights[2];
|
||||
weights[1] = std::min(1.0f, std::max(0.0f,
|
||||
m_weight->getValue(bRec.its).average()));
|
||||
weights[0] = 1-weights[1];
|
||||
|
||||
if (bRec.component == -1) {
|
||||
size_t entry;
|
||||
if (sample.x < weights[0]) {
|
||||
entry = 0; sample.x /= weights[0];
|
||||
} else {
|
||||
entry = 1; sample.x = (sample.x - weights[0]) / weights[1];
|
||||
}
|
||||
|
||||
Float pdf;
|
||||
Spectrum result = m_bsdfs[entry]->sample(bRec, pdf, sample);
|
||||
if (result.isZero()) // sampling failed
|
||||
return result;
|
||||
|
||||
result *= weights[entry] * pdf;
|
||||
pdf *= weights[entry];
|
||||
|
||||
EMeasure measure = BSDF::getMeasure(bRec.sampledType);
|
||||
for (size_t i=0; i<m_bsdfs.size(); ++i) {
|
||||
if (entry == i)
|
||||
continue;
|
||||
pdf += m_bsdfs[i]->pdf(bRec, measure) * weights[i];
|
||||
result += m_bsdfs[i]->eval(bRec, measure) * weights[i];
|
||||
}
|
||||
|
||||
bRec.sampledComponent += m_offsets[entry];
|
||||
return result/pdf;
|
||||
} else {
|
||||
/* Pick out an individual component */
|
||||
int requestedComponent = bRec.component;
|
||||
int bsdfIndex = m_indices[requestedComponent].first;
|
||||
bRec.component = m_indices[requestedComponent].second;
|
||||
Spectrum result = m_bsdfs[bsdfIndex]->sample(bRec, sample)
|
||||
* weights[bsdfIndex];
|
||||
bRec.component = bRec.sampledComponent = requestedComponent;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
Spectrum sample(BSDFQueryRecord &bRec, Float &pdf, const Point2 &_sample) const {
|
||||
Point2 sample(_sample);
|
||||
|
||||
Float weights[2];
|
||||
weights[1] = std::min(1.0f, std::max(0.0f,
|
||||
m_weight->getValue(bRec.its).average()));
|
||||
weights[0] = 1-weights[1];
|
||||
|
||||
if (bRec.component == -1) {
|
||||
size_t entry;
|
||||
if (sample.x < weights[0]) {
|
||||
entry = 0; sample.x /= weights[0];
|
||||
} else {
|
||||
entry = 1; sample.x = (sample.x - weights[0]) / weights[1];
|
||||
}
|
||||
|
||||
Spectrum result = m_bsdfs[entry]->sample(bRec, pdf, sample);
|
||||
if (result.isZero()) // sampling failed
|
||||
return result;
|
||||
|
||||
result *= weights[entry] * pdf;
|
||||
pdf *= weights[entry];
|
||||
|
||||
EMeasure measure = BSDF::getMeasure(bRec.sampledType);
|
||||
for (size_t i=0; i<m_bsdfs.size(); ++i) {
|
||||
if (entry == i)
|
||||
continue;
|
||||
pdf += m_bsdfs[i]->pdf(bRec, measure) * weights[i];
|
||||
result += m_bsdfs[i]->eval(bRec, measure) * weights[i];
|
||||
}
|
||||
|
||||
bRec.sampledComponent += m_offsets[entry];
|
||||
return result/pdf;
|
||||
} else {
|
||||
/* Pick out an individual component */
|
||||
int requestedComponent = bRec.component;
|
||||
int bsdfIndex = m_indices[requestedComponent].first;
|
||||
bRec.component = m_indices[requestedComponent].second;
|
||||
Spectrum result = m_bsdfs[bsdfIndex]->sample(bRec, pdf, sample)
|
||||
* weights[bsdfIndex];
|
||||
bRec.component = bRec.sampledComponent = requestedComponent;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
void addChild(const std::string &name, ConfigurableObject *child) {
|
||||
if (child->getClass()->derivesFrom(MTS_CLASS(BSDF))) {
|
||||
BSDF *bsdf = static_cast<BSDF *>(child);
|
||||
m_bsdfs.push_back(bsdf);
|
||||
bsdf->incRef();
|
||||
} else if (child->getClass()->derivesFrom(MTS_CLASS(Texture)) && name == "weight") {
|
||||
m_weight = static_cast<Texture *>(child);
|
||||
} else {
|
||||
BSDF::addChild(name, child);
|
||||
}
|
||||
}
|
||||
|
||||
std::string toString() const {
|
||||
std::ostringstream oss;
|
||||
oss << "BlendBSDF[" << endl
|
||||
<< " name = \"" << getName() << "\"," << endl
|
||||
<< " weight = " << indent(m_weight->toString()) << endl
|
||||
<< " bsdfs = {" << endl;
|
||||
for (size_t i=0; i<m_bsdfs.size(); ++i)
|
||||
oss << " " << indent(m_bsdfs[i]->toString(), 2) << "," << endl;
|
||||
oss << " }"
|
||||
<< "]";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
MTS_DECLARE_CLASS()
|
||||
private:
|
||||
std::vector<BSDF *> m_bsdfs;
|
||||
ref<Texture> m_weight;
|
||||
std::vector<std::pair<int, int> > m_indices;
|
||||
std::vector<int> m_offsets;
|
||||
};
|
||||
|
||||
|
||||
MTS_IMPLEMENT_CLASS_S(BlendBSDF, false, BSDF)
|
||||
MTS_EXPORT_PLUGIN(BlendBSDF, "Blend BSDF")
|
||||
MTS_NAMESPACE_END
|
Loading…
Reference in New Issue