test_ssf_lambertian_reflection.c (4591B)
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 #include <rsys/double33.h> 21 22 int 23 main(int argc, char** argv) 24 { 25 const size_t NSTEPS = 100000; 26 struct mem_allocator allocator; 27 struct ssp_rng* rng; 28 struct ssf_bsdf* brdf; 29 struct ssf_bsdf* dummy; 30 double E, SE, V; 31 double sum; 32 double sum_sqr; 33 double basis[9]; 34 double wo[3], wi[3]; 35 double N[3]; 36 double pdf; 37 double R; 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 45 CHK(ssf_bsdf_create(&allocator, &ssf_lambertian_reflection, &brdf) == RES_OK); 46 CHK(ssf_bsdf_create(&allocator, &bsdf_dummy, &dummy) == RES_OK); 47 48 CHK(ssf_lambertian_reflection_setup(NULL, -1.0) == RES_BAD_ARG); 49 CHK(ssf_lambertian_reflection_setup(brdf, -1.0) == RES_BAD_ARG); 50 CHK(ssf_lambertian_reflection_setup(NULL, 1.0) == RES_BAD_ARG); 51 CHK(ssf_lambertian_reflection_setup(brdf, 1.0) == RES_OK); 52 CHK(ssf_lambertian_reflection_setup(brdf, 0.0) == RES_OK); 53 CHK(ssf_lambertian_reflection_setup(brdf, 1.1) == RES_BAD_ARG); 54 CHK(ssf_lambertian_reflection_setup(dummy, 0.0) == RES_BAD_ARG); 55 56 d3(N, 0.0, 0.0, 1.0); 57 d3_normalize(wo, d3(wo, 1.0, 0.0, 1.0)); 58 R = ssf_bsdf_sample(brdf, rng, wo, N, wi, &type, &pdf); 59 CHK(eq_eps(wi[2]/PI, pdf, 1.e-6) == 1); 60 CHK(R == 0); 61 CHK(type == (SSF_DIFFUSE|SSF_REFLECTION)); 62 63 CHK(ssf_lambertian_reflection_setup(brdf, 0.7) == RES_OK); 64 R = ssf_bsdf_sample(brdf, rng, wo, N, wi, &type, &pdf); 65 CHK(eq_eps(R, 0.7, 1.e-6) == 1); 66 CHK(eq_eps(pdf, d3_dot(wi, N)/PI, 1.e-6) == 1); 67 CHK(type == (SSF_DIFFUSE|SSF_REFLECTION)); 68 69 pdf = 0, type = 0; 70 CHK(ssf_bsdf_sample(brdf, rng, wo, N, wi, NULL, &pdf) == R); 71 CHK(eq_eps(pdf, d3_dot(wi, N)/PI, 1.e-6) == 1); 72 CHK(ssf_bsdf_sample(brdf, rng, wo, N, wi, &type, NULL) == R); 73 CHK(type == (SSF_DIFFUSE|SSF_REFLECTION)); 74 CHK(ssf_bsdf_sample(brdf, rng, wo, N, wi, NULL, NULL) == R); 75 76 d3_normalize(wo, d3(wo, 1.0, 0.0, 1.0)); 77 N[0] = ssp_rng_uniform_double(rng, -1, 1); 78 N[1] = ssp_rng_uniform_double(rng, -1, 1); 79 N[2] = ssp_rng_uniform_double(rng, -1, 1); 80 d3_normalize(N, N); 81 d33_basis(basis, N); 82 d33_muld3(wo, basis, wo); 83 84 sum = sum_sqr = 0; 85 FOR_EACH(i, 0, NSTEPS) { 86 double cos_wi_N; 87 R = ssf_bsdf_sample(brdf, rng, wo, N, wi, &type, &pdf) / PI; 88 cos_wi_N = d3_dot(wi, N); 89 CHK(eq_eps(R, 0.7/PI, 1.e-6) == 1); 90 CHK(eq_eps(cos_wi_N/PI, pdf, 1.e-6) == 1); 91 CHK(type == (SSF_DIFFUSE|SSF_REFLECTION)); 92 sum += cos_wi_N; 93 sum_sqr += cos_wi_N * cos_wi_N; 94 } 95 E = sum/(double)NSTEPS; 96 V = sum_sqr/(double)NSTEPS - E*E; 97 SE = sqrt(V/(double)NSTEPS); 98 CHK(eq_eps(E, 2.0/3.0, SE) == 1); 99 100 sum = sum_sqr = 0; 101 FOR_EACH(i, 0, NSTEPS) { 102 double cos_wi_N; 103 double w; 104 105 R = ssf_bsdf_sample(brdf, rng, wo, N, wi, &type, &pdf)/PI; 106 cos_wi_N = d3_dot(wi, N); 107 CHK(eq_eps(R, 0.7/PI, 1.e-6) == 1); 108 CHK(eq_eps(cos_wi_N/PI, pdf, 1.e-6) == 1); 109 CHK(type == (SSF_DIFFUSE|SSF_REFLECTION)); 110 w = cos_wi_N*cos_wi_N; 111 sum += w; 112 sum_sqr += w*w; 113 } 114 115 E = sum/(double)NSTEPS; 116 V = sum_sqr/(double)NSTEPS - E*E; 117 SE = sqrt(V/(double)NSTEPS); 118 CHK(eq_eps(E, 2.0/4.0, 2.0*SE) == 1); 119 CHK(eq_eps(SE, 1.0/sqrt((double)NSTEPS) * sqrt(1.0/3.0 - 1.0/4.0), 1.e-6) == 1); 120 121 FOR_EACH(i, 0, NSTEPS) { 122 double val; 123 R = ssf_bsdf_sample(brdf, rng, wo, N, wi, &type, &pdf); 124 CHK(eq_eps(R, 0.7, 1.e-6) == 1); 125 val = ssf_bsdf_eval(brdf, wo, N, wi) * d3_dot(wi, N); 126 CHK(eq_eps(val, R * pdf, 1.e-6) == 1); 127 CHK(type == (SSF_DIFFUSE|SSF_REFLECTION)); 128 } 129 130 CHK(ssf_bsdf_ref_put(brdf) == RES_OK); 131 CHK(ssf_bsdf_ref_put(dummy) == RES_OK); 132 CHK(ssp_rng_ref_put(rng) == RES_OK); 133 134 check_memory_allocator(&allocator); 135 mem_shutdown_proxy_allocator(&allocator); 136 CHK(mem_allocated_size() == 0); 137 return 0; 138 } 139