天天看点

铁匠smith_铁匠中的独特角色阴影

铁匠smith_铁匠中的独特角色阴影

铁匠smith

It was bright and sunny morning. It must have been some time last fall, when we finally got the message we had all been waiting for: a Challenger has arrived!

那是一个阳光明媚的早晨。 去年秋天一定是某个时候,当我们终于收到我们一直在等待的消息时:挑战者已经到来!

Granted, it was still an early draft; bald, clean-shaven, unskinned and without proper materials set up – but we were still excited to finally have him in the project. “Somebody puh-lease slap some materials on him and put this bad boy into the scene!”

当然,这仍然是一个初稿。 秃头,剃光,没有皮肤,没有适当的材料摆设,但我们仍然很高兴最终将他纳入项目。 “有人租给他一些东西,然后把这个坏男孩当场!”

And we did. And it was awesome. Except… something didn’t quite look right. “Uhm.. is this guy really set up to receive dynamic shadows?”. He was. But not quite the kind we were expecting.

而我们做到了。 太棒了。 除了……有些东西看起来不太正确。 “嗯..这家伙真的准备好接收动态阴影吗?”。 他是。 但不是我们所期望的那种。

铁匠smith_铁匠中的独特角色阴影

Most of him didn’t actually seem to receive any shadow whatsoever, and what we did identify as shadowed was very weird and jagged looking.

实际上,他中的大多数人似乎都没有收到任何阴影,而我们确定为阴影的东西看起来很怪异和参差不齐。

问题 (The Problem)

A few quick shader hacks later, and the ugly truth revealed itself; not only was half the character missing shadows altogether; what little was there was indeed looking blocky and buggy.

后来,一些快速的着色器被黑客入侵,丑陋的事实暴露了出来。 不仅角色的一半完全消失了阴影; 几乎没有什么东西确实看起来像是块状和越野车。

铁匠smith_铁匠中的独特角色阴影

‘Why was this happening?’, you might wonder at this point. After all, doesn’t Unity 5 sport this brand new and shiny soft-shadow filtering algorithm? It does, and it looks great. It so happened, though, that some of our scenes had view distances as far as 3,000 meters, and we’d decided we wanted shadows cast from and onto every single pixel in the view frustum. Now, naturally we had tweaked the cascade splits and shadow biases as best we could, and the shots generally looked really good both near the camera and far, far away.

“为什么会这样?”,此时您可能会感到奇怪。 毕竟,Unity 5是否不采用这种崭新的闪亮软阴影过滤算法? 确实如此,而且看起来很棒。 不过,碰巧的是,我们的某些场景的视距最远为3,000米,因此我们决定要从视锥中的每个像素投射阴影到每个像素上。 现在,自然而然地,我们尽可能地调整了级联分裂和阴影偏差,并且无论在相机附近还是在很远的地方,这些镜头通常看起来都非常好。

What we hadn’t really tested properly until now was adding a very detailed character, very close to the camera in such a large-scene setup. Not only did we lack the resolution to produce soft, shadowy goodness on the character; the depth bias required for the scene to look good was so large that it pushed half the character out of shadow. Turns out casting soft shadows from a tiny leather strap, onto a piece or armour 1cm away, isn’t quite the same case as having a medium sized rock cast soft, stable shadows onto the ground. Who’d have thunk, right?

到目前为止,我们还没有真正进行过正确的测试,就是在非常大的场景中添加了非常详细的角色,非常接近相机。 我们不仅缺乏在角色上产生柔和暗淡的善良的决心; 场景看起来不错所需的深度偏差太大,以致于将一半角色从阴影中移出。 原来是从一条细小的皮革表带上将柔和的阴影投射到1厘米外的一件或盔甲上,与将中等大小的岩石将柔和,稳定的阴影投射到地面上的情况不同。 谁有拳头,对不对?

