Extended the ward model with the Ward-Duer and energy balancing variants

metadata
Wenzel Jakob 2011-06-24 00:15:36 +02:00
parent 35d68c19ba
commit 714a2fcf71
4 changed files with 101 additions and 30 deletions

View File

@ -2,6 +2,17 @@
to be tested for consistency. This is done
using the testcase 'test_chisquare' -->
<scene>
<!-- Test the anisotropic Ward model -->
<bsdf type="ward">
<float name="diffuseAmount" value="0"/>
<float name="specularAmount" value="1"/>
<float name="alphaX" value="0.1"/>
<float name="alphaY" value="0.3"/>
<spectrum name="diffuseReflectance" value="1"/>
<spectrum name="specularReflectance" value="1"/>
</bsdf>
<!-- Test the lambertian model -->
<bsdf type="lambertian"/>
@ -30,17 +41,6 @@
</bsdf>
</bsdf>
<!-- Test the anisotropic Ward model -->
<bsdf type="ward">
<float name="diffuseAmount" value="0.5"/>
<float name="specularAmount" value="0.5"/>
<float name="alphaX" value="0.1"/>
<float name="alphaY" value="0.3"/>
<spectrum name="diffuseReflectance" value="1"/>
<spectrum name="specularReflectance" value="1"/>
</bsdf>
<!-- Test the microfacet model -->
<bsdf type="microfacet">
<float name="diffuseAmount" value="0.5"/>

View File

