PS:本文寫於2017.2.1日,使用版本為4.13。第二次更新時間為2017.3.15增加了四、一些材質編輯器中的奇怪的技巧:
一、前言
在Unreal中材質編輯器提供了Custom節點,作為HLSL代碼編寫接口。以此可以實現更多的效果。
雖然使用Custom節點會有若干限制,但是相對的比較方便,適合快速開發。如果遇到限制而導致無法使用Custom解決,此時就需要使用虛幻的RHI(硬件渲染接口)配合USF文件(虛幻着色器文件)來實現,這些我以后可能會寫一篇文章來解析吧,如果着急可以參考Wiki上的HLSL插件。(竟然還可以使用計算着色器感覺好屌),目前類似Unity的材質代碼編輯器的提議已經上了路線圖,但是啥時候實現還遙遙無期。
目前為止我所知道的限制有一下幾點:
1、無法#include XXX.usf
2、無法主動聲明一個函數
1、可以包含usf,經過網友小彭友提醒並且測試
\\pengyancai\\Desktop\\test.usf"
return float4(0,0,0,0);
test.usf: return float4(1,0,0,0);
2、其實是可以自己定義函數的,通過Custom節點,之后在另一個Custom使用對應的CustomExpression0(數字可以參看HLSL代碼),CustomExpression0(Parameters,XXX)來調用
另外就是通過在common.usf寫函數,不過這樣會導致所有shader重新編譯,不適合快速開發。
3、按照官方文檔所說這樣寫對性能又一定影響,例如把Time節點寫入影響就比較大了。
第一二點就導致了Custom節點能做的事還是相當有限的。
二、官方文檔沒有說的事
Custom的使用方法請看官方文檔:https://docs.unrealengine.com/latest/INT/Engine/Rendering/Materials/ExpressionReference/Custom/index.html#warnings
下面我說一些文檔沒說的:
1、在材質編輯器中點擊Window-》HLSLCode,就可以看到對應的材質代碼。你會發現寫在Custom節點里的代碼出現在HLSLCode中。
其實這里的代碼都是從引擎中的Engine\Shaders目錄中的MaterialTemplate.usf文件復制過來的。而我們寫在Custom節點里的代碼也就相當寫在這個材質里面。你可以把代碼復制到文本編輯器中查看,可以使用Notepad++之類的有着色的編輯查看。
2、只有把Custom節點連入材質編輯器,這段代碼才會被寫入這個材質中。
3、Custom節點里的代碼,會寫進一個對應的 CustomExpression函數中,你可以在Custom節點中通過調用對應的CustomExpression函數來實現迭代的功能。
4、材質編輯器中的節點在usf中都有對應的函數,你可以調用對應函數的方式來起到代替節點的功能。但如果是在#if宏后面的函數是不能直接調用的。比如ScreenTexture節點對應的SceneTextureLookup函數,你必須將一個ScreenTexture節點連入材質,才能在Custom節點中調用SceneTextureLookup函數,即使你一點都不用他。
5、你可以通過View.XXXX獲得若干View相關屬性,可以在https://docs.unrealengine.com/latest/INT/API/Runtime/Engine/FViewUniformShaderParameters/index.html中找到,以此對應的UniformShader條目還有幾條,所以可以讀取屬性的不僅僅是View。
6、float3 BaseUV = Parameters.AbsoluteWorldPosition.xyz;可以通過Parameters.XXX的方式添加某一些節點。
三、關於UV節點
Custom的一個比較有用的地方就是寫PostProcess材質,但是對應的屏幕UV節點需要搞清楚。
TexCoord:在寫PostProcess材質的時候,與ScreenPosition節點效果一樣。
ScreenPosition:輸出當前屏幕空間像素的位置。(然而這個節點在編輯器里預覽和獨立游戲預覽的效果是不一樣的,在獨立游戲預覽的情況才是真正的輸出對應窗口分辨率的UV,例如720p,1280-》1(x),720-》1(y)),這個節點有2個選項,一個是ScreenTarget,一個是ViewPort。
ScreenTexelSize:文檔說配合ScreenTexture節點輸出的緩存使用,適合多種分辨系統下的邊緣檢測(可能因為分辨率比例不同而造成的效果錯誤),實際測試出,這個節點不能單獨使用。不知道該如何使用。
之后在官方的風格化渲染案例中發現使用,該節點乘以RenderTargetSize等於float2(1,1),所以某種意義通過這個比值就可以很好的解決不同分辨率情況下的UV相關的后處理效果問題。(然而我懶得修改前面寫的東西了)
RenderTargetSize:可以通過ViewProperty選擇得到,你屏幕緩存的大小。
ViewSize:輸出一個存儲分辨率的二維向量,例如720p為Vec2(1280,720)
ScreenResolution:第一個輸入的VisualResolution就是ViewSize,第二個返回是的RenderTarget的分辨率。
實際測試的結果是在編輯器狀態下RenderTargetSize比ScreenPosition大(編輯器狀態下的Debug顯示還是錯誤的),在獨立游戲下兩者一樣大。
ScreenAlignedUVs:輸出一個與屏幕適配的UV(配合RadialGraduentExponential你就會明白這個節點與ScreenPosition的區別)。
推薦使用Debug函數,這會讓你能夠更好得理解函數。
四、一些材質編輯器中的奇怪的技巧:
1、如何獲得透明物體深度與透明物體到背景之間的距離:

然后節點里是這樣的:

這里說一下SceneDepth與PixelDepth的區別,具體的參考https://docs.unrealengine.com/latest/CHN/Engine/Rendering/Materials/ExpressionReference/Depth/index.html
SceneDepth只能在 translucent 下才能使用,他輸出的 translucent 后面的物體深度。
這個節點算出來的效果是:在 translucent 物體后面的場景的位置信息(攝像機坐標系)

2、如何獲得物體與攝像機之間的距離:
Absolute World Position節點減去ViewPosition節點,即可得到距離。
之后規整化就可以得到攝像機方向。
