stardis-solver

Solve coupled heat transfers
git clone git://git.meso-star.fr/stardis-solver.git
Log | Files | Refs | README | LICENSE

sdis_brdf.c (3860B)


      1 /* Copyright (C) 2016-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 "sdis.h"
     17 #include "sdis_brdf.h"
     18 #include "sdis_interface_c.h"
     19 
     20 #include <star/ssp.h>
     21 #include <rsys/double3.h>
     22 
     23 /*******************************************************************************
     24  * Helper functions
     25  ******************************************************************************/
     26 static INLINE res_T
     27 check_brdf_setup_args(const struct brdf_setup_args* args)
     28 {
     29   const struct sdis_medium* mdm = NULL;
     30 
     31   if(!args) return RES_BAD_ARG;
     32 
     33   if(args->interf == NULL || args->frag == NULL)
     34     return RES_BAD_ARG;
     35 
     36   switch(args->frag->side) {
     37     case SDIS_FRONT: mdm = args->interf->medium_front; break;
     38     case SDIS_BACK: mdm = args->interf->medium_back; break;
     39     default: FATAL("Unreachable code\n"); break;
     40   }
     41 
     42   if(sdis_medium_get_type(mdm) != SDIS_FLUID)
     43     return RES_BAD_ARG;
     44 
     45   return RES_OK;
     46 }
     47 
     48 /* Reflect the V wrt the normal N. By convention V points outward the surface.
     49  * In fact, this function is a double-precision version of the reflect_3d
     50  * function. TODO Clean this "repeat" */
     51 static FINLINE double*
     52 reflect(double res[3], const double V[3], const double N[3])
     53 {
     54   double tmp[3];
     55   double cos_V_N;
     56   ASSERT(res && V && N);
     57   ASSERT(d3_is_normalized(V) && d3_is_normalized(N));
     58   cos_V_N = d3_dot(V, N);
     59   d3_muld(tmp, N, 2*cos_V_N);
     60   d3_sub(res, tmp, V);
     61   return res;
     62 }
     63 
     64 /*******************************************************************************
     65  * Local functions
     66  ******************************************************************************/
     67 res_T
     68 brdf_setup
     69   (struct sdis_device* dev,
     70    const struct brdf_setup_args* args,
     71    struct brdf* brdf)
     72 {
     73   res_T res = RES_OK;
     74 
     75   ASSERT(check_brdf_setup_args(args) == RES_OK);
     76 
     77   #define GET(Attr) {                                                          \
     78     brdf->Attr = interface_side_get_##Attr                                     \
     79       (args->interf, args->source_id, args->frag);                             \
     80                                                                                \
     81     res = interface_side_check_##Attr                                          \
     82       (dev, brdf->Attr, args->frag->P, args->frag->time);                      \
     83     if(res != RES_OK) goto error;                                              \
     84   } (void)0
     85 
     86   GET(emissivity);
     87   GET(specular_fraction);
     88 
     89   #undef GET
     90 
     91 exit:
     92   return res;
     93 error:
     94   *brdf = BRDF_NULL;
     95   goto exit;
     96 }
     97 
     98 void
     99 brdf_sample
    100   (const struct brdf* brdf,
    101    struct ssp_rng* rng,
    102    const double wi[3], /* Incident direction. Point away from the surface */
    103    const double N[3], /* Surface normal */
    104    struct brdf_sample* sample)
    105 {
    106   double r = 0; /* Random number */
    107 
    108   /* Preconditions */
    109   ASSERT(brdf && rng && wi && N && sample);
    110   ASSERT(d3_is_normalized(wi) && d3_is_normalized(N));
    111   ASSERT(d3_dot(wi, N) > 0);
    112 
    113   r = ssp_rng_canonical(rng);
    114 
    115   /* Sample the specular part */
    116   if(r < brdf->specular_fraction) {
    117     reflect(sample->dir, wi, N);
    118     sample->pdf = 1;
    119     sample->cpnt = BRDF_SPECULAR;
    120 
    121   /* Sample the diffuse part */
    122   } else {
    123     ssp_ran_hemisphere_cos(rng, N, sample->dir, NULL);
    124     sample->pdf = 1.0/PI;
    125     sample->cpnt = BRDF_DIFFUSE;
    126   }
    127 }