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
6 changed files with 21 additions and 21 deletions
Showing only changes of commit 4415ebc336 - Show all commits

View File

@ -16,7 +16,7 @@ typedef struct MicrofacetHairExtra {
float TT;
float TRT;
float eccentricity;
float aspect_ratio;
weizhen marked this conversation as resolved Outdated

Do you think it could make sense to support colors here? It would increase the space usage, so we should only do it if there's a realistic use case I guess.

Do you think it could make sense to support colors here? It would increase the space usage, so we should only do it if there's a realistic use case I guess.

Currently if the parametrization is set to Melanin Concentration, an extra Tint socket is enabled, which corresponds to the realistic case of dyed hair (there is melanin present in natural hair, extra pigments from the dye is added). The R, TT, TRT are non-physical modulation factors, I thinking adding colors there would make the hair appearance quite difficult to control, using Tint should be a more proper way.

Currently if the parametrization is set to Melanin Concentration, an extra Tint socket is enabled, which corresponds to the realistic case of dyed hair (there is melanin present in natural hair, extra pigments from the dye is added). The R, TT, TRT are non-physical modulation factors, I thinking adding colors there would make the hair appearance quite difficult to control, using Tint should be a more proper way.
/* Geometry data. */
float4 geom;
@ -844,7 +844,7 @@ ccl_device float3 bsdf_microfacet_hair_eval_r_elliptic(ccl_private const ShaderC
/* get elliptical cross section characteristic */
const float a = 1.0f;
/* TODO: rename this as aspect ratio? e is in [0, 0.85], b is in [0.52, 1]. */
const float b = bsdf->extra->eccentricity;
const float b = bsdf->extra->aspect_ratio;
const float e2 = 1.0f - sqr(b / a);
/* this follows blender's convention (unlike the circular case?) */
@ -966,8 +966,8 @@ ccl_device float3 bsdf_microfacet_hair_eval_tt_trt_elliptic(KernelGlobals kg,
/* get elliptical cross section characteristic */
const float a = 1.0f;
const float b = bsdf->extra->eccentricity;
const float e2 = 1.0f - sqr(b / a);
const float b = bsdf->extra->aspect_ratio;
const float e2 = 1.0f - sqr(b / a); /* Squared Eccentricity. */
float gamma_m_min = to_gamma(phi_m_min, a, b) + 1e-3f;
float gamma_m_max = to_gamma(phi_m_max, a, b) - 1e-3f;
@ -1138,7 +1138,7 @@ ccl_device Spectrum bsdf_microfacet_hair_eval_elliptic(KernelGlobals kg,
const float3 wo = make_float3(dot(omega_in, X), dot(omega_in, Y), dot(omega_in, Z));
/* Treat as transparent material if intersection lies outside of the projected radius. */
const float e2 = 1.0f - sqr(bsdf->extra->eccentricity);
const float e2 = 1.0f - sqr(bsdf->extra->aspect_ratio);
const float radius = sqrtf(1.0f - e2 * sqr(sin_phi(wi)));
if (fabsf(bsdf->extra->geom.w) > radius) {
*pdf = 0.0f;
@ -1180,7 +1180,7 @@ ccl_device int bsdf_microfacet_hair_sample_elliptic(const KernelGlobals kg,
/* get elliptical cross section characteristic */
const float a = 1.0f;
const float b = bsdf->extra->eccentricity;
const float b = bsdf->extra->aspect_ratio;
const float e2 = 1.0f - sqr(b / a);
/* macronormal */

View File

@ -1017,20 +1017,20 @@ 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) {
uint eccentricity_ofs, temp;
svm_unpack_node_uchar4(data_node5.x, &eccentricity_ofs, &temp, &temp, &temp);
uint aspect_ratio_ofs, temp;
svm_unpack_node_uchar4(data_node5.x, &aspect_ratio_ofs, &temp, &temp, &temp);
float eccentricity = stack_load_float_default(stack, eccentricity_ofs, data_node5.y);
float aspect_ratio = stack_load_float_default(stack, aspect_ratio_ofs, data_node5.y);
/* Eccentricity */
bsdf->extra->eccentricity = (eccentricity > 1.0f) ? 1.0f / eccentricity : eccentricity;
/* Aspect Ratio */
bsdf->extra->aspect_ratio = (aspect_ratio > 1.0f) ? 1.0f / aspect_ratio : aspect_ratio;
const AttributeDescriptor attr_descr_normal = find_attribute(kg, sd, data_node5.z);
const float3 normal = curve_attribute_float3(kg, sd, attr_descr_normal, NULL, NULL);
const float3 binormal = safe_normalize(cross(sd->dPdu, normal));
/* Align X axis with the ellipse major axis. */
if (eccentricity > 1.0f) {
if (aspect_ratio > 1.0f) {
const float3 normal = safe_normalize(cross(binormal, sd->dPdu));
bsdf->extra->geom = make_float4(normal.x, normal.y, normal.z, 0.0f);
}

View File

@ -3665,7 +3665,7 @@ NODE_DEFINE(MicrofacetHairBsdfNode)
make_float3(0.245531f, 0.52f, 1.365f),
SocketType::VECTOR);
SOCKET_IN_FLOAT(eccentricity, "Eccentricity", 0.85f);
SOCKET_IN_FLOAT(aspect_ratio, "Aspect Ratio", 0.85f);
SOCKET_IN_FLOAT(offset, "Offset", 2.f * M_PI_F / 180.f);
SOCKET_IN_FLOAT(roughness, "Roughness", 0.3f);
@ -3725,7 +3725,7 @@ void MicrofacetHairBsdfNode::compile(SVMCompiler &compiler)
ShaderInput *TRT_in = input("TRT lobe");
ShaderInput *Blur_in = input("Blur");
ShaderInput *eccentricity_in = input("Eccentricity");
ShaderInput *aspect_ratio_in = input("Aspect Ratio");
int color_ofs = compiler.stack_assign(input("Color"));
int tint_ofs = compiler.stack_assign(input("Tint"));
@ -3789,11 +3789,11 @@ void MicrofacetHairBsdfNode::compile(SVMCompiler &compiler)
__float_as_uint(TRT));
/* data node 5 */
compiler.add_node(compiler.encode_uchar4(compiler.stack_assign_if_linked(eccentricity_in),
compiler.add_node(compiler.encode_uchar4(compiler.stack_assign_if_linked(aspect_ratio_in),
SVM_STACK_INVALID,
SVM_STACK_INVALID,
SVM_STACK_INVALID),
__float_as_uint(eccentricity),
__float_as_uint(aspect_ratio),
compiler.attribute(ATTR_STD_VERTEX_NORMAL),
0);
}

View File

@ -907,8 +907,8 @@ class MicrofacetHairBsdfNode : public BsdfBaseNode {
/* Absorption coefficient (unfiltered). */
NODE_SOCKET_API(float3, absorption_coefficient)
/* Eccentricity. */
NODE_SOCKET_API(float, eccentricity)
/* Aspect Ratio. */
NODE_SOCKET_API(float, aspect_ratio)
/* Randomization factor for axis rotation. */
NODE_SOCKET_API(float, random_axis)
/* Twist rate. */

View File

@ -56,7 +56,7 @@ void node_bsdf_hair_microfacet(vec4 color,
float TRT,
float ior,
float offset,
float eccentricity,
float aspect_ratio,
float random_axis,
float twist_rate,
float Blur,

View File

@ -27,7 +27,7 @@ static void node_declare(NodeDeclarationBuilder &b)
.default_value({0.245531f, 0.52f, 1.365f})
.min(0.0f)
.max(1000.0f);
b.add_input<decl::Float>(N_("Eccentricity"))
b.add_input<decl::Float>(N_("Aspect Ratio"))
.default_value(0.85f)
.min(0.0f)
.max(1.0f)
@ -124,7 +124,7 @@ static void node_shader_update_hair_microfacet(bNodeTree *ntree, bNode *node)
nodeSetSocketAvailability(
ntree, sock, parametrization == SHD_MICROFACET_HAIR_PIGMENT_CONCENTRATION);
}
else if (STREQ(sock->name, "Eccentricity")) {
else if (STREQ(sock->name, "Aspect Ratio")) {
nodeSetSocketAvailability(ntree, sock, elliptical);
}
}