ssf_blinn_distribution.c (3717B)
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 blinn_distribution { 25 double exponent; 26 }; 27 28 /******************************************************************************* 29 * Private functions 30 ******************************************************************************/ 31 static res_T 32 blinn_distribution_init(struct mem_allocator* allocator, void* distrib) 33 { 34 ASSERT(distrib); 35 (void)allocator; 36 ((struct blinn_distribution*)distrib)->exponent = 32.0; 37 return RES_OK; 38 } 39 40 static double 41 blinn_distribution_eval(void* distrib, const double N[3], const double wh[3]) 42 { 43 struct blinn_distribution* blinn = distrib; 44 double cos_wh_N; 45 ASSERT(distrib && N && wh); 46 ASSERT(d3_is_normalized(N) && d3_is_normalized(wh)); 47 ASSERT(blinn->exponent >= 0.0); 48 ASSERT(blinn->exponent <= SSF_BLINN_DISTRIBUTION_MAX_EXPONENT); 49 cos_wh_N = d3_dot(wh, N); 50 return (blinn->exponent + 2) / (2*PI) * pow(cos_wh_N, blinn->exponent); 51 } 52 53 static void 54 blinn_distribution_sample 55 (void* distrib, 56 struct ssp_rng* rng, 57 const double N[3], 58 double wh[3], 59 double* pdf) 60 { 61 struct blinn_distribution* blinn = distrib; 62 double basis[9]; 63 double dir[3]; 64 double cos_theta, sin_theta; 65 double phi; 66 double u, v; 67 ASSERT(distrib && rng && N && wh); 68 ASSERT(d3_is_normalized(N)); 69 70 u = ssp_rng_canonical(rng); 71 v = ssp_rng_canonical(rng); 72 73 phi = v*2*PI; 74 cos_theta = pow(u, 1/(blinn->exponent+1)); 75 sin_theta = sqrt(MMAX(0, 1-cos_theta*cos_theta)); 76 dir[0] = cos(phi) * sin_theta; 77 dir[1] = sin(phi) * sin_theta; 78 dir[2] = cos_theta; 79 80 d33_muld3(dir, d33_basis(basis, N), dir); 81 d3_set(wh, dir); 82 83 if(pdf) *pdf = (blinn->exponent+2)/(2*PI)*pow(cos_theta, blinn->exponent+1); 84 } 85 86 static double 87 blinn_distribution_pdf(void* distrib, const double N[3], const double wh[3]) 88 { 89 struct blinn_distribution* blinn = distrib; 90 double cos_wh_N; 91 ASSERT(distrib && N && wh); 92 ASSERT(d3_is_normalized(N) && d3_is_normalized(wh)); 93 cos_wh_N = fabs(d3_dot(wh, N)); 94 return (blinn->exponent+2)/(2*PI)*pow(cos_wh_N, blinn->exponent+1); 95 } 96 97 /******************************************************************************* 98 * Exported symbols 99 ******************************************************************************/ 100 const struct ssf_microfacet_distribution_type ssf_blinn_distribution = { 101 blinn_distribution_init, 102 NULL, 103 blinn_distribution_sample, 104 blinn_distribution_eval, 105 blinn_distribution_pdf, 106 sizeof(struct blinn_distribution), 107 ALIGNOF(struct blinn_distribution) 108 }; 109 110 res_T 111 ssf_blinn_distribution_setup 112 (struct ssf_microfacet_distribution* distrib, 113 const double exponent) 114 { 115 if(!distrib || exponent < 0 || exponent > SSF_BLINN_DISTRIBUTION_MAX_EXPONENT) 116 return RES_BAD_ARG; 117 if(!MICROFACET_DISTRIBUTION_TYPE_EQ(&distrib->type, &ssf_blinn_distribution)) 118 return RES_BAD_ARG; 119 ((struct blinn_distribution*)distrib->data)->exponent = exponent; 120 return RES_OK; 121 } 122 123