vue2源码分析-响应式原理

正文

下面的 OSL 材质模拟了 Tony Reynolds 制作的皮肤着色器,它采用了由红、绿、蓝波长调制的分层次表面散射(layered subsurface scattering)。此外,着色器实现了一个 Dual lobe Speculartwo-lobe spec,双叶瓣高光)来捕捉人类皮肤上高光的微妙变化。

vue2源码分析-响应式原理_第1张图片

理论

不同波长的光穿透皮肤的深度不同。如果我们将可见光谱简化为三种颜色(红、绿、蓝),那么每一种颜色的平均自由路径(光子在被散射或吸收之前穿过特定物质的距离)的值就会不同。对于人类的皮肤来说,红色是最深的,然后是绿色蓝色是相当浅的。

color Depth = getTextureDif(RGB_Scatter_Depth, color(0.8,0.2,0.1));
...
color SubColor = getTextureDif(Subsurface_Color, color(0.85,0.75,0.65));
...
color SubR = SubColor * color(1,0,0);
color SubG = SubColor * color(0,1,0);
color SubB = SubColor * color(0,0,1); 

基于以上理论,着色器将主颜色纹理(次表面颜色)分离为红色、绿色和蓝色部分,并将这些部分输送到三个次表面着色器中,然后将它们组合在一起。这三个次表面着色器的深度(即平均自由路径)由相应的 RGB_Scatter_Depth 颜色的红、绿、蓝通道驱动。为了加快速度,将绿色和蓝色结合在一起,所以着色器将两个 SSS 闭包组合在一起(红+绿&蓝)而不是三个。

closure color SSS = vray_subsurface ( IOR, PhaseFunction, Depth * Depth_Scale * 0.5, SubColor * Subsurface_Amount, "subdivs", Subdivs);
	closure color SkinR = vray_subsurface ( IOR, PhaseFunction, SubR * Depth[0] * Depth_Scale, SubR * Subsurface_Amount, "subdivs", Subdivs); closure color SkinGB = vray_subsurface ( IOR, PhaseFunction, ((SubG * Depth[1]) + (SubB * Depth[2])) * Depth_Scale, (SubG + SubB) * Subsurface_Amount, "subdivs", Subdivs); 

所基于的想法是,所有人类的主要散射颜色是红色(因为我们在不同的肤色下都有红色的血液)。

换句话说,RGB 散射深度本身并不是一种颜色,而是分别代表红、绿、蓝三种波长的散射系数。因此,将波长 RGB 深度颜色的红色通道设置为 1.0 意味着红色波长的深度是 100% ,而将其设置为 0.7 意味着它是 70%,以此类推,对于所有三个 RGB 通道。

请注意,在下图中,红色通道比绿色或蓝通道更柔和,因为它有更多的深度。

  • RGB 散射深度值: 1.0, 0.4, 0.2 vue2源码分析-响应式原理_第2张图片

优缺点

这种方法的另一个好处是,当它设置的散射量较大时,它几乎消除了 SSS2 材质的薄部分可能出现的 “绿色误差”,因为它将多个次表面着色器线性混合在一起,而不像在 SSS2 材质将中次表面和散射颜色之间进行更复杂的相互作用,虽然更 物理正确,但对艺术家来说可能 不直观

总的来说,这个着色器的 重点 是优先考虑 艺术控制 而不是 物理正确性 。像 VraySkinMtl 这样的分层皮肤着色器的一个 缺点 是,用户需要将不同(通常 不直观)的颜色混合在一起到达想要的皮肤颜色。autodesk 在谈到他们的分层 Miss* 着色器时表示: “每一层都有自己独特的颜色,这使得很难达到给定的“最终”颜色,并且改变图层之间的平衡会使颜色失去效果。” 同样, SSS2 材料的一个 缺点 是,由于次表面散射计算涉及复杂的数学,艺术家可能会选择一个特定的颜色,在渲染中却得到一个完全不同的颜色。

相比之下,使用本文的这个着色器,用户只需输入皮肤的单个纹理贴图到 Subsurface Color 中,就可以得到他们想要的结果。同样地,用户设置想要在渗出效果中看到的 Wavelength RGB Depth 的颜色(记住,这也会影响散射深度),他们也会得到 所见即所得 的结果。

单一散射/漫反射