@ -68,7 +68,7 @@ public:
else if (distr == "ggx")
m_distribution = EGGX;
else
Log(EError, "Invalid distribution function \"%s\", must be "
Log(EError, "Specified an invalid distribution \"%s\", must be "
"\"beckmann\", \"phong\", or \"ggx\"!", distr.c_str());
if (m_distribution == EPhong) {

View File

@ -19,19 +19,38 @@
#include <mitsuba/render/bsdf.h>
#include <mitsuba/render/consttexture.h>
#include <mitsuba/hw/gpuprogram.h>
#include <boost/algorithm/string.hpp>
MTS_NAMESPACE_BEGIN
/**
* Anisotropic Ward BRDF model based on
* Anisotropic Ward BRDF model based on the following four papers
*
* "Measuring and Modeling Anisotropic Reflection" by
* Gregory J. Ward, SIGGRAPH 1992
* and
*
* "Notes on the Ward BRDF" by Bruce Walter, Technical Report
* PCG-05-06, Cornell University
*
* "An Improved Normalization for the Ward Reflectance Model"
* by Arne Duer, Journal of Graphics Tools 11, 1 (2006), 5159
*
* "A New Ward BRDF Model with Bounded Albedo" by
* by David Geisler-Moroder and Arne Dur,
* Computer Graphics Forum, Volume 29, Issue 4
*/
class Ward : public BSDF {
public:
/// Supported model types
enum EModelType {
/// The original Ward model
EWard = 0,
/// Ward model with correction by Arne Duer
EWardDuer = 1,
/// Energy-balanced Ward model
EBalanced = 2
};
Ward(const Properties &props)
: BSDF(props) {
m_diffuseReflectance = new ConstantTexture(
@ -42,6 +61,17 @@ public:
m_kd = props.getFloat("diffuseAmount", 1.0f);
m_ks = props.getFloat("specularAmount", 1.0f);
std::string type = boost::to_lower_copy(props.getString("type", "balanced"));
if (type == "ward")
m_modelType = EWard;
else if (type == "ward-duer")
m_modelType = EWardDuer;
else if (type == "balanced")
m_modelType = EBalanced;
else
Log(EError, "Specified an invalid model type \"%s\", must be "
"\"ward\", \"ward-duer\", or \"balanced\"!", type.c_str());
m_verifyEnergyConservation = props.getBoolean("verifyEnergyConservation", true);
m_specularSamplingWeight = props.getFloat("specularSamplingWeight", -1);
@ -59,6 +89,7 @@ public:
Ward(Stream *stream, InstanceManager *manager)
: BSDF(stream, manager) {
m_modelType = (EModelType) stream->readUInt();
m_diffuseReflectance = static_cast<Texture *>(manager->getInstance(stream));
m_specularReflectance = static_cast<Texture *>(manager->getInstance(stream));
m_alphaX = stream->readFloat();
@ -121,15 +152,32 @@ public:
if (hasGlossy) {
Vector H = bRec.wi+bRec.wo;
Float factor1 = 1.0f / (4.0f * M_PI * m_alphaX * m_alphaY *
std::sqrt(Frame::cosTheta(bRec.wi)*Frame::cosTheta(bRec.wo)));
Float factor1 = 0.0f;
switch (m_modelType) {
case EWard:
factor1 = 1.0f / (4.0f * M_PI * m_alphaX * m_alphaY *
std::sqrt(Frame::cosTheta(bRec.wi)*Frame::cosTheta(bRec.wo)));
break;
case EWardDuer:
factor1 = 1.0f / (4.0f * M_PI * m_alphaX * m_alphaY *
Frame::cosTheta(bRec.wi)*Frame::cosTheta(bRec.wo));
break;
case EBalanced:
factor1 = dot(H,H) / (M_PI * m_alphaX * m_alphaY
* std::pow(Frame::cosTheta(H),4));
break;
default:
Log(EError, "Unknown model type!");
}
Float factor2 = H.x / m_alphaX, factor3 = H.y / m_alphaY;
Float exponent = -(factor2*factor2+factor3*factor3)/(H.z*H.z);
Float specRef = factor1 * std::exp(exponent) * m_ks;
/* Important to prevent numeric issues when evaluating the
sampling density of the Ward model in places where it takes
on miniscule values (Veach-MLT does this for instance) */
if (specRef > Epsilon)
if (specRef > 1e-10f)
result += m_specularReflectance->getValue(bRec.its) * specRef;
}
@ -182,8 +230,8 @@ public:
Float thetaH = std::atan(std::sqrt(std::max((Float) 0.0f,
-std::log(sample.x) / (
(cosPhiH*cosPhiH)/(m_alphaX*m_alphaX) +
(sinPhiH*sinPhiH)/(m_alphaY*m_alphaY)
(cosPhiH*cosPhiH) / (m_alphaX*m_alphaX) +
(sinPhiH*sinPhiH) / (m_alphaY*m_alphaY)
))));
Vector H = sphericalDirection(thetaH, phiH);
bRec.wo = H * (2.0f * dot(bRec.wi, H)) - bRec.wi;
@ -251,6 +299,7 @@ public:
void serialize(Stream *stream, InstanceManager *manager) const {
BSDF::serialize(stream, manager);
stream->writeUInt(m_modelType);
manager->serialize(stream, m_diffuseReflectance.get());
manager->serialize(stream, m_specularReflectance.get());
stream->writeFloat(m_alphaX);
@ -266,7 +315,16 @@ public:
std::string toString() const {
std::ostringstream oss;
oss << "Ward[" << endl
<< " diffuseReflectance = " << indent(m_diffuseReflectance->toString()) << "," << endl
<< " type = ";
switch (m_modelType) {
case EWard: oss << "ward," << endl; break;
case EWardDuer: oss << "wardDuer," << endl; break;
case EBalanced: oss << "balanced," << endl; break;
default: Log(EError, "Unknown model type!");
}
oss << " diffuseReflectance = " << indent(m_diffuseReflectance->toString()) << "," << endl
<< " specularReflectance = " << indent(m_specularReflectance->toString()) << "," << endl
<< " diffuseAmount = " << m_kd << "," << endl
<< " specularAmount = " << m_ks << "," << endl
@ -279,6 +337,7 @@ public:
MTS_DECLARE_CLASS()
private:
EModelType m_modelType;
ref<const Texture> m_diffuseReflectance;
ref<const Texture> m_specularReflectance;
Float m_alphaX, m_alphaY;
@ -292,12 +351,12 @@ private:
class WardShader : public Shader {
public:
WardShader(Renderer *renderer,
WardShader(Renderer *renderer, Ward::EModelType type,
const Texture *diffuseColor,
const Texture *specularColor,
Float ks, Float kd,
Float alphaX, Float alphaY) : Shader(renderer, EBSDFShader),
m_diffuseReflectance(diffuseColor),
m_modelType(type), m_diffuseReflectance(diffuseColor),
m_specularReflectance(specularColor),
m_ks(ks), m_kd(kd), m_alphaX(alphaX), m_alphaY(alphaY) {
m_diffuseReflectanceShader = renderer->registerShaderForResource(m_diffuseReflectance.get());
@ -322,7 +381,8 @@ public:
void generateCode(std::ostringstream &oss,
const std::string &evalName,
const std::vector<std::string> &depNames) const {
oss << "uniform float " << evalName << "_alphaX;" << endl
oss << "uniform int " << evalName << "_type;" << endl
<< "uniform float " << evalName << "_alphaX;" << endl
<< "uniform float " << evalName << "_alphaY;" << endl
<< "uniform float " << evalName << "_ks;" << endl
<< "uniform float " << evalName << "_kd;" << endl
@ -331,8 +391,16 @@ public:
<< " if (wi.z <= 0.0 || wo.z <= 0.0)" << endl
<< " return vec3(0.0);" << endl
<< " vec3 H = normalize(wi + wo);" << endl
<< " float factor1 = 1/(12.566 * " << evalName << "_alphaX * "
<< " float factor1;" << endl
<< " if (" << evalName << "_type == 1)" << endl
<< " factor1 = 1/(12.566 * " << evalName << "_alphaX * " << endl
<< " " << evalName << "_alphaY * sqrt(wi.z * wo.z));" << endl
<< " else if (" << evalName << "_type == 2)" << endl
<< " factor1 = 1/(12.566 * " << evalName << "_alphaX * " << endl
<< " " << evalName << "_alphaY * wi.z * wo.z);" << endl
<< " else" << endl
<< " factor1 = dot(H, H)/(3.1415 * " << evalName << "_alphaX * " << endl
<< " " << evalName << "_alphaY * (H.z * H.z) * (H.z * H.z));" << endl
<< " float factor2 = H.x / " << evalName << "_alphaX;" << endl
<< " float factor3 = H.y / " << evalName << "_alphaY;" << endl
<< " float exponent = -(factor2*factor2 + factor3*factor3)/(H.z*H.z);" << endl
@ -348,6 +416,7 @@ public:
}
void resolve(const GPUProgram *program, const std::string &evalName, std::vector<int> &parameterIDs) const {
parameterIDs.push_back(program->getParameterID(evalName + "_type"));
parameterIDs.push_back(program->getParameterID(evalName + "_alphaX"));
parameterIDs.push_back(program->getParameterID(evalName + "_alphaY"));
parameterIDs.push_back(program->getParameterID(evalName + "_ks"));
@ -355,14 +424,16 @@ public:
}
void bind(GPUProgram *program, const std::vector<int> &parameterIDs, int &textureUnitOffset) const {
program->setParameter(parameterIDs[0], m_alphaX);
program->setParameter(parameterIDs[1], m_alphaY);
program->setParameter(parameterIDs[2], m_ks);
program->setParameter(parameterIDs[3], m_kd);
program->setParameter(parameterIDs[0], (int) m_modelType);
program->setParameter(parameterIDs[1], m_alphaX);
program->setParameter(parameterIDs[2], m_alphaY);
program->setParameter(parameterIDs[3], m_ks);
program->setParameter(parameterIDs[4], m_kd);
}
MTS_DECLARE_CLASS()
private:
Ward::EModelType m_modelType;
ref<const Texture> m_diffuseReflectance;
ref<const Texture> m_specularReflectance;
ref<Shader> m_diffuseReflectanceShader;
@ -372,7 +443,7 @@ private:
};
Shader *Ward::createShader(Renderer *renderer) const {
return new WardShader(renderer, m_diffuseReflectance.get(),
return new WardShader(renderer, m_modelType, m_diffuseReflectance.get(),
m_specularReflectance.get(), m_ks, m_kd, m_alphaX, m_alphaY);
}

View File

@ -69,7 +69,7 @@ public:
bool mismatch = false;
for (int i=0; i<SPECTRUM_SAMPLES; ++i) {
Float a = sampled[i], b=sampled2[i];
Float a = sampled[i], b = sampled2[i];
SAssert(a >= 0 && b >= 0);
Float min = std::min(a, b);
Float err = std::abs(a - b);