star-sf

Set of surface and volume scattering functions
git clone git://git.meso-star.fr/star-sf.git
Log | Files | Refs | README | LICENSE

ssf_beckmann_distribution.c (4394B)


      1 /* Copyright (C) 2016-2018, 2021-2025 |Méso|Star> (contact@meso-star.com)
      2  *
      3  * This program is free software: you can redistribute it and/or modify
      4  * it under the terms of the GNU General Public License as published by
      5  * the Free Software Foundation, either version 3 of the License, or
      6  * (at your option) any later version.
      7  *
      8  * This program is distributed in the hope that it will be useful,
      9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
     11  * GNU General Public License for more details.
     12  *
     13  * You should have received a copy of the GNU General Public License
     14  * along with this program. If not, see <http://www.gnu.org/licenses/>. */
     15 
     16 #include "ssf.h"
     17 #include "ssf_microfacet_distribution_c.h"
     18 
     19 #include <rsys/double3.h>
     20 #include <rsys/double33.h>
     21 
     22 #include <star/ssp.h>
     23 
     24 struct beckmann_distribution {
     25   double roughness;
     26 };
     27 
     28 /*******************************************************************************
     29  * Private functions
     30  ******************************************************************************/
     31 static res_T
     32 beckmann_distribution_init(struct mem_allocator* allocator, void* distrib)
     33 {
     34   ASSERT(distrib);
     35   (void)allocator;
     36   ((struct beckmann_distribution*)distrib)->roughness = 1.0;
     37   return RES_OK;
     38 }
     39 
     40 static double
     41 beckmann_distribution_eval
     42   (void* distrib, const double N[3], const double wh[3])
     43 {
     44   struct beckmann_distribution* beckmann = distrib;
     45   double cos_wh_N, cos2_wh_N, sin2_wh_N, cos4_wh_N;
     46   double m2;
     47   ASSERT(distrib && N && wh);
     48   ASSERT(d3_is_normalized(N) && d3_is_normalized(wh));
     49   ASSERT(beckmann->roughness > 0);
     50   m2 = beckmann->roughness * beckmann->roughness;
     51   cos_wh_N = d3_dot(wh, N);
     52   cos2_wh_N = cos_wh_N * cos_wh_N;
     53   sin2_wh_N = 1.0 - cos2_wh_N;
     54   cos4_wh_N = cos2_wh_N * cos2_wh_N;
     55   return exp(-sin2_wh_N / (cos2_wh_N * m2)) / (PI*m2*cos4_wh_N);
     56 }
     57 
     58 static void
     59 beckmann_distribution_sample
     60   (void* distrib,
     61    struct ssp_rng* rng,
     62    const double N[3],
     63    double wh[3],
     64    double* pdf)
     65 {
     66   struct beckmann_distribution* beckmann = distrib;
     67   double basis[9];
     68   double dir[3];
     69   double m2;
     70   double phi;
     71   double rcp_T;
     72   double cos_theta_T, sin_theta_T;
     73   double cos_theta, sin_theta;
     74   double cos2_theta, sin2_theta;
     75   double u, v;
     76   ASSERT(rng && wh && N);
     77   ASSERT(d3_is_normalized(N));
     78 
     79   u = ssp_rng_canonical(rng);
     80   v = ssp_rng_canonical(rng);
     81 
     82   phi = 2.0*PI*u;
     83   m2 = beckmann->roughness * beckmann->roughness;
     84   sin_theta_T = sqrt(-log(v));
     85   cos_theta_T = sqrt(1.0/m2);
     86   rcp_T = 1.0 / sqrt(cos_theta_T*cos_theta_T + sin_theta_T*sin_theta_T);
     87   cos_theta = cos_theta_T * rcp_T;
     88   sin_theta = sin_theta_T * rcp_T;
     89   cos2_theta = cos_theta * cos_theta;
     90   sin2_theta = sin_theta * sin_theta;
     91   dir[0] = cos(phi) * sin_theta;
     92   dir[1] = sin(phi) * sin_theta;
     93   dir[2] = cos_theta;
     94   d33_muld3(wh, d33_basis(basis, N), dir);
     95   ASSERT(d3_dot(wh, N) > 0);
     96   if(pdf) *pdf = exp(-sin2_theta/(cos2_theta*m2))/(PI*m2*cos_theta*cos2_theta);
     97 }
     98 
     99 static double
    100 beckmann_distribution_pdf
    101   (void* distrib, const double N[3], const double wh[3])
    102 {
    103   struct beckmann_distribution* beckmann = distrib;
    104   double cos_wh_N, cos2_wh_N, sin2_wh_N;
    105   double m2;
    106   ASSERT(distrib && N && wh);
    107   ASSERT(d3_is_normalized(wh) && d3_is_normalized(N));
    108   cos_wh_N = d3_dot(wh, N);
    109   if(cos_wh_N < 0.0) return 0.0;
    110   m2 = beckmann->roughness * beckmann->roughness;
    111   cos2_wh_N = cos_wh_N * cos_wh_N;
    112   sin2_wh_N = 1.0 - cos2_wh_N;
    113   return exp(-sin2_wh_N/(cos2_wh_N*m2)) / (PI * m2 * cos_wh_N * cos2_wh_N);
    114 }
    115 
    116 /*******************************************************************************
    117  * Exported symbols
    118  ******************************************************************************/
    119 const struct ssf_microfacet_distribution_type ssf_beckmann_distribution = {
    120   beckmann_distribution_init,
    121   NULL,
    122   beckmann_distribution_sample,
    123   beckmann_distribution_eval,
    124   beckmann_distribution_pdf,
    125   sizeof(struct beckmann_distribution),
    126   ALIGNOF(struct beckmann_distribution)
    127 };
    128 
    129 res_T
    130 ssf_beckmann_distribution_setup
    131   (struct ssf_microfacet_distribution* distrib,
    132    const double roughness)
    133 {
    134   if(!distrib || roughness <= 0 || roughness > 1) return RES_BAD_ARG;
    135   if(!MICROFACET_DISTRIBUTION_TYPE_EQ(&distrib->type, &ssf_beckmann_distribution))
    136     return RES_BAD_ARG;
    137   ((struct beckmann_distribution*)distrib->data)->roughness = roughness;
    138   return RES_OK;
    139 }
    140