diff --git a/intern/cycles/kernel/closure/bsdf_disney_diffuse.h b/intern/cycles/kernel/closure/bsdf_disney_diffuse.h index 2b927c53858..ff69a7aa8ec 100644 --- a/intern/cycles/kernel/closure/bsdf_disney_diffuse.h +++ b/intern/cycles/kernel/closure/bsdf_disney_diffuse.h @@ -1,3 +1,4 @@ + /* * Adapted from Open Shading Language with this license: * @@ -30,12 +31,153 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef __BSDF_DISNEY_DIFFUSE_ +#ifndef __BSDF_DISNEY_DIFFUSE_H__ #define __BSDF_DISNEY_DIFFUSE_H__ +#include + CCL_NAMESPACE_BEGIN -/* DIFFUSE */ +/* DISNEY DIFFUSE */ + +ccl_device float diff_sqr(float a) { + return a * a; +} + +ccl_device float3 diff_mon2lin(float3 x, float gamma) { + return make_float3(pow(x[0], gamma), pow(x[1], gamma), pow(x[2], gamma)); +} + +ccl_device float diff_GTR1(float NdotH, float a) { + if (a >= 1.0f) return 1.0f / M_PI_F; + float a2 = a*a; + float t = 1.0f + (a2 - 1.0f) * NdotH * NdotH; + return (a2 - 1.0f) / (M_PI_F * log(a2) * t); +} + +ccl_device float diff_GTR2(float NdotH, float a) { + float a2 = a * a; + float t = 1.0f + (a2 - 1.0f) * NdotH * NdotH; + return a2 / (M_PI_F * t * t); +} + +ccl_device float diff_GTR2_aniso( + float NdotH, + float HdotX, + float HdotY, + float ax, + float ay) +{ + return 1.0f / (M_PI_F * ax * ay * diff_sqr(diff_sqr(HdotX / ax) + diff_sqr(HdotY / ay) + + NdotH * NdotH)); +} + +ccl_device float diff_smithG_GGX(float Ndotv, float alphaG) { + float a = alphaG * alphaG; + float b = Ndotv * Ndotv; + return 1.0f / (Ndotv + sqrtf(a + b - a * b)); +} + +ccl_device float diff_SchlickFresnel(float u) { + float m = clamp(1.0f - u, 0.0f, 1.0f); + float m2 = m * m; + return m2 * m2 * m; // pow(m, 5) +} + +ccl_device float3 diff_transform_to_local(const float3& v, const float3& n, + const float3& x, const float3& y) +{ + return make_float3(dot(v, x), dot(v, n), dot(v, y)); +} + +ccl_device float3 diff_mix(float3 x, float3 y, float a) { + return x * (1.0f - a) + y * a; +} + +ccl_device float diff_mix(float x, float y, float a) { + return x * (1.0f - a) + y * a; +} + +/* structures */ +struct DisneyDiffuseBRDFParams { + // brdf parameters + float3 m_base_color; + float m_subsurface; + float m_roughness; + float m_sheen; + float m_sheen_tint; + + // color correction + float m_withNdotL; + float m_brightness; + float m_gamma; + float m_exposure; + float m_mon2lingamma; + + // precomputed values + float3 m_cdlin, m_ctint, m_csheen; + float m_cdlum; + float m_weights[4]; + bool m_withNdotL_b; + + void precompute_values() { + m_cdlin = diff_mon2lin(m_base_color, m_mon2lingamma); //make_float3(1.0f, 0.795f, 0.0f)); + m_cdlum = 0.3f * m_cdlin[0] + 0.6f * m_cdlin[1] + 0.1f * m_cdlin[2]; // luminance approx. + + m_ctint = m_cdlum > 0.0f ? m_cdlin / m_cdlum : make_float3(1.0f, 1.0f, 1.0f); // normalize lum. to isolate hue+sat + m_csheen = diff_mix(make_float3(1.0f, 1.0f, 1.0f), m_ctint, m_sheen_tint); + + m_gamma = clamp(m_gamma, 0.0f, 5.0f); + m_exposure = clamp(m_exposure, -6.0f, 6.0f); + m_withNdotL_b = (m_withNdotL > 0.5f); + } +}; + +typedef struct DisneyDiffuseBRDFParams DisneyDiffuseBRDFParams; + +/* brdf */ +ccl_device float3 calculate_disney_diffuse_brdf(const ShaderClosure *sc, + const DisneyDiffuseBRDFParams *params, float3 N, float3 V, float3 L, + float3 H, float *pdf) +{ + float NdotL = dot(N, L); + float NdotV = dot(N, V); + + if (NdotL < 0 || NdotV < 0) { + *pdf = 0.0f; + return make_float3(0.0f, 0.0f, 0.0f); + } + + float LdotH = dot(L, H); + + float Fd = 0.0f; + float FL = diff_SchlickFresnel(NdotL), FV = diff_SchlickFresnel(NdotV); + + if (params->m_subsurface != 1.0f) { + const float Fd90 = 0.5f + 2.0f * LdotH*LdotH * params->m_roughness; + Fd = diff_mix(1.0f, Fd90, FL) * diff_mix(1.0f, Fd90, FV); + } + + if (params->m_subsurface > 0.0f) { + float Fss90 = LdotH*LdotH * params->m_roughness; + float Fss = diff_mix(1.0f, Fss90, FL) * diff_mix(1.0f, Fss90, FV); + float ss = 1.25f * (Fss * (1.0f / (NdotL + NdotV) - 0.5f) + 0.5f); + Fd = diff_mix(Fd, ss, params->m_subsurface); + } + + float3 value = M_1_PI_F * Fd * params->m_cdlin; + *pdf = NdotL * M_1_PI_F * params->m_cdlum; + + // sheen component + if (params->m_sheen != 0.0f) { + float FH = diff_SchlickFresnel(LdotH); + + value += FH * params->m_sheen * params->m_csheen; + *pdf += (1.0f / M_2PI_F) * params->m_sheen; + } + + return value; +} ccl_device int bsdf_disney_diffuse_setup(ShaderClosure *sc) { @@ -44,46 +186,168 @@ ccl_device int bsdf_disney_diffuse_setup(ShaderClosure *sc) } ccl_device float3 bsdf_disney_diffuse_eval_reflect(const ShaderClosure *sc, - float3 color, const float3 I, const float3 omega_in, float *pdf) + const DisneyDiffuseBRDFParams *params, const float3 I, + const float3 omega_in, float *pdf) { - float3 N = sc->N; + float3 N = normalize(sc->N); + float3 V = I; // outgoing + float3 L = omega_in; // incoming + float3 H = normalize(L + V); - float cos_pi = fmaxf(dot(N, omega_in), 0.0f) * M_1_PI_F; - *pdf = cos_pi; - return make_float3(cos_pi * color[0], cos_pi * color[1], cos_pi * color[2]); + if (dot(sc->N, omega_in) > 0.0f) { + float3 value = calculate_disney_diffuse_brdf(sc, params, N, V, L, H, pdf); + + value *= dot(N, L); + + // brightness + value *= params->m_brightness; + + // exposure + value *= pow(2.0f, params->m_exposure); + + // gamma + value[0] = pow(value[0], 1.0f / params->m_gamma); + value[1] = pow(value[1], 1.0f / params->m_gamma); + value[2] = pow(value[2], 1.0f / params->m_gamma); + + return value; + } + else { + *pdf = 0.0f; + return make_float3(0.0f, 0.0f, 0.0f); + } } -ccl_device float3 bsdf_disney_diffuse_eval_transmit(const ShaderClosure *sc, - float3 color, const float3 I, const float3 omega_in, float *pdf) +ccl_device float3 bsdf_disney_diffuse_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) { return make_float3(0.0f, 0.0f, 0.0f); } -ccl_device int bsdf_disney_diffuse_sample(const ShaderClosure *sc, float3 color, - float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, - float3 *eval, float3 *omega_in, float3 *domega_in_dx, - float3 *domega_in_dy, float *pdf) +ccl_device int bsdf_disney_diffuse_sample(const ShaderClosure *sc, const DisneyDiffuseBRDFParams *params, + float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, + float3 *eval, float3 *omega_in, float3 *domega_in_dx, + float3 *domega_in_dy, float *pdf) { - float3 N = sc->N; + float3 N = normalize(sc->N); - // distribution over the hemisphere - sample_cos_hemisphere(N, randu, randv, omega_in, pdf); + sample_uniform_hemisphere(N, randu, randv, omega_in, pdf); + + if (dot(Ng, *omega_in) > 0) { + float3 V = I; // outgoing + float3 L = *omega_in; // incoming + float3 H = normalize(L + V); + + float3 value = calculate_disney_diffuse_brdf(sc, params, N, V, L, H, pdf); + + if (params->m_withNdotL_b) + value *= dot(N, L); + + // brightness + value *= params->m_brightness; + + // exposure + value *= pow(2.0f, params->m_exposure); + + // gamma + value[0] = pow(value[0], 1.0f / params->m_gamma); + value[1] = pow(value[1], 1.0f / params->m_gamma); + value[2] = pow(value[2], 1.0f / params->m_gamma); + + *eval = make_float3(value[0], value[1], value[2]); - if(dot(Ng, *omega_in) > 0.0f) { - *eval = make_float3(*pdf * color[0], *pdf * color[1], *pdf * color[2]); #ifdef __RAY_DIFFERENTIALS__ // TODO: find a better approximation for the diffuse bounce - *domega_in_dx = (2 * dot(N, dIdx)) * N - dIdx; - *domega_in_dy = (2 * dot(N, dIdy)) * N - dIdy; + *domega_in_dx = -((2 * dot(N, dIdx)) * N - dIdx); + *domega_in_dy = -((2 * dot(N, dIdy)) * N - dIdy); #endif } - else - *pdf = 0.0f; + else { + *pdf = 0; + } - return LABEL_REFLECT|LABEL_DIFFUSE; + /*// we are viewing the surface from the right side - send a ray out with cosine + // distribution over the hemisphere + sample_cos_hemisphere(-N, randu, randv, omega_in, pdf); + if(dot(Ng, *omega_in) < 0) { + float3 H = normalize(*omega_in - I); + *eval = calculate_disney_diffuse_brdf(sc, params, -N, -I, *omega_in, H, pdf); + + // multiply with NdotL + //if (params->m_withNdotL_b) + // *eval *= dot(N, L); + + // brightness + *eval *= params->m_brightness; + + // exposure + *eval *= pow(2.0f, params->m_exposure); + + // gamma + (*eval)[0] = pow((*eval)[0], 1.0f / params->m_gamma); + (*eval)[1] = pow((*eval)[1], 1.0f / params->m_gamma); + (*eval)[2] = pow((*eval)[2], 1.0f / params->m_gamma); + //*eval = make_float3(*pdf, *pdf, *pdf); + +#ifdef __RAY_DIFFERENTIALS__ + // TODO: find a better approximation for the diffuse bounce + *domega_in_dx = -((2 * dot(N, dIdx)) * N - dIdx); + *domega_in_dy = -((2 * dot(N, dIdy)) * N - dIdy); +#endif + } + else { + *pdf = 0; + }*/ + return LABEL_DIFFUSE; + + /*float3 N = normalize(sc->N); + float3 T = normalize(sc->T); + float3 X, Y; + + float cos_theta, phi, theta, sin_phi, cos_phi; + + make_orthonormals_tangent(N, T, &X, &Y); + + phi = 2.0f * M_PI_F * randu; + theta = 2.0f * M_PI_F * randv; + cos_theta = cosf(theta); + sin_phi = sinf(phi); + cos_phi = cosf(phi); + + float sin_theta = sqrtf(fmaxf(0.0f, 1.0f - cos_theta * cos_theta)); + float3 H = normalize(sin_theta * cos_phi * X + sin_theta * sin_phi * Y + cos_theta * N); + + *omega_in = 2.0f * dot(I, H) * H - I; + + float3 V = I; // outgoing + float3 L = *omega_in; // incoming + + *eval = calculate_disney_diffuse_brdf(sc, params, N, V, L, H, pdf); + + // multiply with NdotL + //if (params->m_withNdotL_b) + // *eval *= dot(N, L); + + // brightness + *eval *= params->m_brightness; + + // exposure + *eval *= pow(2.0f, params->m_exposure); + + // gamma + (*eval)[0] = pow((*eval)[0], 1.0f / params->m_gamma); + (*eval)[1] = pow((*eval)[1], 1.0f / params->m_gamma); + (*eval)[2] = pow((*eval)[2], 1.0f / params->m_gamma); + +#ifdef __RAY_DIFFERENTIALS__ + *domega_in_dx = 2 * dot(N, dIdx) * N - dIdx; + *domega_in_dy = 2 * dot(N, dIdy) * N - dIdy; +#endif + + return LABEL_REFLECT|LABEL_DIFFUSE;*/ } CCL_NAMESPACE_END #endif /* __BSDF_DISNEY_DIFFUSE_H__ */ + diff --git a/intern/cycles/kernel/osl/bsdf_disney_diffuse.cpp b/intern/cycles/kernel/osl/bsdf_disney_diffuse.cpp index ba7d233759b..9c4433e47a0 100644 --- a/intern/cycles/kernel/osl/bsdf_disney_diffuse.cpp +++ b/intern/cycles/kernel/osl/bsdf_disney_diffuse.cpp @@ -47,7 +47,7 @@ using namespace OSL; class DisneyDiffuseClosure : public CBSDFClosure { public: - float3 color; + DisneyDiffuseBRDFParams dp; DisneyDiffuseClosure() : CBSDFClosure(LABEL_DIFFUSE) {} @@ -56,21 +56,22 @@ public: { sc.prim = this; m_shaderdata_flag = bsdf_disney_diffuse_setup(&sc); + + dp.precompute_values(); } void blur(float roughness) { - //bsdf_disney_diffuse_blur(&sc, roughness); } float3 eval_reflect(const float3 &omega_out, const float3 &omega_in, float& pdf) const { - return bsdf_disney_diffuse_eval_reflect(&sc, color, omega_out, omega_in, &pdf); + return bsdf_disney_diffuse_eval_reflect(&sc, &dp, omega_out, omega_in, &pdf); } float3 eval_transmit(const float3 &omega_out, const float3 &omega_in, float& pdf) const { - return bsdf_disney_diffuse_eval_transmit(&sc, color, omega_out, omega_in, &pdf); + return bsdf_disney_diffuse_eval_transmit(&sc, omega_out, omega_in, &pdf); } int sample(const float3 &Ng, @@ -79,7 +80,7 @@ public: float3 &omega_in, float3 &domega_in_dx, float3 &domega_in_dy, float &pdf, float3 &eval) const { - return bsdf_disney_diffuse_sample(&sc, color, Ng, omega_out, domega_out_dx, domega_out_dy, + return bsdf_disney_diffuse_sample(&sc, &dp, Ng, omega_out, domega_out_dx, domega_out_dy, randu, randv, &eval, &omega_in, &domega_in_dx, &domega_in_dy, &pdf); } }; @@ -88,7 +89,16 @@ ClosureParam *closure_bsdf_disney_diffuse_params() { static ClosureParam params[] = { CLOSURE_FLOAT3_PARAM(DisneyDiffuseClosure, sc.N), - CLOSURE_FLOAT3_PARAM(DisneyDiffuseClosure, color), + CLOSURE_FLOAT3_PARAM(DisneyDiffuseClosure, dp.m_base_color), + CLOSURE_FLOAT_PARAM(DisneyDiffuseClosure, dp.m_subsurface), + CLOSURE_FLOAT_PARAM(DisneyDiffuseClosure, dp.m_roughness), + CLOSURE_FLOAT_PARAM(DisneyDiffuseClosure, dp.m_sheen), + CLOSURE_FLOAT_PARAM(DisneyDiffuseClosure, dp.m_sheen_tint), + CLOSURE_FLOAT_PARAM(DisneyDiffuseClosure, dp.m_withNdotL), + CLOSURE_FLOAT_PARAM(DisneyDiffuseClosure, dp.m_brightness), + CLOSURE_FLOAT_PARAM(DisneyDiffuseClosure, dp.m_gamma), + CLOSURE_FLOAT_PARAM(DisneyDiffuseClosure, dp.m_exposure), + CLOSURE_FLOAT_PARAM(DisneyDiffuseClosure, dp.m_mon2lingamma), CLOSURE_STRING_KEYPARAM(DisneyDiffuseClosure, label, "label"), CLOSURE_FINISH_PARAM(DisneyDiffuseClosure) }; diff --git a/intern/cycles/kernel/shaders/stdosl.h b/intern/cycles/kernel/shaders/stdosl.h index 83e8bc61c6c..01f391d8e30 100644 --- a/intern/cycles/kernel/shaders/stdosl.h +++ b/intern/cycles/kernel/shaders/stdosl.h @@ -536,7 +536,8 @@ closure color emission() BUILTIN; closure color background() BUILTIN; closure color holdout() BUILTIN; closure color ambient_occlusion() BUILTIN; -closure color disney_diffuse(normal N, color c) BUILTIN; +closure color disney_diffuse(normal N, color baseColor, float subsurface, float roughness, float sheen, + float sheenTint, float withNdotL, float brightness, float gamma, float exposure, float mon2lingamma) BUILTIN; // BSSRDF closure color bssrdf_cubic(normal N, vector radius, float texture_blur, float sharpness) BUILTIN;