Changeset View
Changeset View
Standalone View
Standalone View
intern/cycles/kernel/closure/bsdf_principled_diffuse.h
| Show All 13 Lines | |||||
| * limitations under the License. | * limitations under the License. | ||||
| */ | */ | ||||
| #pragma once | #pragma once | ||||
| /* DISNEY PRINCIPLED DIFFUSE BRDF | /* DISNEY PRINCIPLED DIFFUSE BRDF | ||||
| * | * | ||||
| * Shading model by Brent Burley (Disney): "Physically Based Shading at Disney" (2012) | * Shading model by Brent Burley (Disney): "Physically Based Shading at Disney" (2012) | ||||
| * | |||||
| * "Extending the Disney BRDF to a BSDF with Integrated Subsurface Scattering" (2015) | |||||
| * For the separation of retro-reflection, "2.3 Dielectric BRDF with integrated | |||||
| * subsurface scattering" | |||||
| */ | */ | ||||
| #include "kernel/closure/bsdf_util.h" | #include "kernel/closure/bsdf_util.h" | ||||
| CCL_NAMESPACE_BEGIN | CCL_NAMESPACE_BEGIN | ||||
| enum PrincipledDiffuseBsdfComponents { | |||||
| PRINCIPLED_DIFFUSE_FULL = 1, | |||||
| PRINCIPLED_DIFFUSE_LAMBERT = 2, | |||||
| PRINCIPLED_DIFFUSE_LAMBERT_EXIT = 4, | |||||
| PRINCIPLED_DIFFUSE_RETRO_REFLECTION = 8, | |||||
| }; | |||||
| typedef ccl_addr_space struct PrincipledDiffuseBsdf { | typedef ccl_addr_space struct PrincipledDiffuseBsdf { | ||||
| SHADER_CLOSURE_BASE; | SHADER_CLOSURE_BASE; | ||||
| float roughness; | float roughness; | ||||
| int components; | |||||
| } PrincipledDiffuseBsdf; | } PrincipledDiffuseBsdf; | ||||
| static_assert(sizeof(ShaderClosure) >= sizeof(PrincipledDiffuseBsdf), | static_assert(sizeof(ShaderClosure) >= sizeof(PrincipledDiffuseBsdf), | ||||
| "PrincipledDiffuseBsdf is too large!"); | "PrincipledDiffuseBsdf is too large!"); | ||||
| ccl_device float3 calculate_principled_diffuse_brdf( | ccl_device int bsdf_principled_diffuse_setup(PrincipledDiffuseBsdf *bsdf) | ||||
| { | |||||
| bsdf->type = CLOSURE_BSDF_PRINCIPLED_DIFFUSE_ID; | |||||
| return SD_BSDF | SD_BSDF_HAS_EVAL; | |||||
| } | |||||
| ccl_device float3 bsdf_principled_diffuse_compute_brdf( | |||||
| const PrincipledDiffuseBsdf *bsdf, float3 N, float3 V, float3 L, float *pdf) | const PrincipledDiffuseBsdf *bsdf, float3 N, float3 V, float3 L, float *pdf) | ||||
| { | { | ||||
| float NdotL = dot(N, L); | const float NdotL = dot(N, L); | ||||
| if (NdotL <= 0) { | if (NdotL <= 0) { | ||||
| return make_float3(0.0f, 0.0f, 0.0f); | return make_float3(0.0f, 0.0f, 0.0f); | ||||
| } | } | ||||
| float NdotV = dot(N, V); | const float NdotV = dot(N, V); | ||||
| /* H = normalize(L + V); // Bisector of an angle between L and V. | const float FV = schlick_fresnel(NdotV); | ||||
| * LH2 = 2 * dot(L, H)^2 = 2cos(x)^2 = cos(2x) + 1 = dot(L, V) + 1, | const float FL = schlick_fresnel(NdotL); | ||||
| * half-angle x between L and V is at most 90 deg | |||||
| */ | |||||
| float LH2 = dot(L, V) + 1; | |||||
| float FL = schlick_fresnel(NdotL), FV = schlick_fresnel(NdotV); | float f = 0.0f; | ||||
| const float Fd90 = 0.5f + LH2 * bsdf->roughness; | |||||
| float Fd = (1.0f - FL + Fd90 * FL) * (1.0f - FV + Fd90 * FV); | |||||
| float value = M_1_PI_F * NdotL * Fd; | /* Lambertian component. */ | ||||
| if (bsdf->components & (PRINCIPLED_DIFFUSE_FULL | PRINCIPLED_DIFFUSE_LAMBERT)) { | |||||
| f += (1.0f - 0.5f * FV) * (1.0f - 0.5f * FL); | |||||
| } | |||||
| else if (bsdf->components & PRINCIPLED_DIFFUSE_LAMBERT_EXIT) { | |||||
| f += (1.0f - 0.5f * FL); | |||||
| } | |||||
| /* Retro-reflection component. */ | |||||
| if (bsdf->components & (PRINCIPLED_DIFFUSE_FULL | PRINCIPLED_DIFFUSE_RETRO_REFLECTION)) { | |||||
| /* H = normalize(L + V); // Bisector of an angle between L and V | |||||
| * LH2 = 2 * dot(L, H)^2 = 2cos(x)^2 = cos(2x) + 1 = dot(L, V) + 1, | |||||
| * half-angle x between L and V is at most 90 deg. */ | |||||
| const float LH2 = dot(L, V) + 1; | |||||
| const float RR = bsdf->roughness * LH2; | |||||
| f += RR * (FL + FV + FL * FV * (RR - 1.0f)); | |||||
| } | |||||
| float value = M_1_PI_F * NdotL * f; | |||||
| return make_float3(value, value, value); | return make_float3(value, value, value); | ||||
| } | } | ||||
| ccl_device int bsdf_principled_diffuse_setup(PrincipledDiffuseBsdf *bsdf) | /* Compute Fresnel at entry point, to be compbined with PRINCIPLED_DIFFUSE_LAMBERT_EXIT | ||||
| * at the exit point to get the complete BSDF. */ | |||||
| ccl_device_inline float bsdf_principled_diffuse_compute_entry_fresnel(const float NdotV) | |||||
| { | |||||
| const float FV = schlick_fresnel(NdotV); | |||||
| return (1.0f - 0.5f * FV); | |||||
| } | |||||
| /* Ad-hoc weight adjusment to avoid retro-reflection taking away half the | |||||
| * samples from BSSRDF. */ | |||||
| ccl_device_inline float bsdf_principled_diffuse_retro_reflection_sample_weight( | |||||
| PrincipledDiffuseBsdf *bsdf, const float3 I) | |||||
| { | |||||
| return bsdf->roughness * schlick_fresnel(dot(bsdf->N, I)); | |||||
| } | |||||
| ccl_device int bsdf_principled_diffuse_setup(PrincipledDiffuseBsdf *bsdf, int components) | |||||
| { | { | ||||
| bsdf->type = CLOSURE_BSDF_PRINCIPLED_DIFFUSE_ID; | bsdf->type = CLOSURE_BSDF_PRINCIPLED_DIFFUSE_ID; | ||||
| bsdf->components = components; | |||||
| return SD_BSDF | SD_BSDF_HAS_EVAL; | return SD_BSDF | SD_BSDF_HAS_EVAL; | ||||
| } | } | ||||
| ccl_device float3 bsdf_principled_diffuse_eval_reflect(const ShaderClosure *sc, | ccl_device float3 bsdf_principled_diffuse_eval_reflect(const ShaderClosure *sc, | ||||
| const float3 I, | const float3 I, | ||||
| const float3 omega_in, | const float3 omega_in, | ||||
| float *pdf) | float *pdf) | ||||
| { | { | ||||
| const PrincipledDiffuseBsdf *bsdf = (const PrincipledDiffuseBsdf *)sc; | const PrincipledDiffuseBsdf *bsdf = (const PrincipledDiffuseBsdf *)sc; | ||||
| float3 N = bsdf->N; | float3 N = bsdf->N; | ||||
| float3 V = I; // outgoing | float3 V = I; // outgoing | ||||
| float3 L = omega_in; // incoming | float3 L = omega_in; // incoming | ||||
| if (dot(N, omega_in) > 0.0f) { | if (dot(N, omega_in) > 0.0f) { | ||||
| *pdf = fmaxf(dot(N, omega_in), 0.0f) * M_1_PI_F; | *pdf = fmaxf(dot(N, omega_in), 0.0f) * M_1_PI_F; | ||||
| return calculate_principled_diffuse_brdf(bsdf, N, V, L, pdf); | return bsdf_principled_diffuse_compute_brdf(bsdf, N, V, L, pdf); | ||||
| } | } | ||||
| else { | else { | ||||
| *pdf = 0.0f; | *pdf = 0.0f; | ||||
| return make_float3(0.0f, 0.0f, 0.0f); | return make_float3(0.0f, 0.0f, 0.0f); | ||||
| } | } | ||||
| } | } | ||||
| ccl_device float3 bsdf_principled_diffuse_eval_transmit(const ShaderClosure *sc, | ccl_device float3 bsdf_principled_diffuse_eval_transmit(const ShaderClosure *sc, | ||||
| Show All 19 Lines | |||||
| { | { | ||||
| const PrincipledDiffuseBsdf *bsdf = (const PrincipledDiffuseBsdf *)sc; | const PrincipledDiffuseBsdf *bsdf = (const PrincipledDiffuseBsdf *)sc; | ||||
| float3 N = bsdf->N; | float3 N = bsdf->N; | ||||
| sample_cos_hemisphere(N, randu, randv, omega_in, pdf); | sample_cos_hemisphere(N, randu, randv, omega_in, pdf); | ||||
| if (dot(Ng, *omega_in) > 0) { | if (dot(Ng, *omega_in) > 0) { | ||||
| *eval = calculate_principled_diffuse_brdf(bsdf, N, I, *omega_in, pdf); | *eval = bsdf_principled_diffuse_compute_brdf(bsdf, N, I, *omega_in, pdf); | ||||
| #ifdef __RAY_DIFFERENTIALS__ | #ifdef __RAY_DIFFERENTIALS__ | ||||
| // TODO: find a better approximation for the diffuse bounce | // TODO: find a better approximation for the diffuse bounce | ||||
| *domega_in_dx = -((2 * dot(N, dIdx)) * N - dIdx); | *domega_in_dx = -((2 * dot(N, dIdx)) * N - dIdx); | ||||
| *domega_in_dy = -((2 * dot(N, dIdy)) * N - dIdy); | *domega_in_dy = -((2 * dot(N, dIdy)) * N - dIdy); | ||||
| #endif | #endif | ||||
| } | } | ||||
| else { | else { | ||||
| *pdf = 0.0f; | *pdf = 0.0f; | ||||
| } | } | ||||
| return LABEL_REFLECT | LABEL_DIFFUSE; | return LABEL_REFLECT | LABEL_DIFFUSE; | ||||
| } | } | ||||
| CCL_NAMESPACE_END | CCL_NAMESPACE_END | ||||