unity3d Hair real time rendering 真实头发实时渲染(转)

unity3d Hair real time rendering 真实头发实时渲染(转)

unity3d Hair real time rendering 真实头发实时渲染(转)

惊现塞拉酱

算法是Weta Digital根据siggraph2003的论文加以改进,改进之前使用的是Kajiya and Kay’s 模型,它能量不守恒,也就是说不是基于物理的,不准确

unity3d Hair real time rendering 真实头发实时渲染(转)

电镜下真实头发丝纤维的照片,我们发现上面有很多重叠的角质层叫做毛小皮也叫毛鳞片,他们相对根部的倾斜角度大约为3°,近似模型如下图
unity3d Hair real time rendering 真实头发实时渲染(转)

头发纤维的模型
R为反射(reflection),T为穿透(transmission),也就是折射
这里假设光有三种传播方式R, TT, TRT
R是直接反射,
TT是经过两次折射
TRT是穿透(折射)进头发内部,在头发内部进行反射,在穿透(折射)出,详细如图
unity3d Hair real time rendering 真实头发实时渲染(转)

人头发纤维主要由两部分组成:表皮与皮质。表皮作为外鞘保护内部皮质层,在光散射方面表皮很重要,因为他是折射的边缘,
头发核心部有颜色的东西叫做髓质,在皮质与髓质中的色素决定了头发的颜色,
我们研究头发的光学属性有两种要素:1.折射参数η(大约为1.55)2.横截面的吸收率σa
unity3d Hair real time rendering 真实头发实时渲染(转)

几何图如上图,

发方向从根部到尖部,我们假定u是头发的tan值,向量v和w是一个右手标准正交基,光线入射方向为ωi,散射出的光的方向为ωr,角度分别为
θi,θr(0°垂直于头发,u为90°)。围绕着头发的方位角表示为φi和φr(v为0°w为+90°),差角(θi-θr)/2表示为θd相关方位角
为(φr-φi)/2表示为φd。φr-φi表示为φ。平均值θh = (θi+θr)/2为半角。
头发的吸光性主要取决于真黑色素(eumelanin)和伪黑色素(pheomelanin),他们的浓度我们分别定义为ρe和ρp,他们的吸收率分别为σa,e和σa,p,光谱吸收率为μa = ρeσa,e +  ρpσa,p。
光线离开头发前变化(折射,反射)次数为p。p ∈ {R = 0, TT = 1, TRT = 2, TRRT = 3, ...}
总反射函数S是所有的纵向散射(longitudinal scattering)函数Mp 和方位角散射函数Np之积的和
 
 
我们的最终目标就是把0-3的p所有的S相加,也就是R, TT, TRT , TRRT所有光线之和。

unity3d Hair real time rendering 真实头发实时渲染(转)

纵向散射(longitudinal scattering)

接下来是高斯Mp纵向散射(longitudinal scattering)函数的求法。
在头发是完美圆弧的光滑表面的情况下θr = −θi,如图所示
 unity3d Hair real time rendering 真实头发实时渲染(转)

在光滑的表面反射,形成一个单一的锥形(左图)。因为表面粗糙,Mp模拟了一个没有高光的表面,这种像锥形一样的散射会被缩放,更偏向于法平面(右图)。光散射范围更宽,能量也随之减少。
因为表面粗糙而不能产生完美反射的高光,Marschner使用了半角的高斯函数来求Mp

unity3d Hair real time rendering 真实头发实时渲染(转)

		inline	fixed G(fixed beta, fixed theta)
		{
			return pow(E, -(theta*theta) / (2 * beta * beta)) / (sqrt(2 * PIE)* beta);

		}

G函数是一个以纵向倾角θ为参数的标准高斯函数,β是粗糙程度(在纵向的光滑锥形上的标准偏差角),αp是皮质层倾角的一个简单函数。但是求得的Mp能量不守恒,有如下原因
1.    g函数中的θ ∈ {−∞,∞},但是θh ∈{−π/2,π/2}。使用θh代替θ会使反射能量增倍。
2.    当θi = −θr时,从锥形高光偏光−θi到θr涉及到缩放锥形。在Marschner中只有大约1/cos ²θd
3.     偏转光照角度移动了相当大的能量导致成角大于θ ∈{−π/2,π/2}(角过大,永远不会接收到,导致能量损失)

