diff options
Diffstat (limited to 'intern/cycles/kernel/closure/bsdf_hair_principled.h')
-rw-r--r-- | intern/cycles/kernel/closure/bsdf_hair_principled.h | 299 |
1 files changed, 148 insertions, 151 deletions
diff --git a/intern/cycles/kernel/closure/bsdf_hair_principled.h b/intern/cycles/kernel/closure/bsdf_hair_principled.h index 2cdf6c9f349..f5651d82aae 100644 --- a/intern/cycles/kernel/closure/bsdf_hair_principled.h +++ b/intern/cycles/kernel/closure/bsdf_hair_principled.h @@ -3,10 +3,11 @@ #pragma once -#ifdef __KERNEL_CPU__ +#ifndef __KERNEL_GPU__ # include <fenv.h> #endif +#include "kernel/sample/lcg.h" #include "kernel/util/color.h" CCL_NAMESPACE_BEGIN @@ -20,7 +21,7 @@ typedef struct PrincipledHairBSDF { SHADER_CLOSURE_BASE; /* Absorption coefficient. */ - float3 sigma; + Spectrum sigma; /* Variance of the underlying logistic distribution. */ float v; /* Scale factor of the underlying logistic distribution. */ @@ -56,13 +57,7 @@ ccl_device_inline float delta_phi(int p, float gamma_o, float gamma_t) /* Remaps the given angle to [-pi, pi]. */ ccl_device_inline float wrap_angle(float a) { - while (a > M_PI_F) { - a -= M_2PI_F; - } - while (a < -M_PI_F) { - a += M_2PI_F; - } - return a; + return (a + M_PI_F) - M_2PI_F * floorf((a + M_PI_F) / M_2PI_F) - M_PI_F; } /* Logistic distribution function. */ @@ -166,12 +161,6 @@ ccl_device_inline float longitudinal_scattering( } } -/* Combine the three values using their luminances. */ -ccl_device_inline float4 combine_with_energy(KernelGlobals kg, float3 c) -{ - return make_float4(c.x, c.y, c.z, linear_rgb_to_gray(kg, c)); -} - #ifdef __HAIR__ /* Set up the hair closure. */ ccl_device int bsdf_principled_hair_setup(ccl_private ShaderData *sd, @@ -214,34 +203,36 @@ ccl_device int bsdf_principled_hair_setup(ccl_private ShaderData *sd, #endif /* __HAIR__ */ /* Given the Fresnel term and transmittance, generate the attenuation terms for each bounce. */ -ccl_device_inline void hair_attenuation(KernelGlobals kg, - float f, - float3 T, - ccl_private float4 *Ap) +ccl_device_inline void hair_attenuation( + KernelGlobals kg, float f, Spectrum T, ccl_private Spectrum *Ap, ccl_private float *Ap_energy) { /* Primary specular (R). */ - Ap[0] = make_float4(f, f, f, f); + Ap[0] = make_spectrum(f); + Ap_energy[0] = f; /* Transmission (TT). */ - float3 col = sqr(1.0f - f) * T; - Ap[1] = combine_with_energy(kg, col); + Spectrum col = sqr(1.0f - f) * T; + Ap[1] = col; + Ap_energy[1] = spectrum_to_gray(kg, col); /* Secondary specular (TRT). */ col *= T * f; - Ap[2] = combine_with_energy(kg, col); + Ap[2] = col; + Ap_energy[2] = spectrum_to_gray(kg, col); /* Residual component (TRRT+). */ - col *= safe_divide_color(T * f, make_float3(1.0f, 1.0f, 1.0f) - T * f); - Ap[3] = combine_with_energy(kg, col); + col *= safe_divide(T * f, one_spectrum() - T * f); + Ap[3] = col; + Ap_energy[3] = spectrum_to_gray(kg, col); /* Normalize sampling weights. */ - float totweight = Ap[0].w + Ap[1].w + Ap[2].w + Ap[3].w; + float totweight = Ap_energy[0] + Ap_energy[1] + Ap_energy[2] + Ap_energy[3]; float fac = safe_divide(1.0f, totweight); - Ap[0].w *= fac; - Ap[1].w *= fac; - Ap[2].w *= fac; - Ap[3].w *= fac; + Ap_energy[0] *= fac; + Ap_energy[1] *= fac; + Ap_energy[2] *= fac; + Ap_energy[3] *= fac; } /* Given the tilt angle, generate the rotated theta_i for the different bounces. */ @@ -266,81 +257,84 @@ ccl_device_inline void hair_alpha_angles(float sin_theta_i, } /* Evaluation function for our shader. */ -ccl_device float3 bsdf_principled_hair_eval(KernelGlobals kg, - ccl_private const ShaderData *sd, - ccl_private const ShaderClosure *sc, - const float3 omega_in, - ccl_private float *pdf) +ccl_device Spectrum bsdf_principled_hair_eval(KernelGlobals kg, + ccl_private const ShaderData *sd, + ccl_private const ShaderClosure *sc, + const float3 omega_in, + ccl_private float *pdf) { kernel_assert(isfinite_safe(sd->P) && isfinite_safe(sd->ray_length)); ccl_private const PrincipledHairBSDF *bsdf = (ccl_private const PrincipledHairBSDF *)sc; - float3 Y = float4_to_float3(bsdf->extra->geom); + const float3 Y = float4_to_float3(bsdf->extra->geom); - float3 X = safe_normalize(sd->dPdu); + const float3 X = safe_normalize(sd->dPdu); kernel_assert(fabsf(dot(X, Y)) < 1e-3f); - float3 Z = safe_normalize(cross(X, Y)); + const float3 Z = safe_normalize(cross(X, Y)); - float3 wo = make_float3(dot(sd->I, X), dot(sd->I, Y), dot(sd->I, Z)); - float3 wi = make_float3(dot(omega_in, X), dot(omega_in, Y), dot(omega_in, Z)); + const float3 wo = make_float3(dot(sd->I, X), dot(sd->I, Y), dot(sd->I, Z)); + const float3 wi = make_float3(dot(omega_in, X), dot(omega_in, Y), dot(omega_in, Z)); - float sin_theta_o = wo.x; - float cos_theta_o = cos_from_sin(sin_theta_o); - float phi_o = atan2f(wo.z, wo.y); + const float sin_theta_o = wo.x; + const float cos_theta_o = cos_from_sin(sin_theta_o); + const float phi_o = atan2f(wo.z, wo.y); - float sin_theta_t = sin_theta_o / bsdf->eta; - float cos_theta_t = cos_from_sin(sin_theta_t); + const float sin_theta_t = sin_theta_o / bsdf->eta; + const float cos_theta_t = cos_from_sin(sin_theta_t); - float sin_gamma_o = bsdf->extra->geom.w; - float cos_gamma_o = cos_from_sin(sin_gamma_o); - float gamma_o = safe_asinf(sin_gamma_o); + const float sin_gamma_o = bsdf->extra->geom.w; + const float cos_gamma_o = cos_from_sin(sin_gamma_o); + const float gamma_o = safe_asinf(sin_gamma_o); - float sin_gamma_t = sin_gamma_o * cos_theta_o / sqrtf(sqr(bsdf->eta) - sqr(sin_theta_o)); - float cos_gamma_t = cos_from_sin(sin_gamma_t); - float gamma_t = safe_asinf(sin_gamma_t); + const float sin_gamma_t = sin_gamma_o * cos_theta_o / sqrtf(sqr(bsdf->eta) - sqr(sin_theta_o)); + const float cos_gamma_t = cos_from_sin(sin_gamma_t); + const float gamma_t = safe_asinf(sin_gamma_t); - float3 T = exp(-bsdf->sigma * (2.0f * cos_gamma_t / cos_theta_t)); - float4 Ap[4]; - hair_attenuation(kg, fresnel_dielectric_cos(cos_theta_o * cos_gamma_o, bsdf->eta), T, Ap); + const Spectrum T = exp(-bsdf->sigma * (2.0f * cos_gamma_t / cos_theta_t)); + Spectrum Ap[4]; + float Ap_energy[4]; + hair_attenuation( + kg, fresnel_dielectric_cos(cos_theta_o * cos_gamma_o, bsdf->eta), T, Ap, Ap_energy); - float sin_theta_i = wi.x; - float cos_theta_i = cos_from_sin(sin_theta_i); - float phi_i = atan2f(wi.z, wi.y); + const float sin_theta_i = wi.x; + const float cos_theta_i = cos_from_sin(sin_theta_i); + const float phi_i = atan2f(wi.z, wi.y); - float phi = phi_i - phi_o; + const float phi = phi_i - phi_o; float angles[6]; hair_alpha_angles(sin_theta_i, cos_theta_i, bsdf->alpha, angles); - float4 F; - float Mp, Np; - - /* Primary specular (R). */ - Mp = longitudinal_scattering(angles[0], angles[1], sin_theta_o, cos_theta_o, bsdf->m0_roughness); - Np = azimuthal_scattering(phi, 0, bsdf->s, gamma_o, gamma_t); - F = Ap[0] * Mp * Np; - kernel_assert(isfinite_safe(float4_to_float3(F))); - - /* Transmission (TT). */ - Mp = longitudinal_scattering(angles[2], angles[3], sin_theta_o, cos_theta_o, 0.25f * bsdf->v); - Np = azimuthal_scattering(phi, 1, bsdf->s, gamma_o, gamma_t); - F += Ap[1] * Mp * Np; - kernel_assert(isfinite_safe(float4_to_float3(F))); - - /* Secondary specular (TRT). */ - Mp = longitudinal_scattering(angles[4], angles[5], sin_theta_o, cos_theta_o, 4.0f * bsdf->v); - Np = azimuthal_scattering(phi, 2, bsdf->s, gamma_o, gamma_t); - F += Ap[2] * Mp * Np; - kernel_assert(isfinite_safe(float4_to_float3(F))); + Spectrum F = zero_spectrum(); + float F_energy = 0.0f; + + /* Primary specular (R), Transmission (TT) and Secondary Specular (TRT). */ + for (int i = 0; i < 3; i++) { + const float Mp = longitudinal_scattering(angles[2 * i], + angles[2 * i + 1], + sin_theta_o, + cos_theta_o, + (i == 0) ? bsdf->m0_roughness : + (i == 1) ? 0.25f * bsdf->v : + 4.0f * bsdf->v); + const float Np = azimuthal_scattering(phi, i, bsdf->s, gamma_o, gamma_t); + F += Ap[i] * Mp * Np; + F_energy += Ap_energy[i] * Mp * Np; + kernel_assert(isfinite_safe(F) && isfinite_safe(F_energy)); + } /* Residual component (TRRT+). */ - Mp = longitudinal_scattering(sin_theta_i, cos_theta_i, sin_theta_o, cos_theta_o, 4.0f * bsdf->v); - Np = M_1_2PI_F; - F += Ap[3] * Mp * Np; - kernel_assert(isfinite_safe(float4_to_float3(F))); + { + const float Mp = longitudinal_scattering( + sin_theta_i, cos_theta_i, sin_theta_o, cos_theta_o, 4.0f * bsdf->v); + const float Np = M_1_2PI_F; + F += Ap[3] * Mp * Np; + F_energy += Ap_energy[3] * Mp * Np; + kernel_assert(isfinite_safe(F) && isfinite_safe(F_energy)); + } - *pdf = F.w; - return float4_to_float3(F); + *pdf = F_energy; + return F; } /* Sampling function for the hair shader. */ @@ -349,52 +343,57 @@ ccl_device int bsdf_principled_hair_sample(KernelGlobals kg, ccl_private ShaderData *sd, float randu, float randv, - ccl_private float3 *eval, + ccl_private Spectrum *eval, ccl_private float3 *omega_in, - ccl_private float3 *domega_in_dx, - ccl_private float3 *domega_in_dy, - ccl_private float *pdf) + ccl_private float *pdf, + ccl_private float2 *sampled_roughness, + ccl_private float *eta) { ccl_private PrincipledHairBSDF *bsdf = (ccl_private PrincipledHairBSDF *)sc; - float3 Y = float4_to_float3(bsdf->extra->geom); + *sampled_roughness = make_float2(bsdf->m0_roughness, bsdf->m0_roughness); + *eta = bsdf->eta; - float3 X = safe_normalize(sd->dPdu); + const float3 Y = float4_to_float3(bsdf->extra->geom); + + const float3 X = safe_normalize(sd->dPdu); kernel_assert(fabsf(dot(X, Y)) < 1e-3f); - float3 Z = safe_normalize(cross(X, Y)); + const float3 Z = safe_normalize(cross(X, Y)); - float3 wo = make_float3(dot(sd->I, X), dot(sd->I, Y), dot(sd->I, Z)); + const float3 wo = make_float3(dot(sd->I, X), dot(sd->I, Y), dot(sd->I, Z)); float2 u[2]; u[0] = make_float2(randu, randv); u[1].x = lcg_step_float(&sd->lcg_state); u[1].y = lcg_step_float(&sd->lcg_state); - float sin_theta_o = wo.x; - float cos_theta_o = cos_from_sin(sin_theta_o); - float phi_o = atan2f(wo.z, wo.y); + const float sin_theta_o = wo.x; + const float cos_theta_o = cos_from_sin(sin_theta_o); + const float phi_o = atan2f(wo.z, wo.y); - float sin_theta_t = sin_theta_o / bsdf->eta; - float cos_theta_t = cos_from_sin(sin_theta_t); + const float sin_theta_t = sin_theta_o / bsdf->eta; + const float cos_theta_t = cos_from_sin(sin_theta_t); - float sin_gamma_o = bsdf->extra->geom.w; - float cos_gamma_o = cos_from_sin(sin_gamma_o); - float gamma_o = safe_asinf(sin_gamma_o); + const float sin_gamma_o = bsdf->extra->geom.w; + const float cos_gamma_o = cos_from_sin(sin_gamma_o); + const float gamma_o = safe_asinf(sin_gamma_o); - float sin_gamma_t = sin_gamma_o * cos_theta_o / sqrtf(sqr(bsdf->eta) - sqr(sin_theta_o)); - float cos_gamma_t = cos_from_sin(sin_gamma_t); - float gamma_t = safe_asinf(sin_gamma_t); + const float sin_gamma_t = sin_gamma_o * cos_theta_o / sqrtf(sqr(bsdf->eta) - sqr(sin_theta_o)); + const float cos_gamma_t = cos_from_sin(sin_gamma_t); + const float gamma_t = safe_asinf(sin_gamma_t); - float3 T = exp(-bsdf->sigma * (2.0f * cos_gamma_t / cos_theta_t)); - float4 Ap[4]; - hair_attenuation(kg, fresnel_dielectric_cos(cos_theta_o * cos_gamma_o, bsdf->eta), T, Ap); + const Spectrum T = exp(-bsdf->sigma * (2.0f * cos_gamma_t / cos_theta_t)); + Spectrum Ap[4]; + float Ap_energy[4]; + hair_attenuation( + kg, fresnel_dielectric_cos(cos_theta_o * cos_gamma_o, bsdf->eta), T, Ap, Ap_energy); int p = 0; for (; p < 3; p++) { - if (u[0].x < Ap[p].w) { + if (u[0].x < Ap_energy[p]) { break; } - u[0].x -= Ap[p].w; + u[0].x -= Ap_energy[p]; } float v = bsdf->v; @@ -406,7 +405,7 @@ ccl_device int bsdf_principled_hair_sample(KernelGlobals kg, } u[1].x = max(u[1].x, 1e-5f); - float fac = 1.0f + v * logf(u[1].x + (1.0f - u[1].x) * expf(-2.0f / v)); + const float fac = 1.0f + v * logf(u[1].x + (1.0f - u[1].x) * expf(-2.0f / v)); float sin_theta_i = -fac * sin_theta_o + cos_from_sin(fac) * cosf(M_2PI_F * u[1].y) * cos_theta_o; float cos_theta_i = cos_from_sin(sin_theta_i); @@ -425,48 +424,43 @@ ccl_device int bsdf_principled_hair_sample(KernelGlobals kg, else { phi = M_2PI_F * u[0].y; } - float phi_i = phi_o + phi; + const float phi_i = phi_o + phi; hair_alpha_angles(sin_theta_i, cos_theta_i, bsdf->alpha, angles); - float4 F; - float Mp, Np; - - /* Primary specular (R). */ - Mp = longitudinal_scattering(angles[0], angles[1], sin_theta_o, cos_theta_o, bsdf->m0_roughness); - Np = azimuthal_scattering(phi, 0, bsdf->s, gamma_o, gamma_t); - F = Ap[0] * Mp * Np; - kernel_assert(isfinite_safe(float4_to_float3(F))); - - /* Transmission (TT). */ - Mp = longitudinal_scattering(angles[2], angles[3], sin_theta_o, cos_theta_o, 0.25f * bsdf->v); - Np = azimuthal_scattering(phi, 1, bsdf->s, gamma_o, gamma_t); - F += Ap[1] * Mp * Np; - kernel_assert(isfinite_safe(float4_to_float3(F))); - - /* Secondary specular (TRT). */ - Mp = longitudinal_scattering(angles[4], angles[5], sin_theta_o, cos_theta_o, 4.0f * bsdf->v); - Np = azimuthal_scattering(phi, 2, bsdf->s, gamma_o, gamma_t); - F += Ap[2] * Mp * Np; - kernel_assert(isfinite_safe(float4_to_float3(F))); + Spectrum F = zero_spectrum(); + float F_energy = 0.0f; + + /* Primary specular (R), Transmission (TT) and Secondary Specular (TRT). */ + for (int i = 0; i < 3; i++) { + const float Mp = longitudinal_scattering(angles[2 * i], + angles[2 * i + 1], + sin_theta_o, + cos_theta_o, + (i == 0) ? bsdf->m0_roughness : + (i == 1) ? 0.25f * bsdf->v : + 4.0f * bsdf->v); + const float Np = azimuthal_scattering(phi, i, bsdf->s, gamma_o, gamma_t); + F += Ap[i] * Mp * Np; + F_energy += Ap_energy[i] * Mp * Np; + kernel_assert(isfinite_safe(F) && isfinite_safe(F_energy)); + } /* Residual component (TRRT+). */ - Mp = longitudinal_scattering(sin_theta_i, cos_theta_i, sin_theta_o, cos_theta_o, 4.0f * bsdf->v); - Np = M_1_2PI_F; - F += Ap[3] * Mp * Np; - kernel_assert(isfinite_safe(float4_to_float3(F))); + { + const float Mp = longitudinal_scattering( + sin_theta_i, cos_theta_i, sin_theta_o, cos_theta_o, 4.0f * bsdf->v); + const float Np = M_1_2PI_F; + F += Ap[3] * Mp * Np; + F_energy += Ap_energy[3] * Mp * Np; + kernel_assert(isfinite_safe(F) && isfinite_safe(F_energy)); + } - *eval = float4_to_float3(F); - *pdf = F.w; + *eval = F; + *pdf = F_energy; *omega_in = X * sin_theta_i + Y * cos_theta_i * cosf(phi_i) + Z * cos_theta_i * sinf(phi_i); -#ifdef __RAY_DIFFERENTIALS__ - float3 N = safe_normalize(sd->I + *omega_in); - *domega_in_dx = (2 * dot(N, sd->dI.dx)) * N - sd->dI.dx; - *domega_in_dy = (2 * dot(N, sd->dI.dy)) * N - sd->dI.dy; -#endif - return LABEL_GLOSSY | ((p == 0) ? LABEL_REFLECT : LABEL_TRANSMIT); } @@ -489,25 +483,28 @@ ccl_device_inline float bsdf_principled_hair_albedo_roughness_scale( return (((((0.245f * x) + 5.574f) * x - 10.73f) * x + 2.532f) * x - 0.215f) * x + 5.969f; } -ccl_device float3 bsdf_principled_hair_albedo(ccl_private const ShaderClosure *sc) +ccl_device Spectrum bsdf_principled_hair_albedo(ccl_private const ShaderClosure *sc) { ccl_private PrincipledHairBSDF *bsdf = (ccl_private PrincipledHairBSDF *)sc; return exp(-sqrt(bsdf->sigma) * bsdf_principled_hair_albedo_roughness_scale(bsdf->v)); } -ccl_device_inline float3 -bsdf_principled_hair_sigma_from_reflectance(const float3 color, const float azimuthal_roughness) +ccl_device_inline Spectrum +bsdf_principled_hair_sigma_from_reflectance(const Spectrum color, const float azimuthal_roughness) { - const float3 sigma = log(color) / - bsdf_principled_hair_albedo_roughness_scale(azimuthal_roughness); + const Spectrum sigma = log(color) / + bsdf_principled_hair_albedo_roughness_scale(azimuthal_roughness); return sigma * sigma; } -ccl_device_inline float3 bsdf_principled_hair_sigma_from_concentration(const float eumelanin, - const float pheomelanin) +ccl_device_inline Spectrum bsdf_principled_hair_sigma_from_concentration(const float eumelanin, + const float pheomelanin) { - return eumelanin * make_float3(0.506f, 0.841f, 1.653f) + - pheomelanin * make_float3(0.343f, 0.733f, 1.924f); + const float3 eumelanin_color = make_float3(0.506f, 0.841f, 1.653f); + const float3 pheomelanin_color = make_float3(0.343f, 0.733f, 1.924f); + + return eumelanin * rgb_to_spectrum(eumelanin_color) + + pheomelanin * rgb_to_spectrum(pheomelanin_color); } CCL_NAMESPACE_END |