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