最近,我一直在研究一些着色器(在Unity中),并尝试重新创建“基于光的内联”,可以在最新的《塞尔达传说》中看到它。但是,就目前而言,也许这项任务超出了我的知识范围。



从我的分析来看,它的行为(移动时)似乎类似于“边缘阴影”确实可以做到,除了它有一个锐利的截止点(很容易做到),而且-我正在努力解决的部分-它似乎具有恒定的宽度,而与网格的局部曲率和与相机的距离无关,基本上相对于屏幕的恒定“宽度”。 (实际上,它随相机距离的不同而有所不同,但是大多数情况下并没有,所以我们假设它不是)。

在静止图像中显示有点困难,但是您可以在上面找到很多视频游戏,效果随处可见。

我设法完成了更简单的部分,即截去边缘的阴影。但这产生了尴尬的效果,即取决于相机方向和几何曲率,“内联”或多或少地占据了屏幕区域。以下是我在不同角度的相机上获得的当前结果的图像,绿色箭头表示良好/可以接受的区域,红色箭头表示与预期效果的偏差。



这是我当前的实现参考,作为Unity Surface Light模型:

half4 LightingToonPoster(SurfaceOutputStandard surf, float3 viewDir, UnityGI gi) {
    // Material properties
    half3 specular;
    half oneMinusReflectivity;
    DiffuseAndSpecularFromMetallic(surf.Albedo, surf.Metallic, /*out*/ specular, /*out*/ oneMinusReflectivity);
    float3 reflected = normalize(-reflect(gi.light.dir, surf.Normal));
    float specularity = dot(viewDir, reflected) * _Specularity;

    // Light setup
    float ndotl = dot(surf.Normal, gi.light.dir) * 0.5 + 0.5;
    float lightIncidence = gi.light.color * ndotl;
    float3 ramp = tex2D(_Ramp, lightIncidence.xx).rgb;
    float3 specularRamp = tex2D(_Ramp, specularity.xx).rgb;
    gi.light.color = ramp * _LightColor0.rgb;

    // Rim and camera-light convergence
    float rim = 1 - saturate(dot(surf.Normal, viewDir));
    float facing = -dot(viewDir, gi.light.dir) * 0.5 + 0.25;

    // sigmoid of rim for smooth falloff centered at _EdgeBias
    float outline = 1 / (1 + exp(-100 * (rim - _EdgeBias)));
    float highlight = _HighlightStrength * outline * facing * outline;

    float4 std = LightingStandard(surf, viewDir, gi);

    float3 toonDiffuse = surf.Albedo * (gi.light.color / 2 + ShadeSH9(float4(viewDir, 1)));
    float3 toonSpecular = specular * gi.indirect.specular * specularRamp;
    float4 toon = half4(toonDiffuse + toonSpecular, surf.Alpha);
    return lerp(std, toon, _UnshadeFactor) * half4(1 + highlight.xxx, 1);
}


或检查此Gist以获得完整的着色器文件

现在的问题是,在不考虑曲率并且得到恒定“插入”的情况下,我可以使用什么代替边框阴影来获得类似的效果?

评论

坦白说,我喜欢您取得的进步!

@ user1118321我也很满意,即使不是因为它完美地解决了所应用模型的每个小问题。

#1 楼

好问题!我自己没看过游戏,但是这个问题引起了我的兴趣,因此我在Youtube上观看了一些录像。 ?t = 15m46s


我注意到一些事情:


头发和右腿:请注意,只有漫射照明的部分才具有边缘照明。
左手腕:注意宽度如何随手的角度变细。
在其他部分,您还可以看到边缘照明也受投射阴影的影响。

从这些观察结果中,我认为使用了两种效果:


漫反射阴影在点亮和熄灭之间具有急剧的过渡,发生在低于0的某个位置,因此光线从后面漏了一点。

边缘照明,正如您所提到的,具有几乎恒定的屏幕空间宽度。

从外观和某些工件来看,我最好的猜测是实际上是一些基于深度的边缘检测滤镜,然后将其与漫射照明结合使用,以便边缘照明不会影响未照明的零件。


非常酷的效果,谢谢指出!

评论


$ \ begingroup $
我想到了边缘检测,但是当在地形(具有相当大的三角形)的地形中观察到相同的效果时,可能会看到“宽”边缘和恒定宽度之间与摄像机相同的过渡变成更窄的角度。另外,在这里可以使用哪种边缘检测?我实际上尝试过在深度上使用Sobel,但是后来我不知道如何在不模糊内部线条的情况下调整“宽度”。 (尽管我认为这应该是一个单独的问题)
$ \ endgroup $
– Kroltan
17年7月13日在12:31

$ \ begingroup $
他们可能会区分角色和地形(我认为在地形上没有这种效果,但也许我只是错过了它)。对于Sobel,只需将内核缩放到所需的厚度即可:与其比较相邻的像素,不如进一步比较它们。
$ \ endgroup $
–朱利安·盖尔特(Julien Guertault)
17年7月13日在12:58

$ \ begingroup $
嗯,我将在Sobel再次请教一下,并向我汇报
$ \ endgroup $
– Kroltan
17年7月13日在23:07