Split `model_type` into `cross_section_type` and `distribution_type`

Also disable analytical GGX R because it seems confusing
This commit is contained in:
Weizhen Huang 2023-01-11 18:23:04 +01:00
parent 08684b2601
commit f88b91fe61
14 changed files with 158 additions and 197 deletions

View File

@ -668,11 +668,16 @@ static ShaderNode *add_node(Scene *scene,
"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));
microfacet_hair->set_cross_section_type(
(NodeMicrofacetHairCrossSectionType)get_enum(b_microfacet_hair_node.ptr,
"cross_section_type",
NODE_MICROFACET_HAIR_CROSS_SECTION_TYPE_NUM,
NODE_MICROFACET_HAIR_CIRCULAR));
microfacet_hair->set_distribution_type(
(NodeMicrofacetHairDistributionType)get_enum(b_microfacet_hair_node.ptr,
"distribution_type",
NODE_MICROFACET_HAIR_DISTRIBUTION_TYPE_NUM,
NODE_MICROFACET_HAIR_GGX));
node = microfacet_hair;
}
else if (b_node.is_a(&RNA_ShaderNodeBsdfPrincipled)) {

View File

@ -37,8 +37,11 @@ typedef struct MicrofacetHairBSDF {
/* Blur. */
float blur;
/* Circular/Ellipitic and GGX/Beckmann. */
int model_type;
/* GGX/Beckmann. */
int distribution_type;
/* Circular/Elliptical */
int cross_section_type;
/* Extra closure. */
ccl_private MicrofacetHairExtra *extra;
@ -72,8 +75,7 @@ ccl_device int bsdf_microfacet_hair_setup(ccl_private ShaderData *sd,
kernel_assert(isfinite_safe(X));
kernel_assert(isfinite_safe(h));
if (bsdf->model_type == NODE_MICROFACET_HAIR_ELLIPTIC_GGX ||
bsdf->model_type == NODE_MICROFACET_HAIR_ELLIPTIC_BECKMANN) {
if (bsdf->cross_section_type == NODE_MICROFACET_HAIR_ELLIPTIC) {
/* Local frame is independent of the ray direction for elliptical hairs. */
bsdf->extra->geom.w = h;
}
@ -329,8 +331,7 @@ ccl_device float3 bsdf_microfacet_hair_eval_r_circular(ccl_private const ShaderC
const float tilt = -bsdf->alpha;
const float roughness = bsdf->roughness;
const float eta = bsdf->eta;
const bool beckmann = (bsdf->model_type == NODE_MICROFACET_HAIR_CIRCULAR_BECKMANN);
const bool analytical_ggx = (bsdf->model_type == NODE_MICROFACET_HAIR_CIRCULAR_GGX_ANALYTIC);
const bool beckmann = (bsdf->distribution_type == NODE_MICROFACET_HAIR_BECKMANN);
float3 R = zero_float3();
if (bsdf->extra->R <= 0.0f)
@ -359,68 +360,26 @@ ccl_device float3 bsdf_microfacet_hair_eval_r_circular(ccl_private const ShaderC
float integral = 0.0f;
/* analytical for ggx (no masking term) */
if (analytical_ggx) {
const float phi_h = dir_phi(wh);
const float d_max = phi_h - phi_m_max;
const float d_min = phi_h - phi_m_min;
/* Maximal sample resolution. */
float res = roughness * 0.7f;
/* Number of intervals should be even. */
const size_t intervals = 2 * (size_t)ceilf((phi_m_max - phi_m_min) / res * 0.5f);
const float roughness_squared = roughness * roughness;
/* Modified resolution based on numbers of intervals. */
res = (phi_m_max - phi_m_min) / float(intervals);
float sm, cm;
fast_sincosf(tilt, &sm, &cm);
/* Integrate using Simpson's rule. */
for (size_t i = 0; i <= intervals; i++) {
const float C = sqrtf(1.0f - roughness_squared);
const float A = cm * cos_theta(wh) * C;
const float B = sm * sin_theta(wh) * C;
const float A2 = sqr(A);
const float B2 = sqr(B);
const float tmp1 = 1.0f / sqrtf(sqr(B - 1.0f) - A2);
const float tmp2 = 1.0f / sqrtf(sqr(B + 1.0f) - A2);
const float phi_m = phi_m_min + i * res;
const float3 wm = sph_dir(tilt, phi_m);
float smax, cmax, smin, cmin;
fast_sincosf(d_max, &smax, &cmax);
fast_sincosf(d_min, &smin, &cmin);
const float tmax = smax / (1.0f + cmax);
const float tmin = smin / (1.0f + cmin);
const float temp1 = 2.0f * (A2 - B2 + 3.0f * B - 2) * sqr(tmp1) * tmp1 *
(atanf((A - B + 1.0f) * tmp1 * tmax) -
atanf((A - B + 1.0f) * tmp1 * tmin));
const float temp2 = 2.0f * (A2 - B2 - 3.0f * B - 2) * sqr(tmp2) * tmp2 *
(atanf((B - A + 1.0f) * tmp2 * tmax) -
atanf((B - A + 1.0f) * tmp2 * tmin));
const float temp3 = A * sqr(tmp1) *
(smax / (A * cmax + B - 1.0f) - smin / (A * cmin + B - 1.0f));
const float temp4 = A * sqr(tmp2) *
(smax / (A * cmax + B + 1.0f) - smin / (A * cmin + B + 1.0f));
integral = roughness_squared * M_1_PI_F * 0.5f * (temp1 + temp2 + temp3 + temp4);
}
else { /* Falls back to numerical integration. */
/* Maximal sample resolution. */
float res = roughness * 0.7f;
/* Number of intervals should be even. */
const size_t intervals = 2 * (size_t)ceilf((phi_m_max - phi_m_min) / res * 0.5f);
/* Modified resolution based on numbers of intervals. */
res = (phi_m_max - phi_m_min) / float(intervals);
/* Integrate using Simpson's rule. */
for (size_t i = 0; i <= intervals; i++) {
const float phi_m = phi_m_min + i * res;
const float3 wm = sph_dir(tilt, phi_m);
if (microfacet_visible(wi, wo, make_float3(wm.x, 0.0f, wm.z), wh)) {
const float weight = (i == 0 || i == intervals) ? 0.5f : (i % 2 + 1);
integral += weight * D(beckmann, roughness, wm, wh) *
G(beckmann, roughness, wi, wo, wm, wh);
}
if (microfacet_visible(wi, wo, make_float3(wm.x, 0.0f, wm.z), wh)) {
const float weight = (i == 0 || i == intervals) ? 0.5f : (i % 2 + 1);
integral += weight * D(beckmann, roughness, wm, wh) * G(beckmann, roughness, wi, wo, wm, wh);
}
integral *= (2.0f / 3.0f * res);
}
integral *= (2.0f / 3.0f * res);
const float F = fresnel_dielectric_cos(dot(wi, wh), eta);
@ -438,7 +397,7 @@ ccl_device float3 bsdf_microfacet_hair_eval_tt_trt_circular(KernelGlobals kg,
const float tilt = -bsdf->alpha;
const float roughness = bsdf->roughness;
const float eta = bsdf->eta;
const bool beckmann = (bsdf->model_type == NODE_MICROFACET_HAIR_CIRCULAR_BECKMANN);
const bool beckmann = (bsdf->distribution_type == NODE_MICROFACET_HAIR_BECKMANN);
if (bsdf->extra->TT <= 0.0f && bsdf->extra->TRT <= 0.0f)
return zero_float3();
@ -652,7 +611,7 @@ ccl_device int bsdf_microfacet_hair_sample_circular(const KernelGlobals kg,
const float tilt = -bsdf->alpha;
const float roughness = bsdf->roughness;
const bool beckmann = (bsdf->model_type == NODE_MICROFACET_HAIR_CIRCULAR_BECKMANN);
const bool beckmann = (bsdf->distribution_type == NODE_MICROFACET_HAIR_BECKMANN);
/* generate sample */
float sample_lobe = randu;
@ -833,7 +792,7 @@ ccl_device float3 bsdf_microfacet_hair_eval_r_elliptic(ccl_private const ShaderC
const float tilt = -bsdf->alpha;
const float roughness = bsdf->roughness;
const float eta = bsdf->eta;
const bool beckmann = (bsdf->model_type == NODE_MICROFACET_HAIR_ELLIPTIC_BECKMANN);
const bool beckmann = (bsdf->distribution_type == NODE_MICROFACET_HAIR_BECKMANN);
float3 R = zero_float3();
if (bsdf->extra->R <= 0.0f) {
@ -933,7 +892,7 @@ ccl_device float3 bsdf_microfacet_hair_eval_tt_trt_elliptic(KernelGlobals kg,
const float tilt = -bsdf->alpha;
const float roughness = bsdf->roughness;
const float eta = bsdf->eta;
const bool beckmann = (bsdf->model_type == NODE_MICROFACET_HAIR_ELLIPTIC_BECKMANN);
const bool beckmann = (bsdf->distribution_type == NODE_MICROFACET_HAIR_BECKMANN);
if (bsdf->extra->TT <= 0.0f && bsdf->extra->TRT <= 0.0f) {
return zero_float3();
@ -1203,7 +1162,7 @@ ccl_device int bsdf_microfacet_hair_sample_elliptic(const KernelGlobals kg,
const float tilt = -bsdf->alpha;
const float roughness = bsdf->roughness;
const bool beckmann = (bsdf->model_type == NODE_MICROFACET_HAIR_ELLIPTIC_BECKMANN);
const bool beckmann = (bsdf->distribution_type == NODE_MICROFACET_HAIR_BECKMANN);
/* generate sample */
float sample_lobe = randu;
@ -1387,17 +1346,12 @@ ccl_device Spectrum bsdf_microfacet_hair_eval(KernelGlobals kg,
{
ccl_private MicrofacetHairBSDF *bsdf = (ccl_private MicrofacetHairBSDF *)sc;
switch (bsdf->model_type) {
case NODE_MICROFACET_HAIR_CIRCULAR_GGX:
case NODE_MICROFACET_HAIR_CIRCULAR_GGX_ANALYTIC:
case NODE_MICROFACET_HAIR_CIRCULAR_BECKMANN:
return bsdf_microfacet_hair_eval_circular(kg, sd, sc, omega_in, pdf);
case NODE_MICROFACET_HAIR_ELLIPTIC_GGX:
case NODE_MICROFACET_HAIR_ELLIPTIC_BECKMANN:
return bsdf_microfacet_hair_eval_elliptic(kg, sd, sc, omega_in, pdf);
default:
return bsdf_microfacet_hair_eval_circular(kg, sd, sc, omega_in, pdf);
if (bsdf->cross_section_type == NODE_MICROFACET_HAIR_CIRCULAR ||
bsdf->extra->aspect_ratio == 1.0f) {
return bsdf_microfacet_hair_eval_circular(kg, sd, sc, omega_in, pdf);
}
return bsdf_microfacet_hair_eval_elliptic(kg, sd, sc, omega_in, pdf);
}
ccl_device int bsdf_microfacet_hair_sample(KernelGlobals kg,
@ -1413,20 +1367,14 @@ ccl_device int bsdf_microfacet_hair_sample(KernelGlobals kg,
{
ccl_private MicrofacetHairBSDF *bsdf = (ccl_private MicrofacetHairBSDF *)sc;
switch (bsdf->model_type) {
case NODE_MICROFACET_HAIR_CIRCULAR_GGX:
case NODE_MICROFACET_HAIR_CIRCULAR_GGX_ANALYTIC:
case NODE_MICROFACET_HAIR_CIRCULAR_BECKMANN:
return bsdf_microfacet_hair_sample_circular(
kg, sc, sd, randu, randv, eval, omega_in, pdf, sampled_roughness, eta);
case NODE_MICROFACET_HAIR_ELLIPTIC_GGX:
case NODE_MICROFACET_HAIR_ELLIPTIC_BECKMANN:
return bsdf_microfacet_hair_sample_elliptic(
kg, sc, sd, randu, randv, eval, omega_in, pdf, sampled_roughness, eta);
default:
return bsdf_microfacet_hair_sample_circular(
kg, sc, sd, randu, randv, eval, omega_in, pdf, sampled_roughness, eta);
if (bsdf->cross_section_type == NODE_MICROFACET_HAIR_CIRCULAR ||
bsdf->extra->aspect_ratio == 1.0f) {
return bsdf_microfacet_hair_sample_circular(
kg, sc, sd, randu, randv, eval, omega_in, pdf, sampled_roughness, eta);
}
return bsdf_microfacet_hair_sample_elliptic(
kg, sc, sd, randu, randv, eval, omega_in, pdf, sampled_roughness, eta);
}
/* Implements Filter Glossy by capping the effective roughness. */

View File

@ -43,7 +43,8 @@ shader node_microfacet_hair_bsdf(color Color = color(0.017513, 0.005763, 0.00205
color AbsorptionCoefficient = color(0.245531, 0.52, 1.365),
normal Normal = Ng,
string parametrization = "Direct Coloring",
string model_type = "Microfacet Circular GGX",
string cross_section_type = "Circular",
string distribution_type = "GGX",
float Offset = radians(2),
float Roughness = 0.3,
float RandomRoughness = 0.0,

View File

@ -899,9 +899,9 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
&melanin_redness_ofs,
&absorption_coefficient_ofs);
uint tint_ofs, random_ofs, random_color_ofs, random_roughness_ofs;
uint tint_ofs, random_ofs, random_color_ofs, cross_section_type;
svm_unpack_node_uchar4(
data_node3.x, &tint_ofs, &random_ofs, &random_color_ofs, &random_roughness_ofs);
data_node3.x, &tint_ofs, &random_ofs, &random_color_ofs, &cross_section_type);
const AttributeDescriptor attr_descr_random = find_attribute(kg, sd, data_node3.w);
float random = 0.0f;
@ -912,9 +912,8 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
random = stack_load_float_default(stack, random_ofs, data_node3.y);
}
uint R_ofs, TT_ofs, TRT_ofs, model_type;
svm_unpack_node_uchar4(data_node4.x, &R_ofs, &TT_ofs, &TRT_ofs, &model_type);
uint R_ofs, TT_ofs, TRT_ofs, distribution_type;
svm_unpack_node_uchar4(data_node4.x, &R_ofs, &TT_ofs, &TRT_ofs, &distribution_type);
float R = stack_load_float_default(stack, R_ofs, data_node4.y);
float TT = stack_load_float_default(stack, TT_ofs, data_node4.z);
float TRT = stack_load_float_default(stack, TRT_ofs, data_node4.w);
@ -940,24 +939,17 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
float factor_random_roughness = 1.0f + 2.0f * (random - 0.5f) * random_roughness;
float roughness = param1 * factor_random_roughness;
/* if (model_type >= NODE_MICROFACET_HAIR_HYBRID_NEAR_FIELD && model_type <
* NODE_MICROFACET_HAIR_MODEL_TYPE_NUM) */
/* model_type is a uint, so no need to compare to 0
* (NODE_MICROFACET_HAIR_HYBRID_NEAR_FIELD), which generates a warning */
if (model_type < NODE_MICROFACET_HAIR_MODEL_TYPE_NUM)
bsdf->model_type = model_type;
else
bsdf->model_type = NODE_MICROFACET_HAIR_CIRCULAR_GGX; // default
bsdf->cross_section_type = clamp(
cross_section_type, NODE_MICROFACET_HAIR_CIRCULAR, NODE_MICROFACET_HAIR_ELLIPTIC);
if (bsdf->model_type == NODE_MICROFACET_HAIR_CIRCULAR_GGX ||
bsdf->model_type == NODE_MICROFACET_HAIR_CIRCULAR_GGX_ANALYTIC ||
bsdf->model_type == NODE_MICROFACET_HAIR_ELLIPTIC_GGX) {
// empirical equivalences
bsdf->distribution_type = clamp(
distribution_type, NODE_MICROFACET_HAIR_GGX, NODE_MICROFACET_HAIR_BECKMANN);
/* Empirical equivalences compared with principled hair BSDF. */
if (bsdf->distribution_type == NODE_MICROFACET_HAIR_GGX) {
roughness *= 0.5f;
}
else if (bsdf->model_type == NODE_MICROFACET_HAIR_CIRCULAR_BECKMANN ||
bsdf->model_type == NODE_MICROFACET_HAIR_ELLIPTIC_BECKMANN) {
// empirical equivalences
else { /* bsdf->distribution_type == NODE_MICROFACET_HAIR_BECKMANN*/
roughness *= 2.f / 3.f;
}
@ -1014,8 +1006,7 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
}
}
if (model_type == NODE_MICROFACET_HAIR_ELLIPTIC_GGX ||
model_type == NODE_MICROFACET_HAIR_ELLIPTIC_BECKMANN) {
if (cross_section_type == NODE_MICROFACET_HAIR_ELLIPTIC) {
uint aspect_ratio_ofs, temp;
svm_unpack_node_uchar4(data_node5.x, &aspect_ratio_ofs, &temp, &temp, &temp);

View File

@ -402,14 +402,17 @@ typedef enum NodeMicrofacetHairParametrization {
NODE_MICROFACET_HAIR_NUM,
} NodeMicrofacetHairParametrization;
typedef enum NodeMicrofacetHairModelType {
NODE_MICROFACET_HAIR_CIRCULAR_GGX = 0,
NODE_MICROFACET_HAIR_CIRCULAR_GGX_ANALYTIC = 1,
NODE_MICROFACET_HAIR_CIRCULAR_BECKMANN = 2,
NODE_MICROFACET_HAIR_ELLIPTIC_GGX = 3,
NODE_MICROFACET_HAIR_ELLIPTIC_BECKMANN = 4,
NODE_MICROFACET_HAIR_MODEL_TYPE_NUM,
} NodeMicrofacetHairModelType;
typedef enum NodeMicrofacetHairDistributionType {
NODE_MICROFACET_HAIR_GGX = 0,
NODE_MICROFACET_HAIR_BECKMANN = 1,
NODE_MICROFACET_HAIR_DISTRIBUTION_TYPE_NUM,
} NodeMicrofacetHairDistributionType;
typedef enum NodeMicrofacetHairCrossSectionType {
NODE_MICROFACET_HAIR_CIRCULAR = 0,
NODE_MICROFACET_HAIR_ELLIPTIC = 1,
NODE_MICROFACET_HAIR_CROSS_SECTION_TYPE_NUM,
} NodeMicrofacetHairCrossSectionType;
typedef enum NodeCombSepColorType {
NODE_COMBSEP_COLOR_RGB,

View File

@ -3644,16 +3644,21 @@ NODE_DEFINE(MicrofacetHairBsdfNode)
SOCKET_ENUM(
parametrization, "Parametrization", parametrization_enum, NODE_MICROFACET_HAIR_REFLECTANCE);
/* Hair integration mode specified as enum. */
static NodeEnum model_type_enum;
model_type_enum.insert("Microfacet Circular GGX", NODE_MICROFACET_HAIR_CIRCULAR_GGX);
model_type_enum.insert("Microfacet Circular GGX Analytical",
NODE_MICROFACET_HAIR_CIRCULAR_GGX_ANALYTIC);
model_type_enum.insert("Microfacet Circular Beckmann", NODE_MICROFACET_HAIR_CIRCULAR_BECKMANN);
model_type_enum.insert("Microfacet Elliptical GGX", NODE_MICROFACET_HAIR_ELLIPTIC_GGX);
model_type_enum.insert("Microfacet Elliptical Beckmann", NODE_MICROFACET_HAIR_ELLIPTIC_BECKMANN);
/* Hair microfacet normal distribution mode specified as enum. */
static NodeEnum distribution_type_enum;
distribution_type_enum.insert("GGX", NODE_MICROFACET_HAIR_GGX);
distribution_type_enum.insert("Beckmann", NODE_MICROFACET_HAIR_BECKMANN);
SOCKET_ENUM(
distribution_type, "Distribution Type", distribution_type_enum, NODE_MICROFACET_HAIR_GGX);
SOCKET_ENUM(model_type, "model_type", model_type_enum, NODE_MICROFACET_HAIR_CIRCULAR_GGX);
/* Hair cross-section type specified as enum. */
static NodeEnum cross_section_type_enum;
distribution_type_enum.insert("Circular", NODE_MICROFACET_HAIR_CIRCULAR);
distribution_type_enum.insert("Elliptical", NODE_MICROFACET_HAIR_ELLIPTIC);
SOCKET_ENUM(cross_section_type,
"Cross Section Type",
cross_section_type_enum,
NODE_MICROFACET_HAIR_CIRCULAR);
/* Initialize sockets to their default values. */
SOCKET_IN_COLOR(color, "Color", make_float3(0.017513f, 0.005763f, 0.002059f));
@ -3698,8 +3703,7 @@ MicrofacetHairBsdfNode::MicrofacetHairBsdfNode() : BsdfBaseNode(get_node_type())
void MicrofacetHairBsdfNode::attributes(Shader *shader, AttributeRequestSet *attributes)
{
/* Make sure we have the normal for elliptical cross section tracking */
if (model_type == NODE_MICROFACET_HAIR_ELLIPTIC_BECKMANN ||
model_type == NODE_MICROFACET_HAIR_ELLIPTIC_GGX) {
if (cross_section_type == NODE_MICROFACET_HAIR_ELLIPTIC) {
attributes->add(ATTR_STD_VERTEX_NORMAL);
}
@ -3777,16 +3781,17 @@ void MicrofacetHairBsdfNode::compile(SVMCompiler &compiler)
__float_as_uint(melanin_redness));
/* data node 3 */
compiler.add_node(compiler.encode_uchar4(tint_ofs, random_in_ofs, random_color_ofs, 0),
__float_as_uint(random),
__float_as_uint(random_color),
attr_random);
compiler.add_node(
compiler.encode_uchar4(tint_ofs, random_in_ofs, random_color_ofs, cross_section_type),
__float_as_uint(random),
__float_as_uint(random_color),
attr_random);
/* data node 4 */
compiler.add_node(compiler.encode_uchar4(compiler.stack_assign_if_linked(R_in),
compiler.stack_assign_if_linked(TT_in),
compiler.stack_assign_if_linked(TRT_in),
model_type),
distribution_type),
__float_as_uint(R),
__float_as_uint(TT),
__float_as_uint(TRT));
@ -3805,7 +3810,8 @@ void MicrofacetHairBsdfNode::compile(SVMCompiler &compiler)
void MicrofacetHairBsdfNode::compile(OSLCompiler &compiler)
{
compiler.parameter(this, "parametrization");
compiler.parameter(this, "model_type");
compiler.parameter(this, "cross_section_type");
compiler.parameter(this, "distribution_type");
compiler.add(this, "node_microfacet_hair_bsdf");
}

View File

@ -922,8 +922,10 @@ class MicrofacetHairBsdfNode : public BsdfBaseNode {
NODE_SOCKET_API(float, random)
/* Selected coloring parametrization. */
NODE_SOCKET_API(NodeMicrofacetHairParametrization, parametrization)
/* Selected model type. */
NODE_SOCKET_API(NodeMicrofacetHairModelType, model_type)
/* Selected cross-section type. */
NODE_SOCKET_API(NodeMicrofacetHairCrossSectionType, cross_section_type)
/* Selected microfacet distribution type. */
NODE_SOCKET_API(NodeMicrofacetHairDistributionType, distribution_type)
};
class HairBsdfNode : public BsdfNode {

@ -1 +1 @@
Subproject commit 7be7aff5a18c550465b3f7634539ed4168af7c51
Subproject commit 4f6dbb69893bd6bdf73467effe77ae46c8e4ee37

@ -1 +1 @@
Subproject commit c226f867affd12881533a54c8c90ac6eebfaca6c
Subproject commit 5a774a6dad4378f173ec7fdcdcd406048fcc9a29

@ -1 +1 @@
Subproject commit bdcfdd47ec3451822b21d1cff2ea2db751093c9a
Subproject commit 0f72f6c85c3743a9072273acb6a8a34b1cf1064b

View File

@ -322,10 +322,8 @@ typedef struct bNode {
*/
int16_t type;
char _pad1[2];
/** Used for some builtin nodes that store properties but don't have a storage struct . */
int16_t custom1, custom2;
int16_t custom0, custom1, custom2;
float custom3, custom4;
/** Optional link to libdata. */
@ -1687,12 +1685,13 @@ enum {
#define SHD_MICROFACET_HAIR_PIGMENT_CONCENTRATION 1
#define SHD_MICROFACET_HAIR_DIRECT_ABSORPTION 2
/* microfacet hair modes */
#define SHD_MICROFACET_HAIR_CIRCULAR_GGX 0
#define SHD_MICROFACET_HAIR_CIRCULAR_GGX_ANALYTIC 1
#define SHD_MICROFACET_HAIR_CIRCULAR_BECKMANN 2
#define SHD_MICROFACET_HAIR_ELLIPTIC_GGX 3
#define SHD_MICROFACET_HAIR_ELLIPTIC_BECKMANN 4
/* microfacet hair cross-section */
#define SHD_MICROFACET_HAIR_CIRCULAR 0
#define SHD_MICROFACET_HAIR_ELLIPTIC 1
/* microfacet hair distribution */
#define SHD_MICROFACET_HAIR_GGX 0
#define SHD_MICROFACET_HAIR_BECKMANN 1
/* blend texture */
#define SHD_BLEND_LINEAR 0

View File

@ -4671,37 +4671,31 @@ static const EnumPropertyItem node_microfacet_hair_parametrization_items[] = {
{0, NULL, 0, NULL, NULL},
};
static const EnumPropertyItem node_microfacet_hair_mode_items[] = {
{SHD_MICROFACET_HAIR_CIRCULAR_GGX,
"HAIR_MICROFACET_CIRCULAR_GGX",
static const EnumPropertyItem node_microfacet_hair_cross_section_items[] = {
{SHD_MICROFACET_HAIR_CIRCULAR,
"HAIR_MICROFACET_CIRCULAR",
0,
"Microfacet Circular GGX",
"GGX microfacet-based hair scattering model with circular cross section fiber, numerically "
"integrated across the width"},
{SHD_MICROFACET_HAIR_CIRCULAR_GGX_ANALYTIC,
"HAIR_MICROFACET_CIRCULAR_GGX_ANALYTIC",
"Circular",
"Microfacet-based hair scattering model with circular cross section"},
{SHD_MICROFACET_HAIR_ELLIPTIC,
"HAIR_MICROFACET_CIRCULAR_ELLIPTIC",
0,
"Microfacet Circular GGX Analytic",
"GGX microfacet-based hair scattering model with circular cross section fiber, analytically "
"integrated across the width with no masking term"},
{SHD_MICROFACET_HAIR_CIRCULAR_BECKMANN,
"HAIR_MICROFACET_CIRCULAR_BECKMANN",
"Elliptical",
"Microfacet-based hair scattering model with elliptical cross section fiber"},
{0, NULL, 0, NULL, NULL},
};
static const EnumPropertyItem node_microfacet_hair_distribution_items[] = {
{SHD_MICROFACET_HAIR_GGX,
"HAIR_MICROFACET_GGX",
0,
"Microfacet Circular Beckmann",
"Beckmann microfacet-based hair scattering model with circular cross section fiber, "
"numerically integrated across the width"},
{SHD_MICROFACET_HAIR_ELLIPTIC_GGX,
"HAIR_MICROFACET_ELLIPTIC_GGX",
0,
"Microfacet Elliptical GGX",
"GGX microfacet-based hair scattering model with elliptical cross section fiber, numerically "
"integrated across the width"},
{SHD_MICROFACET_HAIR_ELLIPTIC_BECKMANN,
"GGX",
"Microfacet-based hair scattering model with GGX distribution"},
{SHD_MICROFACET_HAIR_BECKMANN,
"HAIR_MICROFACET_ELLIPTIC_BECKMANN",
0,
"Microfacet Elliptical Beckmann",
"Beckmann microfacet-based hair scattering model with elliptical cross section fiber, "
"numerically integrated across the width"},
"Beckmann",
"Microfacet-based hair scattering model with Beckmann distribution"},
{0, NULL, 0, NULL, NULL},
};
@ -6231,20 +6225,31 @@ static void def_hair_microfacet(StructRNA *srna)
PropertyRNA *prop;
prop = RNA_def_property(srna, "parametrization", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "custom1");
RNA_def_property_enum_sdna(prop, NULL, "custom0");
RNA_def_property_ui_text(
prop, "Color parametrization", "Select the shader's color parametrization");
prop, "Color Parametrization", "Select the shader's color parametrization");
RNA_def_property_enum_items(prop, node_microfacet_hair_parametrization_items);
RNA_def_property_enum_default(prop, SHD_MICROFACET_HAIR_REFLECTANCE);
/* Upon editing, update both the node data AND the UI representation */
/* (This effectively shows/hides the relevant sockets) */
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNode_socket_update");
prop = RNA_def_property(srna, "model_type", PROP_ENUM, PROP_NONE);
prop = RNA_def_property(srna, "cross_section_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "custom1");
RNA_def_property_ui_text(
prop, "Hair Cross Section Shape", "Select the hair's cross section shape");
RNA_def_property_enum_items(prop, node_microfacet_hair_cross_section_items);
RNA_def_property_enum_default(prop, SHD_MICROFACET_HAIR_CIRCULAR);
/* Upon editing, update both the node data AND the UI representation */
/* (This effectively shows/hides the relevant sockets) */
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNode_socket_update");
prop = RNA_def_property(srna, "distribution_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "custom2");
RNA_def_property_ui_text(prop, "Mode", "Select the shader's mode");
RNA_def_property_enum_items(prop, node_microfacet_hair_mode_items);
RNA_def_property_enum_default(prop, SHD_MICROFACET_HAIR_CIRCULAR_GGX);
RNA_def_property_ui_text(
prop, "Microfacet Distribution", "Select the microfacet distribution of the hair surface");
RNA_def_property_enum_items(prop, node_microfacet_hair_distribution_items);
RNA_def_property_enum_default(prop, SHD_MICROFACET_HAIR_GGX);
/* Upon editing, update both the node data AND the UI representation */
/* (This effectively shows/hides the relevant sockets) */
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNode_socket_update");

View File

@ -81,24 +81,25 @@ static void node_declare(NodeDeclarationBuilder &b)
static void node_shader_buts_microfacet_hair(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiItemR(layout, ptr, "parametrization", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
uiItemR(layout, ptr, "model_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
uiItemR(layout, ptr, "cross_section_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
uiItemR(layout, ptr, "distribution_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
}
/* Initialize the custom Parametrization property to Color. */
static void node_shader_init_hair_microfacet(bNodeTree * /*ntree*/, bNode *node)
{
node->custom1 = SHD_MICROFACET_HAIR_REFLECTANCE;
node->custom2 = SHD_MICROFACET_HAIR_CIRCULAR_GGX;
node->custom0 = SHD_MICROFACET_HAIR_REFLECTANCE;
node->custom1 = SHD_MICROFACET_HAIR_CIRCULAR;
node->custom2 = SHD_MICROFACET_HAIR_GGX;
}
/* Triggers (in)visibility of some sockets when changing Parametrization. */
static void node_shader_update_hair_microfacet(bNodeTree *ntree, bNode *node)
{
int parametrization = node->custom1;
int model_type = node->custom2;
int parametrization = node->custom0;
int cross_section_type = node->custom1;
bool elliptical = (model_type == SHD_MICROFACET_HAIR_ELLIPTIC_GGX ||
model_type == SHD_MICROFACET_HAIR_ELLIPTIC_BECKMANN);
bool elliptical = (cross_section_type == SHD_MICROFACET_HAIR_ELLIPTIC);
LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
if (STREQ(sock->name, "Color")) {

@ -1 +1 @@
Subproject commit f542f4d21a077d85ffb3e43aa7f170976dee20b6
Subproject commit e1744b9bd82527cf7e8af63362b61bd309b5711b