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
7 changed files with 19 additions and 26 deletions
Showing only changes of commit 40b8bc055b - Show all commits

View File

@ -742,8 +742,7 @@ ccl_device int bsdf_microfacet_hair_sample(const KernelGlobals kg,
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));
}

View File

@ -94,22 +94,13 @@ shader node_principled_hair_bsdf(color Color = color(0.017513, 0.005763, 0.00205
sigma = sigma_from_concentration(0.0, 0.8054375);
}
normal major_axis = Normal;
if (model == "Far-field Model" && AspectRatio != 1.0) {
getattribute("geom:N", major_axis);
}
if (model == "Far-field Model") {
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?
BSDF = microfacet_hair(major_axis,
sigma,
roughness,
Offset,
IOR,
AspectRatio,
Rlobe,
TTlobe,
TRTlobe);
normal major_axis = Normal;
if (AspectRatio != 1.0) {
getattribute("geom:N", major_axis);
}
BSDF = microfacet_hair(
major_axis, sigma, roughness, Offset, IOR, AspectRatio, Rlobe, TTlobe, TRTlobe);
}
else {
BSDF = principled_hair(Normal, sigma, roughness, radial_roughness, m0_roughness, Offset, IOR);

View File

@ -490,7 +490,8 @@ typedef enum ClosureType {
type <= CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID) || \
(type >= CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID && \
type <= CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID))
#define CLOSURE_IS_BSDF_OR_BSSRDF(type) (type != CLOSURE_NONE_ID && type <= CLOSURE_BSSRDF_RANDOM_WALK_FIXED_RADIUS_ID)
#define CLOSURE_IS_BSDF_OR_BSSRDF(type) \
(type != CLOSURE_NONE_ID && type <= CLOSURE_BSSRDF_RANDOM_WALK_FIXED_RADIUS_ID)
#define CLOSURE_IS_BSSRDF(type) \
(type >= CLOSURE_BSSRDF_BURLEY_ID && type <= CLOSURE_BSSRDF_RANDOM_WALK_FIXED_RADIUS_ID)
#define CLOSURE_IS_VOLUME(type) \

View File

@ -1137,7 +1137,8 @@ int ShaderGraph::get_num_closures()
num_closures += MAX_VOLUME_STACK_SIZE;
}
else if (closure_type == CLOSURE_BSDF_HAIR_PRINCIPLED_ID ||
closure_type == CLOSURE_BSDF_HAIR_MICROFACET_ID) {
closure_type == CLOSURE_BSDF_HAIR_MICROFACET_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`.
else {

View File

@ -3441,15 +3441,17 @@ PrincipledHairBsdfNode::PrincipledHairBsdfNode() : BsdfBaseNode(get_node_type())
closure = CLOSURE_BSDF_HAIR_MICROFACET_ID;
}
/* Enable retrieving Hair Info -> Random if Random isn't linked. */
void PrincipledHairBsdfNode::attributes(Shader *shader, AttributeRequestSet *attributes)
{
/* Make sure we have the normal for elliptical cross section tracking. */
if (model == NODE_PRINCIPLED_HAIR_HUANG && aspect_ratio != 1.0f) {
attributes->add(ATTR_STD_VERTEX_NORMAL);
if (model == NODE_PRINCIPLED_HAIR_HUANG) {
/* Make sure we have the normal for elliptical cross section tracking. */
if (aspect_ratio != 1.0f || input("Aspect Ratio")->link) {
weizhen marked this conversation as resolved Outdated

I think you also need to check whether the socket is connected here?

I think you also need to check whether the socket is connected here?
attributes->add(ATTR_STD_VERTEX_NORMAL);
}
}
if (!input("Random")->link) {
/* Enable retrieving Hair Info -> Random if Random isn't linked. */
attributes->add(ATTR_STD_CURVE_RANDOM);
}
ShaderNode::attributes(shader, attributes);

View File

@ -1286,8 +1286,7 @@ typedef struct NodeShaderPrincipled {
typedef struct NodeShaderHairPrincipled {
short model;
weizhen marked this conversation as resolved Outdated

Not sure if we need this yet, custom1 and custom2 should be enough?

Not sure if we need this yet, `custom1` and `custom2` should be enough?

For the current two enums yes, but named struct seems easier understandable. On the other hand, it introduces additional storage and is seen as a compromise for not having enum-typed sockets. I'm actually not sure what the current recommendation is.

For the current two enums yes, but named struct seems easier understandable. On the other hand, it introduces additional storage and is seen as a compromise for not having enum-typed sockets. I'm actually not sure what the current recommendation is.

I think it's fine to have better names for storage, custom1 / custom2 are not that great.

I think it's fine to have better names for storage, custom1 / custom2 are not that great.
short parametrization;
short cross_section;
char _pad[2];
char _pad[4];
} NodeShaderHairPrincipled;
/** TEX_output. */

View File

@ -4291,7 +4291,7 @@ static const EnumPropertyItem node_principled_hair_model_items[] = {
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 preciser highlight in forward "
"distance, supports elliptical cross-sections and has more precise highlight in forward "
"scattering direction."},
{0, nullptr, 0, nullptr, nullptr},
};