MaterialX icon indicating copy to clipboard operation
MaterialX copied to clipboard

Proposal: MaterialX Hair BSDF

Open msuzuki-nvidia opened this issue 1 year ago • 0 comments

MaterialX Hair BSDF Proposal

This document proposes a new MaterialX hair BSDF node and a set of support functions which
can be used to build an all purpose hair material model. The BSDF is based on the paper A Practical and Controllable Hair and Fur Model for Production Path Tracing (Chiang et al. 2016)[^Chiang2016]. The BSDF is widely used in visual effects and animation to model hair and fur and provides a physically grounded hair and fur shading model with artist friendly parameterization suitable for production quality rendering. The support functions are derived from the supporting literature and allow us to create parameterizations based on the melanin present in the hair strands or based on artist friendly normalized values.

BSDF

chiang_hair_bsdf: Constructs aggregated reflective and transmissive scattering based on the Chiang et al.[^Chiang2016] hair shading model. This hair shading model categorizes the light paths according to the number of internal reflections. The first three categories (and their lobes) are labeled based on event types as R, TT, and TRT, where R denotes a reflection event and T denotes a transmission event. The first three are modeled as separate lobes with roughness parameters along the longitudinal and azimuthal directions, while all longer paths are implicitly accounted for in a fourth lobe in the model without additional parameters; the longitudinal roughness of the fourth lobe is set to the one of the third lobe, while the model needs no roughness parameter for the azimuthal direction.

Parameters

Parameters Type Range Default Description
tint_R color3 (0, 1) (1, 1, 1) Color multiplier for the first R-lobe.
tint_TT color3 (0, 1) (1, 1, 1) Color multiplier for the first TT-lobe.
tint_TRT color3 (0, 1) (1, 1, 1) Color multiplier for the first TRT-lobe.
roughness_R vector2 [0, ∞) (0.1, 0.1) Longitudinal and azimuthal roughness (ν, s) for the first R-lobe. With (0, 0) specifying pure specular scattering.
roughness_TT vector2 [0, ∞) (0.05, 0.05) Longitudinal and azimuthal roughness (ν, s) for the second TT-lobe. With (0, 0) specifying pure specular scattering.
roughness_TRT vector2 [0, ∞) (0.2, 0.2) Longitudinal and azimuthal roughness (ν, s) for the third TRT-lobe. With (0, 0) specifying pure specular scattering.
cuticle_angle float [0, 1] 0.5 Cuticle angle in radians, Values above 0.5 tilt the scales towards the root of the fiber. With 0.5 specifying no tilt.
absorption_coefficient vector3 (0, 0, 0) Absorption coefficient normalized to the hair fiber diameter.
ior float 1.55 Index of refraction. With 1.55 being the value for keratin as default.

Roughness

For artistically intuitive parameterization of roughness, we propose the following functions from Chiang et al.[^Chiang2016] paper (eq. 7 and 8) for the BSDF.

Longitudinal Roughness

$compute\_v(\beta_M)=(0.726\beta_M+0.812\beta_M^2+3.7\beta_M^{20})^2$

Anisotropic Azimuthal Roughness

$compute\_s(\beta_N)=\sqrt{\pi/8}(0.265\beta_N+1.194\beta_N^2+5.372\beta_N^{22})$

(The constant $\sqrt{\pi/8}$ can be found in the Chiang et al.[^Chiang2016] paper Appendix A. eq. 12)

Absorption

Absorption Coefficient from Color

To calculate the absorption coefficient we propose the following artistic friendly function from Chiang et al.[^Chiang2016] (eq. 9).

$compute\_absorption\_from\_color(C,\beta_N)=(lnC/(5.969-0.215\beta_N+2.532\beta_N^2-10.73\beta_N^3+5.574\beta_N^4+0.245\beta_N^5))^2$

Absorption Coefficient from Melanin

For absorption based on pigments eumelanin and pheomelanin we use the work from An Energy-Conserving Hair Reflectance Model (d'Eon et al. 2011, Section 6.1)[^d'Eon2011] and propose the following absorption coefficient function based on melanin workflows.

$\mu_a=\rho_e\sigma_{a,e}+\rho_p\sigma_{a,p}$ $compute\_absorption\_from\_melanin(\rho_e,\rho_p)=\rho_e(0.419, 0.697, 1.37)+\rho_p(0.187, 0.4, 1.04)$

Linearization

Something to be discussed is that Melanin has a range of $[0, \infty)$. In our tests we implemented several normalizations and the results can be found here however we make no recommendations at this time. Blender makes use of a log function (Blender.org)[^Blender] which provides a pretty good result although it has some rapid changes in the upper range.

Practical Implementation

For purposes of discussion, we present a simple implementation in MDL[^NVIDIAMDL2023][^NVIDIAMDLSDK] with examples using the proposed functions. Additional implementations are also available.[^Bitterli][^Blender][^Pharr2016]