该着色器包含一个设置为灰色的漫反射参数,以便在真实皮肤中模拟单一散射。换句话说,这就像一个非常粗糙的镜面反射,因为皮肤是电介质(dielectric),所以应该是无色的。由于 OSL 采用线性混合的工作方式,这比 SSS2 中的漫反射工作得更好,后者实际上抵消了 SSS 。相反,在这里,0.5 左右的值就可以起到不错的效果。如果你想要更偏向一些卡通效果,你可以将其设置为 0

双叶瓣高光(Two-lobe Specular)

着色器将两个高光叶瓣(specular lobe)组合在一起。使用 GGX microfacet BRDF (GGX 相当于尾部衰减参数锁定在 2.0 的广义 Trowbridge-Reitz (GTR) BRDF) 作为 “尖锐”(硬) 高光叶瓣,以及使用 Blinn BRDF 作为 “” 高光叶瓣。OSL 闭包用 SSS 平衡了这两个高光叶瓣,因此闭包总和不超过 1.0,使其 能量守恒(即_反射光总量不能超过入射光总量_)。如果您想要更专业一点,渲染器将闭包各组件根据权重相加,如果它们超过 1.0,则将权重除以它们的和,使它们保持相同的平衡。

/// @note 硬高光
closure color spcHard =Sharp_Amount * SpecColor * Spec_total_amount * 0.5 *microfacet_ggx (Nb, Roughness, Reflection_IOR,"gtr_gamma", Tail,"subdivs", Reflection_Subdivs,	"reflection_glossiness", Spec_sharpness,"highlight_glossiness", Spec_sharpness,"trace_reflections", Trace_Sharp_Reflections);

/// @note 软高光 
closure color spcSoft = Bloom_Amount * Fresnel * Spec_total_amount * 2 *vray_blinn (Nb, SoftGloss, Anisotropy, Aniso_rotation,"subdivs", Reflection_Subdivs, "trace_reflections", Trace_Bloom_Reflections); 

高光光泽度可以通过连接黑白贴图(参见下面的图1)到 Gloss Mask 参数来驱动。该贴图的 白色 部分将获得 “最大光泽度” 值,黑色 部分将获得 “最小光泽度” 值,灰色 区域将获得介于最小和最大值之间的值(见下图2)。如果没有提供贴图,着色器将 默认 使用最大光泽度值。这样一来,可以允许艺术家来确定面部更有光泽的部分,比如嘴唇和 T 字区

color GlossMask = getTextureDif(Gloss_Mask, color(1));
float Spec_sharpness = blendGloss(Gloss_Min, Gloss_Max, GlossMask);
...
float SoftGloss = (1-Spec_bloom * 0.6) * Spec_sharpness; 

注意 下面的图片(图3),嘴唇和鼻子看起来光滑和有光泽,因为遮罩是白色的,接收到最大的光泽值,而嘴唇上面的区域是粗糙的,因为遮罩是黑色的,因此接收到最小的光泽值。

  • 一个黑白光泽纹理贴图和从最小/最大光泽度值产生的高光变化。 vue2源码分析-响应式原理_第3张图片

双叶瓣高光 设置进一步增加了细节,结合了一个 “锐利” 的高光(由最小/最大光泽度值控制)和一个由 spec bloom 数量控制的 “软” 高光。bloom 越高,规格就越大,所以它类似于 “粗糙度” 参数。bloom 也受到光泽遮罩的影响。通过使用它们的 “数量” 滑块,两个高光叶瓣可以被关闭。

  • OSL 锐利和 bloom 高光叶瓣 vue2源码分析-响应式原理_第4张图片

凹凸 (Bump)

这个着色器 没有 凹凸,这是由于目前在 Vray 上 OSL 的限制(或者换句话来说,Vray 凹凸是相当复杂的,所以在 OSL 中实现它并不简单)。要获得 bump,只需将 OSLMtl 连接到 VrayBumpMtl 即可。

作为给用户的额外提示,拥有一个漂亮的凹凸贴图——包括皮肤毛孔之间的微观细节——对于有效捕捉人类皮肤是必不可少的。注意下面的图片,你可以在高光中看到比皮肤毛孔小得多的细节。双高光叶瓣 是捕捉这个细节所 必需 的。创建这些贴图的一种方法是在建模包中雕刻细节,并提取一个浮点 EXR 置换贴图。然而,在像 Mari 这样的程序中简单地将这些绘制成凹凸贴图通常更容易,通过为毛孔和毛孔之间的微观细节使用不同的层即可。在凹凸贴图中获得这种细节的技巧(与之相对的是置换贴图)是降低 凸起的增量比例(bump delta scale) (从 10.1),这将产生一个与置换贴图的精细细节相媲美的更清晰的结果。另一种方法是分离微观细节,并将其应用到高光图中。

  • 皮肤光度扫描的微观细节 vue2源码分析-响应式原理_第5张图片

