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 b0517721d55aff895bdb70982d063b54aa7976d6
parent fa4d4d70e6a09d152f4d4d18b80cb05eb022e86c
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Fri, 20 Jul 2018 11:53:50 +0200

Implement the built-in Rayleigh phase function

Diffstat:
Mcmake/CMakeLists.txt | 1+
Msrc/ssf.h | 4++--
Msrc/ssf_phase_hg.c | 42++++++++++++++++++++++--------------------
Asrc/ssf_phase_rayleigh.c | 111+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 136 insertions(+), 22 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -65,6 +65,7 @@ set(SSF_FILES_SRC ssf_microfacet_reflection.c ssf_phase.c ssf_phase_hg.c + ssf_phase_rayleigh.c ssf_pillbox_distribution.c ssf_specular_dielectric_dielectric_interface.c ssf_specular_reflection.c diff --git a/src/ssf.h b/src/ssf.h @@ -150,8 +150,8 @@ static const struct ssf_microfacet_distribution_type SSF_MICROFACET_DISTRIBUTION_TYPE_NULL = SSF_MICROFACET_DISTRIBUTION_TYPE_NULL__; /* Generic phase function type descriptor. Note that by convention the outgoing - * direction `wo' and the incoming direction `wi' point outward the scattering - * point */ + * direction `wo' and the incoming direction `wi' point *OUTWARD* the scattering + * point. The scattering angle is thus acos(-wo.wi) */ struct ssf_phase_type { res_T (*init)(struct mem_allocator* allocator, void* bsdf); /*Can be NULL*/ void (*release)(void* bsdf); /* Can be NULL */ diff --git a/src/ssf_phase_hg.c b/src/ssf_phase_hg.c @@ -34,11 +34,19 @@ hg_init(struct mem_allocator* allocator, void* phase) return RES_OK; } -static void -hg_release(void* phase) -{ (void)phase; } +static double +hg_pdf + (void* data, + const double wo[3], + const double wi[3]) +{ + double w[3]; + const struct hg* hg = data; + ASSERT(data && wo && wi); + return ssp_ran_sphere_hg_pdf(d3_minus(w, wo), hg->g, wi); +} -/* HG(theta) = 1/(4*PI) * (1 - g^2) / (1 + g^2 - 2*g*cos(theta))^3/2 */ +/* HG(theta) = 1/(4*PI) * (1 - g^2) / (1 + g^2 - 2*g*cos(theta))^3/2 */ static double hg_eval(void* data, const double wo[3], const double wi[3]) { @@ -47,18 +55,21 @@ hg_eval(void* data, const double wo[3], const double wi[3]) double g; double cos_theta; double denom; + double val; ASSERT(data && wo && wi); ASSERT(d3_is_normalized(wo) && d3_is_normalized(wi)); g = hg->g; - /* By convention wo point outward the scattering point. Revert it to point + /* By convention wo points outward the scattering point. Revert it to point * inward the scattering point in order to compute the cosine of the * scattering angle */ d3_minus(w, wo); cos_theta = d3_dot(w, wi); denom = 1 + g*g - 2*g*cos_theta; ASSERT(denom != 0); - return 1.0/(4.0*PI) * (1 - g*g) / (denom*sqrt(denom)); + val = 1.0/(4.0*PI) * (1 - g*g) / (denom*sqrt(denom)); + ASSERT(eq_eps(val, hg_pdf(data, wo, wi), 1.e-6)); + return val; } static void @@ -70,21 +81,12 @@ hg_sample double* pdf) { const struct hg* hg = data; - double sample[3]; + double w[3]; ASSERT(data && wo && wi); - ssp_ran_sphere_hg(rng, wo, hg->g, sample, pdf); - d3_set(wi, sample); -} -static double -hg_pdf - (void* data, - const double wo[3], - const double wi[3]) -{ - const struct hg* hg = data; - ASSERT(data && wo && wi); - return ssp_ran_sphere_hg_pdf(wo, hg->g, wi); + /* By convention wo points outward the scattering point. Revert it to point + * inward the scattering point as expected by the SSP library */ + ssp_ran_sphere_hg(rng, d3_minus(w, wo), hg->g, wi, pdf); } /******************************************************************************* @@ -92,7 +94,7 @@ hg_pdf ******************************************************************************/ const struct ssf_phase_type ssf_phase_hg = { hg_init, - hg_release, + NULL, hg_sample, hg_eval, hg_pdf, diff --git a/src/ssf_phase_rayleigh.c b/src/ssf_phase_rayleigh.c @@ -0,0 +1,111 @@ +/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#define _POSIX_C_SOURCE 200112L /* cbrt support */ + +#include "ssf.h" +#include "ssf_phase_c.h" + +#include <rsys/double3.h> +#include <star/ssp.h> +#include <math.h> + +/******************************************************************************* + * Private functions + ******************************************************************************/ +static res_T +rayleigh_init(struct mem_allocator* allocator, void* phase) +{ + (void)allocator, (void)phase; + return RES_OK; +} + +static void +rayleigh_release(void* phase) +{ (void)phase; } + + +/* Rayleigh(theta) = 3/(16*PI)*(1+cos(theta)^2) */ +static double +rayleigh_eval(void* data, const double wo[3], const double wi[3]) +{ + double cos_theta; + double w[3]; + ASSERT(wo && wi); + ASSERT(d3_is_normalized(wo) && d3_is_normalized(wi)); + (void)data; + /* By convention wo points outward the scattering point. Revert it to point + * inward the scattering point in order to compute the cosine of the + * scattering angle */ + d3_minus(w, wo); + cos_theta = d3_dot(w, wi); + return 3.0/(16.0*PI)*(1.0+cos_theta*cos_theta); +} + +static void +rayleigh_sample + (void* data, + struct ssp_rng* rng, + const double wo[3], + double wi[3], + double* pdf) +{ + double frame[9]; + double sample[3]; + double w[3]; + double phi, cos_theta, sin_theta; + double u; + double s; + ASSERT(rng && wo && wi); + (void)data; + + phi = ssp_rng_uniform_double(rng, 0, 2*PI); + + u = 4*ssp_rng_canonical(rng)-2; + s = cbrt(u + sqrt(1+u*u)); + cos_theta = s - 1.0/s; + sin_theta = cos2sin(cos_theta); + + sample[0] = cos(phi) * sin_theta; + sample[1] = sin(phi) * sin_theta; + sample[2] = cos_theta; + + /* By convention wo points outward the scattering point. Revert it to point + * inward the scattering point */ + d3_minus(w, wo); + d33_muld3(wi, d33_basis(frame, w), sample); + + if(pdf) *pdf = rayleigh_eval(data, wo, wi); +} + +static double +rayleigh_pdf(void* data, const double wo[3], const double wi[3]) +{ + return rayleigh_eval(data, wo, wi); +} + +/******************************************************************************* + * Exported symbols + ******************************************************************************/ +const struct ssf_phase_type ssf_phase_rayleigh = { + rayleigh_init, + rayleigh_release, + rayleigh_sample, + rayleigh_eval, + rayleigh_pdf, + 0, + 1 +}; +