SimpleHairBase is a development material written in MDL and rendered in Omniverse for the purposes of exploring hair rendering. It is a hybrid of the Chiang et al.[^Chiang2016] and d’Eon et al.[^d'Eon2011] methods and provides Users the option to calculate absorption using either the artists friendly function or the melanin function. The material defaults to isotropic roughness but we provide the option to enable azimuthal roughness. Overall the model allows our Users a wide range of flexibility when rendering hair and we believe the proposed components allow for a reasonable means for exchange.

// Public parameters for SimpleHairBase
export material SimpleHairBase
(
	float base_color_weight = 1.0,
	color base_color = color(1.0),
	float melanin_concentration = 1.0,
	float melanin_redness = 0.5,
	float specular_reflection_roughness = 0.1,
	bool specular_reflection_anisotropic_roughness = false,
	float specular_reflection_azimuthal_roughness = 0.2,
	uniform float specular_reflection_ior = 1.55,
	float specular_reflection_shift = 0.5,
	color tint_R = color(1.0),
	color tint_TT = color(1.0),
	color tint_TRT = color(1.0)
)
= let {
	// Specular reflection
	float longitudinal_roughness = compute_v(specular_reflection_roughness);
	float azimuthal_roughness = specular_reflection_anisotropic_roughness ?
		compute_s(specular_reflection_azimuthal_roughness) :
		longitudinal_roughness;

	float2 roughness_r = (longitudinal_roughness, azimuthal_roughness);
	float2 roughness_tt = roughness_r * float2(0.25);  // Roughening/tightening of the different lobes
	float2 roughness_trt = roughness_r * float2(4.0);  // as described in Marschner et al. 2003's paper

	// Remapping cuticle angle [0, 1] to [-PI/2, +PI/2]
	float cutical_angle_in_radians = specular_reflection_shift * math::PI - (math::PI / 2.0);

	// Absorption from Melanin Concentration
	float melanin = -math::log(math::max(1 - melanin_concentration, 0.0001));
	float eumelanin = melanin * (1 - melanin_redness);
	float pheomelanin = melanin * melanin_redness;
	color melanin_sigma_a = compute_absorption_from_melanin(eumelanin, pheomelanin);

	// Absorption from Base Color
	color base_color_sigma_a = compute_absorption_from_color(
		base_color_weight * base_color,
		specular_reflection_anisotropic_roughness ? 
			specular_reflection_azimuthal_roughness :
			longitudinal_roughness
	);

	color absorption_coefficient = 
		base_color == color(1.0) && base_color_weight == 1.0f ?
			melanin_sigma_a :
			base_color_sigma_a;

	hair_bsdf hair = df::chiang_hair_bsdf(
		tint_R: tint_R,
		tint_TT: tint_TT,
		tint_TRT: tint_TRT,
		roughness_R: roughness_r,
		roughness_TT: roughness_tt,
		roughness_TRT: roughness_trt,
		cuticle_angle: cuticle_angle_in_radian,
		absorption_coefficient: absorption_coefficient,
		ior: math::max(specular_reflection_ior, 1.0f + 1.e-5)
	);

	// ... add diffuse component etc ...

} in material (
	thin_walled: true,
	hair: hair
);

Examples

[^Bitterli]: Benedikt Bitterli: The Tungsten Renderer, https://github.com/tunabrain/tungsten
[^Blender]: Blender.org: Principled Hair BSDF, https://docs.blender.org/manual/en/latest/render/shader_nodes/shader/hair_principled.html
[^Chiang2016]: Matt J. Chiang, Benedikt Bitterli, Chuck Tappan, Brent Burley: A Practical and Controllable Hair and Fur Model for Production Path Tracing (2016), https://media.disneyanimation.com/uploads/production/publication_asset/152/asset/eurographics2016Fur_Smaller.pdf [^d'Eon2011]: Eugene d'Eon, Guillaume Francois, Martin Hill, Joe Letteri, Jean-Marie Aubry: An Energy-Conserving Hair Reflectance Model (2011), https://eugenedeon.com/pdfs/egsrhair.pdf [^Pharr2016]: Matt Pharr: THE IMPLEMENTATION OF A HAIR SCATTERING MODEL (2016), https://pbrt.org/hair.pdf
[^NVIDIAMDL2023]: NVIDIA Corporation: NVIDIA Material Definition Language 1.8 (2023), https://raytracing-docs.nvidia.com/mdl/specification/MDL_spec_1.8.2_24May2023.pdf
[^NVIDIAMDLSDK]: NVIDIA Corporation: NVIDIA Material Definition Language SDK, https://github.com/NVIDIA/MDL-SDK/blob/master/src/mdl/jit/libbsdf/libbsdf_hair.h

msuzuki-nvidia avatar Aug 15 '24 01:08 msuzuki-nvidia