博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Technical Artist的不归路 —— Kajiya-Kay Shading
阅读量:4337 次
发布时间:2019-06-07

本文共 2446 字,大约阅读时间需要 8 分钟。

在游戏中,头发一直是比较难以驾驭。头发难的地方有三块,一在模拟,二在着色,三在工具链适配。目前很多游戏的开发通常都会避免长发和散发,只采用短发。

但是哪怕是短发,其着色也是非常重要的一环。


我自己也看到有不少团队的头发完全使用贴图来进行着色。这样的着色的优点在于在特定的光照与摄像机角度下能够有很精彩的表现,但是如果光照条件与摄像机角度变化后,头发的表现就会非常怪异。

这篇博客介绍了Kajiya-Kay Shading,一种简单而酷炫的头发渲染着色器,。

Kajiya-Kay Model

Kajiya-Kay Model与其他Shading Model显著不同一点的就是它使用的是发丝的切线而不是这一点的法线来进行计算。在这个模型中,Specular N.H为:

sin(T,H)speculartiy=1dot(T,H)2speculartiy
而不是:
dot(N,H)specularity

但是需要注意的是,Kajiya-Kay的着色模型需要比较正确的自阴影。否则相对来讲会太亮。

Vertex Shader

VS没有什么特别的,仅仅是将T, N, V, L, AO这些数值传递给PS。

Pixel Shader

  • Diffuse Lighting.

    Kajiya-Kay 的diffuse可以使用衰弱的N.L,也可以使用sin(T, L)。正如前面提到的,sin(T, L)需要有自阴影,否则会太亮。

  • Specular Highlights

    在Kajiya-Kay的着色模型中,我们有两个偏移的Specular量,从而表现头发的高光(下图来自本人小妹的自拍)。

    Hair

Specular Highlights

为了产生沿着发丝方向偏移的高光,我们需要将切线沿着法线方向进行一个偏移,如下图:

Nudge

正向的偏移意味着向发根的高光偏移,而负向的偏移则意味着偏向发梢。

在这个着色模型中,我们通过一张纹理来表示偏移量:

ShiftTexture

代码如下:

float3 ShiftTangent(float3 T, float3 N, float shift){    float3 shiftedT = T + (shift * N);    return normalize(shiftedT);}

发丝光照

在这个着色模型中,我们使用半角向量(half-angle vector)。用reflectionview向量也可以,但是会使Shader略显复杂。

在两个高光中,可以使用不同的颜色、specular exponent以及不同的切线偏移度。第一层高光可以直接计算,而第二层高光表现的主要是闪耀的情况——通过noise texture进行调整。

代码如下:

float StrandSpecular(float3 T, float3 V, float L, float exponent){    float3 H = normalize(L + V);    float dotTH = dot(T, H);    float sinTH = sqrt(1.0 - dotTH*dotTH);    float dirAtten = smoothstep(-1.0, 0.0, dot(T, H));    return dirAtten * pow(sinTH, exponent);}

值得一提的是,对于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;}

最终效果

Final

以后会在Unreal Engine 4中实现Kajiya-Kay Shading……

<全文完>

转载于:https://www.cnblogs.com/arrowinmyknee/p/5470385.html

你可能感兴趣的文章
Windows NTFS格式文件 权限问题的解决
查看>>
Lesson 024 —— python 文件操作
查看>>
mysql中,创建表的时候指定if not exists参数的作用?
查看>>
MySQL主从复制
查看>>
SpringMVC与mybatis整合
查看>>
静态变量和静态常量的区别
查看>>
[LeetCode][JavaScript]Maximum Subarray
查看>>
Node 高性能异步I/O框架
查看>>
AsyncHttpClient 上传两个以上文件出错 急!
查看>>
OpenCV2.4.7 + VS2013 搭建环境
查看>>
安卓开发笔记——关于文件断点续传
查看>>
Logistic回归
查看>>
ASP.NET多个提交按钮页面,回车Enter执行指定按钮的事件(转)
查看>>
Dialog+NumberPicker
查看>>
12306 查票接口
查看>>
Django 路由控制
查看>>
ARM Linux入门与实践(内附光盘1张)
查看>>
【模板】AC自动机(简单版)
查看>>
WINCE BSP包只读属性导致编译出错
查看>>
windows文件传输方法
查看>>