Shader - Hair & Fur
Demo
Mesh
无论是头发材质还是毛发材质,它们的建模都是基于插片的方式,且每个片都是单面(Cull Off)
UV Layout
需要保证Kajiya-Kay高光流向的连续性,UV的布局要是统一且具有方向性的,每个网格片的UV区域重复覆盖。
Vertex Occlusion
通过烘焙保存在顶点颜色的环境光遮蔽,不同于使用AO贴图的方式。离线的烘焙可以计算出不同层级(插片)互相之间的遮挡关系。区别不同层级受到的环境光遮蔽,提升整个毛发渲染的阴影体积感。
Pass
渲染效果分为两个品质:
- Alpha Test(适用中低性能的设备)
- Alpha Test + Alpha Blend(适用高性能的设备)
两个Pass使用的都是同一张Alpha贴图。
Alpha Test
只有一个裁剪Pass,所有毛发的边缘都会被硬切,整个毛发的渲染效果就显得比较毛糙,完全没有柔软感。但是性能方面相对的比较好,写入了深度值,不会导致严重的Overdraw。
Alpha Blend
再加上一个混合Pass,每一根毛发的边缘都变成半透明状态,锯齿感会明显减少,整个毛发的渲染效果也会显得比较有柔软感。但是裁剪(Alpha Test)Pass必须作为基础,因为混合Pass要依赖它提前的深度写入来进行深度测试,从而避免出现错误的混合层级和顺序,还能减少大部分区域的Overdraw。另外一个需要注意的是,因为深度值精度的有限,同一个三角面的混合Pass和裁剪Pass可能会发生深度冲突。为了有正确的渲染效果,要让混合Pass始终能覆盖在裁剪Pass上。使用Shader提供的Offset设置渲染状态,能对混合Pass的深度值进行非常轻微的偏移,这样在不影响渲染效果(透视)的前提下避免了深度冲突。
混合Pass渲染状态:
Blend SrcAlpha OneMinusSrcAlpha
ZWrite Off
Offset 1, -1
Specular
高光是各向异性的,它的流向是依据毛发的方向(顶点空间的切线或次切线)
镜面高光的D项是Kajiya-Kay,F项是Schlick,V项用常量0.25代替。
Kajiya-Kay
// Note: Kajiya-Kay is not energy conserving.
// We attempt at least some energy conservation by approximately normalizing Blinn-Phong NDF.
// We use the formulation with the NdotL.
// Note: this is Blinn-Phong, the original paper uses Phong.
real3 D_KajiyaKay(real3 T, real3 H, real specularExponent)
{
real TdotH = dot(T, H);
real sinTHSq = saturate(1.0 - TdotH * TdotH);
real dirAttn = saturate(TdotH + 1.0);
real n = specularExponent;
real norm = (n + 2) * rcp(2 * PI);
return dirAttn * norm * PositivePow(sinTHSq, 0.5 * n);
}
Dual Lobe
同时使用两个高光瓣,是为了模拟毛发的散射特性。通过Shift顶点空间的切线或次切线,可以分别偏移两个高光的流向,互相之间形成错位分布。
real3 ShiftTangent(real3 T, real3 N, real shift)
{
return normalize(T + N * shift);
}
主高光是镜面反射造成的,高亮且没有色彩;次高光是散射特性造成的,相对较弱并带有色彩。









评论
发表评论