[Bf-blender-cvs] [eb4abf2ca7a] soc-2018-hair-shader: Linearize melanin concentration

L. E. Segovia noreply at git.blender.org
Mon Jul 9 18:14:05 CEST 2018


Commit: eb4abf2ca7a0f38a46ebb122cfcd590f07164ed2
Author: L. E. Segovia
Date:   Mon Jul 9 16:12:31 2018 +0000
Branches: soc-2018-hair-shader
https://developer.blender.org/rBeb4abf2ca7a0f38a46ebb122cfcd590f07164ed2

Linearize melanin concentration

This commit includes factoring remappings into new functions, as well as
adjusted defaults for maintaining roughly the same brownish hair.
(In reality, Melanin 1.3 = New Melanin 0.8054375, so I truncated the
extra decimal places.)

===================================================================

M	intern/cycles/kernel/shaders/node_principled_hair_bsdf.osl
M	intern/cycles/kernel/svm/svm_closure.h
M	intern/cycles/render/nodes.cpp
M	source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.c

===================================================================

diff --git a/intern/cycles/kernel/shaders/node_principled_hair_bsdf.osl b/intern/cycles/kernel/shaders/node_principled_hair_bsdf.osl
index a4709702496..b4451164240 100644
--- a/intern/cycles/kernel/shaders/node_principled_hair_bsdf.osl
+++ b/intern/cycles/kernel/shaders/node_principled_hair_bsdf.osl
@@ -20,10 +20,19 @@ color log3 (color a) {
 	return color(log(a[0]), log(a[1]), log(a[2]));
 }
 
