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 ac0f8e53ea90b6858ab255fd21f78974869fa039
parent be607dad622a0d4b73796b88e70d635415808640
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date:   Tue, 21 Nov 2017 14:45:54 +0100

Merge branch 'release_0.4'

Diffstat:
MREADME.md | 7+++++++
Mcmake/CMakeLists.txt | 6+++---
Msrc/ssf.h | 8+-------
Msrc/ssf_beckmann_distribution.c | 18+++++++-----------
Msrc/ssf_blinn_distribution.c | 33+++++++++++----------------------
Msrc/ssf_lambertian_reflection.c | 5++---
Msrc/ssf_microfacet_distribution.c | 21+++++++++------------
Msrc/ssf_microfacet_reflection.c | 14+++++++-------
Msrc/test_ssf_microfacet_distribution.c | 22+++++-----------------
Msrc/test_ssf_microfacet_reflection.c | 8++++----
Msrc/test_ssf_utils.h | 32+++++++++-----------------------
11 files changed, 65 insertions(+), 109 deletions(-)

diff --git a/README.md b/README.md @@ -26,6 +26,13 @@ project from the `cmake/CMakeLists.txt` file by appending to the ## Release notes +### Version 0.4 + +- Fix the Blinn distribution. +- Change the microfacet distribution API to no longer require the unused + outgoing direction parameter. +- Use and require Star-SamPling version 0.5. + ### Version 0.3 - A BSDF is no more a composition of BxDFs: the caller writes directly the diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -26,7 +26,7 @@ set(SSF_SOURCE_DIR ${PROJECT_SOURCE_DIR}/../src) ################################################################################ find_package(RCMake REQUIRED) find_package(RSys 0.4 REQUIRED) -find_package(StarSP 0.3 REQUIRED) +find_package(StarSP 0.5 REQUIRED) include_directories(${RSys_INCLUDE_DIR} ${StarSP_INCLUDE_DIR}) set(CMAKE_MODULE_PATH ${RCMAKE_SOURCE_DIR}) @@ -39,7 +39,7 @@ rcmake_append_runtime_dirs(_runtime_dirs RSys StarSP) # Define targets ################################################################################ set(VERSION_MAJOR 0) -set(VERSION_MINOR 3) +set(VERSION_MINOR 4) set(VERSION_PATCH 0) set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}) @@ -75,7 +75,7 @@ if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_GNUCC) endif() if(BUILD_STATIC) - add_library(ssf STATIC ${SSF_FILES_INC} ${SSF_FILES_SRC}) + add_library(ssf STATIC ${SSF_FILES_INC} ${SSF_FILES_SRC} ${SSF_FILES_INC_API}) set_target_properties(ssf PROPERTIES COMPILE_DEFINITIONS SSF_STATIC_BUILD) else() add_library(ssf SHARED ${SSF_FILES_INC} ${SSF_FILES_SRC}) diff --git a/src/ssf.h b/src/ssf.h @@ -124,22 +124,19 @@ struct ssf_microfacet_distribution_type { (*sample) (void* distrib, 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 */ - double* pdf); /* PDF to sample wh wrt to wo */ + double* pdf); /* PDF to sample wh */ double (*eval) (void* distrib, - const double wo[3], /* Normalized outgoing direction */ const double N[3], /* Normalized Z-direction of the distribution */ const double wh[3]); /* Normalized half vector */ double (*pdf) (void* distrib, - const double wo[3], /* Normalized outgoing direction */ const double N[3], /* Normalized Z-direction of the distribution */ const double wh[3]); /* Normalized half vector */ @@ -413,7 +410,6 @@ ssf_microfacet_distribution_ref_put SSF_API double ssf_microfacet_distribution_eval (struct ssf_microfacet_distribution* distrib, - const double wo[3], /* Normalized outgoing direction */ const double N[3], /* Normalized Z-direction of the distribution */ const double wh[3]); /* Normalized half vector */ @@ -421,7 +417,6 @@ SSF_API void ssf_microfacet_distribution_sample (struct ssf_microfacet_distribution* distrib, 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 */ double* pdf); /* PDF of the sampled half vector */ @@ -429,7 +424,6 @@ ssf_microfacet_distribution_sample SSF_API double ssf_microfacet_distribution_pdf (struct ssf_microfacet_distribution* distrib, - const double wo[3], /* Normalized outgoing direction */ const double N[3], /* Normalized Z-direction of the distribution */ const double wh[3]); /* Normalized half vector */ diff --git a/src/ssf_beckmann_distribution.c b/src/ssf_beckmann_distribution.c @@ -43,15 +43,14 @@ beckmann_distribution_release(void* distrib) static double beckmann_distribution_eval - (void* distrib, const double wo[3], const double N[3], const double wh[3]) + (void* distrib, const double N[3], const double wh[3]) { struct beckmann_distribution* beckmann = distrib; double cos_wh_N, cos2_wh_N, sin2_wh_N, cos4_wh_N; double m2; - ASSERT(distrib && wo && N && wh); - ASSERT(d3_is_normalized(wo) && d3_is_normalized(N) && d3_is_normalized(wh)); + ASSERT(distrib && N && wh); + ASSERT(d3_is_normalized(N) && d3_is_normalized(wh)); ASSERT(beckmann->roughness > 0); - (void)wo; m2 = beckmann->roughness * beckmann->roughness; cos_wh_N = d3_dot(wh, N); cos2_wh_N = cos_wh_N * cos_wh_N; @@ -64,7 +63,6 @@ static void beckmann_distribution_sample (void* distrib, struct ssp_rng* rng, - const double wo[3], const double N[3], double wh[3], double* pdf) @@ -79,9 +77,8 @@ beckmann_distribution_sample double cos_theta, sin_theta; double cos2_theta, sin2_theta; double u, v; - ASSERT(rng && wh && N && wo); - ASSERT(d3_is_normalized(wo) && d3_is_normalized(N)); - (void)wo; + ASSERT(rng && wh && N); + ASSERT(d3_is_normalized(N)); u = ssp_rng_canonical(rng); v = ssp_rng_canonical(rng); @@ -104,14 +101,13 @@ beckmann_distribution_sample static double beckmann_distribution_pdf - (void* distrib, const double wo[3], const double N[3], const double wh[3]) + (void* distrib, const double N[3], const double wh[3]) { struct beckmann_distribution* beckmann = distrib; double cos_wh_N, cos2_wh_N, sin2_wh_N; double m2; - ASSERT(distrib && wo && N && wh); + ASSERT(distrib && N && wh); ASSERT(d3_is_normalized(wh) && d3_is_normalized(N)); - (void)wo; cos_wh_N = d3_dot(wh, N); if(cos_wh_N < 0.0) return 0.0; m2 = beckmann->roughness * beckmann->roughness; diff --git a/src/ssf_blinn_distribution.c b/src/ssf_blinn_distribution.c @@ -42,16 +42,14 @@ blinn_distribution_release(void* distrib) { (void)distrib; } static double -blinn_distribution_eval - (void* distrib, const double wo[3], const double N[3], const double wh[3]) +blinn_distribution_eval(void* distrib, const double N[3], const double wh[3]) { struct blinn_distribution* blinn = distrib; double cos_wh_N; - ASSERT(distrib && wo && N && wh); - ASSERT(d3_is_normalized(wo) && d3_is_normalized(N) && d3_is_normalized(wh)); + ASSERT(distrib && N && wh); + ASSERT(d3_is_normalized(N) && d3_is_normalized(wh)); ASSERT(blinn->exponent >= 0.0); ASSERT(blinn->exponent <= SSF_BLINN_DISTRIBUTION_MAX_EXPONENT); - (void)wo; cos_wh_N = d3_dot(wh, N); return (blinn->exponent + 2) / (2*PI) * pow(cos_wh_N, blinn->exponent); } @@ -60,7 +58,6 @@ static void blinn_distribution_sample (void* distrib, struct ssp_rng* rng, - const double wo[3], const double N[3], double wh[3], double* pdf) @@ -69,11 +66,10 @@ blinn_distribution_sample double basis[9]; double dir[3]; double cos_theta, sin_theta; - double cos_wh_wo; double phi; double u, v; - ASSERT(distrib && rng && wo && N && wh && pdf); - ASSERT(d3_is_normalized(wo) && d3_is_normalized(N)); + ASSERT(distrib && rng && N && wh && pdf); + ASSERT(d3_is_normalized(N)); u = ssp_rng_canonical(rng); v = ssp_rng_canonical(rng); @@ -86,26 +82,19 @@ blinn_distribution_sample dir[2] = cos_theta; d33_muld3(dir, d33_basis(basis, N), dir); - cos_wh_wo = d3_dot(dir, wo); - *pdf = cos_wh_wo > 0 - ? (blinn->exponent+1)*pow(cos_theta, blinn->exponent) / (2*PI*4*cos_wh_wo) - : 0; + *pdf = (blinn->exponent+2)/(2*PI)*pow(cos_theta, blinn->exponent+1); d3_set(wh, dir); } static double -blinn_distribution_pdf - (void* distrib, const double wo[3], const double N[3], const double wh[3]) +blinn_distribution_pdf(void* distrib, const double N[3], const double wh[3]) { struct blinn_distribution* blinn = distrib; - double cos_wh_N, cos_wh_wo; - ASSERT(distrib && wo && N && wh); - ASSERT(d3_is_normalized(wo) && d3_is_normalized(N) && d3_is_normalized(wh)); - cos_wh_wo = d3_dot(wo, wh); - if(cos_wh_wo <= 0) return 0.0; + double cos_wh_N; + ASSERT(distrib && N && wh); + ASSERT(d3_is_normalized(N) && d3_is_normalized(wh)); cos_wh_N = fabs(d3_dot(wh, N)); - return - ((blinn->exponent+1)*pow(cos_wh_N, blinn->exponent)) / (2*PI*4*cos_wh_wo); + return (blinn->exponent+2)/(2*PI)*pow(cos_wh_N, blinn->exponent+1); } /******************************************************************************* diff --git a/src/ssf_lambertian_reflection.c b/src/ssf_lambertian_reflection.c @@ -63,14 +63,13 @@ lambertian_reflection_sample int* type, double* pdf) { - double sample[4]; + double sample[3]; ASSERT(data && rng && wo && N && wi && type && pdf); ASSERT(d3_is_normalized(wo) && d3_is_normalized(N) && d3_dot(wo, N) > 0); (void)wo; - ssp_ran_hemisphere_cos(rng, N, sample); + ssp_ran_hemisphere_cos(rng, N, sample, pdf); d3_set(wi, sample); - *pdf = sample[3]; *type = SSF_REFLECTION | SSF_DIFFUSE; return ((struct lambertian_reflection*)data)->reflectivity; } diff --git a/src/ssf_microfacet_distribution.c b/src/ssf_microfacet_distribution.c @@ -122,38 +122,35 @@ void ssf_microfacet_distribution_sample (struct ssf_microfacet_distribution* distrib, struct ssp_rng* rng, - const double wo[3], const double N[3], double wh[3], double* pdf) { - ASSERT(distrib && rng && wo && N && wh && pdf); - ASSERT(d3_is_normalized(wo) && d3_is_normalized(N)); - distrib->type.sample(distrib->data, rng, wo, N, wh, pdf); + ASSERT(distrib && rng && N && wh && pdf); + ASSERT(d3_is_normalized(N)); + distrib->type.sample(distrib->data, rng, N, wh, pdf); } double ssf_microfacet_distribution_eval (struct ssf_microfacet_distribution* distrib, - const double wo[3], const double N[3], const double wh[3]) { - ASSERT(distrib && wo && N && wh); - ASSERT(d3_is_normalized(wo) && d3_is_normalized(N) && d3_is_normalized(wh)); - return distrib->type.eval(distrib->data, wo, N, wh); + ASSERT(distrib && N && wh); + ASSERT(d3_is_normalized(N) && d3_is_normalized(wh)); + return distrib->type.eval(distrib->data, N, wh); } double ssf_microfacet_distribution_pdf (struct ssf_microfacet_distribution* distrib, - const double wo[3], const double N[3], const double wh[3]) { - ASSERT(distrib && wh && wo); - ASSERT(d3_is_normalized(wo) && d3_is_normalized(N) && d3_is_normalized(wh)); - return distrib->type.pdf(distrib->data, wo, N, wh); + ASSERT(distrib && wh ); + ASSERT(d3_is_normalized(N) && d3_is_normalized(wh)); + return distrib->type.pdf(distrib->data, N, wh); } res_T diff --git a/src/ssf_microfacet_reflection.c b/src/ssf_microfacet_reflection.c @@ -71,7 +71,7 @@ microfacet_reflection_eval cos_wh_wo = cos_wh_wi; F = ssf_fresnel_eval(bsdf->fresnel, cos_wh_wi); - D = ssf_microfacet_distribution_eval(bsdf->distrib, wo, N, wh); + D = ssf_microfacet_distribution_eval(bsdf->distrib, N, wh); /* Cook Torrance geometry term */ G = MMIN((2*cos_wh_N*cos_wo_N)/cos_wh_wo, (2*cos_wh_N*cos_wi_N)/cos_wh_wo); G = MMIN(1, G); @@ -98,9 +98,9 @@ microfacet_reflection_sample ASSERT(d3_is_normalized(wo) && d3_is_normalized(N) && d3_dot(wo, N) > 0); ASSERT(bsdf->distrib && bsdf->fresnel); - ssf_microfacet_distribution_sample(bsdf->distrib, rng, wo, N, wh, &pdf_wh); + ssf_microfacet_distribution_sample(bsdf->distrib, rng, N, wh, &pdf_wh); reflect(dir, wo, wh); - *pdf = pdf_wh / (4.0*fabs(d3_dot(wo, wh))); + *pdf = pdf_wh / (4.0*fabs(d3_dot(wo, N))); *type = SSF_REFLECTION | SSF_GLOSSY; R = d3_dot(dir, N) > 0 ? ssf_fresnel_eval(bsdf->fresnel, d3_dot(dir, wh)) : 0; d3_set(wi, dir); @@ -119,8 +119,8 @@ microfacet_reflection_pdf ASSERT(d3_dot(wo, N) > 0 && d3_dot(wi, N) > 0); ASSERT(bsdf->distrib); d3_normalize(wh, d3_add(wh, wi, wo)); - pdf_wh = ssf_microfacet_distribution_pdf(bsdf->distrib, wo, N, wh); - return pdf_wh / (4.0*fabs(d3_dot(wo, wh))); + pdf_wh = ssf_microfacet_distribution_pdf(bsdf->distrib, N, wh); + return pdf_wh / (4.0*fabs(d3_dot(wo, N))); } /******************************************************************************* @@ -146,7 +146,7 @@ microfacet2_reflection_sample ASSERT(bsdf->distrib); do { /* Sample a micro facet that front faces 'wo' */ - ssf_microfacet_distribution_sample(bsdf->distrib, rng, wo, N, wh, &p); + ssf_microfacet_distribution_sample(bsdf->distrib, rng, N, wh, &p); } while(d3_dot(wo, wh) <= 0); reflect(dir, wo, wh); @@ -160,7 +160,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(bsdf->distrib, rng, dir, N, wh, &p); + ssf_microfacet_distribution_sample(bsdf->distrib, rng, N, wh, &p); } while(d3_dot(dir, wh) <= 0); reflect(dir, dir, wh); } diff --git a/src/test_ssf_microfacet_distribution.c b/src/test_ssf_microfacet_distribution.c @@ -24,7 +24,6 @@ struct ALIGN(64) ufacet { uint32_t id; struct ssp_rng* rng; double wh[3]; - double wo[3]; double N[3]; double pdf; double value; @@ -53,19 +52,16 @@ static void ufacet_sample (void* distrib, struct ssp_rng* rng, - const double wo[3], const double N[3], double wh[3], double* pdf) { struct ufacet* ufacet = distrib; NCHECK(ufacet, NULL); - NCHECK(wo, NULL); NCHECK(N, NULL); NCHECK(wh, NULL); NCHECK(pdf, NULL); 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)); *pdf = ufacet->pdf; @@ -74,16 +70,13 @@ ufacet_sample static double ufacet_eval (void* distrib, - const double wo[3], const double N[3], const double wh[3]) { struct ufacet* ufacet = distrib; NCHECK(distrib, NULL); - NCHECK(wo, NULL); NCHECK(N, NULL); NCHECK(wh, NULL); - CHECK(d3_eq(ufacet->wo, wo), 1); CHECK(d3_eq(ufacet->wh, wh), 1); CHECK(d3_eq(ufacet->N, N), 1); return ufacet->value; @@ -92,15 +85,12 @@ ufacet_eval static double ufacet_pdf (void* distrib, - const double wo[3], const double N[3], const double wh[3]) { struct ufacet* ufacet = distrib; - NCHECK(wo, NULL); NCHECK(N, NULL); NCHECK(wh, NULL); - CHECK(d3_eq(ufacet->wo, wo), 1); CHECK(d3_eq(ufacet->wh, wh), 1); CHECK(d3_eq(ufacet->N, N), 1); return ufacet->pdf; @@ -115,7 +105,7 @@ main(int argc, char** argv) SSF_MICROFACET_DISTRIBUTION_TYPE_NULL; struct ssf_microfacet_distribution* distrib; struct ssp_rng* rng; - double wo[3], N[3], wh[3], pdf; + double N[3], wh[3], pdf; (void)argc, (void)argv; mem_init_proxy_allocator(&allocator, &mem_default_allocator); @@ -182,24 +172,22 @@ main(int argc, char** argv) CHECK(ssf_microfacet_distribution_get_data(distrib, (void**)&data), RES_OK); CHECK(data->id, 0xDECAFBAD); - d3_normalize(wo, d3(wo, -1, -1, 0)); d3(N, 0.0, 1.0, 0.0); - d3_set(data->wo, wo); d3_set(data->N, N); d3_normalize(data->wh, d3(data->wh, 1, 2, 3)); data->rng = rng; data->pdf = 0.1234; data->value = 0.43; - ssf_microfacet_distribution_sample(distrib, rng, wo, N, wh, &pdf); + ssf_microfacet_distribution_sample(distrib, rng, N, wh, &pdf); CHECK(d3_eq(wh, data->wh), 1); CHECK(pdf, data->pdf); - ssf_microfacet_distribution_sample(distrib, rng, wo, N, wh, &pdf); + ssf_microfacet_distribution_sample(distrib, rng, N, wh, &pdf); CHECK(d3_eq(wh, data->wh), 1); CHECK(pdf, data->pdf); - CHECK(ssf_microfacet_distribution_eval(distrib, wo, N, wh), data->value); - CHECK(ssf_microfacet_distribution_pdf(distrib, wo, N, wh), data->pdf); + CHECK(ssf_microfacet_distribution_eval(distrib, N, wh), data->value); + CHECK(ssf_microfacet_distribution_pdf(distrib, N, wh), data->pdf); CHECK(ssf_microfacet_distribution_ref_put(distrib), RES_OK); CHECK(ufacet_is_init, 0); diff --git a/src/test_ssf_microfacet_reflection.c b/src/test_ssf_microfacet_reflection.c @@ -28,8 +28,8 @@ main(int argc, char** argv) struct ssf_fresnel* F; struct ssf_microfacet_distribution* D; struct ssp_rng* rng; - double N[4]; /* xyz, pdf */ - double wo[4]; /* xyz, pdf */ + double N[3]; + double wo[3]; size_t i, NSTEPS=100000; (void)argc, (void)argv; @@ -53,8 +53,8 @@ main(int argc, char** argv) CHECK(ssf_microfacet_reflection_setup(bsdf, F, D), RES_OK); /* Check energy conservation */ - ssp_ran_sphere_uniform(rng, N); - ssp_ran_hemisphere_cos(rng, N, wo); + ssp_ran_sphere_uniform(rng, N, NULL); + ssp_ran_hemisphere_cos(rng, N, wo, NULL); FOR_EACH(i, 0, NSTEPS) { double wi[3], pdf; int type; diff --git a/src/test_ssf_utils.h b/src/test_ssf_utils.h @@ -141,33 +141,30 @@ static void microfacet_dummy_sample (void* distrib, struct ssp_rng* rng, - const double w[3], const double N[3], double dir[3], double* pdf) { - (void)distrib, (void)rng, (void)w, (void)N, (void)dir, (void)pdf; + (void)distrib, (void)rng, (void)N, (void)dir, (void)pdf; } static double microfacet_dummy_eval (void* distrib, - const double wo[3], const double N[3], const double wi[3]) { - (void)distrib, (void)wo, (void)N, (void)wi; + (void)distrib, (void)N, (void)wi; return 0.0; } static double microfacet_dummy_pdf (void* distrib, - const double wo[3], const double N[3], const double wi[3]) { - (void)distrib, (void)wo, (void)N, (void)wi; + (void)distrib, (void)N, (void)wi; return 0.0; } @@ -192,8 +189,7 @@ check_microfacet_distribution const size_t NSTEPS = 10000; size_t i; size_t n; - double wo[3]; - double sample[4]; + double sample[3]; double E, V, SE; double sum, sum2; @@ -202,19 +198,15 @@ check_microfacet_distribution N[2] = ssp_rng_uniform_double(rng, -1, 1); d3_normalize(N, N); - ssp_ran_hemisphere_uniform(rng, N, sample); - d3_set(wo, sample); - /* Check that D(wh) is normalized wrt \int_{2PI} D(wh) |wh.n| dwh */ sum = sum2 = 0; n = 0; do { FOR_EACH(i, 0, NSTEPS) { double wh[3], pdf, D, weight; - ssp_ran_hemisphere_cos(rng, N, sample); + ssp_ran_hemisphere_cos(rng, N, sample, &pdf); d3_set(wh, sample); - pdf = sample[3]; - D = ssf_microfacet_distribution_eval(distrib, wo, N, wh); + D = ssf_microfacet_distribution_eval(distrib, N, wh); weight = D * d3_dot(wh, N) / pdf; sum += weight; sum2 += weight*weight; @@ -230,17 +222,11 @@ check_microfacet_distribution FOR_EACH(i, 0, NSTEPS) { double wh[3], pdf, D, weight; - ssf_microfacet_distribution_sample(distrib, rng, wo, N, wh, &pdf); - D = ssf_microfacet_distribution_eval(distrib, wo, N, wh); + ssf_microfacet_distribution_sample(distrib, rng, N, wh, &pdf); + D = ssf_microfacet_distribution_eval(distrib, N, wh); weight = D * d3_dot(wh, N) / pdf; - sum += weight; - sum2 += weight*weight; + CHECK(eq_eps(weight, 1.0, 1.e-6), 1); } - n += NSTEPS; - E = sum / (double)n; - V = MMAX(sum2 / (double)n - E*E, 0); - SE = sqrt(V/(double)n); - CHECK(eq_eps(E, 1.0, 3*SE), 1); } static INLINE void