解读头发渲染
本人才疏学浅,翻译难免有误,请不惜指教。
头发渲染
大多数人头上都有头发,它是一个很重要的可视化效果。头发渲染做起来很难:
1、人头发依种族和发色的不同,数量也略有差异。黄种人有10万根,金发色头发的白种人头发较细,有12万根, 红色头发略粗,有8-9万根。
2、人有大量不同类型的发式。
3、要渲染效果精致、看起来很有神韵,要花费整个人体渲染时间超25%的占比。
为什么选用多边形头发模型
1、比line rendering的几何体复杂度更加简单,depth sorting更快
2、美术工作流集成也方便
头发模型创作
1、多层面片近似模拟头发的体积质量
2、用环境光遮蔽(Ambient Occlusion)近似自阴影,逐顶点操作。
3、基本贴图:拉伸的噪音贴图(Stretched noise)
4、Alpha贴图:有完全不透明的区域
5、Specular shift texture/Specular noise texture
头发光照模型:Kajiya-kay Model
1、各向异性股(anisotropic strand)光照模型
2、假设头发法线在T和视角V构成的平面上
3、在光照方程中使用发丝切线T替代法线N
切线T和半角向量H之间夹角为θ,切线T和法线N垂直
反射光H = normalize(入射光方向L+视角方向V)
cosθ = T·H
cosθ^2 + sinθ^2 = 1
头发光照模型:Marschner Model
1、基于测量的头发散射属性
2、观察:主高光向发梢偏移;二级高光向发根偏移,有闪烁的呈现。
主高光是直接反射,二级高光是穿透(折射)进头发内部,在头发内部进行反射,再穿透(折射)出。
3、数学很复杂,只是尝试匹配观察到的效果的和实际的生理效果
shader
1、vertex shader
仅仅传切线向量、法线向量、视角向量、光照向量、环境光遮蔽
2、piexel shader
漫反射光照
-
Kajiya-kay 漫反射中sin(T,L) 看起来太亮,没有自身阴影效果。
-
使用调整过的N.L公式
二层偏移镜面高光(shifted specular highlights)
合并公式
偏移镜面高光(shifting specular highlights)
1、为了沿着头发丝方向产生偏移镜面高光,我们需依着法线的方向将切线做一些偏移。
2、假设T是从发根到发梢一系列点
-
正向偏移为向发根偏移高光
-
负向偏移为向发梢偏移高光
3、通过下面贴图来描述偏移值不连续头发效果
float3 ShiftTangent(float3 T,float3 N,float shift){
float3 shiftedT = T + shift*N;
return normalize(shiftedT);
}
发丝的切线方向T代替了法线方向N来进行各向异性的光照计算,美术沿着发丝的生长方向去展开uv坐标(u或v的方向),使得这个方向恰好是切向方向。
发丝高光(specular strand Lighting)
1、我们使用半角向量来做高光,使用反射向量和视角向量会使着色器更复杂一些
2、两个高光采用了不同颜色的、高光指数(exponent)和不同偏移的切线系数
3、用噪音图来调整二级高光
float3 StrandSpecular(float3 T,float3 V,float3 L,float exponent){
float3 H = normalize(L + V);
float dotTH = dot(T,H);
float sintTH = sqrt(1.0-dotTH*dotTH);
float dirAtten = smoothstep(-1.0,0.0,dot(T,H));
return dirAtten * pow(sintTH,exponent);
}
Smoothstep解释:
float smoothstep(float edge0, float edge1, float x) {
// Scale, bias and saturate x to 0..1 range
x = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);
// Evaluate polynomial
return x * x * (3 - 2 * x);
}
float clamp(float x, float lowerlimit, float upperlimit) {
if (x < lowerlimit)
x = lowerlimit;
if (x > upperlimit)
x = upperlimit;
return x;
}
关于dirAtten解释来自stackoverflow,可见下图。
最终代码
float4 HairLighting (float3 tangent, float3 normal, float3 lightVec,
float3 viewVec, float2 uv, float ambOcc)
{
// shift tangents
float shiftTex = tex2D(tSpecShift, uv) - 0.5;
float3 t1 = ShiftTangent(tangent, normal, primaryShift + shiftTex);
float3 t2 = ShiftTangent(tangent, normal, secondaryShift + shiftTex);
// diffuse lighting
float3 diffuse = saturate(lerp(0.25, 1.0, dot(normal, lightVec)));
// specular lighting
float3 specular = specularColor1 * StrandSpecular(t1, viewVec, lightVec, specExp1);
// add second specular term
float specMask = tex2D(tSpecMask, uv);
specular += specularColor2 * specMask * StrandSpecular(t2, viewVec, lightVec, specExp2);
// Final color
float4 o;
o.rgb = (diffuse + specular) * tex2D(tBase, uv) * lightColor;
o.rgb *= ambOcc;
o.a = tex2D(tAlpha, uv);
return o;
}
最终效果
近似深度排序 Approximate Depth Sorting
1、需要按照从后向前顺序进行绘制,才能正确地进行alpha-blending
2、头发也是由内向外的
3、使用一个静态index buffer由内向外绘制,预先计算。
4、排序连接的组件(发丝贴片)而不是单个三角形
Sorted Hair Rendering Scheme
Pass 1 - 不透明部分
-
启用alpha test仅通过不透明像素
-
禁用背面裁剪
-
启用Z writes, 设置Z test为Less
Pass 2 - 透明背面部分
-
启用alpha test仅通过所有非不透明像素
-
剔除前面的多边形
-
禁用Z writes, 设置Z test为Less
Pass 3 - 透明前面部分
-
启用alpha test仅通过所有非不透明像素
-
剔除背面的多边形
-
启用Z writes, 设置Z test为Less
性能调优 Performance Tuning
1、广泛使用early Z 剔除,以节省我们运行昂贵的pixel shader
2、通常一半的头发藏在脑后,所以先画头
3、当启用 alpha test 时,不能使用early Z 剔除!
-
解决方案: Prime Z buffer with a very simple shader that uses alpha test
-
Use Z testing instead of alpha testing in subsequent passes for same effect
4、Early Z剔除节省了相当大的填充开销(fill overhead)!
Optimized Rendering Scheme
Pass 1-prime Z buffer
-
启用alpha test仅仅传不透明的像素
-
禁用背面剔除
-
启用Z writes, 设置Z test为Less
-
禁用color buffer writes
-
使用只返回alpha的简单pixel shader
Pass 2-不透明部分
-
禁用背面剔除
-
禁用Z writes, 设置Z test为Equal
Pass 3-透明背面部分
-
剔除前面的多边形
-
禁用Z writes, 设置Z test为Less
Pass 4 -透明前面部分
-
剔除背面的多边形
-
禁用Z writes, 设置Z test为Less
优化后渲染效果
优缺点 Pros and Cons
优点:
1、低几何复杂性
a、减少顶点引擎的负载
b、使深度排序更快
2、可用于低端硬件使用简单的着色器或固定功能管道
缺点:
1、排序构架假设头发模型中没有动画
a、像摆动的马尾辫这样的东西需要分开处理
b、在运行时对几何图形进行排序以克服这个问题
2、像摆动的马尾辫这样的东西需要分开处理
Unity Demo工程
Unity工程收集整理于互联网
参考资料
Light Scattering from Human Hair Fibers
Applications of Explicit Early-Z Culling
J. Kajiya and T. Kay. Rendering fur with three dimensional textures. In SIGGRAPH 89 Conference Proceedings, pp. 271-280,1989.
Stephen R. Marschner, Henrik Wann Jensen, Mike Cammarano, Steve Worley, and Pat Hanrahan, Light Scattering from Human Hair Fibers. In Proceedings of SIGGRAPH 2003.