So we needed a solution to this predicament. We could have moved the first cascade really, really, really close to the camera, but that would have cost us a full cascade on the scenery. It would also only have worked in the scenes where the characters were really, really, really close to the camera, which would have solved enough of our problematic shots.

因此,我们需要解决这一困境。 我们本可以将第一个级联确实,非常非常靠近相机移动,但是那样会使我们在风景上花了一个完整的级联。 它也只能在角色真的非常非常接近相机的场景中起作用,这样可以解决我们很多有问题的镜头。

解决方案 (The Solution)

Instead, we decided to apply a bit of old-school technology to the problem. “What if we just explicitly render an additional shadow map focused on the character?”. Said and done. Two hundred lines of code later, the engine was generating these for us to play with:

相反,我们决定对该问题应用一些过时的技术。 “如果我们只是显式渲染一个针对角色的阴影贴图怎么办?” 说完了。 两百行代码之后,引擎正在生成这些代码供我们使用:

铁匠smith_铁匠中的独特角色阴影

At this point, we were able to generate enough data to apply pretty much any kind of fancy schmancy shadow filtering we felt like. We didn’t really have a great deal of time to spend fine tuning the best possible filtering, though, so we decided to go for a simple distance-aware sampling scheme similar to Nvidia’s PCSS[1].

在这一点上,我们能够生成足够的数据以应用几乎任何我们想要的奇特的幻影阴影过滤。 但是,我们实际上并没有太多时间花在微调最佳滤波上,因此我们决定采用类似于Nvidia PCSS [1]的简单的距离感知采样方案。

Although not present in the shots shown here, we also had an option for capturing data from shadow casters outside the character’s focus area; e.g. to still have the static world cast shadows onto these dynamic characters. Such casters were projected onto the near-plane of the shadow rendering camera, ensuring they would always have the maximum blocker-to-receiver distance in the soft-shadow filtering scheme.

尽管此处显示的镜头中没有显示,但我们还有一个选项可以从角色关注区域之外的阴影投射器捕获数据。 例如,仍然让静态世界将阴影投射到这些动态角色上。 将这些脚轮投影到阴影渲染相机的近平面上,以确保在软阴影过滤方案中,它们始终具有最大的阻止者到接收者的距离。

The only problem remaining at this point was how to integrate this nicely into the rendering pipeline. After some pondering and head-scratching, it turned out there was a very simple way to override the shadow functions used by nearly all common Unity shaders. After a few iterations, we eventually simplified it to only requiring two additional lines of code to add unique shadow support to any shader:

此时唯一剩下的问题是如何将其很好地集成到渲染管道中。 经过深思熟虑后,事实证明,有一种非常简单的方法可以覆盖几乎所有常见Unity着色器使用的阴影功能。 经过几次迭代,我们最终将其简化为仅需要两行代码即可为任何着色器添加独特的阴影支持:

#pragma multi_compile _ UNIQUE_SHADOW UNIQUE_SHADOW_LIGHT_COOKIE #include "UniqueShadow_ShadowSample.cginc"

#pragma multi_compile _ UNIQUE_SHADOW UNIQUE_SHADOW_LIGHT_COOKIE #include "UniqueShadow_ShadowSample.cginc"

Note that the include has to go before any other engine includes for the override to work correctly. Obviously, this is slightly misleading as we just hid the actual override complexity behind an include file, so for anyone else looking to do something similar, here’s essentially what it boils down to:

请注意,必须先将include移至其他任何引擎include才能使替代正常工作。 显然,这有点令人误解,因为我们只是将实际的替代复杂性隐藏在了一个include文件的后面,因此对于希望做类似事情的其他人,基本上可以归结为:

#if SOME_CONDITION_ENABLING_OUR_FEATURE #include "AutoLight.cginc" #undef SHADOW_COORDS #undef TRANSFER_SHADOW #undef SHADOW_ATTENUATION #define SHADOW_COORDS(i) SOME_OTHER_COORD(i) #define TRANSFER_SHADOW SOME_OTHER_TRANSFER #define SHADOW_ATTENUATION(i) SOME_OTHER_ATTEN(i) #endif

