commit 9b919713346e6a2127253bbcb398e32c221b9d72
parent 30af9168b267eff27759f7f8ec7dde91e11f8a39
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Mon, 26 Sep 2016 10:41:51 +0200
Add Fresnel to the specular BRDF and add the normal to the rho functions
Diffstat:
10 files changed, 117 insertions(+), 51 deletions(-)
diff --git a/src/ssf.h b/src/ssf.h
@@ -83,7 +83,8 @@ struct ssf_bxdf_type {
double
(*rho)
(void* bxdf,
- const double wo[3]);
+ const double wo[3], /* Normalized outgoing direction */
+ const double N[3]); /* Normalized surface normal */
size_t sizeof_bxdf; /* In Bytes */
size_t alignof_bxdf; /* In Bytes */
@@ -220,7 +221,8 @@ ssf_bsdf_pdf
SSF_API double /* \int_{2\pi} BSDF(wi, wo) |wi.N| dwi */
ssf_bsdf_rho
(struct ssf_bsdf* bsdf,
- const double wo[3]);
+ const double wo[3],
+ const double N[3]);
/*******************************************************************************
* BxDF API - Bidirectional <Reflectance|Transmittance> distribution function.
@@ -269,7 +271,8 @@ ssf_bxdf_pdf
SSF_API double /* \int_{2\pi} BxDF(wi, wo) |wi.N| dwi */
ssf_bxdf_rho
(struct ssf_bxdf* bxdf,
- const double wo[3]);
+ const double wo[3],
+ const double N[3]);
/* Retrieve the internal data of the BxDF. Usefull for user defined BxDFs on
* which the caller has to retrieve their data to setup their parameters */
@@ -281,7 +284,8 @@ ssf_bxdf_get_data
SSF_API res_T
ssf_specular_reflection_setup
(struct ssf_bxdf* bxdf,
- const double reflectivity);
+ const double reflectivity,
+ struct ssf_fresnel* fresnel);
SSF_API res_T
ssf_lambertian_reflection_setup
diff --git a/src/ssf_bsdf.c b/src/ssf_bsdf.c
@@ -174,7 +174,7 @@ ssf_bsdf_sample
* rho the overall rho of the BSDF */
rho = 0;
FOR_EACH(i, 0, bsdf->nbxdfs) {
- probas[i] = bsdf->weights[i] * ssf_bxdf_rho(bsdf->bxdfs[i], wo);
+ probas[i] = bsdf->weights[i] * ssf_bxdf_rho(bsdf->bxdfs[i], wo, N);
rho += probas[i];
}
cumul[0] = (probas[0] /= rho);
@@ -226,7 +226,7 @@ ssf_bsdf_pdf
ASSERT(bsdf);
bsdf_normalize_weights(bsdf);
FOR_EACH(i, 0, bsdf->nbxdfs) {
- const double tmp = bsdf->weights[i] * ssf_bxdf_rho(bsdf->bxdfs[i], wo);
+ const double tmp = bsdf->weights[i] * ssf_bxdf_rho(bsdf->bxdfs[i], wo, N);
pdf += ssf_bxdf_pdf(bsdf->bxdfs[i], wo, N, wi) * tmp;
rho += tmp;
}
@@ -254,14 +254,15 @@ ssf_bsdf_eval
double
ssf_bsdf_rho
(struct ssf_bsdf* bsdf,
- const double wo[3])
+ const double wo[3],
+ const double N[3])
{
double rho = 0;
size_t i;
ASSERT(bsdf);
bsdf_normalize_weights(bsdf);
FOR_EACH(i, 0, bsdf->nbxdfs) {
- rho += bsdf->weights[i] * ssf_bxdf_rho(bsdf->bxdfs[i], wo);
+ rho += bsdf->weights[i] * ssf_bxdf_rho(bsdf->bxdfs[i], wo, N);
}
return rho;
}
diff --git a/src/ssf_bxdf.c b/src/ssf_bxdf.c
@@ -154,10 +154,10 @@ ssf_bxdf_pdf
}
double
-ssf_bxdf_rho(struct ssf_bxdf* bxdf, const double wo[3])
+ssf_bxdf_rho(struct ssf_bxdf* bxdf, const double wo[3], const double N[3])
{
- ASSERT(bxdf && wo && d3_is_normalized(wo));
- return bxdf->type.rho(bxdf->data, wo);
+ ASSERT(bxdf && wo && d3_is_normalized(wo) && d3_is_normalized(N));
+ return bxdf->type.rho(bxdf->data, wo, N);
}
res_T
diff --git a/src/ssf_lambertian_reflection.c b/src/ssf_lambertian_reflection.c
@@ -94,10 +94,10 @@ lambertian_reflection_pdf
}
static double
-lambertian_reflection_rho(void* data, const double wo[3])
+lambertian_reflection_rho(void* data, const double wo[3], const double N[3])
{
- ASSERT(data && wo);
- (void)wo;
+ ASSERT(data && wo && N);
+ (void)wo, (void)N;
return ((struct lambertian_reflection*)data)->reflectivity;
}
diff --git a/src/ssf_microfacet_reflection.c b/src/ssf_microfacet_reflection.c
@@ -125,10 +125,10 @@ microfacet_reflection_pdf
}
static FINLINE double
-microfacet_reflection_rho(void* data, const double wo[3])
+microfacet_reflection_rho(void* data, const double wo[3], const double N[3])
{
- ASSERT(data && wo);
- (void)data, (void)wo;
+ ASSERT(data && wo && N);
+ (void)data, (void)wo, (void)N;
return 0; /* TODO */
}
@@ -159,12 +159,19 @@ ssf_microfacet_reflection_setup
if(!BXDF_TYPE_EQ(&bxdf->type, &ssf_microfacet_reflection))
return RES_BAD_ARG;
- SSF(fresnel_ref_get(fresnel));
- SSF(microfacet_distribution_ref_get(distrib));
microfacet = bxdf->data;
microfacet->reflectivity = reflectivity;
- microfacet->fresnel = fresnel;
- microfacet->distrib = distrib;
+
+ if(microfacet->fresnel != fresnel) {
+ if(microfacet->fresnel) SSF(fresnel_ref_put(fresnel));
+ SSF(fresnel_ref_get(fresnel));
+ microfacet->fresnel = fresnel;
+ }
+ if(microfacet->distrib != distrib) {
+ if(microfacet->distrib) SSF(microfacet_distribution_ref_put(distrib));
+ SSF(microfacet_distribution_ref_get(distrib));
+ microfacet->distrib = distrib;
+ }
return RES_OK;
}
diff --git a/src/ssf_specular_reflection.c b/src/ssf_specular_reflection.c
@@ -21,6 +21,7 @@
struct specular_reflection {
double reflectivity;
+ struct ssf_fresnel* fresnel;
};
/*******************************************************************************
@@ -37,7 +38,11 @@ specular_reflection_init(struct mem_allocator* allocator, void* bxdf)
static void
specular_reflection_release(void* bxdf)
-{ (void)bxdf; }
+{
+ struct specular_reflection* spec = bxdf;
+ ASSERT(spec);
+ if(spec->fresnel) SSF(fresnel_ref_put(spec->fresnel));
+}
static double
specular_reflection_sample
@@ -51,6 +56,7 @@ 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(d3_is_normalized(wo) && d3_is_normalized(N));
(void)u, (void)v;
@@ -59,9 +65,11 @@ specular_reflection_sample
reflect(wi, wo, N);
*pdf = 1.0; /* pdf */
- cos_wo_N = d3_dot(wo, N);
+ cos_wi_N = cos_wo_N = d3_dot(wo, N);
/* TODO check this */
- return cos_wo_N <= 0 ? 0 : brdf->reflectivity / cos_wo_N/*|wi.N|*/;
+ return cos_wo_N > 0
+ ? ssf_fresnel_eval(brdf->fresnel, cos_wi_N) * brdf->reflectivity / cos_wi_N
+ : 0;
}
static double
@@ -81,11 +89,11 @@ specular_reflection_pdf
}
static double
-specular_reflection_rho(void* data, const double wo[3])
+specular_reflection_rho(void* data, const double wo[3], const double N[3])
{
- ASSERT(data && wo);
- (void)wo;
- return ((struct specular_reflection*)data)->reflectivity;
+ struct specular_reflection* brdf = data;
+ ASSERT(data && wo && N && d3_is_normalized(wo) && d3_is_normalized(N));
+ return ssf_fresnel_eval(brdf->fresnel, d3_dot(wo, N)) * brdf->reflectivity;
}
/*******************************************************************************
@@ -103,11 +111,25 @@ const struct ssf_bxdf_type ssf_specular_reflection = {
};
res_T
-ssf_specular_reflection_setup(struct ssf_bxdf* bxdf, const double reflectivity)
+ssf_specular_reflection_setup
+ (struct ssf_bxdf* bxdf,
+ const double reflectivity,
+ struct ssf_fresnel* fresnel)
{
- if(!bxdf || reflectivity < 0 || reflectivity > 1) return RES_BAD_ARG;
- if(!BXDF_TYPE_EQ(&bxdf->type, &ssf_specular_reflection)) return RES_BAD_ARG;
- ((struct specular_reflection*)bxdf->data)->reflectivity = reflectivity;
+ struct specular_reflection* spec;
+ if(!bxdf || reflectivity < 0 || reflectivity > 1 || !fresnel)
+ return RES_BAD_ARG;
+ if(!BXDF_TYPE_EQ(&bxdf->type, &ssf_specular_reflection))
+ return RES_BAD_ARG;
+
+ spec = bxdf->data;
+ spec->reflectivity = reflectivity;
+
+ if(spec->fresnel != fresnel) {
+ if(spec->fresnel) SSF(fresnel_ref_put(spec->fresnel));
+ SSF(fresnel_ref_get(fresnel));
+ spec->fresnel = fresnel;
+ }
return RES_OK;
}
diff --git a/src/test_ssf_bsdf.c b/src/test_ssf_bsdf.c
@@ -26,6 +26,7 @@ main(int argc, char** argv)
struct ssf_bsdf* bsdf;
struct ssf_bxdf* bxdf;
struct ssf_bxdf* bxdf2;
+ struct ssf_fresnel* fresnel;
double wo[3], wi[3], pdf;
double rho;
double N[3];
@@ -39,6 +40,7 @@ main(int argc, char** argv)
CHECK(ssf_bsdf_create(NULL, NULL), RES_BAD_ARG);
CHECK(ssf_bsdf_create(&allocator, NULL), RES_BAD_ARG);
CHECK(ssf_bsdf_create(NULL, &bsdf), RES_OK);
+ CHECK(ssf_fresnel_create(&allocator, &ssf_fresnel_no_op, &fresnel), RES_OK);
CHECK(ssf_bsdf_ref_get(NULL), RES_BAD_ARG);
CHECK(ssf_bsdf_ref_get(bsdf), RES_OK);
@@ -49,8 +51,8 @@ main(int argc, char** argv)
CHECK(ssf_bsdf_create(&allocator, &bsdf), RES_OK);
CHECK(ssf_bxdf_create(&allocator, &ssf_specular_reflection, &bxdf), RES_OK);
CHECK(ssf_bxdf_create(&allocator, &ssf_specular_reflection, &bxdf2), RES_OK);
- CHECK(ssf_specular_reflection_setup(bxdf, 0.123), RES_OK);
- CHECK(ssf_specular_reflection_setup(bxdf2, 0.6789), RES_OK);
+ CHECK(ssf_specular_reflection_setup(bxdf, 0.123, fresnel), RES_OK);
+ CHECK(ssf_specular_reflection_setup(bxdf2, 0.6789, fresnel), RES_OK);
CHECK(ssf_bsdf_add(NULL, NULL, -1.0), RES_BAD_ARG);
CHECK(ssf_bsdf_add(bsdf, NULL, -1.0), RES_BAD_ARG);
@@ -68,7 +70,7 @@ main(int argc, char** argv)
CHECK(ssf_bsdf_eval(bsdf, wo, N, wi), 0);
CHECK(ssf_bsdf_pdf(bsdf, wo, N, wi), 0);
- CHECK(ssf_specular_reflection_setup(bxdf, 0.1234), RES_OK);
+ CHECK(ssf_specular_reflection_setup(bxdf, 0.1234, fresnel), RES_OK);
R = ssf_bsdf_sample(bsdf, 0.5, 0.5, wo, N, wi, &pdf);
CHECK(eq_eps(R, 0.1234 / d3_dot(wi, N), 1.e-6), 1);
@@ -91,7 +93,7 @@ main(int argc, char** argv)
E = sum / (double)NSTEPS;
V = sqr_sum / (double)NSTEPS - E*E;
SE = sqrt(V / (double)NSTEPS);
- rho = ssf_bsdf_rho(bsdf, wo);
+ rho = ssf_bsdf_rho(bsdf, wo, N);
CHECK(eq_eps(rho, E, SE), 1);
CHECK(ssf_bsdf_clear(NULL), RES_BAD_ARG);
@@ -103,9 +105,11 @@ main(int argc, char** argv)
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_memory_allocator(&allocator);
mem_shutdown_proxy_allocator(&allocator);
CHECK(mem_allocated_size(), 0);
return 0;
}
+
diff --git a/src/test_ssf_bxdf.c b/src/test_ssf_bxdf.c
@@ -108,11 +108,12 @@ bxdf_pdf
}
static double
-bxdf_rho(void* bxdf, const double wo[3])
+bxdf_rho(void* bxdf, const double wo[3], const double N[3])
{
struct bxdf* BxDF = bxdf;
NCHECK(BxDF, NULL);
CHECK(d3_eq(BxDF->wo, wo), 1);
+ CHECK(d3_eq(BxDF->N, N), 1);
return BxDF->rho;
}
@@ -214,7 +215,7 @@ main(int argc, char** argv)
CHECK(ssf_bxdf_pdf(bxdf, wo, N, wi), data->pdf);
data->rho = 0.314;
- CHECK(ssf_bxdf_rho(bxdf, wo), data->rho);
+ CHECK(ssf_bxdf_rho(bxdf, wo, N), data->rho);
CHECK(bxdf_is_init, 1);
CHECK(ssf_bxdf_ref_put(bxdf), RES_OK);
diff --git a/src/test_ssf_specular_reflection.c b/src/test_ssf_specular_reflection.c
@@ -21,26 +21,37 @@
int
main(int argc, char** argv)
{
+ const size_t NSTEPS = 100000;
struct mem_allocator allocator;
struct ssf_bxdf* brdf;
struct ssf_bxdf* dummy;
+ struct ssf_fresnel* fresnel;
double wo[3], wi[3];
double N[3];
double pdf;
+ double rho;
double R;
+ size_t i;
(void)argc, (void)argv;
mem_init_proxy_allocator(&allocator, &mem_default_allocator);
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
+ (&allocator, &ssf_fresnel_dielectric_dielectric, &fresnel), RES_OK);
+ CHECK(ssf_fresnel_dielectric_dielectric_setup(fresnel, 0.7, 1), RES_OK);
- CHECK(ssf_specular_reflection_setup(NULL, -1.0), RES_BAD_ARG);
- CHECK(ssf_specular_reflection_setup(brdf, -1.0), RES_BAD_ARG);
- CHECK(ssf_specular_reflection_setup(NULL, 1.0), RES_BAD_ARG);
- CHECK(ssf_specular_reflection_setup(brdf, 1.0), RES_OK);
- CHECK(ssf_specular_reflection_setup(brdf, 0.0), RES_OK);
- CHECK(ssf_specular_reflection_setup(brdf, 1.1), RES_BAD_ARG);
- CHECK(ssf_specular_reflection_setup(dummy, 0.0), RES_BAD_ARG);
+ CHECK(ssf_specular_reflection_setup(NULL, -1.0, NULL), RES_BAD_ARG);
+ CHECK(ssf_specular_reflection_setup(brdf, -1.0, NULL), RES_BAD_ARG);
+ CHECK(ssf_specular_reflection_setup(NULL, 1.0, NULL), RES_BAD_ARG);
+ CHECK(ssf_specular_reflection_setup(brdf, 1.0, NULL), RES_BAD_ARG);
+ CHECK(ssf_specular_reflection_setup(NULL, -1.0, fresnel), RES_BAD_ARG);
+ CHECK(ssf_specular_reflection_setup(brdf, -1.0, fresnel), RES_BAD_ARG);
+ CHECK(ssf_specular_reflection_setup(NULL, 1.0, fresnel), RES_BAD_ARG);
+ CHECK(ssf_specular_reflection_setup(brdf, 1.0, fresnel), RES_OK);
+ CHECK(ssf_specular_reflection_setup(brdf, 0.0, fresnel), RES_OK);
+ CHECK(ssf_specular_reflection_setup(brdf, 1.1, fresnel), RES_BAD_ARG);
+ CHECK(ssf_specular_reflection_setup(dummy, 0.0, fresnel), RES_BAD_ARG);
d3(N, 0.0, 1.0, 0.0);
d3_normalize(wo, d3(wo, 1.0, 1.0, 0.0));
@@ -49,9 +60,10 @@ main(int argc, char** argv)
CHECK(pdf, 1);
d3_normalize(wo, d3(wo, 1.0, 1.0, 0.0));
- CHECK(ssf_specular_reflection_setup(brdf, 0.123), RES_OK);
+ CHECK(ssf_specular_reflection_setup(brdf, 0.123, fresnel), RES_OK);
R = ssf_bxdf_sample(brdf, 0, 0, wo, N, wi, &pdf);
- CHECK(eq_eps(R, 0.123 / d3_dot(N, wi), 1.e-6), 1);
+ CHECK(eq_eps
+ (R, ssf_fresnel_eval(fresnel, d3_dot(N, wi))*0.123/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);
@@ -60,13 +72,15 @@ main(int argc, char** argv)
d3(wo, 0.0, 1.0, 0.0);
R = ssf_bxdf_sample(brdf, 0, 0, wo, N, wi, &pdf);
- CHECK(eq_eps(R, 0.123, 1.e-6), 1);
+ CHECK(eq_eps
+ (R, ssf_fresnel_eval(fresnel, d3_dot(N, wi))*0.123, 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);
- CHECK(eq_eps(R, 0.123 / d3_dot(N, wi), 1.e-6), 1);
+ CHECK(eq_eps
+ (R, ssf_fresnel_eval(fresnel, d3_dot(N, wi))*0.123/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);
@@ -81,8 +95,21 @@ main(int argc, char** argv)
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());
+ d3_normalize(wo, wo);
+ R = ssf_bxdf_sample(brdf, rand_canonic(), rand_canonic(), wo, N, wi, &pdf);
+ rho = R * d3_dot(wi, N);
+
+ 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(rho, ssf_bxdf_rho(brdf, wo, N), 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_memory_allocator(&allocator);
mem_shutdown_proxy_allocator(&allocator);
diff --git a/src/test_ssf_utils.h b/src/test_ssf_utils.h
@@ -72,9 +72,9 @@ bxdf_dummy_pdf
}
static double
-bxdf_dummy_rho(void* bxdf, const double wo[3])
+bxdf_dummy_rho(void* bxdf, const double wo[3], const double N[3])
{
- (void)bxdf, (void)wo;
+ (void)bxdf, (void)wo, (void)N;
return 0.0;
}