Commit: 68573757bc5fb615f6bf2e27056f6e10a556bf70 Author: Weizhen Huang Date: Tue Dec 6 18:43:56 2022 +0100 Branches: microfacet_hair https://developer.blender.org/rB68573757bc5fb615f6bf2e27056f6e10a556bf70
Cycles: initial commit of microfacet hair bsdf This is an implementation of the paper [A Microfacet-based Hair Scattering Model](https://onlinelibrary.wiley.com/doi/full/10.1111/cgf.14588) by Weizhen Huang, Matthias Hullin, and Johannes Hanika. Original implementation in [Mitsuba 2](https://github.com/RiverIntheSky/roughhair) by Weizhen Huang. Adapted to Cycles by Olivier Maury D16682 and Christophe Hery. =================================================================== M intern/cycles/blender/shader.cpp M intern/cycles/kernel/CMakeLists.txt M intern/cycles/kernel/closure/bsdf.h A intern/cycles/kernel/closure/bsdf_hair_microfacet.h M intern/cycles/kernel/film/denoising_passes.h M intern/cycles/kernel/osl/shaders/CMakeLists.txt A intern/cycles/kernel/osl/shaders/node_microfacet_hair_bsdf.osl M intern/cycles/kernel/osl/shaders/stdcycles.h M intern/cycles/kernel/svm/closure.h M intern/cycles/kernel/svm/types.h M intern/cycles/scene/shader_graph.cpp M intern/cycles/scene/shader_nodes.cpp M intern/cycles/scene/shader_nodes.h M release/datafiles/locale M release/scripts/addons M source/blender/blenkernel/BKE_node.h M source/blender/gpu/shaders/material/gpu_shader_material_hair.glsl M source/blender/makesdna/DNA_node_types.h M source/blender/makesrna/intern/rna_nodetree.c M source/blender/nodes/NOD_static_types.h M source/blender/nodes/shader/CMakeLists.txt M source/blender/nodes/shader/node_shader_register.cc M source/blender/nodes/shader/node_shader_register.hh M source/blender/nodes/shader/node_shader_tree.cc A source/blender/nodes/shader/nodes/node_shader_bsdf_hair_microfacet.cc =================================================================== diff --git a/intern/cycles/blender/shader.cpp b/intern/cycles/blender/shader.cpp index f25e98469fb..43bc5538628 100644 --- a/intern/cycles/blender/shader.cpp +++ b/intern/cycles/blender/shader.cpp @@ -660,6 +660,21 @@ static ShaderNode *add_node(Scene *scene, NODE_PRINCIPLED_HAIR_REFLECTANCE)); node = principled_hair; } + else if (b_node.is_a(&RNA_ShaderNodeBsdfHairMicrofacet)) { + BL::ShaderNodeBsdfHairMicrofacet b_microfacet_hair_node(b_node); + MicrofacetHairBsdfNode *microfacet_hair = graph->create_node<MicrofacetHairBsdfNode>(); + microfacet_hair->set_parametrization( + (NodeMicrofacetHairParametrization)get_enum(b_microfacet_hair_node.ptr, + "parametrization", + NODE_MICROFACET_HAIR_NUM, + NODE_MICROFACET_HAIR_REFLECTANCE)); + microfacet_hair->set_model_type( + (NodeMicrofacetHairModelType)get_enum(b_microfacet_hair_node.ptr, + "model_type", + NODE_MICROFACET_HAIR_MODEL_TYPE_NUM, + NODE_MICROFACET_HAIR_CIRCULAR_GGX)); + node = microfacet_hair; + } else if (b_node.is_a(&RNA_ShaderNodeBsdfPrincipled)) { BL::ShaderNodeBsdfPrincipled b_principled_node(b_node); PrincipledBsdfNode *principled = graph->create_node<PrincipledBsdfNode>(); diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt index 9dc343f597d..a203adda324 100644 --- a/intern/cycles/kernel/CMakeLists.txt +++ b/intern/cycles/kernel/CMakeLists.txt @@ -128,6 +128,7 @@ set(SRC_KERNEL_CLOSURE_HEADERS closure/bsdf_principled_diffuse.h closure/bsdf_principled_sheen.h closure/bsdf_hair_principled.h + closure/bsdf_hair_microfacet.h ) set(SRC_KERNEL_SVM_HEADERS diff --git a/intern/cycles/kernel/closure/bsdf.h b/intern/cycles/kernel/closure/bsdf.h index 2f5c5d7bd0c..23c64205c70 100644 --- a/intern/cycles/kernel/closure/bsdf.h +++ b/intern/cycles/kernel/closure/bsdf.h @@ -18,6 +18,7 @@ #include "kernel/closure/bsdf_toon.h" #include "kernel/closure/bsdf_hair.h" #include "kernel/closure/bsdf_hair_principled.h" +#include "kernel/closure/bsdf_hair_microfacet.h" #include "kernel/closure/bsdf_principled_diffuse.h" #include "kernel/closure/bsdf_principled_sheen.h" #include "kernel/closure/bssrdf.h" @@ -243,6 +244,10 @@ ccl_device_inline int bsdf_sample(KernelGlobals kg, label = bsdf_principled_hair_sample( kg, sc, sd, randu, randv, eval, omega_in, pdf, sampled_roughness, eta); break; + case CLOSURE_BSDF_HAIR_MICROFACET_ID: + label = bsdf_microfacet_hair_sample( + kg, sc, sd, randu, randv, eval, omega_in, pdf, sampled_roughness, eta); + break; case CLOSURE_BSDF_PRINCIPLED_DIFFUSE_ID: label = bsdf_principled_diffuse_sample(sc, Ng, sd->I, randu, randv, eval, omega_in, pdf); *sampled_roughness = one_float2(); @@ -408,6 +413,11 @@ ccl_device_inline void bsdf_roughness_eta(const KernelGlobals kg, *roughness = make_float2(alpha, alpha); *eta = ((ccl_private PrincipledHairBSDF *)sc)->eta; break; + case CLOSURE_BSDF_HAIR_MICROFACET_ID: + alpha = ((ccl_private MicrofacetHairBSDF *)sc)->roughness; + *roughness = make_float2(alpha, alpha); + *eta = ((ccl_private MicrofacetHairBSDF *)sc)->eta; + break; case CLOSURE_BSDF_PRINCIPLED_DIFFUSE_ID: *roughness = one_float2(); *eta = 1.0f; @@ -504,6 +514,7 @@ ccl_device_inline int bsdf_label(const KernelGlobals kg, label = LABEL_TRANSMIT | LABEL_GLOSSY; break; case CLOSURE_BSDF_HAIR_PRINCIPLED_ID: + case CLOSURE_BSDF_HAIR_MICROFACET_ID: if (bsdf_is_transmission(sc, omega_in)) label = LABEL_TRANSMIT | LABEL_GLOSSY; else @@ -609,6 +620,9 @@ ccl_device_inline case CLOSURE_BSDF_HAIR_PRINCIPLED_ID: eval = bsdf_principled_hair_eval(kg, sd, sc, omega_in, pdf); break; + case CLOSURE_BSDF_HAIR_MICROFACET_ID: + eval = bsdf_microfacet_hair_eval(kg, sd, sc, omega_in, pdf); + break; case CLOSURE_BSDF_HAIR_REFLECTION_ID: eval = bsdf_hair_reflection_eval(sc, sd->I, omega_in, pdf); break; @@ -676,6 +690,9 @@ ccl_device void bsdf_blur(KernelGlobals kg, ccl_private ShaderClosure *sc, float case CLOSURE_BSDF_HAIR_PRINCIPLED_ID: bsdf_principled_hair_blur(sc, roughness); break; + case CLOSURE_BSDF_HAIR_MICROFACET_ID: + bsdf_microfacet_hair_blur(sc, roughness); + break; default: break; } diff --git a/intern/cycles/kernel/closure/bsdf_hair_microfacet.h b/intern/cycles/kernel/closure/bsdf_hair_microfacet.h new file mode 100644 index 00000000000..6095ebcac41 --- /dev/null +++ b/intern/cycles/kernel/closure/bsdf_hair_microfacet.h @@ -0,0 +1,1598 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright 2018-2022 Blender Foundation */ + +#pragma once + +#ifndef __KERNEL_GPU__ +# include <fenv.h> +#endif + +#include "kernel/util/color.h" + +CCL_NAMESPACE_BEGIN + +typedef struct MicrofacetHairExtra { + float R; + float TT; + float TRT; + + float eccentricity; + float twist_rate; + float attr_descr_intercept; + float attr_descr_length; + + float axis_rot; + float diffraction_weight; + float pad1, pad2, pad3; + + /* Geometry data. */ + float4 geom; +} MicrofacetHairExtra; + +typedef struct MicrofacetHairBSDF { + SHADER_CLOSURE_BASE; + + /* Absorption coefficient. */ + Spectrum sigma; + /* Microfacet distribution roughness. */ + float roughness; + /* Cuticle tilt angle. */ + float alpha; + /* IOR. */ + float eta; + + /* Blur. */ + float blur; + + /* Circular/Ellipitic and GGX/Beckmann. */ + int model_type; + + /* Extra closure. */ + ccl_private MicrofacetHairExtra *extra; +} MicrofacetHairBSDF; + +static_assert(sizeof(ShaderClosure) >= sizeof(MicrofacetHairBSDF), + "MicrofacetHairBSDF is too large!"); +static_assert(sizeof(ShaderClosure) >= sizeof(MicrofacetHairExtra), + "MicrofacetHairExtra is too large!"); + +#ifdef __HAIR__ +/* Set up the hair closure. */ +ccl_device int bsdf_microfacet_hair_setup(ccl_private ShaderData *sd, + ccl_private MicrofacetHairBSDF *bsdf) +{ + bsdf->type = CLOSURE_BSDF_HAIR_MICROFACET_ID; + + bsdf->roughness = clamp(bsdf->roughness, 0.001f, 1.0f); + + /* Compute local frame, aligned to curve tangent and ray direction. */ + float3 X = safe_normalize(sd->dPdu); + float3 Y = safe_normalize(cross(X, sd->I)); + + /* h -1..0..1 means the rays goes from grazing the hair, to hitting it at + * the center, to grazing the other edge. This is the sine of the angle + * between sd->Ng and Z, as seen from the tangent X. */ + + /* TODO: we convert this value to a cosine later and discard the sign, so + * we could probably save some operations. */ + float h = (sd->type & PRIMITIVE_CURVE_RIBBON) ? -sd->v : -dot(Y, sd->Ng); + + kernel_assert(fabsf(h) < 1.0f + 1e-4f); + kernel_assert(isfinite_safe(Y)); + kernel_assert(isfinite_safe(h)); + + bsdf->extra->geom = make_float4(Y.x, Y.y, Y.z, h); + + return SD_BSDF | SD_BSDF_HAS_EVAL | SD_BSDF_NEEDS_LCG | SD_BSDF_HAS_TRANSMISSION; +} + +#endif /* __HAIR__ */ + +ccl_device_inline float3 make_float3_from_float(const float f) +{ + return make_float3(f, f, f); +} + +ccl_device_inline float3 reflect_vector(const float3 w, const float3 n) +{ + return 2.f * dot(w, n) * n - w; +} + +ccl_device float3 refract_vector(const float3 w, + const float3 n, + const float cos_theta_t, + const float eta_ti) +{ + return n * (dot(w, n) * eta_ti + cos_theta_t) - w * eta_ti; +} + +ccl_device_inline float3 microfacet_visible_normal_sample(KernelGlobals kg, + const bool beckmann, + const float roughness, + const float3 wi, + const float randu, + const float randv, + ccl_private float *G1i) +{ + /* Step 1 : stretch wi */ + float3 omega_i_ = normalize(make_float3(roughness * wi.x, roughness * wi.y, wi.z)); + + /* get polar coordinates of omega_i_ */ + float costheta_ = 1.f; + float sintheta_ = 0.f; + float cosphi_ = 1.f; + float sinphi_ = 0.f; + + if (omega_i_.z < 0.99999f) { + costheta_ = omega_i_.z; + sintheta_ = safe_sqrtf(1.f - costheta_ * costheta_); + + float invlen = 1.f / sintheta_; + cosphi_ = omega_i_.x * invlen; + sinphi_ = omega_i_.y * invlen; + } + + /* 2. sample P22_{omega_i}(x_slope, y_slope, 1, 1) */ + float slope_x, slope_y; + + if (beckmann) { + microfacet_beckmann_sample_slopes( + kg, costheta_, sintheta_, randu, randv, &slope_x, &slope_y, G1i); + } + else { + microfacet_ggx_sample_slopes(costheta_, sintheta_, randu, randv, &slope_x, &slope_y, G1i); + } + + /* 3. rotate */ + float tmp = cosphi_ * slope_x - sinphi_ * slope_y; + slope_y = sinphi_ * slope_x + cosphi_ * slope_y; + slope_x = tmp; + + /* 4. unstretch */ + slope_x = roughness * slope_x; + slope_y = roughness * slope_y; + + /* 5. compute normal */ + return normalize(make_float3(-slope_x, -slope_y, 1.f)); +} + +/* returns sin_theta */ +ccl_device_inline float sintheta(const float3 w) +{ + return w.y; +} + +/* returns cos_theta */ +ccl_device_inline float costheta(const float3 w) +{ + return safe_sqrtf(sqr(w.x) + sqr(w.z)); +} + +/* returns tan_theta */ +ccl_device_inline float tantheta(const float3 w) +{ + return sintheta(w) / costheta(w); +} + +/* extract theta coordinate from 3D direction + * -pi < theta < pi */ +ccl_device_inline float dir_theta(const float3 w) +{ + return atan2f(sintheta(w), costheta(w)); +} + +/* extract phi coordinate from 3D direction. + * -pi < phi < pi + * Assuming phi(wi @@ Diff output truncated at 10240 characters. @@ _______________________________________________ Bf-blender-cvs mailing list Bf-blender-cvs@blender.org List details, subscription details or unsubscribe: https://lists.blender.org/mailman/listinfo/bf-blender-cvs