https://zhuanlan.zhihu.com/p/39786002 这篇文章简单记录了一下UE4渲染流程,两种渲染器,然后走basepassrender,第一阶段做Gbuffer,阶段做Lighting。
一:创建GBuffer
1. 起始位置:PixelShaderOutputCommon.ush 中的 MainPS函数。
输入:FVertexFactoryInterpolantsVSToPS FBasePassInterpolantsVSToPS or FMeshDecalInterpolants and SV_Position
输出:out float4 OutTarget0 : SV_Target0
0到7
函数:根据不同参数,调用shader。
#if PIXELSHADEROUTPUT_BASEPASS
FPixelShaderInOut_MainPS(Interpolants, BasePassInterpolants, PixelShaderIn, PixelShaderOut);
#elif PIXELSHADEROUTPUT_MESHDECALPASS
FPixelShaderInOut_MainPS(Interpolants, MeshDecalInterpolants, PixelShaderIn, PixelShaderOut);
#elif PIXELSHADEROUTPUT_INTERPOLANTS
FPixelShaderInOut_MainPS(Interpolants, PixelShaderIn, PixelShaderOut);
#else
FPixelShaderInOut_MainPS(PixelShaderIn, PixelShaderOut);
#endif
#if PIXELSHADEROUTPUT_MRT0
OutTarget0 = PixelShaderOut.MRT[0];
#endif
里面涉及FPixelShaderIn FPixelShaderOut (Common.ush)
// see PixelShaderOutputCommon
struct FPixelShaderIn
{
// read only
float4 SvPosition;
// Pixel Shader InCoverage, only usable if PIXELSHADEROUTPUT_COVERAGE is 1
uint Coverage;
//
bool bIsFrontFace;
};
// see PixelShaderOutputCommon
struct FPixelShaderOut
{
// [0..7], only usable if PIXELSHADEROUTPUT_MRT0, PIXELSHADEROUTPUT_MRT1, ... is 1
float4 MRT[8];
// Pixel Shader OutCoverage, only usable if PIXELSHADEROUTPUT_COVERAGE is 1
uint Coverage;
// Pixel Shader OutDepth
float Depth;
};
2.分析BasePass
#if PIXELSHADEROUTPUT_BASEPASS
FPixelShaderInOut_MainPS(Interpolants, BasePassInterpolants, PixelShaderIn, PixelShaderOut);
在文件BasePassPixelShader.usf中,FPixelShaderInOut_MainPS开始。
先分析:FMaterialPixelParameters MaterialParameters = GetMaterialPixelParameters(Interpolants, In.SvPosition);
在LocalVertexFactory.ush文件内:
/** Converts from vertex factory specific interpolants to a FMaterialPixelParameters, which is used by material inputs. */
FMaterialPixelParameters GetMaterialPixelParameters(FVertexFactoryInterpolantsVSToPS Interpolants, float4 SvPosition)
{
// GetMaterialPixelParameters is responsible for fully initializing the result
FMaterialPixelParameters Result = MakeInitializedMaterialPixelParameters();
#if NUM_TEX_COORD_INTERPOLATORS
UNROLL
for( int CoordinateIndex = 0; CoordinateIndex < NUM_TEX_COORD_INTERPOLATORS; CoordinateIndex++ )
{
Result.TexCoords[CoordinateIndex] = GetUV(Interpolants, CoordinateIndex);
}
#endif
#if USE_PARTICLE_SUBUVS
// Output TexCoord0 for when previewing materials that use ParticleSubUV.
Result.Particle.SubUVCoords[0] = GetUV(Interpolants, 0);
Result.Particle.SubUVCoords[1] = GetUV(Interpolants, 0);
#endif // USE_PARTICLE_SUBUVS
half3 TangentToWorld0 = GetTangentToWorld0(Interpolants).xyz;
half4 TangentToWorld2 = GetTangentToWorld2(Interpolants);
Result.UnMirrored = TangentToWorld2.w;
Result.VertexColor = GetColor(Interpolants);
// Required for previewing materials that use ParticleColor
Result.Particle.Color = half4(1,1,1,1);
#if USE_INSTANCING
Result.PerInstanceParams = Interpolants.PerInstanceParams;
#endif
Result.TangentToWorld = AssembleTangentToWorld( TangentToWorld0, TangentToWorld2 );
#if USE_WORLDVERTEXNORMAL_CENTER_INTERPOLATION
Result.WorldVertexNormal_Center = Interpolants.TangentToWorld2_Center.xyz;
#endif
#if LIGHTMAP_UV_ACCESS
#if NEEDS_LIGHTMAP_COORDINATE
#if (ES2_PROFILE || ES3_1_PROFILE)
// Not supported in pixel shader
Result.LightmapUVs = float2(0, 0);
#else
Result.LightmapUVs = Interpolants.LightMapCoordinate.xy;
#endif // ES2_PROFILE
#endif // NEEDS_LIGHTMAP_COORDINATE
#endif // LIGHTMAP_UV_ACCESS
Result.TwoSidedSign = 1;
Result.PrimitiveId = GetPrimitiveId(Interpolants);
return Result;
}
再分析 CalcMaterialParametersEx()
#if USE_WORLD_POSITION_EXCLUDING_SHADER_OFFSETS
{
float4 ScreenPosition = SvPositionToResolvedScreenPosition(In.SvPosition);
float3 TranslatedWorldPosition = SvPositionToResolvedTranslatedWorld(In.SvPosition);
CalcMaterialParametersEx(MaterialParameters, PixelMaterialInputs, In.SvPosition, ScreenPosition, In.bIsFrontFace, TranslatedWorldPosition, BasePassInterpolants.PixelPositionExcludingWPO);
}
#else
{
float4 ScreenPosition = SvPositionToResolvedScreenPosition(In.SvPosition);
float3 TranslatedWorldPosition = SvPositionToResolvedTranslatedWorld(In.SvPosition);
CalcMaterialParametersEx(MaterialParameters, PixelMaterialInputs, In.SvPosition, ScreenPosition, In.bIsFrontFace, TranslatedWorldPosition, TranslatedWorldPosition);
}
#endif
该函数在MaterialTemplate.ush中,MaterialTemplate是材质的模板,场景的材质都会根据这个模板转换成hlsl。这个函数模板和实例化内容一样。
/** Initializes the subset of Parameters that was not set in GetMaterialPixelParameters. */
void CalcMaterialParametersEx(
in out FMaterialPixelParameters Parameters,
in out FPixelMaterialInputs PixelMaterialInputs,
float4 SvPosition,
float4 ScreenPosition,
FIsFrontFace bIsFrontFace,
float3 TranslatedWorldPosition,
float3 TranslatedWorldPositionExcludingShaderOffsets)
{
// Remove the pre view translation
Parameters.WorldPosition_CamRelative = TranslatedWorldPosition.xyz;
Parameters.AbsoluteWorldPosition = TranslatedWorldPosition.xyz - ResolvedView.PreViewTranslation.xyz;
// If the material uses any non-offset world position expressions, calculate those parameters. If not,
// the variables will have been initialised to 0 earlier.
#if USE_WORLD_POSITION_EXCLUDING_SHADER_OFFSETS
Parameters.WorldPosition_NoOffsets_CamRelative = TranslatedWorldPositionExcludingShaderOffsets;
Parameters.WorldPosition_NoOffsets = TranslatedWorldPositionExcludingShaderOffsets - ResolvedView.PreViewTranslation.xyz;
#endif
Parameters.SvPosition = SvPosition;
Parameters.ScreenPosition = ScreenPosition;
#if COMPILER_GLSL_ES2
// ES2 normalize isn't done accurately. This seems to fix it.
// Originally this was normalize(normalize(TranslatedWorldPosition.xyz)) but tegra4 appears to optimize that out.
Parameters.CameraVector = normalize(-0.01 * Parameters.WorldPosition_CamRelative.xyz);
#else
#if !RAYHITGROUPSHADER
// TranslatedWorldPosition is the world position translated to the camera position, which is just -CameraVector
Parameters.CameraVector = normalize(-Parameters.WorldPosition_CamRelative.xyz);
#else
Parameters.CameraVector = -WorldRayDirection();
#endif
#endif
Parameters.LightVector = 0;
Parameters.TwoSidedSign = 1.0f;
#if MATERIAL_TWOSIDED && HAS_PRIMITIVE_UNIFORM_BUFFER
// #dxr: DirectX Raytracing's HitKind() intrinsic already accounts for negative scaling
#if PIXELSHADER
Parameters.TwoSidedSign *= ResolvedView.CullingSign * GetPrimitiveData(Parameters.PrimitiveId).InvNonUniformScaleAndDeterminantSign.w;
#endif
#if !MATERIAL_TWOSIDED_SEPARATE_PASS
Parameters.TwoSidedSign *= GetFloatFacingSign(bIsFrontFace);
#endif
#endif
#if NUM_VIRTUALTEXTURE_SAMPLES || LIGHTMAP_VT_ENABLED
InitializeVirtualTextureFeedback(Parameters.VirtualTextureFeedback, (uint2)SvPosition.xy, View.FrameNumber);
#endif
// Now that we have all the pixel-related parameters setup, calculate the Material Input/Attributes and Normal
CalcPixelMaterialInputs(Parameters, PixelMaterialInputs);
}
接着看:CalcPixelMaterialInputs,这个函数在模板和实例化不同。
模板内容如下:
void CalcPixelMaterialInputs(in out FMaterialPixelParameters Parameters, in out FPixelMaterialInputs PixelMaterialInputs)
{
// Initial calculations (required for Normal)
%s
// The Normal is a special case as it might have its own expressions and also be used to calculate other inputs, so perform the assignment here
%s
// Note that here MaterialNormal can be in world space or tangent space
float3 MaterialNormal = GetMaterialNormal(Parameters, PixelMaterialInputs);
#if MATERIAL_TANGENTSPACENORMAL
#if SIMPLE_FORWARD_SHADING
Parameters.WorldNormal = float3(0, 0, 1);
#endif
#if FEATURE_LEVEL >= FEATURE_LEVEL_SM4
// ES2 will rely on only the final normalize for performance
MaterialNormal = normalize(MaterialNormal);
#endif
// normalizing after the tangent space to world space conversion improves quality with sheared bases (UV layout to WS causes shrearing)
// use full precision normalize to avoid overflows
Parameters.WorldNormal = TransformTangentNormalToWorld(Parameters.TangentToWorld, MaterialNormal);
#else //MATERIAL_TANGENTSPACENORMAL
Parameters.WorldNormal = normalize(MaterialNormal);
#endif //MATERIAL_TANGENTSPACENORMAL
#if MATERIAL_TANGENTSPACENORMAL
// flip the normal for backfaces being rendered with a two-sided material
Parameters.WorldNormal *= Parameters.TwoSidedSign;
#endif
Parameters.ReflectionVector = ReflectionAboutCustomWorldNormal(Parameters, Parameters.WorldNormal, false);
#if !PARTICLE_SPRITE_FACTORY
Parameters.Particle.MotionBlurFade = 1.0f;
#endif // !PARTICLE_SPRITE_FACTORY
// Now the rest of the inputs
%s
}
实例化内容如下:
void CalcPixelMaterialInputs(in out FMaterialPixelParameters Parameters, in out FPixelMaterialInputs PixelMaterialInputs)
{
// Initial calculations (required for Normal)
// The Normal is a special case as it might have its own expressions and also be used to calculate other inputs, so perform the assignment here
PixelMaterialInputs.Normal = MaterialFloat3(0.00000000,0.00000000,1.00000000);
// Note that here MaterialNormal can be in world space or tangent space
float3 MaterialNormal = GetMaterialNormal(Parameters, PixelMaterialInputs);
#if MATERIAL_TANGENTSPACENORMAL
#if SIMPLE_FORWARD_SHADING
Parameters.WorldNormal = float3(0, 0, 1);
#endif
#if FEATURE_LEVEL >= FEATURE_LEVEL_SM4
// Mobile will rely on only the final normalize for performance
MaterialNormal = normalize(MaterialNormal);
#endif
// normalizing after the tangent space to world space conversion improves quality with sheared bases (UV layout to WS causes shrearing)
// use full precision normalize to avoid overflows
Parameters.WorldNormal = TransformTangentNormalToWorld(Parameters.TangentToWorld, MaterialNormal);
#else //MATERIAL_TANGENTSPACENORMAL
Parameters.WorldNormal = normalize(MaterialNormal);
#endif //MATERIAL_TANGENTSPACENORMAL
#if MATERIAL_TANGENTSPACENORMAL
// flip the normal for backfaces being rendered with a two-sided material
Parameters.WorldNormal *= Parameters.TwoSidedSign;
#endif
Parameters.ReflectionVector = ReflectionAboutCustomWorldNormal(Parameters, Parameters.WorldNormal, false);
#if !PARTICLE_SPRITE_FACTORY
Parameters.Particle.MotionBlurFade = 1.0f;
#endif // !PARTICLE_SPRITE_FACTORY
// Now the rest of the inputs
MaterialFloat4 Local0 = SceneTextureLookup(GetDefaultSceneTextureUV(Parameters, 25), 25, false);
MaterialFloat3 Local1 = lerp(Local0.rgba.rgb,Material.VectorExpressions[1].rgb,MaterialFloat(Material.ScalarExpressions[0].x));
PixelMaterialInputs.EmissiveColor = Local1;
PixelMaterialInputs.Opacity = 1.00000000;
PixelMaterialInputs.OpacityMask = 1.00000000;
PixelMaterialInputs.BaseColor = MaterialFloat3(0.00000000,0.00000000,0.00000000);
PixelMaterialInputs.Metallic = 0.00000000;
PixelMaterialInputs.Specular = 0.50000000;
PixelMaterialInputs.Roughness = 0.50000000;
PixelMaterialInputs.Anisotropy = 0.00000000;
PixelMaterialInputs.Tangent = MaterialFloat3(1.00000000,0.00000000,0.00000000);
PixelMaterialInputs.Subsurface = 0;
PixelMaterialInputs.AmbientOcclusion = 1.00000000;
PixelMaterialInputs.Refraction = 0;
PixelMaterialInputs.PixelDepthOffset = 0.00000000;
PixelMaterialInputs.ShadingModel = 0;
#if MATERIAL_USES_ANISOTROPY
Parameters.WorldTangent = CalculateAnisotropyTangent(Parameters, PixelMaterialInputs);
#else
Parameters.WorldTangent = 0;
#endif
}
二:Lighting