Commit c7999f0c authored by Laurent Belcour's avatar Laurent Belcour

Adding Ward anisotropic function

parent 02008951
......@@ -24,6 +24,7 @@ std::map<params::input, const param_info> create_map()
/* 3D Params */
_map.insert(std::make_pair<params::input, const param_info>(params::RUSIN_TH_TD_PD, param_info("RUSIN_TH_TD_PD", 3, "Isotropic Half angle parametrization")));
_map.insert(std::make_pair<params::input, const param_info>(params::ISOTROPIC_TV_TL_DPHI, param_info("ISOTROPIC_TV_TL_DPHI", 3, "Isotropic Light/View angle parametrization")));
_map.insert(std::make_pair<params::input, const param_info>(params::RUSIN_VH, param_info("RUSIN_VH", 3, "Vector representation of the Half angle only")));
/* 4D Params */
_map.insert(std::make_pair<params::input, const param_info>(params::RUSIN_TH_PH_TD_PD, param_info("RUSIN_TH_PH_TD_PD", 4, "Complete Half angle parametrization")));
......@@ -100,6 +101,9 @@ void params::to_cartesian(const double* invec, params::input intype,
case params::ISOTROPIC_TV_TL_DPHI:
classical_to_cartesian(invec[0], 0.0, invec[1], invec[2], outvec);
break;
case params::RUSIN_VH:
half_to_cartesian(acos(invec[2]), atan2(invec[1], invec[0]), 0.0, 0.0, outvec);
break;
// 4D Parametrization
case params::RUSIN_TH_PH_TD_PD:
......@@ -215,6 +219,11 @@ void params::from_cartesian(const double* invec, params::input outtype,
outvec[1] = acos(invec[5]);
outvec[2] = atan2(invec[1], invec[0]) - atan2(invec[4], invec[3]);
break;
case params::RUSIN_VH:
outvec[0] = half[0];
outvec[1] = half[1];
outvec[2] = half[2];
break;
// 4D Parametrization
case params::RUSIN_TH_PH_TD_PD:
......
......@@ -35,6 +35,10 @@ class params
RUSIN_TH_PH_TD,
RUSIN_TH_TD_PD,
RUSIN_TH_TD, /*!< Half-angle parametrization with no azimutal information */
RUSIN_VH_VD, /*!< Half-angle parametrization with no azimutal information in
vector format */
RUSIN_VH, /*!< Half-angle parametrization with no azimutal information
and no difference direction in vector format */
COS_TH_TD,
COS_TH,
......
#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 ward_function();
}
// Overload the function operator
vec ward_function::operator()(const vec& x) const
{
return value(x);
}
vec ward_function::value(const vec& x) const
{
vec res(dimY());
double h[3];
params::convert(&x[0], params::CARTESIAN, params::RUSIN_VH, h);
for(int i=0; i<dimY(); ++i)
{
const double hx_ax = h[0]/_ax[i];
const double hy_ay = h[1]/_ay[i];
const double exponent = (hx_ax*hx_ax + hy_ay*hy_ay) / (h[2]*h[2]);
res[i] = (_ks[i] / (4.0 * M_PI * _ax[i] * _ay[i] * sqrt(x[2]*x[5]))) * std::exp(- exponent);
}
return res;
}
// Reset the output dimension
void ward_function::setDimY(int nY)
{
_nY = nY ;
// Update the length of the vectors
_ax.resize(_nY) ;
_ay.resize(_nY) ;
_ks.resize(_nY) ;
}
//! Number of parameters to this non-linear function
int ward_function::nbParameters() const
{
return 3*dimY();
}
//! Get the vector of parameters for the function
vec ward_function::parameters() const
{
vec res(3*dimY());
for(int i=0; i<dimY(); ++i)
{
res[i*3 + 0] = _ks[i];
res[i*3 + 1] = _ax[i];
res[i*3 + 2] = _ay[i];
}
return res;
}
//! \brief get the min values for the parameters
vec ward_function::getParametersMin() const
{
vec res(3*dimY());
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 ward_function::setParameters(const vec& p)
{
for(int i=0; i<dimY(); ++i)
{
_ks[i] = p[i*3 + 0];
_ax[i] = p[i*3 + 1];
_ay[i] = p[i*3 + 2];
}
}
//! Obtain the derivatives of the function with respect to the
//! parameters
//! \todo finish.
vec ward_function::parametersJacobian(const vec& x) const
{
double dot = compute_dot(x);
vec jac(dimY()*nbParameters());
for(int i=0; i<dimY(); ++i)
{
for(int j=0; j<dimY(); ++j)
{
if(i == j)
{
/*
// df / dk_s
jac[i*nbParameters() + j*2+0] = exp(_n[j] * (dot - 1));
// df / dN
jac[i*nbParameters() + j*2+1] = _ks[j] * (dot-1) * exp(_n[j]*(dot - 1));
*/
}
else
{
jac[i*nbParameters() + j*2+0] = 0.0;
jac[i*nbParameters() + j*2+1] = 0.0;
}
}
}
return jac;
}
void ward_function::bootstrap(const data* d, const arguments& args)
{
for(int i=0; i<dimY(); ++i)
{
_ks[i] = 1.0;
_ax[i] = 1.0;
_ay[i] = 1.0;
}
}
//! Load function specific files
void ward_function::load(std::istream& in)
{
// Parse line until the next comment
while(in.peek() != '#')
{
char line[256];
in.getline(line, 256);
}
// 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;
}
in >> token;
if(token.compare("nonlinear_function_ward") != 0)
{
std::cerr << "<<ERROR>> parsing the stream. function name is not the next token." << std::endl;
}
// Parse the lobe
for(int i=0; i<_nY; ++i)
{
in >> token >> _ks[i];
in >> token >> _ax[i];
in >> token >> _ay[i];
}
}
void ward_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_ward" << std::endl ;
for(int i=0; i<_nY; ++i)
{
out << "Ks " << _ks[i] << std::endl;
out << "ax " << _ax[i] << std::endl;
out << "ay " << _ay[i] << std::endl;
}
out << std::endl;
}
else
{
out << "ward(L, V, N, X, Y, vec3(";
for(int i=0; i<_nY; ++i)
{
out << _ks[i];
if(i < _nY-1) { out << ", "; }
}
out << "), vec3(";
for(int i=0; i<_nY; ++i)
{
out << _ax[i];
if(i < _nY-1) { out << ", "; }
}
out << "), vec3(";
for(int i=0; i<_nY; ++i)
{
out << _ay[i];
if(i < _nY-1) { out << ", "; }
}
out << "))";
}
}
void ward_function::save_body(std::ostream& out, const arguments& args) const
{
bool is_shader = args["export"] == "shader" || args["export"] == "explorer";
if(is_shader)
{
out << "vec3 ward(vec3 L, vec3 V, vec3 N, vec3 X, vec3 Y, vec3 ks, vec3 ax, vec3 ay)" << std::endl;
out << "{" << std::endl;
out << "\tvec3 H = normalize(L + V);" << std::endl;
out << "\tvec3 hax = dot(H,X) / ax;" << std::endl;
out << "\tvec3 hay = dot(H,Y) / ay;" << std::endl;
out << "\tfloat hn = dot(H,N);" << std::endl;
out << "\treturn (ks / (4 * M_PI * ax*ay * sqrt(dot(L,N)*dot(V,N))) * exp(-(hax*hax + hay*hay)/(hn*hn));" << 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 A spherical Gaussian lobe class.
*
* \details
* A ward lobe is defined as \f${k_s \over 4 \pi \alpha_x \alpha_y
* \sqrt((i.n) (o.n))} exp(- ({(h.x) / \alpha_x)^2 + ((h.y) /
* \alpha_y)^2 \over (h.n)^2}\f$. Where \f$(\alpha_x, alpha_y)\f$ is
* the anisotropic roughness control.
*
* <h3>Plugin parameters</h3>
*
* <ul>
* <li><b>bootstrap</b> function will set the lobe values as 1/li>
* </ul>
*/
class ward_function : public nonlinear_function
{
public: // methods
ward_function()
{
setParametrization(params::CARTESIAN);
setDimX(6);
}
// Overload the function operator
virtual vec operator()(const vec& x) const ;
virtual vec value(const vec& x) const ;
//! \brief Load function specific files
virtual void 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 Provide the dimension of the input space of the function
virtual int dimX() const
{
return 6;
}
//! \brief Set the number of output dimensions
void setDimY(int nY);
private: // methods
//! \brief Compute the cosine for inside the lobe function.
//! Depending on the lobe type, the dot product can have
//! different evaluations.
double compute_dot(const vec& in) const;
private: // data
vec _ks, _ax, _ay; // Lobes data
} ;
TEMPLATE = lib
CONFIG *= plugin \
eigen
DESTDIR = ../../build
INCLUDEPATH += ../..
HEADERS = function.h
SOURCES = function.cpp
LIBS += -L../../build \
-lcore
......@@ -7,16 +7,17 @@ SUBDIRS = \
rational_fitter_eigen \
rational_fitter_leastsquare \
rational_function_chebychev \
rational_fitter_matlab \
# rational_fitter_matlab \
# rational_fitter_dca \
nonlinear_fitter_eigen \
nonlinear_fitter_ceres \
nonlinear_fitter_ipopt \
nonlinear_fitter_nlopt \
# nonlinear_fitter_ceres \
# nonlinear_fitter_ipopt \
# nonlinear_fitter_nlopt \
nonlinear_fresnel_schlick \
nonlinear_function_diffuse \
nonlinear_function_blinn \
nonlinear_function_retroblinn \
nonlinear_function_ward \
nonlinear_function_spherical_gaussian \
nonlinear_function_lafortune \
nonlinear_function_isotropic_lafortune \
......
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