1、蓝图材质转换HLSL代码
- 在蓝图中创建Post Process Material,然后创建SceneTexture,ID选择CustomStencil,如下图:
- 在材质编辑器下,点击Window->Shader Code->HLSL Code,copy对应代码,保存生成custom.hsls文件(名称随便命名,目的方便描述该文件)。
- HLSL code 是基于MaterialTemplate.ush(Engine/Shader/Private)进行生成。
- 如何生成?目前没有深入研究,待后续更新(如果用到)。
- 对比MaterialTemplate.ush和custom.hsls文件。在VSCode中,左侧目录同时选中两个文件,右键,有compare功能,进行对比哪些是custom.hsls新增的。
- 实际对比,发现有大量的不同出现,然而我们在材质蓝图中,仅仅增加了一个SceneTexture函数,不应该有很多变化。没有深入分析原因,后面用到再研究。
- 本次研究的重点是如何获得SceneTexture,测试的ID是CustomStencil。而不是Post Process Material如何被使用,因此下面内容会围绕本次重点展开。
- 在custom.hsls中找出Emissive Color赋值出现的位置:
- void CalcPixelMaterialInputs(in out FMaterialPixelParameters Parameters, in out FPixelMaterialInputs PixelMaterialInputs)
- 不研究CalcPixelMaterialInputs如何被使用,只研究里面的内容。
- EmissiveColor是有两个数值差值的出来。
- Local0是和SceneTexture相关,深入研究
- Material.VectorExpression[1].rgb,不是重点,没有深入研究。
- 关键部分代码
-
MaterialFloat4 Local0 = SceneTextureLookup(GetDefaultSceneTextureUV(Parameters, 25), 25, false); MaterialFloat3 Local1 = erp(Local0.rgba.rgb,Material.VectorExpressions[1].rgb,MaterialFloat(Material.ScalarExpressions[0].x)); PixelMaterialInputs.EmissiveColor = Local1;
- void CalcPixelMaterialInputs(in out FMaterialPixelParameters Parameters, in out FPixelMaterialInputs PixelMaterialInputs)
- SceneTextureLookup函数介绍
-
/** Applies an offset to the scene texture lookup and decodes the HDR linear space color. */ float4 SceneTextureLookup(float2 UV, int SceneTextureIndex, bool bFiltered) { #if SCENE_TEXTURES_DISABLED return float4(0.0f, 0.0f, 0.0f, 0.0f); #endif FScreenSpaceData ScreenSpaceData = GetScreenSpaceData(UV, false); switch(SceneTextureIndex) { // order needs to match to ESceneTextureId case PPI_SceneColor: return float4(CalcSceneColor(UV), 0); case PPI_SceneDepth: return ScreenSpaceData.GBuffer.Depth; case PPI_DiffuseColor: return float4(ScreenSpaceData.GBuffer.DiffuseColor, 0); case PPI_SpecularColor: return float4(ScreenSpaceData.GBuffer.SpecularColor, 0); case PPI_SubsurfaceColor: return IsSubsurfaceModel(ScreenSpaceData.GBuffer.ShadingModelID) ? float4( ExtractSubsurfaceColor(ScreenSpaceData.GBuffer), ScreenSpaceData.GBuffer.CustomData.a ) : ScreenSpaceData.GBuffer.CustomData; case PPI_BaseColor: return float4(ScreenSpaceData.GBuffer.BaseColor, 0); case PPI_Specular: return ScreenSpaceData.GBuffer.Specular; case PPI_Metallic: return ScreenSpaceData.GBuffer.Metallic; case PPI_WorldNormal: return float4(ScreenSpaceData.GBuffer.WorldNormal, 0); case PPI_SeparateTranslucency: return float4(1, 1, 1, 1); // todo case PPI_Opacity: return ScreenSpaceData.GBuffer.CustomData.a; case PPI_Roughness: return ScreenSpaceData.GBuffer.Roughness; case PPI_MaterialAO: return ScreenSpaceData.GBuffer.GBufferAO; case PPI_CustomDepth: return ScreenSpaceData.GBuffer.CustomDepth; #if POST_PROCESS_MATERIAL case PPI_PostProcessInput0: return Texture2DSample(PostProcessInput_0_Texture, bFiltered ? PostProcessInput_BilinearSampler : PostProcessInput_0_SharedSampler, UV); case PPI_PostProcessInput1: return Texture2DSample(PostProcessInput_1_Texture, bFiltered ? PostProcessInput_BilinearSampler : PostProcessInput_1_SharedSampler, UV); case PPI_PostProcessInput2: return Texture2DSample(PostProcessInput_2_Texture, bFiltered ? PostProcessInput_BilinearSampler : PostProcessInput_2_SharedSampler, UV); case PPI_PostProcessInput3: return Texture2DSample(PostProcessInput_3_Texture, bFiltered ? PostProcessInput_BilinearSampler : PostProcessInput_3_SharedSampler, UV); case PPI_PostProcessInput4: return Texture2DSample(PostProcessInput_4_Texture, bFiltered ? PostProcessInput_BilinearSampler : PostProcessInput_4_SharedSampler, UV); #endif // __POST_PROCESS_COMMON__ case PPI_DecalMask: return 0; // material compiler will return an error case PPI_ShadingModelColor: return float4(GetShadingModelColor(ScreenSpaceData.GBuffer.ShadingModelID), 1); case PPI_ShadingModelID: return float4(ScreenSpaceData.GBuffer.ShadingModelID, 0, 0, 0); case PPI_AmbientOcclusion: return ScreenSpaceData.AmbientOcclusion; case PPI_CustomStencil: return ScreenSpaceData.GBuffer.CustomStencil; case PPI_StoredBaseColor: return float4(ScreenSpaceData.GBuffer.StoredBaseColor, 0); case PPI_StoredSpecular: return float4(ScreenSpaceData.GBuffer.StoredSpecular.rrr, 0); #if POST_PROCESS_MATERIAL case PPI_Velocity: return float4(PostProcessVelocityLookup(ConvertToDeviceZ(ScreenSpaceData.GBuffer.Depth), UV), 0, 0); #endif case PPI_WorldTangent: return float4(ScreenSpaceData.GBuffer.WorldTangent, 0); case PPI_Anisotropy: return ScreenSpaceData.GBuffer.Anisotropy; default: return float4(0, 0, 0, 0); } }
GetScreenSpaceData 在DeferredShadingCommon.ush文件中。
// @param UV - UV space in the GBuffer textures (BufferSize resolution)
FScreenSpaceData GetScreenSpaceData(float2 UV, bool bGetNormalizedNormal = true)
{
FScreenSpaceData Out;
Out.GBuffer = GetGBufferData(UV, bGetNormalizedNormal);
float4 ScreenSpaceAO = Texture2DSampleLevel(SceneTexturesStruct.ScreenSpaceAOTexture, SceneTexturesStruct.ScreenSpaceAOTextureSampler, UV, 0);
Out.AmbientOcclusion = ScreenSpaceAO.r;
return Out;
}
在相同文件内:
// @param UV - UV space in the GBuffer textures (BufferSize resolution)
FGBufferData GetGBufferData(float2 UV, bool bGetNormalizedNormal = true)
{
#if 0 //METAL_MRT_PROFILE
// @todo metal mrt: The deferred renderer isn't keeping these in tiled memory all the time - we don't know when this makes sense
// versus just sampling a bound resolved texture
float4 GBufferA = FramebufferFetchMRT(1);
float4 GBufferB = FramebufferFetchMRT(2);
float4 GBufferC = FramebufferFetchMRT(3);
float4 GBufferD = FramebufferFetchMRT(4);
// @todo metal mrt: We can't framebuffer fetch the depth, can we jam it in somewhere?
float CustomNativeDepth = 0.5;
#if ALLOW_STATIC_LIGHTING
float4 GBufferE = FramebufferFetchMRT(5);
#else
float4 GBufferE = 1;
#endif
#else
float4 GBufferA = Texture2DSampleLevel(SceneTexturesStruct.GBufferATexture, SceneTexturesStruct.GBufferATextureSampler, UV, 0);
float4 GBufferB = Texture2DSampleLevel(SceneTexturesStruct.GBufferBTexture, SceneTexturesStruct.GBufferBTextureSampler, UV, 0);
float4 GBufferC = Texture2DSampleLevel(SceneTexturesStruct.GBufferCTexture, SceneTexturesStruct.GBufferCTextureSampler, UV, 0);
float4 GBufferD = Texture2DSampleLevel(SceneTexturesStruct.GBufferDTexture, SceneTexturesStruct.GBufferDTextureSampler, UV, 0);
float CustomNativeDepth = Texture2DSampleLevel(SceneTexturesStruct.CustomDepthTexture, SceneTexturesStruct.CustomDepthTextureSampler, UV, 0).r;
#if FEATURE_LEVEL >= FEATURE_LEVEL_SM4
int2 IntUV = (int2)trunc(UV * View.BufferSizeAndInvSize.xy);
uint CustomStencil = SceneTexturesStruct.CustomStencilTexture.Load(int3(IntUV, 0)) STENCIL_COMPONENT_SWIZZLE;
#else
uint CustomStencil = 0;
#endif
#if ALLOW_STATIC_LIGHTING
float4 GBufferE = Texture2DSampleLevel(SceneTexturesStruct.GBufferETexture, SceneTexturesStruct.GBufferETextureSampler, UV, 0);
#else
float4 GBufferE = 1;
#endif
#if WRITES_VELOCITY_TO_GBUFFER
float4 GBufferVelocity = Texture2DSampleLevel(SceneTexturesStruct.GBufferVelocityTexture, SceneTexturesStruct.GBufferVelocityTextureSampler, UV, 0);
#else
float4 GBufferVelocity = 0;
#endif
#endif
float SceneDepth = CalcSceneDepth(UV);
return DecodeGBufferData(GBufferA, GBufferB, GBufferC, GBufferD, GBufferE, GBufferVelocity, CustomNativeDepth, CustomStencil, SceneDepth, bGetNormalizedNormal, CheckerFromSceneColorUV(UV));
}
在相同文件里:
/** Populates FGBufferData */
// @param bChecker High frequency Checkerboard pattern computed with one of the CheckerFrom.. functions, todo: profile if float 0/1 would be better (need to make sure it's 100% the same)
FGBufferData DecodeGBufferData(
float4 InGBufferA,
float4 InGBufferB,
float4 InGBufferC,
float4 InGBufferD,
float4 InGBufferE,
float4 InGBufferVelocity,
float CustomNativeDepth,
uint CustomStencil,
float SceneDepth,
bool bGetNormalizedNormal,
bool bChecker)
{
FGBufferData GBuffer;
GBuffer.WorldNormal = DecodeNormal( InGBufferA.xyz );
if(bGetNormalizedNormal)
{
GBuffer.WorldNormal = normalize(GBuffer.WorldNormal);
}
GBuffer.PerObjectGBufferData = InGBufferA.a;
GBuffer.Metallic = InGBufferB.r;
GBuffer.Specular = InGBufferB.g;
GBuffer.Roughness = InGBufferB.b;
// Note: must match GetShadingModelId standalone function logic
// Also Note: SimpleElementPixelShader directly sets SV_Target2 ( GBufferB ) to indicate unlit.
// An update there will be required if this layout changes.
GBuffer.ShadingModelID = DecodeShadingModelId(InGBufferB.a);
GBuffer.SelectiveOutputMask = DecodeSelectiveOutputMask(InGBufferB.a);
GBuffer.BaseColor = DecodeBaseColor(InGBufferC.rgb);
#if ALLOW_STATIC_LIGHTING
GBuffer.GBufferAO = 1;
GBuffer.IndirectIrradiance = DecodeIndirectIrradiance(InGBufferC.a);
#else
GBuffer.GBufferAO = InGBufferC.a;
GBuffer.IndirectIrradiance = 1;
#endif
GBuffer.CustomData = !(GBuffer.SelectiveOutputMask & SKIP_CUSTOMDATA_MASK) ? InGBufferD : 0;
GBuffer.PrecomputedShadowFactors = !(GBuffer.SelectiveOutputMask & SKIP_PRECSHADOW_MASK) ? InGBufferE : ((GBuffer.SelectiveOutputMask & ZERO_PRECSHADOW_MASK) ? 0 : 1);
GBuffer.CustomDepth = ConvertFromDeviceZ(CustomNativeDepth);
GBuffer.CustomStencil = CustomStencil;
GBuffer.Depth = SceneDepth;
GBuffer.StoredBaseColor = GBuffer.BaseColor;
GBuffer.StoredMetallic = GBuffer.Metallic;
GBuffer.StoredSpecular = GBuffer.Specular;
FLATTEN
if( GBuffer.ShadingModelID == SHADINGMODELID_EYE )
{
GBuffer.Metallic = 0.0;
#if IRIS_NORMAL
GBuffer.Specular = 0.25;
#endif
}
// derived from BaseColor, Metalness, Specular
{
GBuffer.SpecularColor = ComputeF0(GBuffer.Specular, GBuffer.BaseColor, GBuffer.Metallic);
if (UseSubsurfaceProfile(GBuffer.ShadingModelID))
{
AdjustBaseColorAndSpecularColorForSubsurfaceProfileLighting(GBuffer.BaseColor, GBuffer.SpecularColor, GBuffer.Specular, bChecker);
}
GBuffer.DiffuseColor = GBuffer.BaseColor - GBuffer.BaseColor * GBuffer.Metallic;
#if USE_DEVELOPMENT_SHADERS
{
// this feature is only needed for development/editor - we can compile it out for a shipping build (see r.CompileShadersForDevelopment cvar help)
GBuffer.DiffuseColor = GBuffer.DiffuseColor * View.DiffuseOverrideParameter.www + View.DiffuseOverrideParameter.xyz;
GBuffer.SpecularColor = GBuffer.SpecularColor * View.SpecularOverrideParameter.w + View.SpecularOverrideParameter.xyz;
}
#endif //USE_DEVELOPMENT_SHADERS
}
GBuffer.Velocity = !(GBuffer.SelectiveOutputMask & SKIP_VELOCITY_MASK) ? InGBufferVelocity : 0;
return GBuffer;
}
回归到CustomStencil:
#if FEATURE_LEVEL >= FEATURE_LEVEL_SM4
int2 IntUV = (int2)trunc(UV * View.BufferSizeAndInvSize.xy);
uint CustomStencil = SceneTexturesStruct.CustomStencilTexture.Load(int3(IntUV, 0)) STENCIL_COMPONENT_SWIZZLE;
#else
uint CustomStencil = 0;
#endif