commit 8cb11ef86de32190de430a0337b5d4304383b386
parent 632fda2019338e3f0eb05624ab46c1b60fb377d7
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Tue, 21 Nov 2017 09:41:47 +0100
Upd the microfacet distribution API and fix the Blinn distribution
Remove the useless 'wo' parameter, i.e. the outgoing direction, from the
microfacet distribution API.
Diffstat:
7 files changed, 47 insertions(+), 96 deletions(-)
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_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_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,7 +189,6 @@ check_microfacet_distribution
const size_t NSTEPS = 10000;
size_t i;
size_t n;
- double wo[3];
double sample[4];
double E, V, SE;
double sum, sum2;
@@ -202,9 +198,6 @@ 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;
@@ -214,7 +207,7 @@ check_microfacet_distribution
ssp_ran_hemisphere_cos(rng, N, sample);
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 +223,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