UI 界面

  • 属性编辑器 vue2源码分析-响应式原理_第6张图片

一般参数

  • 透明度: 控制透明度
  • 深度尺度: 对次表面散射深度的全局控制
  • 整体亮度: 控制颜色的亮度。可以用来禁用 sss 和漫反射。
  • 漫反射颜色: 用一个无色的 Labertian 漫反射模拟单一散射。
  • 漫反射量: 控制漫反射量。可以用来禁用漫反射。

次表面参数

  • 底色: 材质的主色。这就是你的颜色纹理。默认 RGB 值: 0.85,0.75,0.65
  • 次表面量: 控制浅散射量,而不是深散射量。可用于禁用 SSS。
  • RGB 散射深度: 控制红色、绿色和蓝色波长的散射百分比,这也影响散射颜色。默认 RGB 值: 0.8,0.2,0.1
  • 纹理伽马: 伽马校正次表面颜色

反射/规格参数

  • 规格颜色: 高光的颜色(皮肤是电介质,所以这应该是白色的)
  • 光泽度蒙版: 黑色和白色贴图之间调节最小/最大光泽度值。
  • 高光总量: 控制两个高光叶瓣的总量。可用于禁用该高光。
  • 锐利数量: 锐利高光的数量。可以用来禁用锋利高光。
  • Bloom 数量: 软高光的数量。可以用来禁用 bloom 高光。
  • 光泽度最小值: 光泽度遮罩贴图黑色部分的光泽度值
  • 光泽度最大值: 光泽度遮罩贴图白色部分的光泽度值
  • 高光 Bloom: 控制高光 bloom 的大小。数值越大,bloom 的尺寸越大。

