star-sf

Set of surface and volume scattering functions
git clone git://git.meso-star.fr/star-sf.git
Log | Files | Refs | README | LICENSE

commit 2b0cd94bbbd91e913c797102ce40d52f395008f4
parent 4b0ba2ff258f5fcb7777963f5dcbd06072b7ccd0
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Mon,  3 Oct 2016 15:13:32 +0200

Update the SSF API

Explicitly relies on the Star-SamPling library to generate random
numbers

Diffstat:
Mcmake/CMakeLists.txt | 9+++++----
Msrc/ssf.h | 16++++++----------
Msrc/ssf_beckmann_distribution.c | 10+++++++---
Msrc/ssf_blinn_distribution.c | 11++++++++---
Msrc/ssf_bsdf.c | 20++++++++------------
Msrc/ssf_bxdf.c | 7+++----
Msrc/ssf_lambertian_reflection.c | 27+++++++++++----------------
Msrc/ssf_microfacet_distribution.c | 7+++----
Msrc/ssf_microfacet_reflection.c | 19+++++++++----------
Msrc/ssf_specular_reflection.c | 7+++----
Msrc/test_ssf_beckmann_distribution.c | 8++++++--
Msrc/test_ssf_blinn_distribution.c | 8++++++--
Msrc/test_ssf_bsdf.c | 19++++++++++++-------
Msrc/test_ssf_bxdf.c | 24+++++++++++-------------
Msrc/test_ssf_lambertian_reflection.c | 34+++++++++++++++++++++++-----------
Msrc/test_ssf_microfacet_distribution.c | 22++++++++++------------
Msrc/test_ssf_microfacet_reflection.c | 47++++++++++++++++++++++++++++-------------------
Msrc/test_ssf_specular_reflection.c | 25++++++++++++++-----------
Msrc/test_ssf_utils.h | 81+++++++++++++++++++++----------------------------------------------------------
19 files changed, 194 insertions(+), 207 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -27,13 +27,14 @@ set(SSF_SOURCE_DIR ${PROJECT_SOURCE_DIR}/../src) ################################################################################ find_package(RCMake REQUIRED) find_package(RSys 0.4 REQUIRED) -include_directories(${RSys_INCLUDE_DIR}) +find_package(StarSP 0.3 REQUIRED) +include_directories(${RSys_INCLUDE_DIR} ${StarSP_INCLUDE_DIR}) set(CMAKE_MODULE_PATH ${RCMAKE_SOURCE_DIR}) include(rcmake) include(rcmake_runtime) -rcmake_append_runtime_dirs(_runtime_dirs RSys) +rcmake_append_runtime_dirs(_runtime_dirs RSys StarSP) ################################################################################ # Define targets @@ -73,7 +74,7 @@ if(BUILD_STATIC) set_target_properties(ssf PROPERTIES DEFINE_SYMBOL SSF_STATIC) else() add_library(ssf SHARED ${SSF_FILES_INC} ${SSF_FILES_SRC}) - target_link_libraries(ssf RSys) + target_link_libraries(ssf RSys StarSP) set_target_properties(ssf PROPERTIES DEFINE_SYMBOL SSF_SHARED_BUILD VERSION ${VERSION} @@ -93,7 +94,7 @@ if(NOT NO_TEST) function(new_test _name) add_executable(${_name} ${SSF_SOURCE_DIR}/${_name}.c) - target_link_libraries(${_name} ssf RSys ${MATH_LIB}) + target_link_libraries(${_name} ssf RSys StarSP ${MATH_LIB}) add_test(${_name} ${_name}) endfunction() diff --git a/src/ssf.h b/src/ssf.h @@ -40,6 +40,7 @@ /* Forward declaration */ struct mem_allocator; +struct ssp_rng; /* Opaque data types */ struct ssf_bsdf; /* Bidirectional Scattering Distribution Function */ @@ -63,8 +64,7 @@ struct ssf_bxdf_type { double (*sample) (void* bxdf, - const double u, /* Canonical random number */ - const double v, /* Canonical random number */ + struct ssp_rng* rng, /* Random number generator */ const double wo[3], /* Normalized outgoing direction */ const double N[3], /* Normalized surface normal */ double wi[3], /* Sampled normalized incoming direction */ @@ -116,8 +116,7 @@ struct ssf_microfacet_distribution_type { void (*sample) (void* distrib, - const double u, /* Canonical random number */ - const double v, /* Canonical random number */ + struct ssp_rng* rng, /* Random number generator */ const double wo[3], /* Normalized outgoing direction */ const double N[3], /* Normalized Z-direction of the distribution */ double wh[3], /* Sampled normalized half vector */ @@ -208,8 +207,7 @@ ssf_bsdf_clear SSF_API double ssf_bsdf_sample (struct ssf_bsdf* bsdf, - const double u, /* Canonical number */ - const double v, /* Canonical number */ + struct ssp_rng* rng, /* Random number generator */ const double wo[3], /* Normalized outgoing direction */ const double N[3], /* Normalized surface normal */ double wi[3], /* Sampeled normalized incoming direction */ @@ -256,8 +254,7 @@ ssf_bxdf_ref_put SSF_API double ssf_bxdf_sample (struct ssf_bxdf* bxdf, - const double u, /* Canonical random number */ - const double v, /* Canonical random number */ + struct ssp_rng* rng, /* Random number generator */ const double wo[3], /* Normalized outgoing direction */ const double N[3], /* Normalized surface normal */ double wi[3], /* Sampled normalized incoming direction. */ @@ -373,8 +370,7 @@ ssf_microfacet_distribution_eval SSF_API void ssf_microfacet_distribution_sample (struct ssf_microfacet_distribution* distrib, - const double u, /* Canonical random number */ - const double v, /* Canonical random number */ + struct ssp_rng* rng, /* Random number generator */ const double wo[3], /* Normalized outgoing direction */ const double N[3], /* Normalized Z-direction of the distribution */ double wh[3], /* Normalized half vector */ diff --git a/src/ssf_beckmann_distribution.c b/src/ssf_beckmann_distribution.c @@ -19,6 +19,8 @@ #include <rsys/double3.h> #include <rsys/double33.h> +#include <star/ssp.h> + struct beckmann_distribution { double roughness; }; @@ -61,8 +63,7 @@ beckmann_distribution_eval static void beckmann_distribution_sample (void* distrib, - const double u, - const double v, + struct ssp_rng* rng, const double wo[3], const double N[3], double wh[3], @@ -77,10 +78,13 @@ beckmann_distribution_sample double cos_theta_T, sin_theta_T; double cos_theta, sin_theta; double cos2_theta, sin2_theta; - ASSERT(u >= 0 && u < 1 && v >= 0 && v < 1 && wh && N && wo); + double u, v; + ASSERT(rng && wh && N && wo); ASSERT(d3_is_normalized(wo) && d3_is_normalized(N)); (void)wo; + u = ssp_rng_canonical(rng); + v = ssp_rng_canonical(rng); phi = 2.0*PI*u; m2 = beckmann->roughness * beckmann->roughness; diff --git a/src/ssf_blinn_distribution.c b/src/ssf_blinn_distribution.c @@ -19,6 +19,8 @@ #include <rsys/double3.h> #include <rsys/double33.h> +#include <star/ssp.h> + struct blinn_distribution { double exponent; }; @@ -57,8 +59,7 @@ blinn_distribution_eval static void blinn_distribution_sample (void* distrib, - const double u, - const double v, + struct ssp_rng* rng, const double wo[3], const double N[3], double wh[3], @@ -70,9 +71,13 @@ blinn_distribution_sample double cos_theta, sin_theta; double cos_wh_wo; double phi; - ASSERT(distrib && u>=0 && u<1 && v>=0 && v<1 && wo && N && wh && pdf); + double u, v; + ASSERT(distrib && rng && wo && N && wh && pdf); ASSERT(d3_is_normalized(wo) && d3_is_normalized(N)); + u = ssp_rng_canonical(rng); + v = ssp_rng_canonical(rng); + phi = v*2*PI; cos_theta = pow(u, 1/(blinn->exponent+1)); sin_theta = sqrt(MMAX(0, 1-cos_theta*cos_theta)); diff --git a/src/ssf_bsdf.c b/src/ssf_bsdf.c @@ -23,6 +23,8 @@ #include <rsys/mem_allocator.h> #include <rsys/ref_count.h> +#include <star/ssp.h> + #define MAX_BxDFs 8 struct ssf_bsdf { @@ -142,8 +144,7 @@ ssf_bsdf_clear(struct ssf_bsdf* bsdf) double ssf_bsdf_sample (struct ssf_bsdf* bsdf, - const double u, - const double v, + struct ssp_rng* rng, const double wo[3], const double N[3], double wi[3], @@ -153,9 +154,8 @@ ssf_bsdf_sample double R_wi; double r; double pdf; - double lower; size_t i; - ASSERT(bsdf && u>=0 && u<1 && v>=0 && v<1 && wi && N && wo && out_pdf); + ASSERT(bsdf && rng && wi && N && wo && out_pdf); ASSERT(d3_is_normalized(wo) && d3_is_normalized(N)); if(!bsdf->nbxdfs) { @@ -163,7 +163,7 @@ ssf_bsdf_sample return 0; } if(bsdf->nbxdfs == 1) { - return ssf_bxdf_sample(bsdf->bxdfs[0], u, v, wo, N, wi, out_pdf); + return ssf_bxdf_sample(bsdf->bxdfs[0], rng, wo, N, wi, out_pdf); } bsdf_normalize_weights(bsdf); @@ -175,17 +175,13 @@ ssf_bsdf_sample } /* Sample a component */ - lower = 0; + r = ssp_rng_canonical(rng); FOR_EACH(i, 0, bsdf->nbxdfs-1) { - if(u <= cumul[i]) break; - lower = cumul[i]; + if(r <= cumul[i]) break; } - /* Rescale the random number u in [0, 1) */ - r = (u - lower) / nextafter(cumul[i] - lower, DBL_MAX); - /* Sample a direction from the selected component */ - R_wi = ssf_bxdf_sample(bsdf->bxdfs[i], r, v, wo, N, wi, &pdf); + R_wi = ssf_bxdf_sample(bsdf->bxdfs[i], rng, wo, N, wi, &pdf); *out_pdf = pdf*bsdf->weights[i]; return R_wi; } diff --git a/src/ssf_bxdf.c b/src/ssf_bxdf.c @@ -116,16 +116,15 @@ ssf_bxdf_ref_put(struct ssf_bxdf* bxdf) double ssf_bxdf_sample (struct ssf_bxdf* bxdf, - const double u, - const double v, + struct ssp_rng* rng, const double wo[3], const double N[3], double wi[3], double* pdf) { - ASSERT(bxdf && u>=0 && u<1 && v>=0 && v<1 && wo && N && wi && pdf); + ASSERT(bxdf && rng && wo && N && wi && pdf); ASSERT(d3_is_normalized(wo) && d3_is_normalized(N)); - return bxdf->type.sample(bxdf->data, u, v, wo, N, wi, pdf); + return bxdf->type.sample(bxdf->data, rng, wo, N, wi, pdf); } double diff --git a/src/ssf_lambertian_reflection.c b/src/ssf_lambertian_reflection.c @@ -19,6 +19,8 @@ #include <rsys/double3.h> #include <rsys/double33.h> +#include <star/ssp.h> + struct lambertian_reflection { double reflectivity; }; @@ -55,29 +57,22 @@ lambertian_reflection_eval static double lambertian_reflection_sample (void* data, - const double u, - const double v, + struct ssp_rng* rng, const double wo[3], const double N[3], double wi[3], double* pdf) { - double basis[9]; - double dir[3]; - double cos_theta, sin_theta; - double phi; - ASSERT(data && u>=0 && u<1 && v>=0 && v<1 && wo && N && wi); + float normal[3]; + float sample[4]; + ASSERT(data && rng && wo && N && wi); ASSERT(d3_is_normalized(wo) && d3_is_normalized(N)); + (void)wo; - phi = 2.0 * PI * u; - cos_theta = sqrt(v); - sin_theta = sqrt(1.0 - v); - dir[0] = cos(phi) * sin_theta; - dir[1] = sin(phi) * sin_theta; - dir[2] = cos_theta; - if(d3_dot(wo, N) < 0) dir[2] = -dir[2]; - d33_muld3(wi, d33_basis(basis, N), dir); - *pdf = cos_theta / PI; + f3_set_d3(normal, N); + ssp_ran_hemisphere_cos(rng, normal, sample); + d3_set_f3(wi, sample); + *pdf = sample[3]; return ((struct lambertian_reflection*)data)->reflectivity; } diff --git a/src/ssf_microfacet_distribution.c b/src/ssf_microfacet_distribution.c @@ -121,16 +121,15 @@ ssf_microfacet_distribution_ref_put(struct ssf_microfacet_distribution* distrib) void ssf_microfacet_distribution_sample (struct ssf_microfacet_distribution* distrib, - const double u, - const double v, + struct ssp_rng* rng, const double wo[3], const double N[3], double wh[3], double* pdf) { - ASSERT(distrib && u>=0 && u<1 && v>=0 && v<1 && wo && N && wh && pdf); + ASSERT(distrib && rng && wo && N && wh && pdf); ASSERT(d3_is_normalized(wo) && d3_is_normalized(N)); - distrib->type.sample(distrib->data, u, v, wo, N, wh, pdf); + distrib->type.sample(distrib->data, rng, wo, N, wh, pdf); } double diff --git a/src/ssf_microfacet_reflection.c b/src/ssf_microfacet_reflection.c @@ -80,8 +80,7 @@ microfacet_reflection_eval static FINLINE double microfacet_reflection_sample (void* data, - const double u, - const double v, + struct ssp_rng* rng, const double wo[3], const double N[3], double wi[3], @@ -92,13 +91,13 @@ microfacet_reflection_sample double wh[3]; double pdf_wh; double R; - ASSERT(data && u>=0 && u<1 && v>=0 && v<1 && wo && N && wi); + ASSERT(data && wo && N && wi); ASSERT(d3_is_normalized(wo) && d3_is_normalized(N)); ASSERT(bxdf->distrib && bxdf->fresnel); if(d3_dot(wo, N) <= 0.0) return 0.0; - ssf_microfacet_distribution_sample(bxdf->distrib, u, v, wo, N, wh, &pdf_wh); + ssf_microfacet_distribution_sample(bxdf->distrib, rng, wo, N, wh, &pdf_wh); reflect(dir, wo, wh); *pdf = pdf_wh / (4.0*fabs(d3_dot(wo, wh))); R = d3_dot(dir, N) > 0 ? ssf_fresnel_eval(bxdf->fresnel, d3_dot(dir, wh)) : 0; @@ -135,8 +134,7 @@ microfacet_reflection_rho(void* data, const double wo[3], const double N[3]) static FINLINE double microfacet2_reflection_sample (void* data, - const double u, - const double v, + struct ssp_rng* rng, const double wo[3], const double N[3], double wi[3], @@ -147,14 +145,14 @@ microfacet2_reflection_sample double wh[3]; double p; double troughput = 1; - ASSERT(data && u>=0 && u<1 && v>=0 && v<1 && wo && N && wi); + ASSERT(data && wo && N && wi); ASSERT(d3_is_normalized(wo) && d3_is_normalized(N)); ASSERT(bxdf->distrib); if(d3_dot(wo, N) <= 0.0) return 0.0; do { /* Sample a micro facet that front faces 'wo' */ - ssf_microfacet_distribution_sample(bxdf->distrib, u, v, wo, N, wh, &p); + ssf_microfacet_distribution_sample(bxdf->distrib, rng, wo, N, wh, &p); } while(d3_dot(wo, wh) <= 0); reflect(dir, wo, wh); @@ -168,7 +166,7 @@ microfacet2_reflection_sample /* Handle directions that point toward the macro surface has * inter-reflections */ do { /* Sample a microfacet that front faces 'wi' */ - ssf_microfacet_distribution_sample(bxdf->distrib, u, v, dir, N, wh, &p); + ssf_microfacet_distribution_sample(bxdf->distrib, rng, dir, N, wh, &p); } while(d3_dot(dir, wh) <= 0); reflect(dir, dir, wh); } @@ -226,7 +224,8 @@ ssf_microfacet_reflection_setup struct microfacet_reflection* microfacet; if(!bxdf || !fresnel || !distrib) return RES_BAD_ARG; - if(!BXDF_TYPE_EQ(&bxdf->type, &ssf_microfacet_reflection)) + if(!BXDF_TYPE_EQ(&bxdf->type, &ssf_microfacet_reflection) + && !BXDF_TYPE_EQ(&bxdf->type, &ssf_microfacet2_reflection)) return RES_BAD_ARG; microfacet = bxdf->data; diff --git a/src/ssf_specular_reflection.c b/src/ssf_specular_reflection.c @@ -45,8 +45,7 @@ specular_reflection_release(void* bxdf) static double specular_reflection_sample (void* data, - const double u, - const double v, + struct ssp_rng* rng, const double wo[3], const double N[3], double wi[3], @@ -55,9 +54,9 @@ specular_reflection_sample struct specular_reflection* brdf = data; double cos_wo_N; double cos_wi_N; - ASSERT(u >= 0 && u < 1 && v >= 0 && v < 1 && wi && N && wo); + ASSERT(rng && wi && N && wo); ASSERT(d3_is_normalized(wo) && d3_is_normalized(N)); - (void)u, (void)v; + (void)rng; /* Reflect the outgoing direction wo with respect to the surface normal N */ reflect(wi, wo, N); diff --git a/src/test_ssf_beckmann_distribution.c b/src/test_ssf_beckmann_distribution.c @@ -26,12 +26,15 @@ main(int argc, char** argv) struct mem_allocator allocator; struct ssf_microfacet_distribution* distrib; struct ssf_microfacet_distribution* dummy; + struct ssp_rng* rng; const size_t NTESTS = 10; size_t itest; (void)argc, (void)argv; mem_init_proxy_allocator(&allocator, &mem_default_allocator); + CHECK(ssp_rng_create(&allocator, &ssp_rng_threefry, &rng), RES_OK); + CHECK(ssf_microfacet_distribution_create (&allocator, &ssf_beckmann_distribution, &distrib), RES_OK); CHECK(ssf_microfacet_distribution_create @@ -49,13 +52,14 @@ main(int argc, char** argv) CHECK(ssf_beckmann_distribution_setup(distrib, 0), RES_BAD_ARG); FOR_EACH(itest, 0, NTESTS) { - const double roughness = nextafter(rand_canonic(), 2); /* in ]0, 1] */ + const double roughness = nextafter(ssp_rng_canonical(rng), 2); /*in ]0, 1]*/ CHECK(ssf_beckmann_distribution_setup(distrib, roughness), RES_OK); - check_microfacet_distribution(distrib); + check_microfacet_distribution(distrib, rng); } CHECK(ssf_microfacet_distribution_ref_put(distrib), RES_OK); CHECK(ssf_microfacet_distribution_ref_put(dummy), RES_OK); + CHECK(ssp_rng_ref_put(rng), RES_OK); check_memory_allocator(&allocator); mem_shutdown_proxy_allocator(&allocator); diff --git a/src/test_ssf_blinn_distribution.c b/src/test_ssf_blinn_distribution.c @@ -22,6 +22,7 @@ int main(int argc, char** argv) { struct mem_allocator allocator; + struct ssp_rng* rng; struct ssf_microfacet_distribution* distrib; struct ssf_microfacet_distribution* dummy; const size_t NTESTS = 5; @@ -29,6 +30,7 @@ main(int argc, char** argv) (void)argc, (void)argv; mem_init_proxy_allocator(&allocator, &mem_default_allocator); + CHECK(ssp_rng_create(&allocator, &ssp_rng_threefry, &rng), RES_OK); CHECK(ssf_microfacet_distribution_create (&allocator, &ssf_blinn_distribution, &distrib), RES_OK); @@ -51,13 +53,15 @@ main(int argc, char** argv) CHECK(ssf_blinn_distribution_setup(distrib, 32.32), RES_OK); FOR_EACH(itest, 0, NTESTS) { - const double exponent = rand_canonic()*SSF_BLINN_DISTRIBUTION_MAX_EXPONENT; + const double exponent = ssp_rng_uniform_double + (rng, 0, SSF_BLINN_DISTRIBUTION_MAX_EXPONENT); CHECK(ssf_blinn_distribution_setup(distrib, exponent), RES_OK); - check_microfacet_distribution(distrib); + check_microfacet_distribution(distrib, rng); } CHECK(ssf_microfacet_distribution_ref_put(distrib), RES_OK); CHECK(ssf_microfacet_distribution_ref_put(dummy), RES_OK); + CHECK(ssp_rng_ref_put(rng), RES_OK); check_memory_allocator(&allocator); mem_shutdown_proxy_allocator(&allocator); diff --git a/src/test_ssf_bsdf.c b/src/test_ssf_bsdf.c @@ -23,6 +23,7 @@ main(int argc, char** argv) { const size_t NSTEPS = 100000; struct mem_allocator allocator; + struct ssp_rng* rng; struct ssf_bsdf* bsdf; struct ssf_bxdf* bxdf; struct ssf_bxdf* bxdf2; @@ -31,10 +32,13 @@ main(int argc, char** argv) double N[3]; double E, V, SE, R; double sum, sqr_sum; + float normal[3]; + float sample[3]; size_t i; (void)argc, (void)argv; mem_init_proxy_allocator(&allocator, &mem_default_allocator); + CHECK(ssp_rng_create(&allocator, &ssp_rng_threefry, &rng), RES_OK); CHECK(ssf_bsdf_create(NULL, NULL), RES_BAD_ARG); CHECK(ssf_bsdf_create(&allocator, NULL), RES_BAD_ARG); @@ -64,13 +68,13 @@ main(int argc, char** argv) d3_normalize(wo, d3(wo, 1, 1, 0)); d3(N, 0.0, 1.0, 0.0); - R = ssf_bsdf_sample(bsdf, 0.5, 0.5, wo, N, wi, &pdf); + R = ssf_bsdf_sample(bsdf, rng, wo, N, wi, &pdf); CHECK(eq_eps(R, ssf_fresnel_eval(fresnel, d3_dot(wi, N)), 1.e-6), 1); CHECK(ssf_bsdf_eval(bsdf, wo, N, wi), 0); CHECK(ssf_bsdf_pdf(bsdf, wo, N, wi), 0); CHECK(ssf_specular_reflection_setup(bxdf, fresnel), RES_OK); - R = ssf_bsdf_sample(bsdf, 0.5, 0.5, wo, N, wi, &pdf); + R = ssf_bsdf_sample(bsdf, rng, wo, N, wi, &pdf); CHECK(eq_eps(R, ssf_fresnel_eval(fresnel, d3_dot(wi, N)), 1.e-6), 1); CHECK(ssf_bsdf_add(bsdf, bxdf2, 1), RES_OK); @@ -79,11 +83,11 @@ main(int argc, char** argv) * totally wrong */ sum = 0; sqr_sum = 0; - ran_hemisphere(N, wo, NULL); + f3_set_d3(normal, N); + ssp_ran_hemisphere_uniform(rng, normal, sample); + d3_set_f3(wo, sample); FOR_EACH(i, 0, NSTEPS) { - const double u = rand_canonic(); - const double v = rand_canonic(); - double weight = ssf_bsdf_sample(bsdf, u, v, wo, N, wi, &pdf); + double weight = ssf_bsdf_sample(bsdf, rng, wo, N, wi, &pdf); CHECK(ssf_bsdf_eval(bsdf, wo, N, wi), 0); CHECK(ssf_bsdf_pdf(bsdf, wo, N, wi), 0); sum += weight; @@ -97,13 +101,14 @@ main(int argc, char** argv) CHECK(ssf_bsdf_clear(NULL), RES_BAD_ARG); CHECK(ssf_bsdf_clear(bsdf), RES_OK); - CHECK(ssf_bsdf_sample(bsdf, 0, 0, wo, N, wi, &pdf), 0.0); + CHECK(ssf_bsdf_sample(bsdf, rng, wo, N, wi, &pdf), 0.0); CHECK(pdf, 0.0); CHECK(ssf_bsdf_ref_put(bsdf), RES_OK); CHECK(ssf_bxdf_ref_put(bxdf), RES_OK); CHECK(ssf_bxdf_ref_put(bxdf2), RES_OK); CHECK(ssf_fresnel_ref_put(fresnel), RES_OK); + CHECK(ssp_rng_ref_put(rng), RES_OK); check_memory_allocator(&allocator); mem_shutdown_proxy_allocator(&allocator); diff --git a/src/test_ssf_bxdf.c b/src/test_ssf_bxdf.c @@ -22,8 +22,7 @@ static int bxdf_is_init = 0; struct ALIGN(64) bxdf { uint32_t id; - double u; - double v; + struct ssp_rng* rng; double wi[3]; double wo[3]; double N[3]; @@ -55,8 +54,7 @@ bxdf_release(void* bxdf) static double bxdf_sample (void* bxdf, - const double u, - const double v, + struct ssp_rng* rng, const double wo[3], const double N[3], double wi[3], @@ -64,8 +62,7 @@ bxdf_sample { struct bxdf* BxDF = bxdf; NCHECK(BxDF, NULL); - CHECK(BxDF->u, u); - CHECK(BxDF->v, v); + CHECK(BxDF->rng, rng); CHECK(d3_eq(BxDF->wo, wo), 1); CHECK(d3_eq(BxDF->N, N), 1); d3(wi, 1.0, 2.0, 3.0); @@ -111,6 +108,7 @@ int main(int argc, char** argv) { struct mem_allocator allocator; + struct ssp_rng* rng; struct bxdf* data; struct ssf_bxdf* bxdf; struct ssf_bxdf_type type = SSF_BXDF_TYPE_NULL; @@ -121,6 +119,7 @@ main(int argc, char** argv) (void)argc, (void)argv; mem_init_proxy_allocator(&allocator, &mem_default_allocator); + CHECK(ssp_rng_create(&allocator, &ssp_rng_threefry, &rng), RES_OK); type.init = bxdf_init; type.release = bxdf_release; @@ -184,17 +183,14 @@ main(int argc, char** argv) d3(N, 0.0, 1.0, 0.0); d3_set(data->wo, wo); d3_set(data->N, N); - data->u = 0.0; - data->v = 0.0; + data->rng = rng; data->reflectivity = 0.1234; - CHECK(ssf_bxdf_sample(bxdf, 0, 0, wo, N, wi, &pdf), 0.1234); - data->u = 0.5; - data->v = 0.5; - CHECK(ssf_bxdf_sample(bxdf, 0.5, 0.5, wo, N, wi, &pdf), 0.1234); + CHECK(ssf_bxdf_sample(bxdf, rng, wo, N, wi, &pdf), 0.1234); + CHECK(ssf_bxdf_sample(bxdf, rng, wo, N, wi, &pdf), 0.1234); data->reflectivity = 0.314; - CHECK(ssf_bxdf_sample(bxdf, 0.5, 0.5, wo, N, wi, &pdf), 0.314); + CHECK(ssf_bxdf_sample(bxdf, rng, wo, N, wi, &pdf), 0.314); d3_normalize(wi, wi); d3_set(data->wi, wi); @@ -207,6 +203,8 @@ main(int argc, char** argv) CHECK(ssf_bxdf_ref_put(bxdf), RES_OK); CHECK(bxdf_is_init, 0); + CHECK(ssp_rng_ref_put(rng), RES_OK); + check_memory_allocator(&allocator); mem_shutdown_proxy_allocator(&allocator); CHECK(mem_allocated_size(), 0); diff --git a/src/test_ssf_lambertian_reflection.c b/src/test_ssf_lambertian_reflection.c @@ -24,6 +24,7 @@ main(int argc, char** argv) { const size_t NSTEPS = 100000; struct mem_allocator allocator; + struct ssp_rng* rng; struct ssf_bxdf* brdf; struct ssf_bxdf* dummy; double E, SE, V; @@ -38,6 +39,7 @@ main(int argc, char** argv) (void)argc, (void)argv; mem_init_proxy_allocator(&allocator, &mem_default_allocator); + CHECK(ssp_rng_create(&allocator, &ssp_rng_threefry, &rng), RES_OK); CHECK(ssf_bxdf_create(&allocator, &ssf_lambertian_reflection, &brdf), RES_OK); CHECK(ssf_bxdf_create(&allocator, &bxdf_dummy, &dummy), RES_OK); @@ -52,36 +54,36 @@ main(int argc, char** argv) d3(N, 0.0, 0.0, 1.0); d3_normalize(wo, d3(wo, 1.0, 0.0, 1.0)); - R = ssf_bxdf_sample(brdf, 0, 0, wo, N, wi, &pdf); + R = ssf_bxdf_sample(brdf, rng, wo, N, wi, &pdf); CHECK(eq_eps(wi[2]/PI, pdf, 1.e-6), 1); CHECK(R, 0); CHECK(ssf_lambertian_reflection_setup(brdf, 0.7), RES_OK); - R = ssf_bxdf_sample(brdf, rand_canonic(), rand_canonic(), wo, N, wi, &pdf); + R = ssf_bxdf_sample(brdf, rng, wo, N, wi, &pdf); CHECK(eq_eps(R, 0.7, 1.e-6), 1); CHECK(eq_eps(pdf, d3_dot(wi, N)/PI, 1.e-6), 1); d3_normalize(wo, d3(wo, 1.0, 0.0, -1.0)); - R = ssf_bxdf_sample(brdf, rand_canonic(), rand_canonic(), wo, N, wi, &pdf); + R = ssf_bxdf_sample(brdf, rng, wo, N, wi, &pdf); CHECK(R, 0.7); d3_normalize(wo, d3(wo, 1.0, 1.0, 0.0)); - R = ssf_bxdf_sample(brdf, rand_canonic(), rand_canonic(), wo, N, wi, &pdf); + R = ssf_bxdf_sample(brdf, rng, wo, N, wi, &pdf); CHECK(eq_eps(R, 0.7, 1.e-6), 1); CHECK(eq_eps(R, ssf_bxdf_eval(brdf, wo, N, wi)*PI, 1.e-6), 1); d3_normalize(wo, d3(wo, 1.0, 0.0, 1.0)); - d3(N, rand_canonic(), rand_canonic(), rand_canonic()); + N[0] = ssp_rng_uniform_double(rng, -1, 1); + N[1] = ssp_rng_uniform_double(rng, -1, 1); + N[2] = ssp_rng_uniform_double(rng, -1, 1); d3_normalize(N, N); d33_basis(basis, N); d33_muld3(wo, basis, wo); sum = sum_sqr = 0; FOR_EACH(i, 0, NSTEPS) { - const double u = rand_canonic(); - const double v = rand_canonic(); double cos_wi_N; - R = ssf_bxdf_sample(brdf, u, v, wo, N, wi, &pdf) / PI; + R = ssf_bxdf_sample(brdf, rng, wo, N, wi, &pdf) / PI; cos_wi_N = d3_dot(wi, N); CHECK(eq_eps(R, 0.7/PI, 1.e-6), 1); CHECK(eq_eps(cos_wi_N/PI, pdf, 1.e-6), 1); @@ -95,12 +97,10 @@ main(int argc, char** argv) sum = sum_sqr = 0; FOR_EACH(i, 0, NSTEPS) { - const double u = rand_canonic(); - const double v = rand_canonic(); double cos_wi_N; double w; - R = ssf_bxdf_sample(brdf, u, v, wo, N, wi, &pdf)/PI; + R = ssf_bxdf_sample(brdf, rng, wo, N, wi, &pdf)/PI; cos_wi_N = d3_dot(wi, N); CHECK(eq_eps(R, 0.7/PI, 1.e-6), 1); CHECK(eq_eps(cos_wi_N/PI, pdf, 1.e-6), 1); @@ -115,8 +115,20 @@ main(int argc, char** argv) CHECK(eq_eps(E, 2.0/4.0, 2.0*SE), 1); CHECK(eq_eps(SE, 1.0/sqrt((double)NSTEPS) * sqrt(1.0/3.0 - 1.0/4.0), 1.e-6), 1); + sum = sum_sqr = 0; + FOR_EACH(i, 0, NSTEPS) { + R = ssf_bxdf_sample(brdf, rng, wo, N, wi, &pdf); + sum += R; + sum_sqr += R*R; + } + E = sum/(double)NSTEPS; + V = MMAX(sum_sqr/(double)NSTEPS - E*E, 0); + SE = sqrt(V/(double)NSTEPS); + CHECK(eq_eps(E, 0.7, SE), 1); + CHECK(ssf_bxdf_ref_put(brdf), RES_OK); CHECK(ssf_bxdf_ref_put(dummy), RES_OK); + CHECK(ssp_rng_ref_put(rng), RES_OK); check_memory_allocator(&allocator); mem_shutdown_proxy_allocator(&allocator); diff --git a/src/test_ssf_microfacet_distribution.c b/src/test_ssf_microfacet_distribution.c @@ -22,8 +22,7 @@ static int ufacet_is_init = 0; struct ALIGN(64) ufacet { uint32_t id; - double u; - double v; + struct ssp_rng* rng; double wh[3]; double wo[3]; double N[3]; @@ -53,8 +52,7 @@ ufacet_release(void* distrib) static void ufacet_sample (void* distrib, - const double u, - const double v, + struct ssp_rng* rng, const double wo[3], const double N[3], double wh[3], @@ -62,14 +60,11 @@ ufacet_sample { struct ufacet* ufacet = distrib; NCHECK(ufacet, NULL); - CHECK(u >= 0 && u < 1, 1); - CHECK(v >= 0 && v < 1, 1); NCHECK(wo, NULL); NCHECK(N, NULL); NCHECK(wh, NULL); NCHECK(pdf, NULL); - CHECK(ufacet->u, u); - CHECK(ufacet->v, v); + CHECK(ufacet->rng, rng); CHECK(d3_eq(ufacet->wo, wo), 1); CHECK(d3_eq(ufacet->N, N), 1); d3_normalize(wh, d3(wh, 1.0, 2.0, 3.0)); @@ -119,10 +114,12 @@ main(int argc, char** argv) struct ssf_microfacet_distribution_type type = SSF_MICROFACET_DISTRIBUTION_TYPE_NULL; struct ssf_microfacet_distribution* distrib; + struct ssp_rng* rng; double wo[3], N[3], wh[3], pdf; (void)argc, (void)argv; mem_init_proxy_allocator(&allocator, &mem_default_allocator); + CHECK(ssp_rng_create(&allocator, &ssp_rng_threefry, &rng), RES_OK); type.init = ufacet_init; type.release = ufacet_release; @@ -190,15 +187,14 @@ main(int argc, char** argv) d3_set(data->wo, wo); d3_set(data->N, N); d3_normalize(data->wh, d3(data->wh, 1, 2, 3)); - data->u = data->v = 0.0; + data->rng = rng; data->pdf = 0.1234; data->value = 0.43; - ssf_microfacet_distribution_sample(distrib, 0, 0, wo, N, wh, &pdf); + ssf_microfacet_distribution_sample(distrib, rng, wo, N, wh, &pdf); CHECK(d3_eq(wh, data->wh), 1); CHECK(pdf, data->pdf); - data->u = data->v = 0.5; - ssf_microfacet_distribution_sample(distrib, 0.5, 0.5, wo, N, wh, &pdf); + ssf_microfacet_distribution_sample(distrib, rng, wo, N, wh, &pdf); CHECK(d3_eq(wh, data->wh), 1); CHECK(pdf, data->pdf); @@ -208,6 +204,8 @@ main(int argc, char** argv) CHECK(ssf_microfacet_distribution_ref_put(distrib), RES_OK); CHECK(ufacet_is_init, 0); + CHECK(ssp_rng_ref_put(rng), RES_OK); + check_memory_allocator(&allocator); mem_shutdown_proxy_allocator(&allocator); CHECK(mem_allocated_size(), 0); diff --git a/src/test_ssf_microfacet_reflection.c b/src/test_ssf_microfacet_reflection.c @@ -17,6 +17,7 @@ #include "test_ssf_utils.h" #include <rsys/double3.h> +#include <star/ssp.h> int main(int argc, char** argv) @@ -26,10 +27,12 @@ main(int argc, char** argv) struct ssf_bxdf* dummy; struct ssf_fresnel* F; struct ssf_microfacet_distribution* D; + struct ssp_rng* rng; (void)argc, (void)argv; mem_init_proxy_allocator(&allocator, &mem_default_allocator); - CHECK(ssf_bxdf_create(&allocator, &ssf_microfacet_reflection, &bxdf), RES_OK); + CHECK(ssp_rng_create(&allocator, &ssp_rng_threefry, &rng), RES_OK); + CHECK(ssf_bxdf_create(&allocator, &ssf_microfacet2_reflection, &bxdf), RES_OK); CHECK(ssf_bxdf_create(&allocator, &bxdf_dummy, &dummy), RES_OK); CHECK(ssf_fresnel_create(&allocator, &ssf_fresnel_no_op, &F), RES_OK); CHECK(ssf_microfacet_distribution_create @@ -47,32 +50,38 @@ main(int argc, char** argv) CHECK(ssf_microfacet_reflection_setup(bxdf, F, D), RES_OK); /* Numerically evaluate rho */ - /* TODO */ #if 0 - d3(N, 0, 1, 0); - sum = sum_sqr = 0; - ran_hemisphere_cos(N, wo, NULL); - FOR_EACH(i, 0, NSTEPS) { - double R; - double weight; - ran_hemisphere_cos(N, wi, &pdf); - R = ssf_bxdf_eval(bxdf, wo, N, wi); - weight = R * d3_dot(wi, N) / pdf; - sum += weight; - sum_sqr += weight*weight; - } + { + double N[3]; + double wo[3]; + double wi[3]; + double pdf; + double sum, sum_sqr; + double E, SE, V; + size_t i, NSTEPS=1000; + + d3(N, 0, 1, 0); + sum = sum_sqr = 0; + ran_hemisphere_cos(N, wo, NULL); + FOR_EACH(i, 0, NSTEPS) { + double R; + R = ssf_bxdf_sample(bxdf, rng, wo, N, wi, &pdf); + sum += R; + sum_sqr += R*R; + } - E = sum / (double)NSTEPS; - V = sum_sqr / (double)NSTEPS - E*E; - SE = sqrt(V/(double)NSTEPS); - printf("%g +/- %g\n", E, SE); - CHECK(eq_eps(E, ssf_bxdf_rho(bxdf, wo, N), SE), 1); + E = sum / (double)NSTEPS; + V = sum_sqr / (double)NSTEPS - E*E; + SE = sqrt(V/(double)NSTEPS); + printf("%g +/- %g\n", E, SE); + } #endif CHECK(ssf_bxdf_ref_put(bxdf), RES_OK); CHECK(ssf_bxdf_ref_put(dummy), RES_OK); CHECK(ssf_fresnel_ref_put(F), RES_OK); CHECK(ssf_microfacet_distribution_ref_put(D), RES_OK); + CHECK(ssp_rng_ref_put(rng), RES_OK); check_memory_allocator(&allocator); mem_shutdown_proxy_allocator(&allocator); diff --git a/src/test_ssf_specular_reflection.c b/src/test_ssf_specular_reflection.c @@ -23,6 +23,7 @@ main(int argc, char** argv) { const size_t NSTEPS = 100000; struct mem_allocator allocator; + struct ssp_rng* rng; struct ssf_bxdf* brdf; struct ssf_bxdf* dummy; struct ssf_fresnel* fresnel; @@ -34,6 +35,7 @@ main(int argc, char** argv) (void)argc, (void)argv; mem_init_proxy_allocator(&allocator, &mem_default_allocator); + CHECK(ssp_rng_create(&allocator, &ssp_rng_threefry, &rng), RES_OK); CHECK(ssf_bxdf_create(&allocator, &ssf_specular_reflection, &brdf), RES_OK); CHECK(ssf_bxdf_create(&allocator, &bxdf_dummy, &dummy), RES_OK); CHECK(ssf_fresnel_create @@ -48,13 +50,13 @@ main(int argc, char** argv) d3(N, 0.0, 1.0, 0.0); d3_normalize(wo, d3(wo, 1.0, 1.0, 0.0)); - R = ssf_bxdf_sample(brdf, 0, 0, wo, N, wi, &pdf); + R = ssf_bxdf_sample(brdf, rng, wo, N, wi, &pdf); CHECK(eq_eps(R, ssf_fresnel_eval(fresnel, d3_dot(N, wi)), 1.e-6), 1); CHECK(pdf, 1); d3_normalize(wo, d3(wo, 1.0, 1.0, 0.0)); CHECK(ssf_specular_reflection_setup(brdf, fresnel), RES_OK); - R = ssf_bxdf_sample(brdf, 0, 0, wo, N, wi, &pdf); + R = ssf_bxdf_sample(brdf, rng, wo, N, wi, &pdf); CHECK(eq_eps(R, ssf_fresnel_eval(fresnel, d3_dot(N, wi)), 1.e-6), 1); CHECK(pdf, 1); CHECK(d3_eq_eps(d3(wo, -wo[0], wo[1], 0.0), wi, 1.e-6), 1); @@ -63,41 +65,42 @@ main(int argc, char** argv) CHECK(ssf_bxdf_pdf(brdf, wo, N, wi), 0.0); d3(wo, 0.0, 1.0, 0.0); - R = ssf_bxdf_sample(brdf, 0, 0, wo, N, wi, &pdf); + R = ssf_bxdf_sample(brdf, rng, wo, N, wi, &pdf); CHECK(eq_eps(R, ssf_fresnel_eval(fresnel, d3_dot(N, wi)), 1.e-6), 1); CHECK(pdf, 1); CHECK(d3_eq_eps(d3(wo, 0.0, 1.0, 0.0), wi, 1.e-6), 1); d3_normalize(wo, d3(wo, -1.0, 1.0, 0.0)); - R = ssf_bxdf_sample(brdf, 0, 0, wo, N, wi, &pdf); + R = ssf_bxdf_sample(brdf, rng, wo, N, wi, &pdf); CHECK(eq_eps(R, ssf_fresnel_eval(fresnel, d3_dot(N, wi)), 1.e-6), 1); CHECK(pdf, 1); CHECK(d3_eq_eps(d3(wo, -wo[0], wo[1], 0.0), wi, 1.e-6), 1); d3(wo, 0.0, -1.0, 0.0); - R = ssf_bxdf_sample(brdf, 0, 0, wo, N, wi, &pdf); + R = ssf_bxdf_sample(brdf, rng, wo, N, wi, &pdf); CHECK(eq_eps(R, 0, 1.e-6), 1); CHECK(pdf, 1); CHECK(d3_eq_eps(d3(wo, 0.0, -1.0, 0.0), wi, 1.e-6), 1); d3(wo, 1.0, 0.0, 0.0); - R = ssf_bxdf_sample(brdf, 0, 0, wo, N, wi, &pdf); + R = ssf_bxdf_sample(brdf, rng, wo, N, wi, &pdf); CHECK(eq_eps(R, 0, 1.e-6), 1); CHECK(d3_eq_eps(d3(wo, -1.0, 0, 0), wi, 1.e-6), 1); - d3(wo, rand_canonic(), rand_canonic(), rand_canonic()); + wo[0] = ssp_rng_uniform_double(rng, -1, 1); + wo[1] = ssp_rng_uniform_double(rng, -1, 1); + wo[2] = ssp_rng_uniform_double(rng, -1, 1); d3_normalize(wo, wo); - R = ssf_bxdf_sample(brdf, rand_canonic(), rand_canonic(), wo, N, wi, &pdf); + R = ssf_bxdf_sample(brdf, rng, wo, N, wi, &pdf); FOR_EACH(i, 0, NSTEPS) { - const double u = rand_canonic(); - const double v = rand_canonic(); - CHECK(eq_eps(ssf_bxdf_sample(brdf, u, v, wo, N, wi, &pdf), R, 1.e-6), 1); + CHECK(eq_eps(ssf_bxdf_sample(brdf, rng, wo, N, wi, &pdf), R, 1.e-6), 1); } CHECK(ssf_bxdf_ref_put(brdf), RES_OK); CHECK(ssf_bxdf_ref_put(dummy), RES_OK); CHECK(ssf_fresnel_ref_put(fresnel), RES_OK); + CHECK(ssp_rng_ref_put(rng), RES_OK); check_memory_allocator(&allocator); mem_shutdown_proxy_allocator(&allocator); diff --git a/src/test_ssf_utils.h b/src/test_ssf_utils.h @@ -19,6 +19,9 @@ #include <rsys/double33.h> #include <rsys/math.h> #include <rsys/mem_allocator.h> + +#include <star/ssp.h> + #include <stdio.h> /******************************************************************************* @@ -40,14 +43,13 @@ bxdf_dummy_release(void* bxdf) static double bxdf_dummy_sample (void* bxdf, - const double u, - const double v, + struct ssp_rng* rng, const double w[3], const double N[3], double dir[3], double* pdf) { - (void)bxdf, (void)u, (void)v, (void)w, (void)N, (void)dir, (void)pdf; + (void)bxdf, (void)rng, (void)w, (void)N, (void)dir, (void)pdf; return 0.0; } @@ -133,14 +135,13 @@ microfacet_dummy_release(void* distrib) static void microfacet_dummy_sample (void* distrib, - const double u, - const double v, + struct ssp_rng* rng, const double w[3], const double N[3], double dir[3], double* pdf) { - (void)distrib, (void)u, (void)v, (void)w, (void)N, (void)dir, (void)pdf; + (void)distrib, (void)rng, (void)w, (void)N, (void)dir, (void)pdf; } static double @@ -177,69 +178,29 @@ static const struct ssf_microfacet_distribution_type microfacet_dummy = { /******************************************************************************* * Miscellaneous functions ******************************************************************************/ -static INLINE double -rand_canonic(void) -{ - return (double)rand()/(double)RAND_MAX; -} - -static INLINE double* -ran_hemisphere_cos - (const double N[3], - double dir[3], - double *pdf) -{ - const double u = rand_canonic(); - const double v = rand_canonic(); - const double phi = 2.0 * PI * u; - const double cos_theta = sqrt(v); - const double sin_theta = sqrt(1.0 - v); - double basis[9]; - double tmp[3]; - tmp[0] = cos(phi) * sin_theta; - tmp[1] = sin(phi) * sin_theta; - tmp[2] = cos_theta; - d33_muld3(dir, d33_basis(basis, N), tmp); - if(pdf) *pdf = cos_theta / PI; - return dir; -} - -static INLINE double* -ran_hemisphere(const double N[3], double dir[3], double *pdf) -{ - const double u = rand_canonic(); - const double v = rand_canonic(); - const double phi = 2.0 * PI * u; - const double cos_theta = v; - const double sin_theta = cos2sin(cos_theta); - double basis[9]; - double tmp[3]; - tmp[0] = cos(phi) * sin_theta; - tmp[1] = sin(phi) * sin_theta; - tmp[2] = cos_theta; - d33_muld3(dir, d33_basis(basis, N), tmp); - if(pdf) *pdf = 1/(2*PI); - return dir; -} - static INLINE void check_microfacet_distribution - (struct ssf_microfacet_distribution* distrib) + (struct ssf_microfacet_distribution* distrib, + struct ssp_rng* rng) { double N[3]; + float Nf[3]; const size_t NSTEPS = 10000; size_t i; size_t n; double wo[3]; + float sample[4]; double E, V, SE; double sum, sum2; - N[0] = rand_canonic()*2 - 1; - N[1] = rand_canonic()*2 - 1; - N[2] = rand_canonic()*2 - 1; + N[0] = ssp_rng_uniform_double(rng, -1, 1); + N[1] = ssp_rng_uniform_double(rng, -1, 1); + N[2] = ssp_rng_uniform_double(rng, -1, 1); d3_normalize(N, N); - ran_hemisphere(N, wo, NULL); + f3_set_d3(Nf, N); + ssp_ran_hemisphere_uniform(rng, Nf, sample); + d3_set_f3(wo, sample); /* Check that D(wh) is normalized wrt \int_{2PI} D(wh) |wh.n| dwh */ sum = sum2 = 0; @@ -247,7 +208,9 @@ check_microfacet_distribution do { FOR_EACH(i, 0, NSTEPS) { double wh[3], pdf, D, weight; - ran_hemisphere_cos(N, wh, &pdf); + ssp_ran_hemisphere_cos(rng, Nf, sample); + d3_set_f3(wh, sample); + pdf = sample[3]; D = ssf_microfacet_distribution_eval(distrib, wo, N, wh); weight = D * d3_dot(wh, N) / pdf; sum += weight; @@ -262,11 +225,9 @@ check_microfacet_distribution /* Check the sampling of a direction wh and the returned pdf */ FOR_EACH(i, 0, NSTEPS) { - const double u = rand_canonic(); - const double v = rand_canonic(); double wh[3], pdf, D, weight; - ssf_microfacet_distribution_sample(distrib, u, v, wo, N, wh, &pdf); + ssf_microfacet_distribution_sample(distrib, rng, wo, N, wh, &pdf); D = ssf_microfacet_distribution_eval(distrib, wo, N, wh); weight = D * d3_dot(wh, N) / pdf; sum += weight;