Cycles: new Microfacet-based Hair BSDF with elliptical cross-section support #105600

Merged
Weizhen Huang merged 114 commits from weizhen/blender:microfacet_hair into main 2023-08-18 12:46:20 +02:00
16 changed files with 251 additions and 251 deletions
Showing only changes of commit e6b102efc9 - Show all commits

View File

@ -139,8 +139,8 @@ set(SRC_KERNEL_CLOSURE_HEADERS
closure/bssrdf.h
closure/emissive.h
closure/volume.h
closure/bsdf_hair_principled.h
closure/bsdf_hair_microfacet.h
closure/bsdf_principled_hair_chiang.h
closure/bsdf_principled_hair_huang.h
)
set(SRC_KERNEL_SVM_HEADERS

View File

@ -16,8 +16,8 @@
#include "kernel/closure/bsdf_ashikhmin_shirley.h"
#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_hair_chiang.h"
#include "kernel/closure/bsdf_principled_hair_huang.h"
#include "kernel/closure/bssrdf.h"
#include "kernel/closure/volume.h"
// clang-format on
@ -196,11 +196,11 @@ ccl_device_inline int bsdf_sample(KernelGlobals kg,
sc, Ng, sd->wi, rand_xy, eval, wo, pdf, sampled_roughness);
*eta = 1.0f;
break;
case CLOSURE_BSDF_HAIR_PRINCIPLED_ID:
label = bsdf_principled_hair_sample(kg, sc, sd, rand, eval, wo, pdf, sampled_roughness, eta);
case CLOSURE_BSDF_HAIR_CHIANG_ID:
label = bsdf_hair_chiang_sample(kg, sc, sd, rand, eval, wo, pdf, sampled_roughness, eta);
break;
case CLOSURE_BSDF_HAIR_MICROFACET_ID:
label = bsdf_microfacet_hair_sample(kg, sc, sd, rand, eval, wo, pdf, sampled_roughness, eta);
case CLOSURE_BSDF_HAIR_HUANG_ID:
label = bsdf_hair_huang_sample(kg, sc, sd, rand, eval, wo, pdf, sampled_roughness, eta);
break;
case CLOSURE_BSDF_SHEEN_ID:
label = bsdf_sheen_sample(sc, Ng, sd->wi, rand_xy, eval, wo, pdf);
@ -329,15 +329,15 @@ ccl_device_inline void bsdf_roughness_eta(const KernelGlobals kg,
((ccl_private HairBsdf *)sc)->roughness2);
*eta = 1.0f;
break;
case CLOSURE_BSDF_HAIR_PRINCIPLED_ID:
alpha = ((ccl_private PrincipledHairBSDF *)sc)->m0_roughness;
case CLOSURE_BSDF_HAIR_CHIANG_ID:
alpha = ((ccl_private ChiangHairBSDF *)sc)->m0_roughness;
*roughness = make_float2(alpha, alpha);
*eta = ((ccl_private PrincipledHairBSDF *)sc)->eta;
*eta = ((ccl_private ChiangHairBSDF *)sc)->eta;
break;
case CLOSURE_BSDF_HAIR_MICROFACET_ID:
alpha = ((ccl_private MicrofacetHairBSDF *)sc)->roughness;
case CLOSURE_BSDF_HAIR_HUANG_ID:
alpha = ((ccl_private HuangHairBSDF *)sc)->roughness;
*roughness = make_float2(alpha, alpha);
*eta = ((ccl_private MicrofacetHairBSDF *)sc)->eta;
*eta = ((ccl_private HuangHairBSDF *)sc)->eta;
break;
case CLOSURE_BSDF_SHEEN_ID:
alpha = ((ccl_private SheenBsdf *)sc)->roughness;
@ -414,13 +414,13 @@ ccl_device_inline int bsdf_label(const KernelGlobals kg,
case CLOSURE_BSDF_HAIR_TRANSMISSION_ID:
label = LABEL_TRANSMIT | LABEL_GLOSSY;
break;
case CLOSURE_BSDF_HAIR_PRINCIPLED_ID:
case CLOSURE_BSDF_HAIR_CHIANG_ID:
if (bsdf_is_transmission(sc, wo))
label = LABEL_TRANSMIT | LABEL_GLOSSY;
else
label = LABEL_REFLECT | LABEL_GLOSSY;
break;
case CLOSURE_BSDF_HAIR_MICROFACET_ID:
case CLOSURE_BSDF_HAIR_HUANG_ID:
label = LABEL_REFLECT | LABEL_GLOSSY;
break;
case CLOSURE_BSDF_SHEEN_ID:
@ -505,11 +505,11 @@ ccl_device_inline
case CLOSURE_BSDF_GLOSSY_TOON_ID:
eval = bsdf_glossy_toon_eval(sc, sd->wi, wo, pdf);
break;
case CLOSURE_BSDF_HAIR_PRINCIPLED_ID:
eval = bsdf_principled_hair_eval(kg, sd, sc, wo, pdf);
case CLOSURE_BSDF_HAIR_CHIANG_ID:
eval = bsdf_hair_chiang_eval(kg, sd, sc, wo, pdf);
break;
case CLOSURE_BSDF_HAIR_MICROFACET_ID:
eval = bsdf_microfacet_hair_eval(kg, sd, sc, wo, pdf);
case CLOSURE_BSDF_HAIR_HUANG_ID:
eval = bsdf_hair_huang_eval(kg, sd, sc, wo, pdf);
break;
case CLOSURE_BSDF_HAIR_REFLECTION_ID:
eval = bsdf_hair_reflection_eval(sc, sd->wi, wo, pdf);
@ -566,11 +566,11 @@ ccl_device void bsdf_blur(KernelGlobals kg, ccl_private ShaderClosure *sc, float
case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID:
bsdf_ashikhmin_shirley_blur(sc, roughness);
break;
case CLOSURE_BSDF_HAIR_PRINCIPLED_ID:
bsdf_principled_hair_blur(sc, roughness);
case CLOSURE_BSDF_HAIR_CHIANG_ID:
bsdf_hair_chiang_blur(sc, roughness);
break;
case CLOSURE_BSDF_HAIR_MICROFACET_ID:
bsdf_microfacet_hair_blur(sc, roughness);
case CLOSURE_BSDF_HAIR_HUANG_ID:
bsdf_hair_huang_blur(sc, roughness);
break;
default:
break;
@ -599,13 +599,13 @@ ccl_device_inline Spectrum bsdf_albedo(KernelGlobals kg,
albedo *= bsdf_microfacet_estimate_albedo(
kg, sd, (ccl_private const MicrofacetBsdf *)sc, reflection, transmission);
}
else if (sc->type == CLOSURE_BSDF_HAIR_PRINCIPLED_ID) {
else if (sc->type == CLOSURE_BSDF_HAIR_CHIANG_ID) {
/* TODO(lukas): Principled Hair could also be split into a glossy and a transmission component,
* similar to Glass BSDFs. */
albedo *= bsdf_principled_hair_albedo(sd, sc);
albedo *= bsdf_hair_chiang_albedo(sd, sc);
}
else if (sc->type == CLOSURE_BSDF_HAIR_MICROFACET_ID) {
albedo *= bsdf_microfacet_hair_albedo(sd, sc);
else if (sc->type == CLOSURE_BSDF_HAIR_HUANG_ID) {
albedo *= bsdf_hair_huang_albedo(sd, sc);
}
#endif
return albedo;

View File

@ -1,6 +1,9 @@
/* SPDX-FileCopyrightText: 2018-2022 Blender Foundation
*
* SPDX-License-Identifier: Apache-2.0 */
* SPDX-License-Identifier: Apache-2.0
*
* This code implements the paper [A practical and controllable hair and fur model for production
* path tracing](https://doi.org/10.1145/2775280.2792559) by Chiang, Matt Jen-Yuan, et al. */
#pragma once
@ -12,12 +15,12 @@
CCL_NAMESPACE_BEGIN
typedef struct PrincipledHairExtra {
typedef struct ChiangHairExtra {
/* Geometry data. */
float4 geom;
} PrincipledHairExtra;
} ChiangHairExtra;
typedef struct PrincipledHairBSDF {
typedef struct ChiangHairBSDF {
SHADER_CLOSURE_BASE;
/* Absorption coefficient. */
@ -34,13 +37,11 @@ typedef struct PrincipledHairBSDF {
float m0_roughness;
/* Extra closure. */
ccl_private PrincipledHairExtra *extra;
} PrincipledHairBSDF;
ccl_private ChiangHairExtra *extra;
} ChiangHairBSDF;
static_assert(sizeof(ShaderClosure) >= sizeof(PrincipledHairBSDF),
"PrincipledHairBSDF is too large!");
static_assert(sizeof(ShaderClosure) >= sizeof(PrincipledHairExtra),
"PrincipledHairExtra is too large!");
static_assert(sizeof(ShaderClosure) >= sizeof(ChiangHairBSDF), "ChiangHairBSDF is too large!");
static_assert(sizeof(ShaderClosure) >= sizeof(ChiangHairExtra), "ChiangHairExtra is too large!");
/* Gives the change in direction in the normal plane for the given angles and p-th-order
* scattering. */
@ -158,10 +159,9 @@ ccl_device_inline float longitudinal_scattering(
#ifdef __HAIR__
/* Set up the hair closure. */
ccl_device int bsdf_principled_hair_setup(ccl_private ShaderData *sd,
ccl_private PrincipledHairBSDF *bsdf)
ccl_device int bsdf_hair_chiang_setup(ccl_private ShaderData *sd, ccl_private ChiangHairBSDF *bsdf)
{
bsdf->type = CLOSURE_BSDF_HAIR_PRINCIPLED_ID;
bsdf->type = CLOSURE_BSDF_HAIR_CHIANG_ID;
bsdf->v = clamp(bsdf->v, 0.001f, 1.0f);
bsdf->s = clamp(bsdf->s, 0.001f, 1.0f);
/* Apply Primary Reflection Roughness modifier. */
@ -252,15 +252,15 @@ ccl_device_inline void hair_alpha_angles(float sin_theta_i,
}
/* Evaluation function for our shader. */
ccl_device Spectrum bsdf_principled_hair_eval(KernelGlobals kg,
ccl_private const ShaderData *sd,
ccl_private const ShaderClosure *sc,
const float3 wo,
ccl_private float *pdf)
ccl_device Spectrum bsdf_hair_chiang_eval(KernelGlobals kg,
ccl_private const ShaderData *sd,
ccl_private const ShaderClosure *sc,
const float3 wo,
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;
ccl_private const ChiangHairBSDF *bsdf = (ccl_private const ChiangHairBSDF *)sc;
const float3 Y = float4_to_float3(bsdf->extra->geom);
const float3 X = safe_normalize(sd->dPdu);
@ -334,17 +334,17 @@ ccl_device Spectrum bsdf_principled_hair_eval(KernelGlobals kg,
}
/* Sampling function for the hair shader. */
ccl_device int bsdf_principled_hair_sample(KernelGlobals kg,
ccl_private const ShaderClosure *sc,
ccl_private ShaderData *sd,
float3 rand,
ccl_private Spectrum *eval,
ccl_private float3 *wo,
ccl_private float *pdf,
ccl_private float2 *sampled_roughness,
ccl_private float *eta)
ccl_device int bsdf_hair_chiang_sample(KernelGlobals kg,
ccl_private const ShaderClosure *sc,
ccl_private ShaderData *sd,
float3 rand,
ccl_private Spectrum *eval,
ccl_private float3 *wo,
ccl_private float *pdf,
ccl_private float2 *sampled_roughness,
ccl_private float *eta)
{
ccl_private PrincipledHairBSDF *bsdf = (ccl_private PrincipledHairBSDF *)sc;
ccl_private ChiangHairBSDF *bsdf = (ccl_private ChiangHairBSDF *)sc;
*sampled_roughness = make_float2(bsdf->m0_roughness, bsdf->m0_roughness);
*eta = bsdf->eta;
@ -456,27 +456,20 @@ ccl_device int bsdf_principled_hair_sample(KernelGlobals kg,
}
/* Implements Filter Glossy by capping the effective roughness. */
ccl_device void bsdf_principled_hair_blur(ccl_private ShaderClosure *sc, float roughness)
ccl_device void bsdf_hair_chiang_blur(ccl_private ShaderClosure *sc, float roughness)
{
ccl_private PrincipledHairBSDF *bsdf = (ccl_private PrincipledHairBSDF *)sc;
ccl_private ChiangHairBSDF *bsdf = (ccl_private ChiangHairBSDF *)sc;
bsdf->v = fmaxf(roughness, bsdf->v);
bsdf->s = fmaxf(roughness, bsdf->s);
bsdf->m0_roughness = fmaxf(roughness, bsdf->m0_roughness);
}
/* Hair Albedo. Also used in `bsdf_hair_microfacet.h` */
ccl_device_inline float bsdf_principled_hair_albedo_roughness_scale(
const float azimuthal_roughness)
/* Hair Albedo. */
ccl_device Spectrum bsdf_hair_chiang_albedo(ccl_private const ShaderData *sd,
ccl_private const ShaderClosure *sc)
{
const float x = azimuthal_roughness;
return (((((0.245f * x) + 5.574f) * x - 10.73f) * x + 2.532f) * x - 0.215f) * x + 5.969f;
}
ccl_device Spectrum bsdf_principled_hair_albedo(ccl_private const ShaderData *sd,
ccl_private const ShaderClosure *sc)
{
ccl_private PrincipledHairBSDF *bsdf = (ccl_private PrincipledHairBSDF *)sc;
ccl_private ChiangHairBSDF *bsdf = (ccl_private ChiangHairBSDF *)sc;
const float cos_theta_o = cos_from_sin(dot(sd->wi, safe_normalize(sd->dPdu)));
const float cos_gamma_o = cos_from_sin(bsdf->extra->geom.w);
@ -487,22 +480,4 @@ ccl_device Spectrum bsdf_principled_hair_albedo(ccl_private const ShaderData *sd
return exp(-sqrt(bsdf->sigma) * roughness_scale) + make_spectrum(f);
}
ccl_device_inline Spectrum
bsdf_principled_hair_sigma_from_reflectance(const Spectrum color, const float azimuthal_roughness)
{
const Spectrum sigma = log(color) /
bsdf_principled_hair_albedo_roughness_scale(azimuthal_roughness);
return sigma * sigma;
}
ccl_device_inline Spectrum bsdf_principled_hair_sigma_from_concentration(const float eumelanin,
const float pheomelanin)
{
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

View File

@ -1,8 +1,8 @@
/* SPDX-FileCopyrightText: 2023 Blender Foundation
*
* SPDX-License-Identifier: Apache-2.0 */
* SPDX-License-Identifier: Apache-2.0
/* This code implements the paper [A Microfacet-based Hair Scattering
* This code implements the paper [A Microfacet-based Hair Scattering
* Model](https://onlinelibrary.wiley.com/doi/full/10.1111/cgf.14588) by Weizhen Huang, Matthias B.
* Hullin and Johannes Hanika. */
@ -14,7 +14,7 @@
CCL_NAMESPACE_BEGIN
typedef struct MicrofacetHairExtra {
typedef struct HuangHairExtra {
/* Optional modulation factors. */
float R, TT, TRT;
@ -29,9 +29,9 @@ typedef struct MicrofacetHairExtra {
/* Squared Eccentricity. */
float e2;
} MicrofacetHairExtra;
} HuangHairExtra;
typedef struct MicrofacetHairBSDF {
typedef struct HuangHairBSDF {
SHADER_CLOSURE_BASE;
/* Absorption coefficient. */
@ -53,13 +53,11 @@ typedef struct MicrofacetHairBSDF {
float h;
/* Extra closure for optional modulation factors and local coordinate system. */
ccl_private MicrofacetHairExtra *extra;
} MicrofacetHairBSDF;
ccl_private HuangHairExtra *extra;
} HuangHairBSDF;
static_assert(sizeof(ShaderClosure) >= sizeof(MicrofacetHairBSDF),
"MicrofacetHairBSDF is too large!");
static_assert(sizeof(ShaderClosure) >= sizeof(MicrofacetHairExtra),
"MicrofacetHairExtra is too large!");
static_assert(sizeof(ShaderClosure) >= sizeof(HuangHairBSDF), "HuangHairBSDF is too large!");
static_assert(sizeof(ShaderClosure) >= sizeof(HuangHairExtra), "HuangHairExtra is too large!");
/* -------------------------------------------------------------------- */
/** \name Hair coordinate system utils.
@ -176,11 +174,11 @@ ccl_device_inline float arc_length(float e2, float gamma)
#ifdef __HAIR__
/* Set up the hair closure. */
ccl_device int bsdf_microfacet_hair_setup(ccl_private ShaderData *sd,
ccl_private MicrofacetHairBSDF *bsdf,
uint32_t path_flag)
ccl_device int bsdf_hair_huang_setup(ccl_private ShaderData *sd,
ccl_private HuangHairBSDF *bsdf,
uint32_t path_flag)
{
bsdf->type = CLOSURE_BSDF_HAIR_MICROFACET_ID;
bsdf->type = CLOSURE_BSDF_HAIR_HUANG_ID;
bsdf->roughness = clamp(bsdf->roughness, 0.001f, 1.0f);
@ -243,7 +241,7 @@ ccl_device int bsdf_microfacet_hair_setup(ccl_private ShaderData *sd,
#endif /* __HAIR__ */
/* Albedo correction, treat as glass. `rough` has already applied square root. */
ccl_device_forceinline float microfacet_hair_energy_scale(KernelGlobals kg,
ccl_device_forceinline float bsdf_hair_huang_energy_scale(KernelGlobals kg,
float mu,
float rough,
float ior)
@ -293,12 +291,12 @@ ccl_device_inline float bsdf_Go(float alpha2, float cos_NI, float cos_NO)
return (1.0f + lambdaI) / (1.0f + lambdaI + lambdaO);
}
ccl_device Spectrum bsdf_microfacet_hair_eval_r(KernelGlobals kg,
ccl_private const ShaderClosure *sc,
const float3 wi,
const float3 wo)
ccl_device Spectrum bsdf_hair_huang_eval_r(KernelGlobals kg,
ccl_private const ShaderClosure *sc,
const float3 wi,
const float3 wo)
{
ccl_private MicrofacetHairBSDF *bsdf = (ccl_private MicrofacetHairBSDF *)sc;
ccl_private HuangHairBSDF *bsdf = (ccl_private HuangHairBSDF *)sc;
if (bsdf->extra->R <= 0.0f) {
return zero_float3();
@ -376,7 +374,7 @@ ccl_device Spectrum bsdf_microfacet_hair_eval_r(KernelGlobals kg,
const float G = bsdf_G<MicrofacetType::GGX>(roughness2, cos_mi, dot(wm, wo));
integral += weight * bsdf_D<MicrofacetType::GGX>(roughness2, dot(wm, wh)) * G *
arc_length(bsdf->extra->e2, gamma_m) *
microfacet_hair_energy_scale(kg, cos_mi, sqrtf(roughness), bsdf->eta);
bsdf_hair_huang_energy_scale(kg, cos_mi, sqrtf(roughness), bsdf->eta);
}
}
@ -389,7 +387,7 @@ ccl_device Spectrum bsdf_microfacet_hair_eval_r(KernelGlobals kg,
/* Approximate components beyond TRT (starting TRRT) by summing up a geometric series. Attenuations
* are approximated from previous interactions. */
ccl_device Spectrum bsdf_microfacet_hair_eval_trrt(const float T, const float R, const Spectrum A)
ccl_device Spectrum bsdf_hair_huang_eval_trrt(const float T, const float R, const Spectrum A)
{
/* `T` could be zero due to total internal reflection. Clamp to avoid numerical issues. */
const float T_avg = max(1.0f - R, 1e-5f);
@ -399,13 +397,13 @@ ccl_device Spectrum bsdf_microfacet_hair_eval_trrt(const float T, const float R,
/* Evaluate components beyond R using numerical integration. TT and TRT are computed via combined
* Monte Carlo-Simpson integration; components beyond TRRT are integrated via Simpson's method. */
ccl_device Spectrum bsdf_microfacet_hair_eval_residual(KernelGlobals kg,
ccl_private const ShaderClosure *sc,
const float3 wi,
const float3 wo,
uint rng_quadrature)
ccl_device Spectrum bsdf_hair_huang_eval_residual(KernelGlobals kg,
ccl_private const ShaderClosure *sc,
const float3 wi,
const float3 wo,
uint rng_quadrature)
{
ccl_private MicrofacetHairBSDF *bsdf = (ccl_private MicrofacetHairBSDF *)sc;
ccl_private HuangHairBSDF *bsdf = (ccl_private HuangHairBSDF *)sc;
if (bsdf->extra->TT <= 0.0f && bsdf->extra->TRT <= 0.0f) {
return zero_spectrum();
@ -472,7 +470,7 @@ ccl_device Spectrum bsdf_microfacet_hair_eval_residual(KernelGlobals kg,
const float cos_mi1 = dot(wi, wmi);
float cos_theta_t1;
const float T1 = 1.0f - fresnel_dielectric(cos_hi1, eta, &cos_theta_t1);
const float scale1 = microfacet_hair_energy_scale(kg, cos_mi1, sqrt_roughness, eta);
const float scale1 = bsdf_hair_huang_energy_scale(kg, cos_mi1, sqrt_roughness, eta);
/* Refraction at the first interface. */
const float3 wt = refract_angle(wi, wh1, cos_theta_t1, inv_eta);
@ -495,7 +493,7 @@ ccl_device Spectrum bsdf_microfacet_hair_eval_residual(KernelGlobals kg,
2.0f * cosf(gamma_mi - phi_t) :
-len(to_point(gamma_mi, b) - to_point(gamma_mt + M_PI_F, b))));
const float scale2 = microfacet_hair_energy_scale(kg, cos_mi2, sqrt_roughness, inv_eta);
const float scale2 = bsdf_hair_huang_energy_scale(kg, cos_mi2, sqrt_roughness, inv_eta);
/* TT */
if (bsdf->extra->TT > 0.0f) {
@ -538,7 +536,7 @@ ccl_device Spectrum bsdf_microfacet_hair_eval_residual(KernelGlobals kg,
const float3 wtr = -reflect(wt, wh2);
if (dot(-wtr, wo) < inv_eta - 1e-5f) {
/* Total internal reflection. */
S_trrt += weight * bsdf_microfacet_hair_eval_trrt(T1, R2, A_t);
S_trrt += weight * bsdf_hair_huang_eval_trrt(T1, R2, A_t);
continue;
}
@ -558,7 +556,7 @@ ccl_device Spectrum bsdf_microfacet_hair_eval_residual(KernelGlobals kg,
if (cos_mh3 < 0.0f || !microfacet_visible(wtr, -wo, wmtr, wh3) ||
!microfacet_visible(wtr, -wo, wmtr_, wh3))
{
S_trrt += weight * bsdf_microfacet_hair_eval_trrt(T1, R2, A_t);
S_trrt += weight * bsdf_hair_huang_eval_trrt(T1, R2, A_t);
continue;
}
@ -567,7 +565,7 @@ ccl_device Spectrum bsdf_microfacet_hair_eval_residual(KernelGlobals kg,
const float cos_mi3 = dot(wmtr, wtr);
const float T3 = (1.0f - fresnel_dielectric_cos(cos_hi3, inv_eta)) *
microfacet_hair_energy_scale(kg, cos_mi3, sqrt_roughness, inv_eta);
bsdf_hair_huang_energy_scale(kg, cos_mi3, sqrt_roughness, inv_eta);
const float D3 = bsdf_D<MicrofacetType::GGX>(roughness2, cos_mh3);
const Spectrum A_tr = exp(mu_a / cos_theta(wtr) *
@ -587,7 +585,7 @@ ccl_device Spectrum bsdf_microfacet_hair_eval_residual(KernelGlobals kg,
S_trt += bsdf->extra->TRT * result * arc_length(bsdf->extra->e2, gamma_mtr);
}
S_trrt += weight * bsdf_microfacet_hair_eval_trrt(T1, R2, A_t);
S_trrt += weight * bsdf_hair_huang_eval_trrt(T1, R2, A_t);
}
}
@ -602,17 +600,17 @@ ccl_device Spectrum bsdf_microfacet_hair_eval_residual(KernelGlobals kg,
3.0f;
}
ccl_device int bsdf_microfacet_hair_sample(const KernelGlobals kg,
ccl_private const ShaderClosure *sc,
ccl_private ShaderData *sd,
float3 rand,
ccl_private Spectrum *eval,
ccl_private float3 *wo,
ccl_private float *pdf,
ccl_private float2 *sampled_roughness,
ccl_private float *eta)
ccl_device int bsdf_hair_huang_sample(const KernelGlobals kg,
ccl_private const ShaderClosure *sc,
ccl_private ShaderData *sd,
float3 rand,
ccl_private Spectrum *eval,
ccl_private float3 *wo,
ccl_private float *pdf,
ccl_private float2 *sampled_roughness,
ccl_private float *eta)
{
ccl_private MicrofacetHairBSDF *bsdf = (ccl_private MicrofacetHairBSDF *)sc;
ccl_private HuangHairBSDF *bsdf = (ccl_private HuangHairBSDF *)sc;
const float roughness = bsdf->roughness;
*sampled_roughness = make_float2(roughness, roughness);
@ -676,7 +674,7 @@ ccl_device int bsdf_microfacet_hair_sample(const KernelGlobals kg,
float cos_theta_t1;
const float R1 = fresnel_dielectric(dot(wi, wh1), *eta, &cos_theta_t1);
const float scale1 = microfacet_hair_energy_scale(kg, cos_mi1, sqrt_roughness, bsdf->eta);
const float scale1 = bsdf_hair_huang_energy_scale(kg, cos_mi1, sqrt_roughness, bsdf->eta);
const float R = bsdf->extra->R * R1 * scale1 * microfacet_visible(wr, wmi_, wh1) *
bsdf_Go(roughness2, cos_mi1, dot(wmi, wr));
@ -710,7 +708,7 @@ ccl_device int bsdf_microfacet_hair_sample(const KernelGlobals kg,
const float R2 = fresnel_dielectric(dot(-wt, wh2), inv_eta, &cos_theta_t2);
const float T1 = (1.0f - R1) * scale1 * bsdf_Go(roughness2, cos_mi1, dot(wmi, -wt));
const float T2 = 1.0f - R2;
const float scale2 = microfacet_hair_energy_scale(kg, cos_mi2, sqrt_roughness, inv_eta);
const float scale2 = bsdf_hair_huang_energy_scale(kg, cos_mi2, sqrt_roughness, inv_eta);
wtt = refract_angle(-wt, wh2, cos_theta_t2, *eta);
@ -738,13 +736,14 @@ ccl_device int bsdf_microfacet_hair_sample(const KernelGlobals kg,
len(to_point(gamma_mt, b) - to_point(gamma_mtr, b))));
const Spectrum TR = T1 * R2 * scale2 * A_t * A_tr *
microfacet_hair_energy_scale(kg, cos_mi3, sqrt_roughness, inv_eta) *
bsdf_hair_huang_energy_scale(kg, cos_mi3, sqrt_roughness, inv_eta) *
bsdf_Go(roughness2, cos_mi2, dot(wmt, -wtr));
const float T3 = 1.0f - R3;
if (cos_theta_t3 != 0.0f &&
microfacet_visible(wtr, -wtrt, make_float3(wmtr.x, 0.0f, wmtr.z), wh3)) {
microfacet_visible(wtr, -wtrt, make_float3(wmtr.x, 0.0f, wmtr.z), wh3))
{
TRT = bsdf->extra->TRT * TR * make_spectrum(T3) *
bsdf_Go(roughness2, cos_mi3, dot(wmtr, -wtrt));
}
@ -829,13 +828,13 @@ ccl_device int bsdf_microfacet_hair_sample(const KernelGlobals kg,
return LABEL_GLOSSY | LABEL_REFLECT;
}
ccl_device Spectrum bsdf_microfacet_hair_eval(KernelGlobals kg,
ccl_private const ShaderData *sd,
ccl_private const ShaderClosure *sc,
const float3 wo,
ccl_private float *pdf)
ccl_device Spectrum bsdf_hair_huang_eval(KernelGlobals kg,
ccl_private const ShaderData *sd,
ccl_private const ShaderClosure *sc,
const float3 wo,
ccl_private float *pdf)
{
ccl_private MicrofacetHairBSDF *bsdf = (ccl_private MicrofacetHairBSDF *)sc;
ccl_private HuangHairBSDF *bsdf = (ccl_private HuangHairBSDF *)sc;
kernel_assert(fabsf(bsdf->h) < bsdf->extra->radius);
@ -851,25 +850,25 @@ ccl_device Spectrum bsdf_microfacet_hair_eval(KernelGlobals kg,
/* TODO: better estimation of the pdf */
*pdf = 1.0f;
return (bsdf_microfacet_hair_eval_r(kg, sc, local_I, local_O) +
bsdf_microfacet_hair_eval_residual(kg, sc, local_I, local_O, sd->lcg_state)) /
return (bsdf_hair_huang_eval_r(kg, sc, local_I, local_O) +
bsdf_hair_huang_eval_residual(kg, sc, local_I, local_O, sd->lcg_state)) /
cos_theta(local_I);
}
/* Implements Filter Glossy by capping the effective roughness. */
ccl_device void bsdf_microfacet_hair_blur(ccl_private ShaderClosure *sc, float roughness)
ccl_device void bsdf_hair_huang_blur(ccl_private ShaderClosure *sc, float roughness)
{
ccl_private MicrofacetHairBSDF *bsdf = (ccl_private MicrofacetHairBSDF *)sc;
ccl_private HuangHairBSDF *bsdf = (ccl_private HuangHairBSDF *)sc;
bsdf->roughness = fmaxf(roughness, bsdf->roughness);
}
/* Hair Albedo. Computed by summing up geometric series, assuming circular cross-section and
* specular reflection. */
ccl_device Spectrum bsdf_microfacet_hair_albedo(ccl_private const ShaderData *sd,
ccl_private const ShaderClosure *sc)
ccl_device Spectrum bsdf_hair_huang_albedo(ccl_private const ShaderData *sd,
ccl_private const ShaderClosure *sc)
{
ccl_private MicrofacetHairBSDF *bsdf = (ccl_private MicrofacetHairBSDF *)sc;
ccl_private HuangHairBSDF *bsdf = (ccl_private HuangHairBSDF *)sc;
const float3 wmi = make_float3(bsdf->h, 0.0f, cos_from_sin(bsdf->h));
float cos_t;

View File

@ -236,4 +236,30 @@ ccl_device float3 maybe_ensure_valid_specular_reflection(ccl_private ShaderData
return ensure_valid_specular_reflection(sd->Ng, sd->wi, N);
}
/* Principled Hair albedo and absorption coefficients. */
ccl_device_inline float bsdf_principled_hair_albedo_roughness_scale(
const float 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;
}
ccl_device_inline Spectrum
bsdf_principled_hair_sigma_from_reflectance(const Spectrum color, const float azimuthal_roughness)
{
const Spectrum sigma = log(color) /
bsdf_principled_hair_albedo_roughness_scale(azimuthal_roughness);
return sigma * sigma;
}
ccl_device_inline Spectrum bsdf_principled_hair_sigma_from_concentration(const float eumelanin,
const float pheomelanin)
{
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

View File

@ -57,15 +57,15 @@ ccl_device_forceinline void film_write_denoising_features_surface(KernelGlobals
/* All closures contribute to the normal feature, but only diffuse-like ones to the albedo. */
/* If far-field hair, use fiber tangent as feature instead of normal. */
normal += (sc->type == CLOSURE_BSDF_HAIR_MICROFACET_ID ? safe_normalize(sd->dPdu) : sc->N) *
normal += (sc->type == CLOSURE_BSDF_HAIR_HUANG_ID ? safe_normalize(sd->dPdu) : sc->N) *

Is this conditional just due to compatibility?
If yes, and the tangent works better, I think we should just change it for the old model as well.

Is this conditional just due to compatibility? If yes, and the tangent works better, I think we should just change it for the old model as well.

This piece of code is provided by @olivier.fx. I didn't came up with the logic myself, but for a far-field model the "normal" is always the incoming direction, not really a feature of the object itself, so tangent makes more sense here. For the previous near-field model the normal does influence the appearance and it makes sense to use normal as feature. Not sure if tangent works better, I'm not very knowledgeable about denoising.

This piece of code is provided by @olivier.fx. I didn't came up with the logic myself, but for a far-field model the "normal" is always the incoming direction, not really a feature of the object itself, so tangent makes more sense here. For the previous near-field model the normal does influence the appearance and it makes sense to use normal as feature. Not sure if tangent works better, I'm not very knowledgeable about denoising.
sc->sample_weight;
sum_weight += sc->sample_weight;
Spectrum closure_albedo = bsdf_albedo(kg, sd, sc, true, true);
if (bsdf_get_specular_roughness_squared(sc) > sqr(0.075f) ||
sc->type == CLOSURE_BSDF_HAIR_MICROFACET_ID)
sc->type == CLOSURE_BSDF_HAIR_HUANG_ID)
{
/* Hair far field models "count" as diffuse. */
/* Far-field hair models "count" as diffuse. */
diffuse_albedo += closure_albedo;
sum_nonspecular_weight += sc->sample_weight;
}

View File

@ -818,26 +818,26 @@ ccl_device void osl_closure_hair_transmission_setup(
sd->flag |= bsdf_hair_transmission_setup(bsdf);
}
ccl_device void osl_closure_principled_hair_setup(KernelGlobals kg,
ccl_private ShaderData *sd,
uint32_t path_flag,
float3 weight,
ccl_private const PrincipledHairClosure *closure,
float3 *layer_albedo)
ccl_device void osl_closure_hair_chiang_setup(KernelGlobals kg,
ccl_private ShaderData *sd,
uint32_t path_flag,
float3 weight,
ccl_private const ChiangHairClosure *closure,
float3 *layer_albedo)
{
#ifdef __HAIR__
if (osl_closure_skip(kg, sd, path_flag, LABEL_GLOSSY)) {
return;
}
ccl_private PrincipledHairBSDF *bsdf = (ccl_private PrincipledHairBSDF *)bsdf_alloc(
sd, sizeof(PrincipledHairBSDF), rgb_to_spectrum(weight));
ccl_private ChiangHairBSDF *bsdf = (ccl_private ChiangHairBSDF *)bsdf_alloc(
sd, sizeof(ChiangHairBSDF), rgb_to_spectrum(weight));
if (!bsdf) {
return;
}
ccl_private PrincipledHairExtra *extra = (ccl_private PrincipledHairExtra *)closure_alloc_extra(
sd, sizeof(PrincipledHairExtra));
ccl_private ChiangHairExtra *extra = (ccl_private ChiangHairExtra *)closure_alloc_extra(
sd, sizeof(ChiangHairExtra));
if (!extra) {
return;
}
@ -852,16 +852,16 @@ ccl_device void osl_closure_principled_hair_setup(KernelGlobals kg,
bsdf->extra = extra;
sd->flag |= bsdf_principled_hair_setup(sd, bsdf);
sd->flag |= bsdf_hair_chiang_setup(sd, bsdf);
#endif
}
ccl_device void osl_closure_microfacet_hair_setup(KernelGlobals kg,
ccl_private ShaderData *sd,
uint32_t path_flag,
float3 weight,
ccl_private const MicrofacetHairClosure *closure,
float3 *layer_albedo)
ccl_device void osl_closure_hair_huang_setup(KernelGlobals kg,
ccl_private ShaderData *sd,
uint32_t path_flag,
float3 weight,
ccl_private const HuangHairClosure *closure,
float3 *layer_albedo)
{
#ifdef __HAIR__
if (osl_closure_skip(kg, sd, path_flag, LABEL_GLOSSY)) {
@ -872,14 +872,14 @@ ccl_device void osl_closure_microfacet_hair_setup(KernelGlobals kg,
return;
}
ccl_private MicrofacetHairBSDF *bsdf = (ccl_private MicrofacetHairBSDF *)bsdf_alloc(
sd, sizeof(MicrofacetHairBSDF), rgb_to_spectrum(weight));
ccl_private HuangHairBSDF *bsdf = (ccl_private HuangHairBSDF *)bsdf_alloc(
sd, sizeof(HuangHairBSDF), rgb_to_spectrum(weight));
if (!bsdf) {
return;
}
ccl_private MicrofacetHairExtra *extra = (ccl_private MicrofacetHairExtra *)closure_alloc_extra(
sd, sizeof(MicrofacetHairExtra));
ccl_private HuangHairExtra *extra = (ccl_private HuangHairExtra *)closure_alloc_extra(
sd, sizeof(HuangHairExtra));
if (!extra) {
return;
}
@ -896,7 +896,7 @@ ccl_device void osl_closure_microfacet_hair_setup(KernelGlobals kg,
bsdf->extra->TT = closure->tt_lobe;
bsdf->extra->TRT = closure->trt_lobe;
sd->flag |= bsdf_microfacet_hair_setup(sd, bsdf, path_flag);
sd->flag |= bsdf_hair_huang_setup(sd, bsdf, path_flag);
#endif
}

View File

@ -167,27 +167,27 @@ OSL_CLOSURE_STRUCT_BEGIN(HairTransmission, hair_transmission)
OSL_CLOSURE_STRUCT_MEMBER(HairReflection, FLOAT, float, offset, NULL)
OSL_CLOSURE_STRUCT_END(HairTransmission, hair_transmission)
OSL_CLOSURE_STRUCT_BEGIN(PrincipledHair, principled_hair)
OSL_CLOSURE_STRUCT_MEMBER(PrincipledHair, VECTOR, packed_float3, N, NULL)
OSL_CLOSURE_STRUCT_MEMBER(PrincipledHair, VECTOR, packed_float3, sigma, NULL)
OSL_CLOSURE_STRUCT_MEMBER(PrincipledHair, FLOAT, float, v, NULL)
OSL_CLOSURE_STRUCT_MEMBER(PrincipledHair, FLOAT, float, s, NULL)
OSL_CLOSURE_STRUCT_MEMBER(PrincipledHair, FLOAT, float, m0_roughness, NULL)
OSL_CLOSURE_STRUCT_MEMBER(PrincipledHair, FLOAT, float, alpha, NULL)
OSL_CLOSURE_STRUCT_MEMBER(PrincipledHair, FLOAT, float, eta, NULL)
OSL_CLOSURE_STRUCT_END(PrincipledHair, principled_hair)
OSL_CLOSURE_STRUCT_BEGIN(ChiangHair, hair_chiang)
OSL_CLOSURE_STRUCT_MEMBER(ChiangHair, VECTOR, packed_float3, N, NULL)
OSL_CLOSURE_STRUCT_MEMBER(ChiangHair, VECTOR, packed_float3, sigma, NULL)
OSL_CLOSURE_STRUCT_MEMBER(ChiangHair, FLOAT, float, v, NULL)
OSL_CLOSURE_STRUCT_MEMBER(ChiangHair, FLOAT, float, s, NULL)
OSL_CLOSURE_STRUCT_MEMBER(ChiangHair, FLOAT, float, m0_roughness, NULL)
OSL_CLOSURE_STRUCT_MEMBER(ChiangHair, FLOAT, float, alpha, NULL)
OSL_CLOSURE_STRUCT_MEMBER(ChiangHair, FLOAT, float, eta, NULL)
OSL_CLOSURE_STRUCT_END(ChiangHair, hair_chiang)
OSL_CLOSURE_STRUCT_BEGIN(MicrofacetHair, microfacet_hair)
OSL_CLOSURE_STRUCT_MEMBER(MicrofacetHair, VECTOR, packed_float3, N, NULL)
OSL_CLOSURE_STRUCT_MEMBER(MicrofacetHair, VECTOR, packed_float3, sigma, NULL)
OSL_CLOSURE_STRUCT_MEMBER(MicrofacetHair, FLOAT, float, roughness, NULL)
OSL_CLOSURE_STRUCT_MEMBER(MicrofacetHair, FLOAT, float, tilt, NULL)
OSL_CLOSURE_STRUCT_MEMBER(MicrofacetHair, FLOAT, float, eta, NULL)
OSL_CLOSURE_STRUCT_MEMBER(MicrofacetHair, FLOAT, float, aspect_ratio, NULL)
OSL_CLOSURE_STRUCT_MEMBER(MicrofacetHair, FLOAT, float, r_lobe, NULL)
OSL_CLOSURE_STRUCT_MEMBER(MicrofacetHair, FLOAT, float, tt_lobe, NULL)
OSL_CLOSURE_STRUCT_MEMBER(MicrofacetHair, FLOAT, float, trt_lobe, NULL)
OSL_CLOSURE_STRUCT_END(MicrofacetHair, microfacet_hair)
OSL_CLOSURE_STRUCT_BEGIN(HuangHair, hair_huang)
OSL_CLOSURE_STRUCT_MEMBER(HuangHair, VECTOR, packed_float3, N, NULL)
OSL_CLOSURE_STRUCT_MEMBER(HuangHair, VECTOR, packed_float3, sigma, NULL)
OSL_CLOSURE_STRUCT_MEMBER(HuangHair, FLOAT, float, roughness, NULL)
OSL_CLOSURE_STRUCT_MEMBER(HuangHair, FLOAT, float, tilt, NULL)
OSL_CLOSURE_STRUCT_MEMBER(HuangHair, FLOAT, float, eta, NULL)
OSL_CLOSURE_STRUCT_MEMBER(HuangHair, FLOAT, float, aspect_ratio, NULL)
OSL_CLOSURE_STRUCT_MEMBER(HuangHair, FLOAT, float, r_lobe, NULL)
OSL_CLOSURE_STRUCT_MEMBER(HuangHair, FLOAT, float, tt_lobe, NULL)
OSL_CLOSURE_STRUCT_MEMBER(HuangHair, FLOAT, float, trt_lobe, NULL)
OSL_CLOSURE_STRUCT_END(HuangHair, hair_huang)
OSL_CLOSURE_STRUCT_BEGIN(VolumeAbsorption, absorption)
OSL_CLOSURE_STRUCT_END(VolumeAbsorption, absorption)

View File

@ -30,7 +30,7 @@ shader node_principled_hair_bsdf(color Color = color(0.017513, 0.005763, 0.00205
color Tint = 1.0,
color AbsorptionCoefficient = color(0.245531, 0.52, 1.365),
normal Normal = Ng,
string model = "Far-field Model",
string model = "Huang",
string parametrization = "Direct Coloring",
float Offset = radians(2),
float Roughness = 0.3,
@ -94,15 +94,15 @@ shader node_principled_hair_bsdf(color Color = color(0.017513, 0.005763, 0.00205
sigma = sigma_from_concentration(0.0, 0.8054375);
}
if (model == "Far-field Model") {
if (model == "Huang") {
weizhen marked this conversation as resolved Outdated

I think we can move this into the main if below?

I think we can move this into the main `if` below?
normal major_axis = Normal;
if (AspectRatio != 1.0) {
getattribute("geom:N", major_axis);
}
BSDF = microfacet_hair(
BSDF = hair_huang(
major_axis, sigma, roughness, Offset, IOR, AspectRatio, Rlobe, TTlobe, TRTlobe);
}
else {
BSDF = principled_hair(Normal, sigma, roughness, radial_roughness, m0_roughness, Offset, IOR);
BSDF = hair_chiang(Normal, sigma, roughness, radial_roughness, m0_roughness, Offset, IOR);
}
}

View File

@ -39,22 +39,22 @@ closure color
hair_reflection(normal N, float roughnessu, float roughnessv, vector T, float offset) BUILTIN;
closure color
hair_transmission(normal N, float roughnessu, float roughnessv, vector T, float offset) BUILTIN;
closure color principled_hair(normal N,
color sigma,
float roughnessu,
float roughnessv,
float coat,
float alpha,
float eta) BUILTIN;
closure color microfacet_hair(normal N,
color sigma,
float roughness,
float tilt,
float eta,
float aspect_ratio,
float r_lobe,
float tt_lobe,
float trt_lobe) BUILTIN;
closure color hair_chiang(normal N,
color sigma,
float roughnessu,
float roughnessv,
float coat,
float alpha,
float eta) BUILTIN;
closure color hair_huang(normal N,
color sigma,
float roughness,
float tilt,
float eta,
float aspect_ratio,
float r_lobe,
float tt_lobe,
float trt_lobe) BUILTIN;
// Volume
closure color henyey_greenstein(float g) BUILTIN;

View File

@ -566,8 +566,8 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
break;
}
#ifdef __HAIR__
case CLOSURE_BSDF_HAIR_PRINCIPLED_ID:
case CLOSURE_BSDF_HAIR_MICROFACET_ID: {
case CLOSURE_BSDF_HAIR_CHIANG_ID:
case CLOSURE_BSDF_HAIR_HUANG_ID: {
uint4 data_node2 = read_node(kg, &offset);
uint4 data_node3 = read_node(kg, &offset);
uint4 data_node4 = read_node(kg, &offset);
@ -603,7 +603,7 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
float random_roughness = param2;
float factor_random_roughness = 1.0f + 2.0f * (random - 0.5f) * random_roughness;
float roughness = param1 * factor_random_roughness;
float radial_roughness = (type == CLOSURE_BSDF_HAIR_PRINCIPLED_ID) ?
float radial_roughness = (type == CLOSURE_BSDF_HAIR_CHIANG_ID) ?
stack_load_float_default(stack, shared_ofs2, data_node4.y) *
factor_random_roughness :
roughness;
@ -657,12 +657,12 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
}
}
if (type == CLOSURE_BSDF_HAIR_PRINCIPLED_ID) {
ccl_private PrincipledHairBSDF *bsdf = (ccl_private PrincipledHairBSDF *)bsdf_alloc(
sd, sizeof(PrincipledHairBSDF), weight);
if (type == CLOSURE_BSDF_HAIR_CHIANG_ID) {
ccl_private ChiangHairBSDF *bsdf = (ccl_private ChiangHairBSDF *)bsdf_alloc(
sd, sizeof(ChiangHairBSDF), weight);
if (bsdf) {
ccl_private PrincipledHairExtra *extra = (ccl_private PrincipledHairExtra *)
closure_alloc_extra(sd, sizeof(PrincipledHairExtra));
ccl_private ChiangHairExtra *extra = (ccl_private ChiangHairExtra *)closure_alloc_extra(
sd, sizeof(ChiangHairExtra));
if (!extra) {
break;
@ -680,11 +680,11 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
bsdf->extra = extra;
bsdf->sigma = sigma;
sd->flag |= bsdf_principled_hair_setup(sd, bsdf);
sd->flag |= bsdf_hair_chiang_setup(sd, bsdf);
}
}
else {
kernel_assert(type == CLOSURE_BSDF_HAIR_MICROFACET_ID);
kernel_assert(type == CLOSURE_BSDF_HAIR_HUANG_ID);
uint R_ofs, TT_ofs, TRT_ofs, unused;
svm_unpack_node_uchar4(data_node4.x, &R_ofs, &TT_ofs, &TRT_ofs, &unused);
float R = stack_load_float_default(stack, R_ofs, data_node4.y);
@ -694,11 +694,11 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
break;
}
ccl_private MicrofacetHairBSDF *bsdf = (ccl_private MicrofacetHairBSDF *)bsdf_alloc(
sd, sizeof(MicrofacetHairBSDF), weight);
ccl_private HuangHairBSDF *bsdf = (ccl_private HuangHairBSDF *)bsdf_alloc(
sd, sizeof(HuangHairBSDF), weight);
if (bsdf) {
ccl_private MicrofacetHairExtra *extra = (ccl_private MicrofacetHairExtra *)
closure_alloc_extra(sd, sizeof(MicrofacetHairExtra));
ccl_private HuangHairExtra *extra = (ccl_private HuangHairExtra *)closure_alloc_extra(
sd, sizeof(HuangHairExtra));
if (!extra) {
break;
@ -721,7 +721,7 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
bsdf->eta = ior;
bsdf->sigma = sigma;
sd->flag |= bsdf_microfacet_hair_setup(sd, bsdf, path_flag);
sd->flag |= bsdf_hair_huang_setup(sd, bsdf, path_flag);
}
}
break;

View File

@ -445,8 +445,8 @@ typedef enum ClosureType {
CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID,
CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID,
CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID, /* virtual closure */
CLOSURE_BSDF_HAIR_PRINCIPLED_ID,
CLOSURE_BSDF_HAIR_MICROFACET_ID,
CLOSURE_BSDF_HAIR_CHIANG_ID,
CLOSURE_BSDF_HAIR_HUANG_ID,
/* Special cases */
CLOSURE_BSDF_TRANSPARENT_ID,
@ -475,7 +475,7 @@ typedef enum ClosureType {
(type >= CLOSURE_BSDF_DIFFUSE_ID && type <= CLOSURE_BSDF_TRANSLUCENT_ID)
#define CLOSURE_IS_BSDF_GLOSSY(type) \
((type >= CLOSURE_BSDF_MICROFACET_GGX_ID && type <= CLOSURE_BSDF_HAIR_REFLECTION_ID) || \
(type == CLOSURE_BSDF_HAIR_PRINCIPLED_ID) || (type == CLOSURE_BSDF_HAIR_MICROFACET_ID))
(type == CLOSURE_BSDF_HAIR_CHIANG_ID) || (type == CLOSURE_BSDF_HAIR_HUANG_ID))
#define CLOSURE_IS_BSDF_TRANSMISSION(type) \
(type >= CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID && \
type <= CLOSURE_BSDF_HAIR_TRANSMISSION_ID)

View File

@ -1136,8 +1136,8 @@ int ShaderGraph::get_num_closures()
* for the volume steps. */
num_closures += MAX_VOLUME_STACK_SIZE;
}
else if (closure_type == CLOSURE_BSDF_HAIR_PRINCIPLED_ID ||
closure_type == CLOSURE_BSDF_HAIR_MICROFACET_ID)
else if (closure_type == CLOSURE_BSDF_HAIR_CHIANG_ID ||
closure_type == CLOSURE_BSDF_HAIR_HUANG_ID)
{
num_closures += 2;
}
weizhen marked this conversation as resolved Outdated

Not sure why this was 4 before, there are only 2 closures, ...HairBSDF and ...HairExtra.

Not sure why this was 4 before, there are only 2 closures, `...HairBSDF` and `...HairExtra`.

View File

@ -3393,8 +3393,8 @@ NODE_DEFINE(PrincipledHairBsdfNode)
/* Scattering models. */
static NodeEnum model_enum;
model_enum.insert("Near-field Model", NODE_PRINCIPLED_HAIR_CHIANG);
model_enum.insert("Far-field Model", NODE_PRINCIPLED_HAIR_HUANG);
model_enum.insert("Chiang", NODE_PRINCIPLED_HAIR_CHIANG);
model_enum.insert("Huang", NODE_PRINCIPLED_HAIR_HUANG);
SOCKET_ENUM(model, "Model", model_enum, NODE_PRINCIPLED_HAIR_HUANG);
/* Color parametrization specified as enum. */
@ -3438,7 +3438,7 @@ NODE_DEFINE(PrincipledHairBsdfNode)
PrincipledHairBsdfNode::PrincipledHairBsdfNode() : BsdfBaseNode(get_node_type())
{
closure = CLOSURE_BSDF_HAIR_MICROFACET_ID;
closure = CLOSURE_BSDF_HAIR_HUANG_ID;
}
void PrincipledHairBsdfNode::attributes(Shader *shader, AttributeRequestSet *attributes)
@ -3460,8 +3460,8 @@ void PrincipledHairBsdfNode::attributes(Shader *shader, AttributeRequestSet *att
/* Prepares the input data for the SVM shader. */
void PrincipledHairBsdfNode::compile(SVMCompiler &compiler)
{
closure = (model == NODE_PRINCIPLED_HAIR_HUANG) ? CLOSURE_BSDF_HAIR_MICROFACET_ID :
CLOSURE_BSDF_HAIR_PRINCIPLED_ID;
closure = (model == NODE_PRINCIPLED_HAIR_HUANG) ? CLOSURE_BSDF_HAIR_HUANG_ID :
CLOSURE_BSDF_HAIR_CHIANG_ID;
compiler.add_node(NODE_CLOSURE_SET_WEIGHT, one_float3());

View File

@ -642,6 +642,7 @@ void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain)
* \note Keep this message at the bottom of the function.
*/
{
/* Keep this block, even when empty. */
if (!DNA_struct_find(fd->filesdna, "NodeShaderHairPrincipled")) {
FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
if (ntree->type == NTREE_SHADER) {
@ -650,7 +651,6 @@ void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain)
}
FOREACH_NODETREE_END;
}
/* Keep this block, even when empty. */
if (!DNA_struct_elem_find(fd->filesdna, "LightProbe", "float", "grid_flag")) {
LISTBASE_FOREACH (LightProbe *, lightprobe, &bmain->lightprobes) {

View File

@ -4281,18 +4281,18 @@ static const EnumPropertyItem node_hair_items[] = {
static const EnumPropertyItem node_principled_hair_model_items[] = {
{SHD_PRINCIPLED_HAIR_CHIANG,
"HAIR_PRINCIPLED_CHIANG",
"CHIANG",
0,
"Near-field Model",
"Hair scattering model by Chiang et. al 2016, suitable for close-up looks, but is in general "
"more noisy."},
"Chiang",
"Near-field hair scattering model by Chiang et. al 2016, suitable for close-up looks, but is "
"more noisy when viewing from a distance"},
{SHD_PRINCIPLED_HAIR_HUANG,
"HAIR_PRINCIPLED_HUANG",
"HUANG",
0,
"Far-field Model",
"Microfacet-based hair scattering model by Huang et. al 2022, suitable for viewing from a "
"distance, supports elliptical cross-sections and has more precise highlight in forward "
"scattering direction."},
"Huang",
"Far-field hair scattering model by Huang et. al 2022, suitable for viewing from a distance, "
"supports elliptical cross-sections and has more precise highlight in forward scattering "
"directions"},
{0, nullptr, 0, nullptr, nullptr},
};
@ -5755,7 +5755,7 @@ static void def_hair_principled(StructRNA *srna)
prop = RNA_def_property(srna, "model", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, nullptr, "model");
RNA_def_property_ui_text(prop, "Scattering model", "Select from near- or far-field model");
RNA_def_property_ui_text(prop, "Scattering model", "Select from Chiang or Huang model");
RNA_def_property_enum_items(prop, node_principled_hair_model_items);
RNA_def_property_enum_default(prop, SHD_PRINCIPLED_HAIR_HUANG);
/* Upon editing, update both the node data AND the UI representation */