高级的反射参数

  • 反射 IOR 指数: 该高光的折射的反射索引
  • 反射细分: 反射细分 (在 OSL for Vray 的 SSS 中目前没有细分。当渲染设置中 “use local subdivs” 关闭时,此选项将被忽略。
  • 追踪锐利反射: 为锐利高光的 BRDF 启用光线追踪反射(禁用此功能只会产生高光组件)
  • 追踪 Bloom 反射: 为 Bloom 高光 BRDF 启用光线追踪反射(禁用此功能只会产生高光组件)
  • 使用单一 SSS: 禁用 RGB 波长分层 SSS,并使用单一次表面(相当于 VraySSS2Mtl)。效果虽然没有那么好,但是更快。

完整 OSL 代码

要使用以下代码,将其复制粘贴到 VRayOSLMtl

/*
 *
 * 依赖波长的次表面散射 OSL 材料由 Derek Flood (cc)2016
 * 灵感来自 Tony Reynolds 的超阴影树,增加了 two-lobe spec 和可映射光泽度。
 * 
 *
 */

color getTextureDif(string texture_name, color no_texture_default_color) {int channels = -1;if (gettextureinfo(texture_name, "channels", channels)){return texture(texture_name, u, v);}
 return no_texture_default_color;
}

float fresnelReflectionFactor(normal Nb, float ior) {float c = abs(dot(I, Nb));float g = ior * ior - 1.0 + c * c;if (g > 0.0) {g = sqrt (g);float A = (g - c) / (g + c);float B = (c * (g + c) - 1.0) / (c * (g - c) + 1.0);return 0.5 * A * A * (1.0 + B * B);}
 return 1.0;
}

float blendGloss(float GlossMin, float GlossMax, color Blender) {
	Blender = luminance(Blender);return GlossMin * (1.0 - Blender[0]) + GlossMax * Blender[0];
}

surface DFskinMtl[[ string description = "blended skin material" ]]
(/* 全局区 */string Transparency = "trs.png",float Depth_Scale = 1,float Overall_Brightness = 0.8,
	color Diffuse_Color = 0.5,
	float Diffuse_Amount = 0.5,
	/* SSS 区 */string Subsurface_Color = "color.png",float Subsurface_Amount = 1,string RGB_Scatter_Depth = "RGB.png"
		[[ string description = 
		"Proportional scatter depth for red, green, and blue wavelengths." 
		]],float Texture_Gamma = 2.2,
	/* 高光区 */string Spec_color = "specular.png",string Gloss_Mask = "mask.png"
		[[ string description = 
		"black and white mask for glossiness min/max values." 
		]],
		float Spec_total_amount = 0.5
		[[ string description = 
		"Total amount of sharp and soft spec." 
		]],float Sharp_Amount = 0.3	[[ string description = 
		"For the sharp spec lobe." 
		]],float Bloom_Amount = 0.7	[[ string description = 
		"For the soft spec lobe." 
		]],
		float Gloss_Min = 0.6
	[[ string description = 
		"Glossiness value for the black parts of the Gloss Mask map." 
		]],float Gloss_Max = 0.8
	[[ string description = 
		"Glossiness value for the white parts of the Gloss Mask map." 
		]],float Spec_bloom = 0.3	[[ string description = 
		"For the soft spec lobe (Blinn). Controls tail size of spec." 
		]], float Reflection_IOR = 1.5,int Reflection_Subdivs = 8,
	int Trace_Sharp_Reflections = 1[[ string widget = "checkBox" ]],
	int Trace_Bloom_Reflections = 1[[ string widget = "checkBox" ]],
	int Use_Single_SSS = 0[[ string widget = "checkBox" ]],
 output color result = 1
)
{/* 定义 Bump */normal Nb = N;/* 声明 SSS 变量并读取纹理贴图 */color TrsColor = getTextureDif(Transparency, color(0));color Opacity = 1-TrsColor;
	color Depth = getTextureDif(RGB_Scatter_Depth, color(0.8,0.2,0.1));Depth = clamp(Depth,0.001,1); // 防止深度值为零,这会破坏着色器 RGB 混合color SubColor = getTextureDif(Subsurface_Color, color(0.85,0.75,0.65));SubColor = pow(SubColor, Texture_Gamma); // gamma 校正纹理
	SubColor *= Overall_Brightness;color SubR = SubColor * color(1,0,0);color SubG = SubColor * color(0,1,0);color SubB = SubColor * color(0,0,1);

	/* 定义高光 */float IOR = 1.38;float PhaseFunction = 0.8;int Subdivs = 8;
	color SpecColor = getTextureDif(Spec_color, color(1,1,1));color GlossMask = getTextureDif(Gloss_Mask, color(1));float Spec_sharpness = blendGloss(Gloss_Min, Gloss_Max, GlossMask);color Fresnel = SpecColor * fresnelReflectionFactor(Nb, Reflection_IOR);// Blinn 的菲涅尔float SoftGloss = (1-Spec_bloom * 0.6) * Spec_sharpness; float Tail = 2.0;float Roughness = 0;float Anisotropy = 0;float Aniso_rotation = 0;/* 闭包区 */closure color Diff = Diffuse_Color * Diffuse_Amount * Overall_Brightness *
			diffuse(Nb, "roughness", 0);
			closure color SSS = vray_subsurface ( IOR, PhaseFunction, Depth * Depth_Scale * 0.5, SubColor * Subsurface_Amount, "subdivs", Subdivs);
	closure color SkinR = vray_subsurface ( IOR, PhaseFunction, SubR * Depth[0] * Depth_Scale, SubR * Subsurface_Amount, "subdivs", Subdivs); closure color SkinGB = vray_subsurface ( IOR, PhaseFunction, ((SubG * Depth[1]) + (SubB * Depth[2])) * Depth_Scale, (SubG + SubB) * Subsurface_Amount, "subdivs", Subdivs);
	 closure color spcHard =Sharp_Amount * SpecColor * Spec_total_amount * 0.5 *microfacet_ggx (Nb, Roughness, Reflection_IOR,"gtr_gamma", Tail,"subdivs", Reflection_Subdivs,	"reflection_glossiness", Spec_sharpness,"highlight_glossiness", Spec_sharpness,"trace_reflections", Trace_Sharp_Reflections);
	closure color spcSoft = Bloom_Amount * Fresnel * Spec_total_amount * 2 *vray_blinn (Nb, SoftGloss, Anisotropy, Aniso_rotation,"subdivs", Reflection_Subdivs, "trace_reflections", Trace_Bloom_Reflections);	 if (Use_Single_SSS)
	{ Ci = Opacity * Diff + SSS + spcHard + spcSoft + (1.0 - Opacity) * transparent(); }else
	{ Ci = Opacity * Diff + SkinR + SkinGB + spcHard + spcSoft + (1.0 - Opacity) * transparent(); }
} 

最后

最近找到一个VUE的文档,它将VUE的各个知识点进行了总结,整理成了《Vue 开发必须知道的36个技巧》。内容比较详实,对各个知识点的讲解也十分到位。



有需要的小伙伴,可以点击下方卡片领取,无偿分享

你可能感兴趣的:(人工智能,python,开发语言)