我们使用一种能量守恒的Mp
这种方法在球形重新分配反射角度,使用球形高斯卷积(spherical- Gaussian convolution)得到
 unity3d Hair real time rendering 真实头发实时渲染(转)

G经过一系列的变形化简得到最终的Mp:

unity3d Hair real time rendering 真实头发实时渲染(转)

	Mp = (1 / ((pow(E, V) - pow(E, -V))*V))*pow(E, (sin(-Theta_i)*sin(Theta_r) / V))*I0(cos(-Theta_i)*cos(Theta_r) / V);

在这里v = β²是粗糙度的平方
I0函数为第一类贝塞尔函数
 unity3d Hair real time rendering 真实头发实时渲染(转)

得到的能量守恒的纵向散射曲线如下
 unity3d Hair real time rendering 真实头发实时渲染(转)

锥形高光是不对称的,off-specular peak近似于二维BRDF所有粗糙度是能量守恒的
 
unity3d Hair real time rendering 真实头发实时渲染(转)

方位角散射(Azimuthal Scattering)

接下来计算方位角散射(Azimuthal Scattering)Np
Marschner利用在发丝是光滑圆情况下的Bravais特性,研究在发丝纤维内部的方位角散射。
unity3d Hair real time rendering 真实头发实时渲染(转)

修正折射指数η’  
方位角改变方向Φ与在发丝中的偏移h ∈ {−1,1}和p值有关,反射模式为:
 unity3d Hair real time rendering 真实头发实时渲染(转)

γi = arcsin(h) , γt = arcsin(h/η’ )

unity3d Hair real time rendering 真实头发实时渲染(转)

由于h不可求,所以我们采用另一种可以模拟h的方法
Marschner使用立方近似来模拟h,但是尚未验证其准确性,当p值较大或反射指数较低时(头发在水中)

粗糙度方位角散射(Roughened Azimuthal Scattering)函数Np

我们用高斯分布模拟一个变形法平面表面粗糙度的效果。在发丝纤维中的每一个偏移h  产生了一个方位角的连续的分布Dp(φ−Φ(p,h)),这个分布是由φ中的高斯和光滑头发中的离散方位角Φ(p,h)产生的。如下图所示:
 unity3d Hair real time rendering 真实头发实时渲染(转)

粗糙离散角散射(TT):在光滑发丝上的偏移h能产生确定的方位角Φ(p,h),可以求出方位角的高斯分布Dp(φ−Φ(p,h))。
全部的出射光线集成在一起:

unity3d Hair real time rendering 真实头发实时渲染(转)

A(p,h)是光线吸收和菲涅尔产生的衰减。我们使用一个新的标准高速分布函数Dp称之为Gaussian detector

unity3d Hair real time rendering 真实头发实时渲染(转)

				for (fixed i = -1; i < 1; i += 0.1)
				{
					Mu_a_d = Mu_a / cos(i / Eta_d);
					ref_1 = acos(cos(Theta_d) * cos(asin(i)));
					f = -_SC + (1 + _SC)*pow(2, -10 * dot(ref_1, _Eta));
					T = exp(-2 * Mu_a_d*(1 + cos(2 * asin(i / Eta_d))));
					A = pow((1 - f), 2) * pow(f, p - 1) * T;

					//	Np += A *	Dp(Phi - Phi_p_h(p, i, Eta_d));
					Np += A *	Dp(Phi - Phi_p_h(i, Eta_d));

				}
				Np *= 0.5;

到此我们所有公式全部完事,我们可以用for循环累加不同p值的S得到最终结果

经过论文中的测量σa,e = {0.419,0.697,1.37}σa,p ={0.187,0.4,1.05}得到结果相对真实。

上图论文中的实现结果
 unity3d Hair real time rendering 真实头发实时渲染(转)

博主目前能力不够不能在Unity中弄出这样的头发(感觉他这个头发像是曲面细分生成的),只能用个好一点的模型来凑数了:

unity3d Hair real time rendering 真实头发实时渲染(转)

本文为部分翻译的加上博主自身的理解与实现,如有不正确的地方欢迎批评指正

上一篇:[Webpack 2] Use Karma for Unit Testing with Webpack


下一篇:47.C#--使用FileStream文件流来实现多媒体文件的复制