+color sigma_from_concentration(float Eumelanin, float Pheomelanin) {
+	return Eumelanin*color(0.506, 0.841, 1.653) + Pheomelanin*color(0.343, 0.733, 1.924);
+}
+
+color sigma_from_reflectance(color Color, float AzimuthalRoughness) {
+	float roughness_fac = (((((0.245*AzimuthalRoughness) + 5.574)*AzimuthalRoughness - 10.73)*AzimuthalRoughness + 2.532)*AzimuthalRoughness - 0.215)*AzimuthalRoughness + 5.969;
+	return log3(Color)/roughness_fac;
+}
+
 shader node_principled_hair_bsdf(
-	color Color = color(0.09292, 0.02100, 0.00417),
-	float Melanin = 0.0,
-	float MelaninRedness = 1.3,
+	color Color = color(0.017513, 0.005763, 0.002059),
+	float Melanin = 0.8,
+	float MelaninRedness = 1.0,
 	float RandomColor = 0.0,
 	color Tint = 1.0,
 	color AbsorptionCoefficient = color(0.245531, 0.52, 1.365),
@@ -41,7 +50,6 @@ shader node_principled_hair_bsdf(
 	output closure color BSDF = 0)
 {
 	color sigma;
-
 	float random_value = 0.0;
 
 	if (AttrRandom != "none") {
@@ -57,28 +65,27 @@ shader node_principled_hair_bsdf(
 
 	float adjusted_roughness = Roughness*factor_random_roughness;
 	float adjusted_radial_roughness = RadialRoughness*factor_random_roughness;
-	float adjusted_eumelanin = Melanin*(1.0-MelaninRedness)*factor_random_color;
-	float adjusted_pheomelanin = Melanin*MelaninRedness*factor_random_color;
+	float melanin_qty = -log(max(1.0 - Melanin, 0.0001));
+	float adjusted_eumelanin = melanin_qty*(1.0-MelaninRedness)*factor_random_color;
+	float adjusted_pheomelanin = melanin_qty*MelaninRedness*factor_random_color;
 
 	if (parametrization == "Absorption coefficient") {
 		sigma = AbsorptionCoefficient;
 	}
 	else if (parametrization == "Melanin concentration") {
-		color melanin_sigma = adjusted_eumelanin*color(0.419, 0.697, 1.37) + adjusted_pheomelanin*color(0.187, 0.4, 1.05);
-		float roughness_fac = (((((0.245*adjusted_radial_roughness) + 5.574)*adjusted_radial_roughness - 10.73)*adjusted_radial_roughness + 2.532)*adjusted_radial_roughness - 0.215)*adjusted_radial_roughness + 5.969;
-		color tint_sigma = log3(Tint)/roughness_fac;
+		color melanin_sigma = sigma_from_concentration(adjusted_eumelanin, adjusted_pheomelanin);
+		color tint_sigma = sigma_from_reflectance(Tint, adjusted_radial_roughness);
 		tint_sigma *= tint_sigma;
 		sigma = melanin_sigma + tint_sigma;
 	}
 	else if (parametrization == "Direct coloring"){
-		float roughness_fac = (((((0.245*adjusted_radial_roughness) + 5.574)*adjusted_radial_roughness - 10.73)*adjusted_radial_roughness + 2.532)*adjusted_radial_roughness - 0.215)*adjusted_radial_roughness + 5.969;
-		sigma = log3(Color)/roughness_fac;
+		sigma = sigma_from_reflectance(Color, adjusted_radial_roughness);
 		sigma *= sigma;
 	}
 	else {
 		// Falling back to Benedikt Bitterli's brownish hair with Tungsten (via PHEOmelanin concentration)
 		// This gives the exact amount set as default above
-		sigma = 0.0*color(0.419, 0.697, 1.37) + 1.3*color(0.187, 0.4, 1.05);
+		sigma = sigma_from_concentration(0.0, 0.8054375);
 	}
 
 	//printf("Info: color %f, incoming eumelanin %f, incoming pheomelanin %f, incoming sigma %f, incoming color range %f, incoming normal %f, parametrization %s, resulting sigma %f, Longitudinal %f, Azimuthal %f, roughness range %f, Scale deviation %f, IOR %f\n", Color, Melanin, MelaninRedness, AbsorptionCoefficient, Normal, parametrization, sigma, RandomColor, Roughness, RadialRoughness, RandomRoughness, Offset, IOR);
diff --git a/intern/cycles/kernel/svm/svm_closure.h b/intern/cycles/kernel/svm/svm_closure.h
index c4f27bb5232..0b1d8551dbc 100644
--- a/intern/cycles/kernel/svm/svm_closure.h
+++ b/intern/cycles/kernel/svm/svm_closure.h
@@ -16,6 +16,19 @@
 
 CCL_NAMESPACE_BEGIN
 
+/* Helper functions */
+
+ccl_device_inline float3 sigma_from_concentration(float eumelanin, float pheomelanin)
+{
+	return eumelanin*make_float3(0.506f, 0.841f, 1.653f) + pheomelanin*make_float3(0.343f, 0.733f, 1.924f);
+}
+
+ccl_device_inline float3 sigma_from_reflectance(float3 color, float azimuthal_roughness)
+{
+	float roughness_fac = (((((0.245f*azimuthal_roughness) + 5.574f)*azimuthal_roughness - 10.73f)*azimuthal_roughness + 2.532f)*azimuthal_roughness - 0.215f)*azimuthal_roughness + 5.969f;
+	return log3(color) / roughness_fac;
+}
+
 /* Closure Nodes */
 
 ccl_device void svm_node_glass_setup(ShaderData *sd, MicrofacetBsdf *bsdf, int type, float eta, float roughness, bool refract)
@@ -787,30 +800,30 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
 						bsdf->sigma = absorption_coefficient;
 						break;
 					case NODE_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION: {
-						// Benedikt Bitterli's melanin ratio remapping.
+						// Benedikt Bitterli's melanin ratio remapping (adjusted for linearity).
+						melanin_qty = -logf(fmaxf(1.0 - melanin_qty, 0.0001));
 						float eumelanin = melanin_qty*(1.0f-melanin_ratio);
 						float pheomelanin = melanin_qty*melanin_ratio;
 						float factor_random_color = 1.0f + 2.0f*(random - 0.5f)*random_color;
 						eumelanin *= factor_random_color;
 						pheomelanin *= factor_random_color;
 
-						float3 melanin_sigma = eumelanin*make_float3(0.419f, 0.697f, 1.37f) + pheomelanin*make_float3(0.187f, 0.4f, 1.05f);
-						float roughness_fac = (((((0.245f*param2) + 5.574f)*param2 - 10.73f)*param2 + 2.532f)*param2 - 0.215f)*param2 + 5.969f;
-						float3 tint_sigma = log3(tint)/roughness_fac;
+						float3 melanin_sigma = sigma_from_concentration(eumelanin, pheomelanin);
+						float3 tint_sigma = sigma_from_reflectance(tint, param2);
 						tint_sigma *= tint_sigma;
 						bsdf->sigma = melanin_sigma+tint_sigma;
 						break;
 					}
 					case NODE_PRINCIPLED_HAIR_REFLECTANCE: {
-						float roughness_fac = (((((0.245f*param2) + 5.574f)*param2 - 10.73f)*param2 + 2.532f)*param2 - 0.215f)*param2 + 5.969f;
-						bsdf->sigma = log3(color)/roughness_fac;
+						bsdf->sigma = sigma_from_reflectance(color, param2);
 						bsdf->sigma *= bsdf->sigma;
 						break;
 					}
 					default: {
 						kernel_assert(!"Invalid Principled Hair parametrization!");
 						// Falling back to Benedikt Bitterli's brownish hair with Tungsten (via PHEOmelanin concentration)
-						bsdf->sigma = 0.0f*make_float3(0.419f, 0.697f, 1.37f) + 1.3f*make_float3(0.187f, 0.4f, 1.05f);
+						// Original mapping: 1.3 -> Blender's mapping: 0.8054375
+						bsdf->sigma = sigma_from_concentration(0.0f, 0.8054375f);
 						break;
 					}
 				}
diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp
index b2deb4bd2ab..684f17def9a 100644
--- a/intern/cycles/render/nodes.cpp
+++ b/intern/cycles/render/nodes.cpp
@@ -3068,8 +3068,8 @@ NODE_DEFINE(PrincipledHairBsdfNode)
 	NodeType* type = NodeType::add("principled_hair_bsdf", create, NodeType::SHADER);
 
 	// Initialize all sockets to their default values.
-	SOCKET_IN_COLOR(color, "Color", make_float3(0.09292f, 0.02100f, 0.00417f));
-	SOCKET_IN_FLOAT(melanin, "Melanin", 1.3f);
+	SOCKET_IN_COLOR(color, "Color", make_float3(0.017513f, 0.005763f, 0.002059f));
+	SOCKET_IN_FLOAT(melanin, "Melanin", 0.8f);
 	SOCKET_IN_FLOAT(melanin_redness, "Melanin Redness", 1.0f);
 	SOCKET_IN_COLOR(tint, "Tint", make_float3(1.f, 1.f, 1.f));
 	SOCKET_IN_FLOAT(random_color, "Random Color", 0.0f);
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.c
index 1b2a86c0a4e..d1621c16a08 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.c
@@ -31,8 +31,8 @@
 
 static bNodeSocketTemplate sh_node_bsdf_hair_principled_in[] = {
 	// This value was chosen empirically from rendering Bitterli's hair
-	{	SOCK_RGBA,		1, N_("Color"),						0.09292f, 0.02100f, 0.00417f, 1.0f, 0.0f, 1.0f},
-	{	SOCK_FLOAT,		1, N_("Melanin"),					1.3f, 0.0f, 0.0f, 0.0f, 0.0f, 10.0f},
+	{	SOCK_RGBA,		1, N_("Color"),						0.017513f, 0.005763f, 0.002059f, 1.0f, 0.0f, 1.0f},
+	{	SOCK_FLOAT,		1, N_("Melanin"),					0.8f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
 	{	SOCK_FLOAT,		1, N_("Melanin Redness"),			1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
 	{	SOCK_RGBA,		1, N_("Tint"),						1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f},
 	// Benedikt Bitterli's default brownish hair with PHEOmelanin



More information about the Bf-blender-cvs mailing list