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 }