[UnrealEngine][開發日誌] Shadre pipeline:Usage Flags vs ShadingModel

posted in: UnrealEngine, 開發日誌 | 1

UsageFlag文檔:https://docs.unrealengine.com/4.27/en-US/RenderingAndGraphics/Materials/MaterialProperties/

ShadingModel文檔: https://docs.unrealengine.com/4.27/en-US/RenderingAndGraphics/Materials/MaterialProperties/LightingModels/

本文章是基於4.27

之前有空想要比對一下mobile pass跟SM5 pass到底差在哪裡。有發現在windows editor中,只有SM5跟ES3二種,就算是選了蘋果icon也不是真的metal,真正的metal shader code只能在mac環境下編譯出來。

在追code的過程中相關些名詞一直出現,引起了我的好奇,因此決定仔細研究一下。想要追shader相關的程式碼,這幾個ini參數最好設一下會比較好debug:

DefaultEngine.ini:
[DevOptions.Shaders]
bAllowCompilingThroughWorkers=false
bAllowAsynchronousShaderCompiling=false

[ConsoleVariables]
r.DumpShaderDebugInfo=1

在material上有usage跟shading model的選項,usage主要的用途是用來決定哪些shader組合是不是要compile permutation;ShadingModel主要是用來決定計算光源貢獻時要走哪條IntegrateBxDF的路。

在Unreal中shader code的generation主要是靠C++ Template的機制來大量產生各種組合(permutation),其中可以看到引擎大量的使用Policy-Based Design。我們知道template的機制是compile time產code,所以我們只要有n個base shader,再加上m種policy的話,我們就可以產生n*m種組合。

每個Policy都會實作ShouldCompilePermutation跟ModifyCompilationEnvironment這二個function;前者搭配Usage使用,替BaseShaderType決定要搭配哪些Policy組合的編譯,例如,NoLightMapPolicy,接著實作會呼叫ModifyCompilationEnvironment,他會替Shader加macro,決定某段shader code要不要留下來。

以bIsUsedWithStaticLighting為例,若該usage有勾選的話,在跑IMPLEMENT_SHADER_TYPE時,其相關連到一組的BasePassVertexShader.usf、BasePassTessellationShaders.usf以及BasePassPixelShader.usf(Vertex Shader, Hull and Domain Shader, Pixel Shader)就會被用搭配到的TLightMapPolicy建立出來。

例如在${PROJECT_ROOT}/Saved/ShaderDebugInfo/PCD3D_SM5/AmbientOcclusion/FLocalVertexFactory可以看到類似於下面中的資料夾。其中產生的permutation shader code,針對BasePassVertexShader.usf,產生NoLightMapPolicy以及NoLightMapPolicyAtmosphericFog這二組;針對BasePassPixelShader.usf,則產生了FNoLightMapPolicy跟FNoLightMapPolicySkylight。

這些Policy主要的功能是用來ModifyCompilationEnvironment,替shader code加入需要的macro define,之後每個permutation就會利用mcpp這個preprocess來幫我們濾掉不需要code,並把所有include到的shader結合成一個大檔之後,產生特製的shader code出來。

另外Usage除了決定permutation要不要產生出來外,有一些還會用來附加一些macro進shader中,例如OutEnvironment.SetDefine(TEXT(“USES_DISTORTION”), Material->IsDistorted());

有發現Usage雖然有八成左右的功能都只是用來決定編譯組合;ShadingModel主要是用來決定計算光源貢獻的做法。但有看到有少部份會直接去加shader macro,例如Usage中的UsesDistortion以及ShadingModel中的MSM_SingleLayerWater,不確定這樣的做法是不是原設計者的意圖,比較像是hack。

ShadingModel主要是用來決定計算光源貢獻時要走哪條IntegrateBxDF的路,以下是在ShadingModels.ush中的實作:

FDirectLighting IntegrateBxDF( FGBufferData GBuffer, half3 N, half3 V, half3 L, float Falloff, float NoL, FAreaLight AreaLight, FShadowTerms Shadow )
{
        switch( GBuffer.ShadingModelID )
        {
                case SHADINGMODELID_DEFAULT_LIT:
                case SHADINGMODELID_SINGLELAYERWATER:
                case SHADINGMODELID_THIN_TRANSLUCENT:
                        return DefaultLitBxDF( GBuffer, N, V, L, Falloff, NoL, AreaLight, Shadow );
                case SHADINGMODELID_SUBSURFACE:
                        return SubsurfaceBxDF( GBuffer, N, V, L, Falloff, NoL, AreaLight, Shadow );
                case SHADINGMODELID_PREINTEGRATED_SKIN:
                        return PreintegratedSkinBxDF( GBuffer, N, V, L, Falloff, NoL, AreaLight, Shadow );
                case SHADINGMODELID_CLEAR_COAT:
                        return ClearCoatBxDF( GBuffer, N, V, L, Falloff, NoL, AreaLight, Shadow );
                case SHADINGMODELID_SUBSURFACE_PROFILE:
                        return SubsurfaceProfileBxDF( GBuffer, N, V, L, Falloff, NoL, AreaLight, Shadow );
                case SHADINGMODELID_TWOSIDED_FOLIAGE:
                        return TwoSidedBxDF( GBuffer, N, V, L, Falloff, NoL, AreaLight, Shadow );
                case SHADINGMODELID_HAIR:
                        return HairBxDF( GBuffer, N, V, L, Falloff, NoL, AreaLight, Shadow );
                case SHADINGMODELID_CLOTH:
                        return ClothBxDF( GBuffer, N, V, L, Falloff, NoL, AreaLight, Shadow );
                case SHADINGMODELID_EYE:
                        return EyeBxDF( GBuffer, N, V, L, Falloff, NoL, AreaLight, Shadow );
                default:
                        return (FDirectLighting)0;
        }
}

Leave a Reply

Your email address will not be published. Required fields are marked *