Commit bab8c2e4 authored by Laurent Belcour's avatar Laurent Belcour

Adding the ABC reflectance model from Stover

parent b65685e2
......@@ -11,6 +11,7 @@ SConscript('rational_fitter_quadprog/SConscript')
SConscript('nonlinear_function_diffuse/SConscript')
SConscript('nonlinear_function_beckmann/SConscript')
SConscript('nonlinear_function_retrobeckmann/SConscript')
SConscript('nonlinear_function_abc/SConscript')
SConscript('nonlinear_function_blinn/SConscript')
SConscript('nonlinear_function_retroblinn/SConscript')
SConscript('nonlinear_function_retroyoo/SConscript')
......
env = Environment()
env.Append(CPPPATH = ['../../../external/build/include', '../../'])
env.Append(LIBPATH = ['../../../external/build/lib', '../../build'])
sources = ['function.cpp']
libs = ['-lcore']
env.SharedLibrary('../../build/nonlinear_function_abs', sources, LIBS=libs)
#include "function.h"
#include <string>
#include <sstream>
#include <iostream>
#include <fstream>
#include <limits>
#include <algorithm>
#include <cmath>
#include <core/common.h>
ALTA_DLL_EXPORT function* provide_function()
{
return new abc_function();
}
// Overload the function operator
vec abc_function::operator()(const vec& x) const
{
return value(x);
}
vec abc_function::value(const vec& x) const
{
// Compute the Shadow term to init res
vec res = vec::Zero(dimY());
const double hn = 1.0 - x[0];
for(int i=0; i<dimY(); ++i)
{
res[i] = _a[i] / pow(1.0 + _b[i]*hn, _c[i]);
}
return res;
}
// Reset the output dimension
void abc_function::setDimY(int nY)
{
_nY = nY ;
// Update the length of the vectors
_a.resize(_nY) ;
_b.resize(_nY) ;
_c.resize(_nY) ;
}
//! Number of parameters to this non-linear function
int abc_function::nbParameters() const
{
return 3*dimY();
}
//! Get the vector of parameters for the function
vec abc_function::parameters() const
{
vec res(nbParameters());
for(int i=0; i<dimY(); ++i)
{
res[i*3 + 0] = _a[i];
res[i*3 + 1] = _b[i];
res[i*3 + 2] = _c[i];
}
return res;
}
//! \brief get the min values for the parameters
vec abc_function::getParametersMin() const
{
vec res(nbParameters());
for(int i=0; i<dimY(); ++i)
{
res[i*3 + 0] = 0.0;
res[i*3 + 1] = 0.0;
res[i*3 + 2] = 0.0;
}
return res;
}
//! Update the vector of parameters for the function
void abc_function::setParameters(const vec& p)
{
for(int i=0; i<dimY(); ++i)
{
_a[i] = p[i*3 + 0];
_b[i] = p[i*3 + 1];
_c[i] = p[i*3 + 2];
}
}
//! Obtain the derivatives of the function with respect to the
//! parameters
//! \todo finish.
vec abc_function::parametersJacobian(const vec& x) const
{
vec jac(dimY()*nbParameters());
for(int i=0; i<dimY(); ++i)
{
for(int j=0; j<dimY(); ++j)
{
if(i == j)
{
const double hn = 1.0 - x[0];
const double f = 1.0 + _b[i]*hn;
const double denom = pow(f, _c[i]);
const double fact = 1.0 / denom;
const double fact2 = fact*fact;
// df / da
jac[i*nbParameters() + j*3+0] = fact;
// df / db
jac[i*nbParameters() + j*3+1] = - _a[i] * hn *_c[i] * pow(f, _c[i]-1.0) * fact2;
// df / dc
if(f > 0.0)
{
jac[i*nbParameters() + j*3+2] = - _a[i] * log(f) * fact;
}
else
{
jac[i*nbParameters() + j*3+2] = 0.0;
}
}
else
{
jac[i*nbParameters() + j*3+0] = 0.0;
jac[i*nbParameters() + j*3+1] = 0.0;
jac[i*nbParameters() + j*3+2] = 0.0;
}
}
}
return jac;
}
void abc_function::bootstrap(const data* d, const arguments& args)
{
for(int i=0; i<dimY(); ++i)
{
_a[i] = 1.0;
_b[i] = 1.0;
_c[i] = 1.0;
}
}
//! Load function specific files
bool abc_function::load(std::istream& in)
{
// Parse line until the next comment
while(in.peek() != '#')
{
char line[256];
in.getline(line, 256);
// If we cross the end of the file, or the badbit is
// set, the file cannot be loaded
if(!in.good())
return false;
}
// Checking for the comment line #FUNC nonlinear_function_lafortune
std::string token;
in >> token;
if(token.compare("#FUNC") != 0)
{
std::cerr << "<<ERROR>> parsing the stream. The #FUNC is not the next line defined." << std::endl;
return false;
}
in >> token;
if(token.compare("nonlinear_function_abc") != 0)
{
std::cerr << "<<ERROR>> parsing the stream. function name is not the next token." << std::endl;
return false;
}
// Parse the lobe
for(int i=0; i<_nY; ++i)
{
in >> token >> _a[i];
in >> token >> _b[i];
in >> token >> _c[i];
}
return true;
}
void abc_function::save_call(std::ostream& out, const arguments& args) const
{
bool is_alta = !args.is_defined("export") || args["export"] == "alta";
if(is_alta)
{
out << "#FUNC nonlinear_function_abc" << std::endl ;
for(int i=0; i<_nY; ++i)
{
out << "a " << _a[i] << std::endl;
out << "b " << _b[i] << std::endl;
out << "c " << _c[i] << std::endl;
}
out << std::endl;
}
else
{
out << "abc(L, V, N, X, Y, vec3(";
for(int i=0; i<_nY; ++i)
{
out << _a[i];
if(i < _nY-1) { out << ", "; }
}
out << "), vec3(";
for(int i=0; i<_nY; ++i)
{
out << _b[i];
if(i < _nY-1) { out << ", "; }
}
out << "), vec3(";
for(int i=0; i<_nY; ++i)
{
out << _c[i];
if(i < _nY-1) { out << ", "; }
}
out << "))";
}
}
void abc_function::save_body(std::ostream& out, const arguments& args) const
{
bool is_shader = args["export"] == "shader" || args["export"] == "explorer";
if(is_shader)
{
out << "vec3 abc(vec3 L, vec3 V, vec3 N, vec3 X, vec3 Y, vec3 a, vec3 b, vec3 c)" << std::endl;
out << "{" << std::endl;
out << "\tvec3 H = normalize(L + V);" << std::endl;
out << "\tfloat hn = dot(H,N);" << std::endl;
out << "\t" << std::endl;
out << "\treturn a / pow(vec3(1.0f) + b*hn, c);" << std::endl;
out << "}" << std::endl;
}
}
#pragma once
// Include STL
#include <vector>
#include <string>
// Interface
#include <core/function.h>
#include <core/data.h>
#include <core/fitter.h>
#include <core/args.h>
#include <core/common.h>
/*! \brief The ABC brdf model.
* \details
* Follows the implementation of Löw <i>et al.</i> [2012].
*
* <h3>Plugin parameters</h3>
*
*/
class abc_function : public nonlinear_function
{
public: // methods
abc_function()
{
setParametrization(params::COS_TH);
setDimX(1);
}
// Overload the function operator
virtual vec operator()(const vec& x) const ;
virtual vec value(const vec& x) const ;
//! \brief Load function specific files
virtual bool load(std::istream& in) ;
//! \brief Export function
virtual void save_call(std::ostream& out, const arguments& args) const;
virtual void save_body(std::ostream& out, const arguments& args) const;
//! \brief Boostrap the function by defining the diffuse term
//!
//! \details
virtual void bootstrap(const data* d, const arguments& args);
//! \brief Number of parameters to this non-linear function
virtual int nbParameters() const ;
//! \brief Get the vector of parameters for the function
virtual vec parameters() const ;
//! \brief get the min values for the parameters
virtual vec getParametersMin() const;
//! \brief Update the vector of parameters for the function
virtual void setParameters(const vec& p) ;
//! \brief Obtain the derivatives of the function with respect to the
//! parameters.
virtual vec parametersJacobian(const vec& x) const ;
//! \brief Set the number of output dimensions
void setDimY(int nY);
private: // data
vec _a, _b, _c; // Lobes data
} ;
TEMPLATE = lib
CONFIG *= plugin \
eigen
DESTDIR = ../../build
INCLUDEPATH += ../..
HEADERS = function.h
SOURCES = function.cpp
LIBS += -L../../build \
-lcore
......@@ -19,6 +19,7 @@ SUBDIRS = \
nonlinear_fresnel_retroschlick \
nonlinear_function_diffuse \
nonlinear_function_microfacets \
nonlinear_function_abc \
nonlinear_function_beckmann \
nonlinear_function_retrobeckmann \
nonlinear_function_blinn \
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment