ssf_beckmann_distribution.c (4394B)
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 beckmann_distribution { 25 double roughness; 26 }; 27 28 /******************************************************************************* 29 * Private functions 30 ******************************************************************************/ 31 static res_T 32 beckmann_distribution_init(struct mem_allocator* allocator, void* distrib) 33 { 34 ASSERT(distrib); 35 (void)allocator; 36 ((struct beckmann_distribution*)distrib)->roughness = 1.0; 37 return RES_OK; 38 } 39 40 static double 41 beckmann_distribution_eval 42 (void* distrib, const double N[3], const double wh[3]) 43 { 44 struct beckmann_distribution* beckmann = distrib; 45 double cos_wh_N, cos2_wh_N, sin2_wh_N, cos4_wh_N; 46 double m2; 47 ASSERT(distrib && N && wh); 48 ASSERT(d3_is_normalized(N) && d3_is_normalized(wh)); 49 ASSERT(beckmann->roughness > 0); 50 m2 = beckmann->roughness * beckmann->roughness; 51 cos_wh_N = d3_dot(wh, N); 52 cos2_wh_N = cos_wh_N * cos_wh_N; 53 sin2_wh_N = 1.0 - cos2_wh_N; 54 cos4_wh_N = cos2_wh_N * cos2_wh_N; 55 return exp(-sin2_wh_N / (cos2_wh_N * m2)) / (PI*m2*cos4_wh_N); 56 } 57 58 static void 59 beckmann_distribution_sample 60 (void* distrib, 61 struct ssp_rng* rng, 62 const double N[3], 63 double wh[3], 64 double* pdf) 65 { 66 struct beckmann_distribution* beckmann = distrib; 67 double basis[9]; 68 double dir[3]; 69 double m2; 70 double phi; 71 double rcp_T; 72 double cos_theta_T, sin_theta_T; 73 double cos_theta, sin_theta; 74 double cos2_theta, sin2_theta; 75 double u, v; 76 ASSERT(rng && wh && N); 77 ASSERT(d3_is_normalized(N)); 78 79 u = ssp_rng_canonical(rng); 80 v = ssp_rng_canonical(rng); 81 82 phi = 2.0*PI*u; 83 m2 = beckmann->roughness * beckmann->roughness; 84 sin_theta_T = sqrt(-log(v)); 85 cos_theta_T = sqrt(1.0/m2); 86 rcp_T = 1.0 / sqrt(cos_theta_T*cos_theta_T + sin_theta_T*sin_theta_T); 87 cos_theta = cos_theta_T * rcp_T; 88 sin_theta = sin_theta_T * rcp_T; 89 cos2_theta = cos_theta * cos_theta; 90 sin2_theta = sin_theta * sin_theta; 91 dir[0] = cos(phi) * sin_theta; 92 dir[1] = sin(phi) * sin_theta; 93 dir[2] = cos_theta; 94 d33_muld3(wh, d33_basis(basis, N), dir); 95 ASSERT(d3_dot(wh, N) > 0); 96 if(pdf) *pdf = exp(-sin2_theta/(cos2_theta*m2))/(PI*m2*cos_theta*cos2_theta); 97 } 98 99 static double 100 beckmann_distribution_pdf 101 (void* distrib, const double N[3], const double wh[3]) 102 { 103 struct beckmann_distribution* beckmann = distrib; 104 double cos_wh_N, cos2_wh_N, sin2_wh_N; 105 double m2; 106 ASSERT(distrib && N && wh); 107 ASSERT(d3_is_normalized(wh) && d3_is_normalized(N)); 108 cos_wh_N = d3_dot(wh, N); 109 if(cos_wh_N < 0.0) return 0.0; 110 m2 = beckmann->roughness * beckmann->roughness; 111 cos2_wh_N = cos_wh_N * cos_wh_N; 112 sin2_wh_N = 1.0 - cos2_wh_N; 113 return exp(-sin2_wh_N/(cos2_wh_N*m2)) / (PI * m2 * cos_wh_N * cos2_wh_N); 114 } 115 116 /******************************************************************************* 117 * Exported symbols 118 ******************************************************************************/ 119 const struct ssf_microfacet_distribution_type ssf_beckmann_distribution = { 120 beckmann_distribution_init, 121 NULL, 122 beckmann_distribution_sample, 123 beckmann_distribution_eval, 124 beckmann_distribution_pdf, 125 sizeof(struct beckmann_distribution), 126 ALIGNOF(struct beckmann_distribution) 127 }; 128 129 res_T 130 ssf_beckmann_distribution_setup 131 (struct ssf_microfacet_distribution* distrib, 132 const double roughness) 133 { 134 if(!distrib || roughness <= 0 || roughness > 1) return RES_BAD_ARG; 135 if(!MICROFACET_DISTRIBUTION_TYPE_EQ(&distrib->type, &ssf_beckmann_distribution)) 136 return RES_BAD_ARG; 137 ((struct beckmann_distribution*)distrib->data)->roughness = roughness; 138 return RES_OK; 139 } 140