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:
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