#if SOME_CONDITION_ENABLING_OUR_FEATURE #include "AutoLight.cginc" #undef SHADOW_COORDS #undef TRANSFER_SHADOW #undef SHADOW_ATTENUATION #define SHADOW_COORDS(i) SOME_OTHER_COORD(i) #define TRANSFER_SHADOW SOME_OTHER_TRANSFER #define SHADOW_ATTENUATION(i) SOME_OTHER_ATTEN(i) #endif

The conditions in our case are whether unique shadows are enabled, and whether we’re currently rendering a directional light or not. This second condition allows the feature to co-exist peacefully with other types of shadow casting light sources.

我们的情况是是否启用了唯一的阴影,以及当前是否正在渲染定向光。 第二个条件允许该功能与其他类型的阴影投射光源和平共处。

利润! (Profit!)

So after all this hard work, did we end up with satisfactory results? Here’s the same debug view again, this time toggling unique shadows on and off:

因此,经过所有这些艰苦的工作,我们是否最终获得了令人满意的结果? 这再次是相同的调试视图,这次打开和关闭唯一的阴影:

铁匠smith_铁匠中的独特角色阴影

Old-school tech for the win!

老式技术必胜!

综上所述 (In Summary)

One aspect to keep in mind is that – like most other rendering features – adding more shadow maps to your project doesn’t come for free. The shadow maps take up additional video memory, and there’s extra draw calls required to render into them, as well as increased bandwidth usage and computation power required to use them in your shaders.

要记住的一个方面是-与大多数其他渲染功能一样-向您的项目添加更多阴影贴图并不是免费的。 阴影贴图会占用额外的视频内存,并且需要额外的绘制调用才能将其渲染到其中,以及在着色器中使用它们需要增加的带宽使用量和计算能力。

For The Blacksmith, we set the system up so that we could dynamically toggle unique shadows on and off depending on how close to the camera the actors needed to be. Thus, we only paid the extra rendering cost in the shots where the characters occupied a large portion of the screen. For a game where the player might never get very close to the camera in normal gameplay, one could imagine only enabling this feature for close-ups in selected cut-scenes.

对于《铁匠》 ,我们将系统进行设置,以便我们可以根据演员需要与相机之间的距离来动态地打开和关闭独特的阴影。 因此,我们只在角色占据屏幕很大一部分的镜头中支付了额外的渲染成本。 对于一款游戏,在正常游戏过程中,玩家可能永远不会非常靠近相机,可以想象只有在选定的过场动画中对特写镜头启用此功能。

To better demonstrate this feature in isolation, we’ve put together a small demo project which you can get from the Asset Store. There’s a very basic scene included, meant to illustrate the problem case of having fine character detail near the camera in a large outdoors environment. Even with the first cascade covering only 1% of the total shadow distance, there’s a fairly radical difference between the uniquely shadowed challenger on the left, and the cascade shadowed challenger on the right.

为了更好地单独展示此功能,我们整理了一个小型演示项目,您可以从Asset Store中获得该项目。 其中包括一个非常基本的场景,旨在说明在大型户外环境中相机附近具有精细角色细节的问题情况。 即使第一个级联仅覆盖总阴影距离的1%,左侧的唯一带阴影的挑战者与右侧的级联带阴影的挑战者之间也存在相当大的差异。

铁匠smith_铁匠中的独特角色阴影

References: [1] http://developer.download.nvidia.com/shaderlibrary/docs/shadow_PCSS.pdf

参考文献:[1] http://developer.download.nvidia.com/shaderlibrary/docs/shadow_PCSS.pdf

翻译自: https://blogs.unity3d.com/2015/05/28/unique-character-shadows-in-the-blacksmith/

铁匠smith