star-sf

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

test_ssf_thin_specular_dielectric.c (6597B)


      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 "test_ssf_utils.h"
     18 
     19 #include <rsys/double3.h>
     20 
     21 int
     22 main(int argc, char** argv)
     23 {
     24   const size_t NSTEPS = 1000000;
     25   struct mem_allocator allocator;
     26   struct ssp_rng* rng;
     27   struct ssf_bsdf* bsdf;
     28   struct ssf_bsdf* dummy;
     29   double wo[3], wi[3];
     30   double N[3];
     31   double tmp[3];
     32   double reflect[3];
     33   double refract[3];
     34   double pdf;
     35   double R; /* Directional reflectance */
     36   double SR, ST;
     37   double SR2 = 0, ST2 = 0;
     38   size_t i;
     39   int type;
     40   (void)argc, (void)argv;
     41 
     42   mem_init_proxy_allocator(&allocator, &mem_default_allocator);
     43   CHK(ssp_rng_create(&allocator, SSP_RNG_THREEFRY, &rng) == RES_OK);
     44   CHK(ssf_bsdf_create
     45     (&allocator, &ssf_thin_specular_dielectric, &bsdf) == RES_OK);
     46   CHK(ssf_bsdf_create(&allocator, &bsdf_dummy, &dummy) == RES_OK);
     47 
     48   #define SETUP ssf_thin_specular_dielectric_setup
     49   CHK(SETUP(NULL, -1, 0, 0, -1) == RES_BAD_ARG);
     50   CHK(SETUP(bsdf, -1, 0, 0, -1) == RES_BAD_ARG);
     51   CHK(SETUP(NULL, 1, 0, 0, -1) == RES_BAD_ARG);
     52   CHK(SETUP(bsdf, 1, 0, 0, -1) == RES_BAD_ARG);
     53   CHK(SETUP(NULL, -1, 1.00027, 0, -1) == RES_BAD_ARG);
     54   CHK(SETUP(bsdf, -1, 1.00027, 0, -1) == RES_BAD_ARG);
     55   CHK(SETUP(NULL, 1, 1.00027,  0, -1) == RES_BAD_ARG);
     56   CHK(SETUP(bsdf, 1, 1.00027, 0, -1) == RES_BAD_ARG);
     57   CHK(SETUP(NULL, -1, 0, 1.5, -1) == RES_BAD_ARG);
     58   CHK(SETUP(bsdf, -1, 0, 1.5, -1) == RES_BAD_ARG);
     59   CHK(SETUP(NULL, 1, 0, 1.5, -1) == RES_BAD_ARG);
     60   CHK(SETUP(bsdf, 1, 0, 1.5, -1) == RES_BAD_ARG);
     61   CHK(SETUP(NULL, -1, 1.00027, 1.5, -1) == RES_BAD_ARG);
     62   CHK(SETUP(bsdf, -1, 1.00027, 1.5, -1) == RES_BAD_ARG);
     63   CHK(SETUP(NULL, 1, 1.00027,  1.5, -1) == RES_BAD_ARG);
     64   CHK(SETUP(bsdf, 1, 1.00027, 1.5, -1) == RES_BAD_ARG);
     65   CHK(SETUP(NULL, -1, 0, 0, 0.1) == RES_BAD_ARG);
     66   CHK(SETUP(bsdf, -1, 0, 0, 0.1) == RES_BAD_ARG);
     67   CHK(SETUP(NULL, 1, 0, 0, 0.1) == RES_BAD_ARG);
     68   CHK(SETUP(bsdf, 1, 0, 0, 0.1) == RES_BAD_ARG);
     69   CHK(SETUP(NULL, -1, 1.00027, 0, 0.1) == RES_BAD_ARG);
     70   CHK(SETUP(bsdf, -1, 1.00027, 0, 0.1) == RES_BAD_ARG);
     71   CHK(SETUP(NULL, 1, 1.00027,  0, 0.1) == RES_BAD_ARG);
     72   CHK(SETUP(bsdf, 1, 1.00027, 0, 0.1) == RES_BAD_ARG);
     73   CHK(SETUP(NULL, -1, 0, 1.5, 0.1) == RES_BAD_ARG);
     74   CHK(SETUP(bsdf, -1, 0, 1.5, 0.1) == RES_BAD_ARG);
     75   CHK(SETUP(NULL, 1, 0, 1.5, 0.1) == RES_BAD_ARG);
     76   CHK(SETUP(bsdf, 1, 0, 1.5, 0.1) == RES_BAD_ARG);
     77   CHK(SETUP(NULL, -1, 1.00027, 1.5, 0.1) == RES_BAD_ARG);
     78   CHK(SETUP(bsdf, -1, 1.00027, 1.5, 0.1) == RES_BAD_ARG);
     79   CHK(SETUP(NULL, 1, 1.00027,  1.5, 0.1) == RES_BAD_ARG);
     80   CHK(SETUP(bsdf, 1, 1.00027, 1.5, 0.1) == RES_OK);
     81   CHK(SETUP(dummy, 1, 1.00027, 1.5, 0.1) == RES_BAD_ARG);
     82   #undef SETUP
     83 
     84   d3(N, 0.0, 1.0, 0.0);
     85   d3_normalize(wo, d3(wo, 1.0, 1.0, 0.0));
     86   R = ssf_bsdf_sample(bsdf, rng, wo, N, wi, &type, &pdf);
     87   CHK(R != 0);
     88   CHK(type & SSF_SPECULAR);
     89   CHK(IS_INF(pdf) == 1);
     90   CHK(d3_eq_eps(wi, d3(tmp, -wo[0], wo[1], 0), 1.e-6)
     91    || d3_eq_eps(wi, d3(tmp, -wo[0],-wo[1], 0), 1.e-6));
     92 
     93   CHK(ssf_bsdf_eval(bsdf, wo, N, wi) == 0.0);
     94   CHK(ssf_bsdf_pdf(bsdf, wo, N, wi) == 0.0);
     95 
     96   d3(wo, 0.0, 1.0, 0.0);
     97   R = ssf_bsdf_sample(bsdf, rng, wo, N, wi, &type, &pdf);
     98   CHK(R != 0);
     99   CHK(IS_INF(pdf) == 1);
    100   CHK(d3_eq_eps(wi, d3(tmp, -wo[0], -wo[1], 0), 1.e-6) == 1);
    101   CHK(type == (SSF_SPECULAR | SSF_TRANSMISSION));
    102 
    103   d3(wo, 1.0, 0.0, 0.0);
    104   R = ssf_bsdf_sample(bsdf, rng, wo, N, wi, &type, &pdf);
    105   CHK(R != 0);
    106   CHK(IS_INF(pdf) == 1);
    107   CHK(d3_eq_eps(wi, d3(tmp, -wo[0], wo[1], 0), 1.e-6) == 1);
    108   CHK(type == (SSF_SPECULAR | SSF_REFLECTION));
    109 
    110   /* Check total internal reflection, i.e. no transmission */
    111   d3_normalize(wo, d3(wo, 1, 0.0000001, 0));
    112   CHK(ssf_thin_specular_dielectric_setup(bsdf, 0, 1.4, 1.0, 1) == RES_OK);
    113   R = ssf_bsdf_sample(bsdf, rng, wo, N, wi, &type, &pdf);
    114   CHK(R == 1);
    115   CHK(IS_INF(pdf) == 1);
    116   CHK(d3_eq_eps(wi, d3(tmp, -wo[0], wo[1], 0), 1.e-6) == 1);
    117   CHK(type == (SSF_SPECULAR | SSF_REFLECTION));
    118 
    119   /* Check optional arguments */
    120   pdf = 0, type = 0;
    121   CHK(ssf_bsdf_sample(bsdf, rng, wo, N, wi, NULL, &pdf) == R);
    122   CHK(IS_INF(pdf));
    123   CHK(ssf_bsdf_sample(bsdf, rng, wo, N, wi, &type, NULL) == R);
    124   CHK(type == (SSF_SPECULAR | SSF_REFLECTION));
    125   CHK(ssf_bsdf_sample(bsdf, rng, wo, N, wi, NULL, NULL) == R);
    126 
    127   FOR_EACH(i, 0, NSTEPS) {
    128     R = ssf_bsdf_sample(bsdf, rng, wo, N, wi, &type, &pdf);
    129     CHK(type & SSF_REFLECTION);
    130     CHK(R == 1);
    131   }
    132 
    133   /* Check T VS R proportion and E conservation */
    134   SR = ST = 0;
    135   SR2 = ST2 = 0;
    136   d3(wo, 0.0, 1.0, 0.0);
    137   FOR_EACH(i, 0, NSTEPS) {
    138     R = ssf_bsdf_sample(bsdf, rng, wo, N, wi, &type, &pdf);
    139     if (type & SSF_TRANSMISSION) {
    140       ST += R; ST2 += R*R;
    141     } else {
    142       SR += R; SR2 += R*R;
    143     }
    144   }
    145 
    146   #define MEAN(x, n) ((x) / (double)(n))
    147   #define VAR(x, x2, n) (MEAN((x2), (n)) - MEAN((x), (n))*MEAN((x), (n)))
    148   #define STD(x, x2, n) \
    149     (VAR((x), (x2), (n)) > 0 ? sqrt(VAR((x), (x2), (n)) / (double)(n)) : 0)
    150   /* Check conservation of energy */
    151   CHK(MEAN(SR+ST, NSTEPS) == 1);
    152   /* Check T VS R proportion */
    153   CHK(eq_eps(MEAN(SR, NSTEPS), 0.0540540540, 3 * STD(SR,SR2,NSTEPS)) == 1);
    154   #undef MEAN
    155   #undef VAR
    156   #undef STD
    157 
    158   wo[0] = ssp_rng_uniform_double(rng, -1, 1);
    159   wo[1] = ssp_rng_uniform_double(rng, -1, 1);
    160   wo[2] = ssp_rng_uniform_double(rng, -1, 1);
    161   if(d3_dot(wo, N) < 0) d3_minus(N, N);
    162   d3_normalize(wo, wo);
    163   d3_sub(reflect, d3_muld(reflect, N, 2*d3_dot(wo, N)), wo);
    164   d3_minus(refract, wo);
    165 
    166   FOR_EACH(i, 0, NSTEPS) {
    167     R = ssf_bsdf_sample(bsdf, rng, wo, N, wi, &type, &pdf);
    168     CHK(R != 0);
    169     CHK(IS_INF(pdf) == 1);
    170     if(d3_eq_eps(wi, reflect, 1.e-6)) {
    171       CHK(type == (SSF_SPECULAR | SSF_REFLECTION));
    172     } else if(d3_eq_eps(wi, refract, 1e-6), 1) {
    173       CHK(type == (SSF_SPECULAR | SSF_TRANSMISSION));
    174     } else {
    175       FATAL("Unexpected value.\n");
    176     }
    177   }
    178 
    179   CHK(ssp_rng_ref_put(rng) == RES_OK);
    180   CHK(ssf_bsdf_ref_put(bsdf) == RES_OK);
    181   CHK(ssf_bsdf_ref_put(dummy) == RES_OK);
    182 
    183   return 0;
    184 }