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_microfacet_reflection.c (7034B)


      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_bsdf_c.h"
     18 #include "ssf_optics.h"
     19 
     20 #include <rsys/double3.h>
     21 
     22 struct microfacet_reflection {
     23   struct ssf_fresnel* fresnel;
     24   struct ssf_microfacet_distribution* distrib;
     25 };
     26 
     27 /*******************************************************************************
     28  * Microfacet functions
     29  ******************************************************************************/
     30 static void
     31 microfacet_reflection_release(void* data)
     32 {
     33   struct microfacet_reflection* bsdf = data;
     34   ASSERT(bsdf);
     35   if(bsdf->fresnel)
     36     SSF(fresnel_ref_put(bsdf->fresnel));
     37   if(bsdf->distrib)
     38     SSF(microfacet_distribution_ref_put(bsdf->distrib));
     39 }
     40 
     41 static FINLINE double
     42 microfacet_reflection_eval
     43   (void* data, const double wo[3], const double N[3], const double wi[3])
     44 {
     45   struct microfacet_reflection* bsdf = data;
     46   double wh[3];
     47   double cos_wo_N, cos_wi_N, cos_wh_N, cos_wh_wo, cos_wh_wi;
     48   double F, D, G;
     49   ASSERT(bsdf && bsdf->fresnel && bsdf->distrib);
     50   ASSERT(wo && N && wi);
     51   ASSERT(d3_is_normalized(wo) && d3_is_normalized(N) && d3_is_normalized(wi));
     52   ASSERT(d3_dot(wo, N) > 0 && d3_dot(wi, N) > 0);
     53 
     54   cos_wi_N = d3_dot(wi, N);
     55   cos_wo_N = d3_dot(wo, N);
     56 
     57   d3_normalize(wh, d3_add(wh, wo, wi));
     58   cos_wh_N = d3_dot(wh, N);
     59   cos_wh_wi = d3_dot(wh, wi);
     60   cos_wh_wo = cos_wh_wi;
     61 
     62   F = ssf_fresnel_eval(bsdf->fresnel, cos_wh_wi);
     63   D = ssf_microfacet_distribution_eval(bsdf->distrib, N, wh);
     64   /* Cook Torrance geometry term */
     65   G = MMIN((2*cos_wh_N*cos_wo_N)/cos_wh_wo, (2*cos_wh_N*cos_wi_N)/cos_wh_wo);
     66   G = MMIN(1, G);
     67 
     68   return F*D*G/(4*cos_wi_N*cos_wo_N);
     69 }
     70 
     71 static FINLINE double
     72 microfacet_reflection_sample
     73   (void* data,
     74    struct ssp_rng* rng,
     75    const double wo[3],
     76    const double N[3],
     77    double wi[3],
     78    int* type,
     79    double* pdf)
     80 {
     81   struct microfacet_reflection* bsdf = data;
     82   double dir[3];
     83   double wh[3];
     84   double pdf_wh;
     85   double R;
     86   ASSERT(data && wo && N && wi);
     87   ASSERT(d3_is_normalized(wo) && d3_is_normalized(N) && d3_dot(wo, N) > 0);
     88   ASSERT(bsdf->distrib && bsdf->fresnel);
     89 
     90   ssf_microfacet_distribution_sample(bsdf->distrib, rng, N, wh, &pdf_wh);
     91   reflect(dir, wo, wh);
     92   if(pdf) *pdf = pdf_wh / (4.0*fabs(d3_dot(wo, N)));
     93   if(type) *type = SSF_REFLECTION | SSF_GLOSSY;
     94   R = d3_dot(dir, N) > 0 ? ssf_fresnel_eval(bsdf->fresnel, d3_dot(dir, wh)) : 0;
     95   d3_set(wi, dir);
     96   return R;
     97 }
     98 
     99 static FINLINE double
    100 microfacet_reflection_pdf
    101   (void* data, const double wo[3], const double N[3], const double wi[3])
    102 {
    103   struct microfacet_reflection* bsdf = data;
    104   double wh[3];
    105   double pdf_wh;
    106   ASSERT(data && wo && N && wi);
    107   ASSERT(d3_is_normalized(wo) && d3_is_normalized(N) && d3_is_normalized(wi));
    108   ASSERT(d3_dot(wo, N) > 0);
    109   ASSERT(bsdf->distrib);
    110   d3_normalize(wh, d3_add(wh, wi, wo));
    111   if(d3_dot(wh, N) < 0) d3_minus(wh, wh);
    112   pdf_wh = ssf_microfacet_distribution_pdf(bsdf->distrib, N, wh);
    113   return pdf_wh / (4.0*fabs(d3_dot(wo, N)));
    114 }
    115 
    116 /*******************************************************************************
    117  * Microfacet 2 functions
    118  ******************************************************************************/
    119 static FINLINE double
    120 microfacet2_reflection_sample
    121   (void* data,
    122    struct ssp_rng* rng,
    123    const double wo[3],
    124    const double N[3],
    125    double wi[3],
    126    int* type,
    127    double* pdf)
    128 {
    129   struct microfacet_reflection* bsdf = data;
    130   double dir[3];
    131   double wh[3];
    132   double p;
    133   double troughput = 1;
    134   ASSERT(data && wo && N && wi);
    135   ASSERT(d3_is_normalized(wo) && d3_is_normalized(N) && d3_dot(N, wo) > 0.0);
    136   ASSERT(bsdf->distrib);
    137 
    138   do { /* Sample a micro facet that front faces 'wo' */
    139     ssf_microfacet_distribution_sample(bsdf->distrib, rng, N, wh, &p);
    140   } while(d3_dot(wo, wh) <= 0);
    141 
    142   reflect(dir, wo, wh);
    143   for(;;) {
    144     troughput *= ssf_fresnel_eval(bsdf->fresnel, d3_dot(wh, dir));
    145 
    146     /* Do not take care of inter-reflections for sampled directions that point
    147      * outward the macro surface, i.e. simply stop the "random walk". */
    148     if(d3_dot(dir, N) > 0) break;
    149 
    150     /* Handle directions that point toward the macro surface has
    151      * inter-reflections */
    152     do { /* Sample a microfacet that front faces 'wi' */
    153       ssf_microfacet_distribution_sample(bsdf->distrib, rng, N, wh, &p);
    154     } while(d3_dot(dir, wh) <= 0);
    155     reflect(dir, dir, wh);
    156   }
    157 
    158   if(pdf) *pdf = NaN;
    159   if(type) *type = SSF_REFLECTION | SSF_GLOSSY;
    160   d3_set(wi, dir);
    161   return troughput;
    162 }
    163 
    164 static FINLINE double
    165 microfacet2_reflection_eval
    166   (void* data, const double wo[3], const double N[3], const double wi[3])
    167 {
    168   (void)data, (void)wo, (void)N, (void)wi;
    169   return NaN;
    170 }
    171 
    172 static FINLINE double
    173 microfacet2_reflection_pdf
    174   (void* data, const double wo[3], const double N[3], const double wi[3])
    175 {
    176   (void)data, (void)wo, (void)N, (void)wi;
    177   return NaN;
    178 }
    179 
    180 /*******************************************************************************
    181  * Exported symbols
    182  ******************************************************************************/
    183 const struct ssf_bsdf_type ssf_microfacet_reflection = {
    184   NULL,
    185   microfacet_reflection_release,
    186   microfacet_reflection_sample,
    187   microfacet_reflection_eval,
    188   microfacet_reflection_pdf,
    189   sizeof(struct microfacet_reflection),
    190   ALIGNOF(struct microfacet_reflection)
    191 };
    192 
    193 const struct ssf_bsdf_type ssf_microfacet2_reflection = {
    194   NULL,
    195   microfacet_reflection_release,
    196   microfacet2_reflection_sample,
    197   microfacet2_reflection_eval,
    198   microfacet2_reflection_pdf,
    199   sizeof(struct microfacet_reflection),
    200   ALIGNOF(struct microfacet_reflection)
    201 };
    202 
    203 res_T
    204 ssf_microfacet_reflection_setup
    205   (struct ssf_bsdf* bsdf,
    206    struct ssf_fresnel* fresnel,
    207    struct ssf_microfacet_distribution* distrib)
    208 {
    209   struct microfacet_reflection* microfacet;
    210   if(!bsdf || !fresnel || !distrib)
    211     return RES_BAD_ARG;
    212   if(!BSDF_TYPE_EQ(&bsdf->type, &ssf_microfacet_reflection)
    213   && !BSDF_TYPE_EQ(&bsdf->type, &ssf_microfacet2_reflection))
    214     return RES_BAD_ARG;
    215 
    216   microfacet = bsdf->data;
    217   if(microfacet->fresnel != fresnel) {
    218     if(microfacet->fresnel) SSF(fresnel_ref_put(fresnel));
    219     SSF(fresnel_ref_get(fresnel));
    220     microfacet->fresnel = fresnel;
    221   }
    222   if(microfacet->distrib != distrib) {
    223     if(microfacet->distrib) SSF(microfacet_distribution_ref_put(distrib));
    224     SSF(microfacet_distribution_ref_get(distrib));
    225     microfacet->distrib = distrib;
    226   }
    227   return RES_OK;
    228 }
    229