天天看點

鐵匠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