/* ALTA --- Analysis of Bidirectional Reflectance Distribution Functions Copyright (C) 2014 CNRS Copyright (C) 2013, 2014, 2015 Inria This file is part of ALTA. This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #pragma once #include #include #include #include #include #include #include #include "common.h" /*! \class params * \ingroup core * \brief a static class allowing to change from one parametrization * to another. * * Any function object or data object should have an associated * parametrization. * * We use the following convention to defined the tangent, normal and * bi-normal of the surface: * * The normal is the upper vector (0, 0, 1) * * The tangent direction is along x direction (1, 0, 0) * * The bi-normal is along the y direction (0, 1, 0) */ class params { public: // data //! \brief list of all supported parametrization for the input space. //! An unsupported parametrization will go under the name ! *unknown*. We //!use the following notations: //! * The View vector is \f$V\f$ //! * The Light vector is \f$L\f$ //! * The Normal vector is \f$N\f$ //! * The Reflected vector is \f$R = 2\mbox{dot}(\vec{V}, \vec{N})\vec{N} - \vec{V}\f$ //! * The Half vector is \f$H = \frac{V+L}{||V+L||}\f$ //! * The Back vector is \f$K = \frac{V-L}{||V-L||}\f$ //! * The elevation angle of vector \f$V\f$ is \f$\theta_V\f$ //! * The azimuth angle of vector \f$V\f$ is \f$\phi_V\f$ enum input { RUSIN_TH_PH_TD_PD, /*!< Half-angle parametrization as described by Rusinkiewicz [1998] */ RUSIN_TH_PH_TD, RUSIN_TH_TD_PD, RUSIN_TH_TD, /*!< Half-angle parametrization with no azimutal information */ RUSIN_VH_VD, /*!< Half-angle parametrization in vector format. Coordinates are: \f$[H_x, H_y, H_z, D_x, D_y, D_z] \f$.*/ RUSIN_VH, /*!< Half-angle parametrization with no difference direction in vector format. Coordinates are: [\f$\vec{h}_x, \vec{h}_y, \vec{h}_z\f$]. */ COS_TH_TD, /*!< Cosine of the RUSIN_TH_TD parametrization: Coordinates are in \f$[\cos_{\theta_H},\cos_{\theta_D}] \f$. */ COS_TH, SCHLICK_TK_PK, /*!< Schlick's back vector parametrization */ SCHLICK_VK, /*!< Schlick's back vector */ SCHLICK_TL_TK_PROJ_DPHI,/*!< 3D Parametrization where the phi component is projected and the parametrization is centered around the back direction. \f$[\theta_L, x, y] = [\theta_L, \theta_K \cos(\phi_K), \theta_K \sin(\phi_K)]\f$*/ COS_TK, /*!< Schlick's back vector dot product with the normal */ RETRO_TL_TVL_PROJ_DPHI,/*!< 2D Parametrization where the phi component is projected and the parametrization is centered around the retro direction \f$[x, y] = [\theta_{VL} \cos(\Delta\phi), \theta_{VL} \sin(\Delta\phi)]\f$.*/ STEREOGRAPHIC, /*!< Stereographic projection of the Light and View vectors */ SPHERICAL_TL_PL_TV_PV, /*!< Light and View vectors represented in spherical coordinates */ COS_TLV, /*!< Dot product between the Light and View vector */ COS_TLR, /*!< Dot product between the Light and Reflected vector */ ISOTROPIC_TV_TL, /*!< Light and View vectors represented in spherical coordinates, */ ISOTROPIC_TV_TL_DPHI, /*!< Light and View vectors represented in spherical coordinates, with the difference of azimutal coordinates in the last component */ ISOTROPIC_TV_PROJ_DPHI,/*!< 2D Parametrization where the phi component is projected. Coordinates are: [\f$\theta_v \cos(\Delta\phi), \theta_v \sin(\Delta\phi).\f$]*/ ISOTROPIC_TL_TV_PROJ_DPHI,/*!< 3D Parametrization where the phi component is projected. Coordinates are: [\f$\theta_l, \theta_v \cos(\Delta\phi), \theta_v \sin(\Delta\phi).\f$]*/ ISOTROPIC_TD_PD, /*!< Difference between two directions such as R and H */ STARK_2D, /*!< Modified Stark et al. 2D parametrization. This parametrization is defined by the couple \f$\vec{x} = ||\tilde{H}_p||, ||\tilde{B}|| \f$, where \f$\tilde{H} = \frac{1}{2}(L+V) \f$ and \f$\tilde{B} = \frac{1}{2}(L-V) \f$. \f$\tilde{H}_p \f$ is the projected coordinates of \f$\tilde{H} \f$ on the tanget plane. */ NEUMANN_2D, /*!< Neumann and Neumann [1996] parametrization. This parametrization is defined by the couple \f$\vec{x} = ||\tilde{H}_p||, ||\tilde{B}_p|| \f$, where \f$\tilde{H} = \frac{1}{2}(L+V) \f$ and \f$\tilde{B} = \frac{1}{2}(L-V) \f$. \f$\tilde{H}_p \f$ is the projected coordinates of \f$\tilde{H} \f$ on the tanget plane.*/ STARK_3D, /*!< Modified Stark et al. 2D parametrization. This parametrization is defined by the tuple \f$\vec{x} = ||\tilde{H}_p||, ||\tilde{B}||, \phi_B-\phi_H \f$. */ NEUMANN_3D, /*!< Neumann and Neumann [1996] 3D parametrization. This parametrization is defined by the tuple \f$\vec{x} = ||\tilde{H}_p||, ||\tilde{B}_p||, \phi_B-\phi_H \f$.*/ CARTESIAN, /*!< View and Light vectors represented in cartesian coordinates. We always pack the view vector first: \f$[V.x, V.y, V.z, L.x, L.y, L.z] \f$*/ UNKNOWN_INPUT /*!< Default behaviour. Only use this is you do not fit BRDF data */ }; //! \brief list of all supported parametrization for the output space. //! An unsupported parametrization will go under the name //! unknown. enum output { INV_STERADIAN, /*!< Output values in inverse steradian (sr-1). This is the standard definition for a BRDF. */ INV_STERADIAN_COSINE_FACTOR, /*!< Output values in inverse steradian (sr-1) weighted by the cosine factor of the output direction. */ ENERGY, RGB_COLOR, XYZ_COLOR, UNKNOWN_OUTPUT }; public: // methods //! \brief parse a string to provide a parametrization type. static params::input parse_input(const std::string& txt); //! \brief parse a string to provide a parametrization type. static params::output parse_output(const std::string& txt); //! \brief look for the string associated with a parametrization //! type. static const std::string& get_name(const params::input param); //! \brief look for the string associated with a parametrization //! type. //! \todo Finish this implementation. It requires another static //! object. static const std::string& get_name(const params::output); //! \brief static function for input type convertion. This //! function allocate the resulting vector. static double* convert(const double* invec, params::input intype, params::input outtype) { int dim = dimension(outtype); // Get the size of the output vector if(dim > 0) { double* outvec = new double[dim]; double temvec[6] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; // Temp CARTESIAN vectors to_cartesian(invec, intype, temvec); from_cartesian(temvec, outtype, outvec); return outvec; } else { return NULL; } } //! \brief static function for input type convertion. The outvec //! resulting vector should be allocated with the correct //! output size. //! TODO: RP this function is weird the outtype and intype ARE NEVER USED static void convert(const double* invec, params::output intype, int indim, params::output outtype, int outdim, double* outvec) { // The convertion is done using the cartesian parametrization as // an intermediate one. If the two parametrizations are equals // there is no need to perform the conversion. if(outdim == indim) { for(int i=0; i(indim); } else { NOT_IMPLEMENTED(); } } //! \brief static function for input type convertion. The outvec //! resulting vector should be allocated with the correct //! output size. static void convert(const double* invec, params::input intype, params::input outtype, double* outvec) { // The convertion is done using the cartesian parametrization as // an intermediate one. If the two parametrizations are equals // there is no need to perform the conversion. if(intype == outtype) { int dim = dimension(outtype); for(int i=0; i= 0.0 && out[5] >= 0.0); #endif } //! \brief from the 4D definition of a classical vector parametrization, //! export the cartesian coordinates. static void classical_to_cartesian(double theta_l, double phi_l, double theta_v, double phi_v, double* out) { out[0] = cos(phi_l)*sin(theta_l); out[1] = sin(phi_l)*sin(theta_l); out[2] = cos(theta_l); out[3] = cos(phi_v)*sin(theta_v); out[4] = sin(phi_v)*sin(theta_v); out[5] = cos(theta_v); } //! \brief rotate a cartesian vector with respect to the normal of //! theta degrees. static void rotate_normal(double* vec, double theta) { const double cost = cos(theta); const double sint = sin(theta); const double temp = cost * vec[0] - sint * vec[1]; vec[1] = cost * vec[1] + sint * vec[0]; vec[0] = temp; } //! \brief rotate a cartesian vector with respect to the bi-normal of //! theta degrees. static void rotate_binormal(double* vec, double theta) { const double cost = cos(theta); const double sint = sin(theta); const double temp = cost * vec[0] + sint * vec[2]; vec[2] = cost * vec[2] - sint * vec[0]; vec[0] = temp; } static void print_input_params(); }; /*! \brief A parametrized object. Allow to define function object (either data * or functions that are defined over an input space and output space. This * Object allowas to change the parametrization of the input or output space. */ class parametrized { public: parametrized() : _in_param(params::UNKNOWN_INPUT), _out_param(params::UNKNOWN_OUTPUT), _nX( 0 ), _nY( 0 ) { } parametrized( unsigned int dim_X, unsigned int dim_Y) : _in_param(params::UNKNOWN_INPUT), _out_param(params::UNKNOWN_OUTPUT), _nX( dim_X ), _nY( dim_Y ), _min( vec::Zero( _nX+_nY) ), _max( vec::Zero( _nX+_nY) ) {} parametrized(params::input in_param, params::output out_param) : _in_param( in_param ), _out_param( out_param ), _nX( params::dimension(_in_param) ), _nY( params::dimension(_out_param) ) , _min( vec::Zero( _nX+_nY) ), _max( vec::Zero( _nX+_nY) ) { } //! \brief provide the input parametrization of the object. virtual params::input parametrization() const { return _in_param; } //! \brief provide the input parametrization of the object. virtual params::input input_parametrization() const { return _in_param; } //! \brief provide the outout parametrization of the object. virtual params::output output_parametrization() const { return _out_param; } //! \brief can set the input parametrization of a non-parametrized //! object. Print an error if it is already defined. virtual void setParametrization(params::input new_param) { //! \todo Here is something strange happening. The equality between //! those enums is not correct for UNKNOWN_INPUT if(_in_param == new_param) { return; } else if(_in_param == params::UNKNOWN_INPUT) { _in_param = new_param; } else { std::cout << "<> an input parametrization is already defined: " << params::get_name(_in_param) << std::endl; std::cout << "<> changing to: " << params::get_name(new_param) << std::endl; _in_param = new_param; } } //! \brief can set the output parametrization of a non-parametrized //! function. Throw an exception if it tries to erase a previously //! defined one. virtual void setParametrization(params::output new_param) { if(_out_param == new_param) { return; } else if(_out_param == params::UNKNOWN_OUTPUT) { _out_param = new_param; } else { std::cout << "<> an output parametrization is already defined: " << std::endl; } } //! \brief Set the input and output parametrizations directly virtual void setParametrizations(params::input new_in_param, params::output new_out_param) { setParametrization( new_in_param); setParametrization( new_out_param ); } /* DIMENSION OF THE INPUT AND OUTPUT DOMAIN */ //! Provide the dimension of the input space of the function virtual int dimX() const { return _nX ; } //! Provide the dimension of the output space of the function virtual int dimY() const { return _nY ; } //! Set the dimension of the input space of the function virtual void setDimX(int nX) { if(_nX != nX) { _nX = nX; _min.resize(nX); _max.resize(nX); } } //! Set the dimension of the output space of the function virtual void setDimY(int nY) { if(_nY != nY) { _nY = nY; _min.resize(nY); _max.resize(nY); } } /* DEFINITION DOMAIN OF THE FUNCTION */ //! \brief Set the minimum value the input can take virtual void setMin(const vec& min) ; //! \brief Set the maximum value the input can take virtual void setMax(const vec& max) ; //! \brief Get the minimum value the input can take virtual vec min() const ; //! \brief Get the maximum value the input can take virtual vec max() const ; protected: // Input and output parametrization params::input _in_param ; params::output _out_param ; // Dimension of the function & domain of definition. int _nX, _nY ; vec _min, _max ; };