Changeset View
Changeset View
Standalone View
Standalone View
intern/cycles/kernel/closure/bsdf_hair_principled.h
| /* | /* | ||||
| * Copyright 2018 Blender Foundation | * Copyright 2018 Blender Foundation | ||||
| * | * | ||||
| * Licensed under the Apache License, Version 2.0 (the "License"); | * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| * you may not use this file except in compliance with the License. | * you may not use this file except in compliance with the License. | ||||
| * You may obtain a copy of the License at | * You may obtain a copy of the License at | ||||
| * | * | ||||
| * http://www.apache.org/licenses/LICENSE-2.0 | * http://www.apache.org/licenses/LICENSE-2.0 | ||||
| * | * | ||||
| * Unless required by applicable law or agreed to in writing, software | * Unless required by applicable law or agreed to in writing, software | ||||
| * distributed under the License is distributed on an "AS IS" BASIS, | * distributed under the License is distributed on an "AS IS" BASIS, | ||||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| * See the License for the specific language governing permissions and | * See the License for the specific language governing permissions and | ||||
| * limitations under the License. | * limitations under the License. | ||||
| */ | */ | ||||
| #pragma once | |||||
| #ifdef __KERNEL_CPU__ | #ifdef __KERNEL_CPU__ | ||||
| # include <fenv.h> | # include <fenv.h> | ||||
| #endif | #endif | ||||
| #include "kernel/kernel_color.h" | #include "kernel/kernel_color.h" | ||||
| #ifndef __BSDF_HAIR_PRINCIPLED_H__ | |||||
| # define __BSDF_HAIR_PRINCIPLED_H__ | |||||
| CCL_NAMESPACE_BEGIN | CCL_NAMESPACE_BEGIN | ||||
| typedef ccl_addr_space struct PrincipledHairExtra { | typedef ccl_addr_space struct PrincipledHairExtra { | ||||
| /* Geometry data. */ | /* Geometry data. */ | ||||
| float4 geom; | float4 geom; | ||||
| } PrincipledHairExtra; | } PrincipledHairExtra; | ||||
| typedef ccl_addr_space struct PrincipledHairBSDF { | typedef ccl_addr_space struct PrincipledHairBSDF { | ||||
| ▲ Show 20 Lines • Show All 142 Lines • ▼ Show 20 Lines | ccl_device_inline float longitudinal_scattering( | ||||
| else { | else { | ||||
| float i0 = bessel_I0(cos_arg); | float i0 = bessel_I0(cos_arg); | ||||
| float val = (expf(-sin_arg) * i0) / (sinhf(inv_v) * 2.0f * v); | float val = (expf(-sin_arg) * i0) / (sinhf(inv_v) * 2.0f * v); | ||||
| return val; | return val; | ||||
| } | } | ||||
| } | } | ||||
| /* Combine the three values using their luminances. */ | /* Combine the three values using their luminances. */ | ||||
| ccl_device_inline float4 combine_with_energy(KernelGlobals *kg, float3 c) | ccl_device_inline float4 combine_with_energy(const KernelGlobals *kg, float3 c) | ||||
| { | { | ||||
| return make_float4(c.x, c.y, c.z, linear_rgb_to_gray(kg, c)); | return make_float4(c.x, c.y, c.z, linear_rgb_to_gray(kg, c)); | ||||
| } | } | ||||
| # ifdef __HAIR__ | #ifdef __HAIR__ | ||||
| /* Set up the hair closure. */ | /* Set up the hair closure. */ | ||||
| ccl_device int bsdf_principled_hair_setup(ShaderData *sd, PrincipledHairBSDF *bsdf) | ccl_device int bsdf_principled_hair_setup(ShaderData *sd, PrincipledHairBSDF *bsdf) | ||||
| { | { | ||||
| bsdf->type = CLOSURE_BSDF_HAIR_PRINCIPLED_ID; | bsdf->type = CLOSURE_BSDF_HAIR_PRINCIPLED_ID; | ||||
| bsdf->v = clamp(bsdf->v, 0.001f, 1.0f); | bsdf->v = clamp(bsdf->v, 0.001f, 1.0f); | ||||
| bsdf->s = clamp(bsdf->s, 0.001f, 1.0f); | bsdf->s = clamp(bsdf->s, 0.001f, 1.0f); | ||||
| /* Apply Primary Reflection Roughness modifier. */ | /* Apply Primary Reflection Roughness modifier. */ | ||||
| bsdf->m0_roughness = clamp(bsdf->m0_roughness * bsdf->v, 0.001f, 1.0f); | bsdf->m0_roughness = clamp(bsdf->m0_roughness * bsdf->v, 0.001f, 1.0f); | ||||
| Show All 23 Lines | ccl_device int bsdf_principled_hair_setup(ShaderData *sd, PrincipledHairBSDF *bsdf) | ||||
| kernel_assert(isfinite3_safe(Y)); | kernel_assert(isfinite3_safe(Y)); | ||||
| kernel_assert(isfinite_safe(h)); | kernel_assert(isfinite_safe(h)); | ||||
| bsdf->extra->geom = make_float4(Y.x, Y.y, Y.z, h); | bsdf->extra->geom = make_float4(Y.x, Y.y, Y.z, h); | ||||
| return SD_BSDF | SD_BSDF_HAS_EVAL | SD_BSDF_NEEDS_LCG; | return SD_BSDF | SD_BSDF_HAS_EVAL | SD_BSDF_NEEDS_LCG; | ||||
| } | } | ||||
| # endif /* __HAIR__ */ | #endif /* __HAIR__ */ | ||||
| /* Given the Fresnel term and transmittance, generate the attenuation terms for each bounce. */ | /* 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, float4 *Ap) | ccl_device_inline void hair_attenuation(const KernelGlobals *kg, float f, float3 T, float4 *Ap) | ||||
| { | { | ||||
| /* Primary specular (R). */ | /* Primary specular (R). */ | ||||
| Ap[0] = make_float4(f, f, f, f); | Ap[0] = make_float4(f, f, f, f); | ||||
| /* Transmission (TT). */ | /* Transmission (TT). */ | ||||
| float3 col = sqr(1.0f - f) * T; | float3 col = sqr(1.0f - f) * T; | ||||
| Ap[1] = combine_with_energy(kg, col); | Ap[1] = combine_with_energy(kg, col); | ||||
| Show All 32 Lines | ccl_device_inline void hair_alpha_angles(float sin_theta_i, | ||||
| angles[1] = fabsf(cos_theta_i * cos_2alpha - sin_theta_i * sin_2alpha); | angles[1] = fabsf(cos_theta_i * cos_2alpha - sin_theta_i * sin_2alpha); | ||||
| angles[2] = sin_theta_i * cos_1alpha - cos_theta_i * sin_1alpha; | angles[2] = sin_theta_i * cos_1alpha - cos_theta_i * sin_1alpha; | ||||
| angles[3] = fabsf(cos_theta_i * cos_1alpha + sin_theta_i * sin_1alpha); | angles[3] = fabsf(cos_theta_i * cos_1alpha + sin_theta_i * sin_1alpha); | ||||
| angles[4] = sin_theta_i * cos_4alpha - cos_theta_i * sin_4alpha; | angles[4] = sin_theta_i * cos_4alpha - cos_theta_i * sin_4alpha; | ||||
| angles[5] = fabsf(cos_theta_i * cos_4alpha + sin_theta_i * sin_4alpha); | angles[5] = fabsf(cos_theta_i * cos_4alpha + sin_theta_i * sin_4alpha); | ||||
| } | } | ||||
| /* Evaluation function for our shader. */ | /* Evaluation function for our shader. */ | ||||
| ccl_device float3 bsdf_principled_hair_eval(KernelGlobals *kg, | ccl_device float3 bsdf_principled_hair_eval(const KernelGlobals *kg, | ||||
| const ShaderData *sd, | const ShaderData *sd, | ||||
| const ShaderClosure *sc, | const ShaderClosure *sc, | ||||
| const float3 omega_in, | const float3 omega_in, | ||||
| float *pdf) | float *pdf) | ||||
| { | { | ||||
| kernel_assert(isfinite3_safe(sd->P) && isfinite_safe(sd->ray_length)); | kernel_assert(isfinite3_safe(sd->P) && isfinite_safe(sd->ray_length)); | ||||
| const PrincipledHairBSDF *bsdf = (const PrincipledHairBSDF *)sc; | const PrincipledHairBSDF *bsdf = (const PrincipledHairBSDF *)sc; | ||||
| ▲ Show 20 Lines • Show All 61 Lines • ▼ Show 20 Lines | ccl_device float3 bsdf_principled_hair_eval(const KernelGlobals *kg, | ||||
| F += Ap[3] * Mp * Np; | F += Ap[3] * Mp * Np; | ||||
| kernel_assert(isfinite3_safe(float4_to_float3(F))); | kernel_assert(isfinite3_safe(float4_to_float3(F))); | ||||
| *pdf = F.w; | *pdf = F.w; | ||||
| return float4_to_float3(F); | return float4_to_float3(F); | ||||
| } | } | ||||
| /* Sampling function for the hair shader. */ | /* Sampling function for the hair shader. */ | ||||
| ccl_device int bsdf_principled_hair_sample(KernelGlobals *kg, | ccl_device int bsdf_principled_hair_sample(const KernelGlobals *kg, | ||||
| const ShaderClosure *sc, | const ShaderClosure *sc, | ||||
| ShaderData *sd, | ShaderData *sd, | ||||
| float randu, | float randu, | ||||
| float randv, | float randv, | ||||
| float3 *eval, | float3 *eval, | ||||
| float3 *omega_in, | float3 *omega_in, | ||||
| float3 *domega_in_dx, | float3 *domega_in_dx, | ||||
| float3 *domega_in_dy, | float3 *domega_in_dy, | ||||
| ▲ Show 20 Lines • Show All 100 Lines • ▼ Show 20 Lines | ccl_device int bsdf_principled_hair_sample(const KernelGlobals *kg, | ||||
| F += Ap[3] * Mp * Np; | F += Ap[3] * Mp * Np; | ||||
| kernel_assert(isfinite3_safe(float4_to_float3(F))); | kernel_assert(isfinite3_safe(float4_to_float3(F))); | ||||
| *eval = float4_to_float3(F); | *eval = float4_to_float3(F); | ||||
| *pdf = F.w; | *pdf = F.w; | ||||
| *omega_in = X * sin_theta_i + Y * cos_theta_i * cosf(phi_i) + Z * cos_theta_i * sinf(phi_i); | *omega_in = X * sin_theta_i + Y * cos_theta_i * cosf(phi_i) + Z * cos_theta_i * sinf(phi_i); | ||||
| # ifdef __RAY_DIFFERENTIALS__ | #ifdef __RAY_DIFFERENTIALS__ | ||||
| float3 N = safe_normalize(sd->I + *omega_in); | float3 N = safe_normalize(sd->I + *omega_in); | ||||
| *domega_in_dx = (2 * dot(N, sd->dI.dx)) * N - sd->dI.dx; | *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; | *domega_in_dy = (2 * dot(N, sd->dI.dy)) * N - sd->dI.dy; | ||||
| # endif | #endif | ||||
| return LABEL_GLOSSY | ((p == 0) ? LABEL_REFLECT : LABEL_TRANSMIT); | return LABEL_GLOSSY | ((p == 0) ? LABEL_REFLECT : LABEL_TRANSMIT); | ||||
| } | } | ||||
| /* Implements Filter Glossy by capping the effective roughness. */ | /* Implements Filter Glossy by capping the effective roughness. */ | ||||
| ccl_device void bsdf_principled_hair_blur(ShaderClosure *sc, float roughness) | ccl_device void bsdf_principled_hair_blur(ShaderClosure *sc, float roughness) | ||||
| { | { | ||||
| PrincipledHairBSDF *bsdf = (PrincipledHairBSDF *)sc; | PrincipledHairBSDF *bsdf = (PrincipledHairBSDF *)sc; | ||||
| bsdf->v = fmaxf(roughness, bsdf->v); | bsdf->v = fmaxf(roughness, bsdf->v); | ||||
| bsdf->s = fmaxf(roughness, bsdf->s); | bsdf->s = fmaxf(roughness, bsdf->s); | ||||
| bsdf->m0_roughness = fmaxf(roughness, bsdf->m0_roughness); | bsdf->m0_roughness = fmaxf(roughness, bsdf->m0_roughness); | ||||
| } | } | ||||
| /* Hair Albedo */ | /* Hair Albedo */ | ||||
| ccl_device_inline float bsdf_principled_hair_albedo_roughness_scale( | ccl_device_inline float bsdf_principled_hair_albedo_roughness_scale( | ||||
| const float azimuthal_roughness) | const float azimuthal_roughness) | ||||
| { | { | ||||
| const float x = azimuthal_roughness; | const float x = azimuthal_roughness; | ||||
| return (((((0.245f * x) + 5.574f) * x - 10.73f) * x + 2.532f) * x - 0.215f) * x + 5.969f; | 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(ShaderClosure *sc) | ccl_device float3 bsdf_principled_hair_albedo(const ShaderClosure *sc) | ||||
| { | { | ||||
| PrincipledHairBSDF *bsdf = (PrincipledHairBSDF *)sc; | PrincipledHairBSDF *bsdf = (PrincipledHairBSDF *)sc; | ||||
| return exp3(-sqrt(bsdf->sigma) * bsdf_principled_hair_albedo_roughness_scale(bsdf->v)); | return exp3(-sqrt(bsdf->sigma) * bsdf_principled_hair_albedo_roughness_scale(bsdf->v)); | ||||
| } | } | ||||
| ccl_device_inline float3 | ccl_device_inline float3 | ||||
| bsdf_principled_hair_sigma_from_reflectance(const float3 color, const float azimuthal_roughness) | bsdf_principled_hair_sigma_from_reflectance(const float3 color, const float azimuthal_roughness) | ||||
| { | { | ||||
| const float3 sigma = log3(color) / | const float3 sigma = log3(color) / | ||||
| bsdf_principled_hair_albedo_roughness_scale(azimuthal_roughness); | bsdf_principled_hair_albedo_roughness_scale(azimuthal_roughness); | ||||
| return sigma * sigma; | return sigma * sigma; | ||||
| } | } | ||||
| ccl_device_inline float3 bsdf_principled_hair_sigma_from_concentration(const float eumelanin, | ccl_device_inline float3 bsdf_principled_hair_sigma_from_concentration(const float eumelanin, | ||||
| const float pheomelanin) | const float pheomelanin) | ||||
| { | { | ||||
| return eumelanin * make_float3(0.506f, 0.841f, 1.653f) + | return eumelanin * make_float3(0.506f, 0.841f, 1.653f) + | ||||
| pheomelanin * make_float3(0.343f, 0.733f, 1.924f); | pheomelanin * make_float3(0.343f, 0.733f, 1.924f); | ||||
| } | } | ||||
| CCL_NAMESPACE_END | CCL_NAMESPACE_END | ||||
| #endif /* __BSDF_HAIR_PRINCIPLED_H__ */ | |||||