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_pillbox_distribution.c (4237B)


      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 pillbox_distribution {
     25   double sin2_theta_max;
     26 };
     27 
     28 /*******************************************************************************
     29  * Private functions
     30  ******************************************************************************/
     31 static res_T
     32 pillbox_distribution_init(struct mem_allocator* allocator, void* distrib)
     33 {
     34   ASSERT(distrib);
     35   (void)allocator;
     36   ((struct pillbox_distribution*)distrib)->sin2_theta_max = 1.0;
     37   return RES_OK;
     38 }
     39 
     40 static void
     41 pillbox_distribution_release(void* distrib)
     42 { (void)distrib; }
     43 
     44 static double
     45 pillbox_distribution_eval(void* distrib, const double N[3], const double wh[3])
     46 {
     47   struct pillbox_distribution* pillbox = distrib;
     48   double cos2_theta_max;
     49   double cos2_wh_N;
     50   ASSERT(distrib && N && wh);
     51   ASSERT(d3_is_normalized(wh) && d3_is_normalized(N));
     52   cos2_wh_N = d3_dot(N, wh);
     53   cos2_wh_N *= cos2_wh_N;
     54   cos2_theta_max = 1.0 - pillbox->sin2_theta_max;
     55   /*     if |wh.N| >= theta_max then 0
     56    * <=> if cos(|wh.N|)^2 < cos(theta_max)^2 then 0 */
     57   return (cos2_wh_N >= cos2_theta_max) ? 1.0 / (PI - PI*cos2_theta_max) : 0.0;
     58 }
     59 
     60 static void
     61 pillbox_distribution_sample
     62   (void* distrib,
     63    struct ssp_rng* rng,
     64    const double N[3],
     65    double wh[3],
     66    double* pdf)
     67 {
     68   struct pillbox_distribution* pillbox = distrib;
     69   double basis[9];
     70   double dir[3];
     71   double cos2_theta_max;
     72   double phi, sin2_theta, sin_theta, cos_theta;
     73   ASSERT(rng && wh && N);
     74   ASSERT(d3_is_normalized(N));
     75 
     76   cos2_theta_max = 1 - pillbox->sin2_theta_max;
     77   sin2_theta = ssp_rng_uniform_double(rng, 0, pillbox->sin2_theta_max);
     78   sin_theta = sqrt(sin2_theta);
     79   cos_theta = sqrt(1 - sin2_theta);
     80   phi = ssp_rng_uniform_double(rng, 0, 2 * PI);
     81   dir[0] = cos(phi) * sin_theta;
     82   dir[1] = sin(phi) * sin_theta;
     83   dir[2] = cos_theta;
     84   d33_muld3(wh, d33_basis(basis, N), dir);
     85 
     86   if(pdf) *pdf = cos_theta / (PI-PI*cos2_theta_max);
     87 }
     88 
     89 static double
     90 pillbox_distribution_pdf(void* distrib, const double N[3], const double wh[3])
     91 {
     92   struct pillbox_distribution* pillbox = distrib;
     93   double cos_wh_N;
     94   double cos2_wh_N;
     95   double cos2_theta_max;
     96   ASSERT(distrib && N && wh);
     97   ASSERT(d3_is_normalized(wh) && d3_is_normalized(N));
     98   cos_wh_N = d3_dot(wh, N);
     99   if(cos_wh_N < 0.0) return 0.0;
    100   cos2_theta_max = 1 - pillbox->sin2_theta_max;
    101   cos2_wh_N = cos_wh_N * cos_wh_N;
    102   if(cos2_wh_N < cos2_theta_max) return 0.0;
    103   return cos_wh_N / (PI-PI*cos2_theta_max);
    104 }
    105 
    106 /*******************************************************************************
    107  * Exported symbols
    108  ******************************************************************************/
    109 const struct ssf_microfacet_distribution_type ssf_pillbox_distribution = {
    110   pillbox_distribution_init,
    111   pillbox_distribution_release,
    112   pillbox_distribution_sample,
    113   pillbox_distribution_eval,
    114   pillbox_distribution_pdf,
    115   sizeof(struct pillbox_distribution),
    116   ALIGNOF(struct pillbox_distribution)
    117 };
    118 
    119 res_T
    120 ssf_pillbox_distribution_setup
    121   (struct ssf_microfacet_distribution* distrib,
    122    const double roughness)
    123 {
    124   double sin2_theta_max;
    125   if(!distrib || roughness <= 0 || roughness > 1) return RES_BAD_ARG;
    126   if(!MICROFACET_DISTRIBUTION_TYPE_EQ(&distrib->type, &ssf_pillbox_distribution))
    127     return RES_BAD_ARG;
    128   sin2_theta_max = sin(roughness);
    129   sin2_theta_max *= sin2_theta_max;
    130   ((struct pillbox_distribution*)distrib->data)->sin2_theta_max = sin2_theta_max;
    131   return RES_OK;
    132 }
    133