Files
UnrealEngine/Engine/Shaders/Private/DebugViewModePixelShader.usf
2025-05-18 13:04:45 +08:00

556 lines
19 KiB
HLSL

// Copyright Epic Games, Inc. All Rights Reserved.
/*=============================================================================
DebugViewModePixelShader.usf: Ubershader for debug pixel modes.
=============================================================================*/
#define TEX_COORD_SCALE_ANALYSIS 1
#define DEBUG_MATERIAL_PARAMETERS 1
// Don't allow scene texture as we use ESceneRenderTargetsMode::DontSet in FMaterialTexCoordScalePS::SetParameters
// to avoid crashes in commandlet mode.
#undef SCENE_TEXTURES_DISABLED
#define SCENE_TEXTURES_DISABLED 1
#undef EYE_ADAPTATION_DISABLED
#define EYE_ADAPTATION_DISABLED 1
#include "Common.ush"
#include "SHCommon.ush"
#if OUTPUT_QUAD_OVERDRAW
#include "QuadOverdraw.ush"
#endif
#include "VirtualTextureCommon.ush"
#define UNDEF_ACCURACY 1024
// If -1, output everything to the RW texture.
float4 OneOverCPUTexCoordScales[MAX_NUM_TEXTURE_REGISTER / 4];
int4 TexCoordIndices[MAX_NUM_TEXTURE_REGISTER / 4];
float4 CPUTexelFactor; // In world space units.
float4 NormalizedComplexity;
int2 AnalysisParams; // (TextureAnalysisIndex, bOutputScales) or // (TextureAnalysisIndex, TextureResolution)
float PrimitiveAlpha;
int TexCoordAnalysisIndex;
float CPULogDistance;
uint bShowQuadOverdraw;
uint bOutputQuadOverdraw;
int LODIndex;
float3 SkinCacheDebugColor;
int VisualizeMode;
// Analysis index will be in [0, 31] if analysing a single texture, otherwise -1
#define TextureAnalysisIndex (AnalysisParams.x)
#define bOutputScales (AnalysisParams.y)
// Texture resolution if we're analysing a single texture
#define TextureResolution (AnalysisParams.y)
// Updated MAX_NUM_TEXTURE_REGISTER to 256
float GetComponent(float4 V, int Index)
{
FLATTEN
if (Index == 0) return V.x;
FLATTEN
if (Index == 1) return V.y;
FLATTEN
if (Index == 2) return V.z;
return V.w;
}
struct FTexCoordScalesParams
{
// Global var used to reduce the number of param passed to the shaders.
int2 PixelPosition;
// ddU, ddV for each coord index (up to 4 currently)
float4 OneOverDDU;
float4 OneOverDDV;
// Used when inspecting single elements.
float MinScale;
float MaxScale;
float TexSample;
float TexSampleAverage;
// When computing the texture scales, this holds 4 scales for consecutive texture register indices.
float4 ScalesPerIndex;
float RequiredResolution;
};
MaterialFloat StoreTexCoordScale(in out FTexCoordScalesParams Params, float2 UV, int TextureReferenceIndex)
{
// Take the minimum scale since high scale requires less resolution.
float GPUScaleX = length(ddx(UV));
float GPUScaleY = length(ddy(UV));
if (TextureReferenceIndex >= 0 && TextureReferenceIndex < MAX_NUM_TEXTURE_REGISTER)
{
float OneOverCPUScale = OneOverCPUTexCoordScales[TextureReferenceIndex / 4][TextureReferenceIndex % 4];
int TexCoordIndex = TexCoordIndices[TextureReferenceIndex / 4][TextureReferenceIndex % 4];
float GPUScale = min(GPUScaleX * GetComponent(Params.OneOverDDU, TexCoordIndex), GPUScaleY * GetComponent(Params.OneOverDDV, TexCoordIndex));
// Code path when searching the worst scales. MinScale and MaxScale are only used when rendering for accuracies (!bOutputScales)
const bool bUpdateMinMax = (OneOverCPUScale > 0 && (TextureAnalysisIndex == -1 || TextureAnalysisIndex == TextureReferenceIndex));
Params.MinScale = bUpdateMinMax ? min(Params.MinScale, GPUScale * OneOverCPUScale) : Params.MinScale;
Params.MaxScale = bUpdateMinMax ? max(Params.MaxScale, GPUScale * OneOverCPUScale) : Params.MaxScale;
// Code path when rendering the material in a render target. Each TILE_RESOLUTION X TILE_RESOLUTION maps to different texture.
const bool bUpdateScale = (bOutputScales && Params.PixelPosition.x / TILE_RESOLUTION == TextureReferenceIndex / 4);
Params.ScalesPerIndex[TextureReferenceIndex % 4] = bUpdateScale ? min(Params.ScalesPerIndex[TextureReferenceIndex % 4], GPUScale) : Params.ScalesPerIndex[TextureReferenceIndex % 4];
}
#if FEATURE_LEVEL >= FEATURE_LEVEL_SM5
float2 CoordDDX = ddx_fine(UV);
float2 CoordDDY = ddy_fine(UV);
#else
float2 CoordDDX = ddx(UV);
float2 CoordDDY = ddy(UV);
#endif
if (TextureAnalysisIndex == TextureReferenceIndex)
{
float MinDelta = min(length(CoordDDX), length(CoordDDY));
float RequiredResolution = (1 / max(MinDelta, 0.0000000001f));
Params.RequiredResolution = max(Params.RequiredResolution, RequiredResolution);
}
return 1.f;
}
MaterialFloat StoreTexSample(in out FTexCoordScalesParams Params, float4 C, int TextureReferenceIndex)
{
// Alpha?
if (TextureAnalysisIndex == TextureReferenceIndex)
{
Params.TexSample = TextureAnalysisIndex == TextureReferenceIndex ? lerp(.4f, 1.f, saturate(Luminance(C.rgb))) : Params.TexSample;
}
Params.TexSampleAverage = TextureAnalysisIndex == TextureReferenceIndex ? lerp(.4f, 1.f, saturate((C.r + C.g + C.b) / 3)) : Params.TexSample;
return 1.f;
}
#include "/Engine/Generated/Material.ush"
#include "DebugViewModeCommon.ush"
float3 AccuracyColorLookup(float Accuracy)
{
Accuracy = clamp(Accuracy, -1.99, 1.99);
int ColorIndex = floor(Accuracy) + 2;
float3 Color0 = DebugViewModeStruct.AccuracyColors[ColorIndex].rgb;
float3 Color1 = DebugViewModeStruct.AccuracyColors[ColorIndex + 1].rgb;
float ColorLerp = frac(Accuracy);
return lerp(Color0, Color1, ColorLerp);
}
float GetCPUTexelFactor(int CoordIndex)
{
FLATTEN
if (CoordIndex == 0) return CPUTexelFactor.x;
FLATTEN
if (CoordIndex == 1) return CPUTexelFactor.y;
FLATTEN
if (CoordIndex == 2) return CPUTexelFactor.z;
return CPUTexelFactor.w;
}
float2 GetTexCoord(in FDebugPSIn Inputs, int CoordIndex)
{
FLATTEN
if (CoordIndex == 0) return Inputs.TexCoord01.xy;
FLATTEN
if (CoordIndex == 1) return Inputs.TexCoord01.zw;
FLATTEN
if (CoordIndex == 2) return Inputs.TexCoord23.xy;
return Inputs.TexCoord23.zw;
}
float GetTexCoordSizeAccuracy(in FDebugPSIn Inputs, int CoordIndex, float CPUSize)
{
float3 WorldPosition = SvPositionToResolvedTranslatedWorld(Inputs.SvPosition);
float2 TexCoord = GetTexCoord(Inputs, CoordIndex);
#if FEATURE_LEVEL >= FEATURE_LEVEL_SM5
float2 CoordDDX = ddx_fine(TexCoord);
float2 CoordDDY = ddy_fine(TexCoord);
float3 WorldPosDDX = ddx_fine(WorldPosition);
float3 WorldPosDDY = ddy_fine(WorldPosition);
#else
float2 CoordDDX = ddx(TexCoord);
float2 CoordDDY = ddy(TexCoord);
float3 WorldPosDDX = ddx(WorldPosition);
float3 WorldPosDDY = ddy(WorldPosition);
#endif
float UVAera = abs(CoordDDX.x * CoordDDY.y - CoordDDX.y * CoordDDY.x);
float WorldAera = length(cross(WorldPosDDX, WorldPosDDY));
float GPUTexelFactor = sqrt(WorldAera / max(UVAera, 0.0000000001f));
return clamp(log2(CPUSize) - log2(GPUTexelFactor), -1.99, 1.99);
}
float4 VisualizeMaterialTexCoordScales(in FDebugPSIn DebugInputs, in bool bIsFrontFace)
{
// This default value will make it dark grey when nothing updates the texSample.
float3 Result = float3(UNDEFINED_ACCURACY, UNDEFINED_ACCURACY, UNDEFINED_ACCURACY);
FTexCoordScalesParams Params;
// Set global var used for outputting data
Params.PixelPosition = DebugInputs.SvPosition.xy;
Params.OneOverDDU = 1 / float4(length(ddx(DebugInputs.TexCoord01.xy)), length(ddx(DebugInputs.TexCoord01.zw)), length(ddx(DebugInputs.TexCoord23.xy)), length(ddx(DebugInputs.TexCoord23.zw)));
Params.OneOverDDV = 1 / float4(length(ddy(DebugInputs.TexCoord01.xy)), length(ddy(DebugInputs.TexCoord01.zw)), length(ddy(DebugInputs.TexCoord23.xy)), length(ddy(DebugInputs.TexCoord23.zw)));
Params.TexSample = 1.f;
Params.TexSampleAverage = 1.f;
Params.MinScale = INITIAL_GPU_SCALE;
Params.MaxScale = 0;
Params.ScalesPerIndex = INITIAL_GPU_SCALE;
Params.RequiredResolution = 0;
FMaterialPixelParameters MaterialParameters = GetMaterialPixelParameters(DebugInputs, DebugInputs.SvPosition);
// This is used to patch invalid parameters when computing the scales with FMeshMaterialRenderItem::EnqueueMaterialRender
FLATTEN
if (bOutputScales)
{
#if NUM_MATERIAL_TEXCOORDS > 0
// Set all texcoord but one to 0. This allows the analysis to figure out which texcoord is driving the lookup.
int CurrentCoordIndex = (Params.PixelPosition.y / TILE_RESOLUTION) % MAX_NUM_TEX_COORD;
UNROLL
for (int CoordinateIndex = 0; CoordinateIndex < NUM_MATERIAL_TEXCOORDS; ++CoordinateIndex)
{
// The quad material used only has a valid TexCoord for UV 0
MaterialParameters.TexCoords[CoordinateIndex] = CoordinateIndex != CurrentCoordIndex ? 0 : DebugInputs.TexCoord01.xy;
}
// The scale must also be computed to match the actual coord inspected. That would be required when rendering the mesh in world space
// Although not required here as using the material quad only use texcoord0.
// Params.OneOverDDU = GetComponent(Params.OneOverDDU, CurrentCoordIndex).xxxx;
// Params.OneOverDDV = GetComponent(Params.OneOverDDV, CurrentCoordIndex).xxxx;
#endif
}
half3 BaseColor;
MaterialParameters.TexCoordScalesParams = Params;
{
FPixelMaterialInputs PixelMaterialInputs;
CalcMaterialParameters(MaterialParameters, PixelMaterialInputs, DebugInputs.SvPosition, bIsFrontFace);
// Sample material properties. The results are not used, but the calls to StoreTexCoordScale will still be made.
BaseColor = GetMaterialBaseColorRaw(PixelMaterialInputs);
half Metallic = GetMaterialMetallicRaw(PixelMaterialInputs);
half Specular = GetMaterialSpecularRaw(PixelMaterialInputs);
float Roughness = GetMaterialRoughnessRaw(PixelMaterialInputs);
half3 Normal = GetMaterialNormalRaw(PixelMaterialInputs);
half3 Emissive = GetMaterialEmissiveRaw(PixelMaterialInputs);
half Opacity = GetMaterialOpacityRaw(PixelMaterialInputs);
#if MATERIALBLENDING_MASKED
half Mask = GetMaterialMask(PixelMaterialInputs);
if (!bOutputScales)
{
clip(GetMaterialMask(PixelMaterialInputs));
}
#endif
half4 SSData = GetMaterialSubsurfaceDataRaw(PixelMaterialInputs);
float Custom0 = GetMaterialCustomData0(PixelMaterialInputs);
float Custom1 = GetMaterialCustomData1(PixelMaterialInputs);
float MaterialAO = GetMaterialAmbientOcclusionRaw(PixelMaterialInputs);
float PixelDepthOffset = GetMaterialPixelDepthOffset(PixelMaterialInputs);
#if CLEAR_COAT_BOTTOM_NORMAL && NUM_MATERIAL_OUTPUTS_CLEARCOATBOTTOMNORMAL > 0
float3 BottomNormal = ClearCoatBottomNormal0(MaterialParameters);
#endif
}
Params = MaterialParameters.TexCoordScalesParams;
Result *= saturate(Luminance(BaseColor));
float4 OutColor;
if (bOutputScales)
{
// Output the scales
OutColor = Params.ScalesPerIndex;
}
else
{
float PixelScale = ((Params.PixelPosition.x & 0x08) == (Params.PixelPosition.y & 0x08) || TextureAnalysisIndex != -1) ? Params.MinScale : Params.MaxScale;
// Output accuracy. If the GPU Scale is INITIAL_GPU_SCALE, then the texcoord was not updated.
if (Params.MinScale != INITIAL_GPU_SCALE)
{
Params.TexSample = TextureAnalysisIndex == -1 ? lerp(.4f, 1.f, saturate(Luminance(BaseColor))) : Params.TexSample;
float Accuracy = clamp(log2(PixelScale), -1.99, 1.99);
int ColorIndex = floor(Accuracy) + 2;
Result = Params.TexSample * lerp(DebugViewModeStruct.AccuracyColors[ColorIndex].rgb, DebugViewModeStruct.AccuracyColors[ColorIndex + 1].rgb, frac(Accuracy));
}
OutColor = float4(Result, PrimitiveAlpha);
}
return OutColor;
}
float4 VisualizeMeshTexCoordSizeAccuracy(in FDebugPSIn DebugInputs, in bool bIsFrontFace)
{
float3 Result = float3(UNDEFINED_ACCURACY, UNDEFINED_ACCURACY, UNDEFINED_ACCURACY);
if (TexCoordAnalysisIndex >= 0)
{
float CPUSize = GetCPUTexelFactor(TexCoordAnalysisIndex);
if (CPUSize > 0)
{
float Accuracy = GetTexCoordSizeAccuracy(DebugInputs, TexCoordAnalysisIndex, CPUSize);
int ColorIndex = floor(Accuracy) + 2;
Result = lerp(DebugViewModeStruct.AccuracyColors[ColorIndex].rgb, DebugViewModeStruct.AccuracyColors[ColorIndex + 1].rgb, frac(Accuracy));
}
}
else
{
float MinAccuracy = UNDEF_ACCURACY;
float MaxAccuracy = -UNDEF_ACCURACY;
[unroll]
for (int CoordIndex = 0; CoordIndex < 4; ++CoordIndex)
{
float CPUSize = GetCPUTexelFactor(CoordIndex);
if (CPUSize > 0)
{
float Accuracy = GetTexCoordSizeAccuracy(DebugInputs, CoordIndex, CPUSize);
MinAccuracy = min(Accuracy, MinAccuracy);
MaxAccuracy = max(Accuracy, MaxAccuracy);
}
}
int2 PixelPosition = DebugInputs.SvPosition.xy;
float Accuracy = (PixelPosition.x & 0x08) == (PixelPosition.y & 0x08) ? MinAccuracy : MaxAccuracy;
if (abs(Accuracy) != UNDEF_ACCURACY)
{
int ColorIndex = floor(Accuracy) + 2;
Result = lerp(DebugViewModeStruct.AccuracyColors[ColorIndex].rgb, DebugViewModeStruct.AccuracyColors[ColorIndex + 1].rgb, frac(Accuracy));
}
}
return float4(Result, PrimitiveAlpha);
}
float4 VisualizePrimitiveDistanceAccuracy(in FDebugPSIn DebugInputs, in bool bIsFrontFace)
{
float3 Result = float3(UNDEFINED_ACCURACY, UNDEFINED_ACCURACY, UNDEFINED_ACCURACY);
if (CPULogDistance >= 0)
{
float ViewDistance = length(SvPositionToResolvedTranslatedWorld(DebugInputs.SvPosition));
float GPULogDistance = log2(max(1, ViewDistance));
float Accuracy = clamp(GPULogDistance - CPULogDistance, -1.99, 1.99);
int ColorIndex = floor(Accuracy) + 2;
Result = lerp(DebugViewModeStruct.AccuracyColors[ColorIndex].rgb, DebugViewModeStruct.AccuracyColors[ColorIndex + 1].rgb, frac(Accuracy));
}
return float4(Result, PrimitiveAlpha);
}
float4 VisualizeRequiredTextureResolution(in FDebugPSIn DebugInputs, in bool bIsFrontFace)
{
FMaterialPixelParameters MaterialParameters = GetMaterialPixelParameters(DebugInputs, DebugInputs.SvPosition);
MaterialParameters.TexCoordScalesParams.RequiredResolution = 0;
MaterialParameters.TexCoordScalesParams.TexSample = 0;
half3 BaseColor;
{
FPixelMaterialInputs PixelMaterialInputs;
CalcMaterialParameters(MaterialParameters, PixelMaterialInputs, DebugInputs.SvPosition, bIsFrontFace);
// Sample material properties. The results are not used, but the calls to StoreTexCoordScale are still be made.
BaseColor = GetMaterialBaseColorRaw(PixelMaterialInputs);
half Metallic = GetMaterialMetallicRaw(PixelMaterialInputs);
half Specular = GetMaterialSpecularRaw(PixelMaterialInputs);
float Roughness = GetMaterialRoughnessRaw(PixelMaterialInputs);
half3 Normal = GetMaterialNormalRaw(PixelMaterialInputs);
half3 Emissive = GetMaterialEmissiveRaw(PixelMaterialInputs);
half Opacity = GetMaterialOpacityRaw(PixelMaterialInputs);
#if MATERIALBLENDING_MASKED
half Mask = GetMaterialMask(PixelMaterialInputs);
clip(GetMaterialMask(PixelMaterialInputs));
#endif
half4 SSData = GetMaterialSubsurfaceDataRaw(PixelMaterialInputs);
float Custom0 = GetMaterialCustomData0(PixelMaterialInputs);
float Custom1 = GetMaterialCustomData1(PixelMaterialInputs);
float MaterialAO = GetMaterialAmbientOcclusionRaw(PixelMaterialInputs);
float PixelDepthOffset = GetMaterialPixelDepthOffset(PixelMaterialInputs);
#if CLEAR_COAT_BOTTOM_NORMAL && NUM_MATERIAL_OUTPUTS_CLEARCOATBOTTOMNORMAL > 0
float3 BottomNormal = ClearCoatBottomNormal0(MaterialParameters);
#endif
}
float3 Result = float3(UNDEFINED_ACCURACY, UNDEFINED_ACCURACY, UNDEFINED_ACCURACY);
Result *= saturate(Luminance(BaseColor));
if (VisualizeMode == DVSM_RequiredTextureResolution)
{
if (MaterialParameters.TexCoordScalesParams.RequiredResolution > 0)
{
float Accuracy = log2(TextureResolution / MaterialParameters.TexCoordScalesParams.RequiredResolution);
Result = AccuracyColorLookup(Accuracy);
Result *= MaterialParameters.TexCoordScalesParams.TexSample;
}
}
#if MATERIAL_VIRTUALTEXTURE_FEEDBACK || LIGHTMAP_VT_ENABLED
FinalizeVirtualTextureFeedback(
MaterialParameters.VirtualTextureFeedback,
MaterialParameters.SvPosition,
View.VTFeedbackBuffer
);
#endif
return float4(Result, PrimitiveAlpha);
}
float4 VisualizeShaderComplexityAccumulate(in FDebugPSIn DebugInputs, in bool bIsFrontFace)
{
float3 Result = float3(1, 0, 1);
if (bOutputQuadOverdraw)
{
float3 FinalComplexity = NormalizedComplexity.xyz;
#if !(COMPILER_METAL) && (OUTPUT_QUAD_OVERDRAW)
[branch]
if (bShowQuadOverdraw && NormalizedComplexity.x > 0)
{
uint Coverage = ComputeQuadCoverage(DebugInputs.SvPosition.xy, DebugInputs.SvPrimitiveID, 24, false, false, 0);
// The extra cost from quad overdraw is assumed to be linear.
FinalComplexity.x *= 4.f / (float)(Coverage);
}
#endif // !(COMPILER_METAL) && (OUTPUT_QUAD_OVERDRAW)
// use the maximum range allowed for scene color
Result = FinalComplexity;
}
else
{
Result = NormalizedComplexity.xyz;
}
// alpha channel needs to be 1 to have decals working where the framebuffer blend is setup to multiply with alpha
return float4(Result, 1);
}
float4 ApplyDebugColor(in FDebugPSIn DebugInputs, in bool bIsFrontFace, in float3 DebugColor)
{
float3 Result = DebugColor;
FMaterialPixelParameters MaterialParameters = GetMaterialPixelParameters(DebugInputs, DebugInputs.SvPosition);
half3 BaseColor;
half Opacity;
{
FPixelMaterialInputs PixelMaterialInputs;
CalcMaterialParameters(MaterialParameters, PixelMaterialInputs, DebugInputs.SvPosition, bIsFrontFace);
// Sample material properties. The results are not used, but the calls to StoreTexCoordScale are still be made.
BaseColor = GetMaterialBaseColor(PixelMaterialInputs);
Opacity = GetMaterialOpacity(PixelMaterialInputs);
half3 Emissive = GetMaterialEmissive(PixelMaterialInputs);
#if MATERIALBLENDING_ADDITIVE
Opacity = (.05 + .95 * Luminance(Emissive));
#else
BaseColor += Emissive;
#endif
#if MATERIALBLENDING_MASKED
clip(GetMaterialMask(PixelMaterialInputs));
#endif
}
Result *= (.05 + .95 * Luminance(BaseColor));
#if MATERIAL_VIRTUALTEXTURE_FEEDBACK || LIGHTMAP_VT_ENABLED
FinalizeVirtualTextureFeedback(
MaterialParameters.VirtualTextureFeedback,
MaterialParameters.SvPosition,
View.VTFeedbackBuffer
);
#endif
return float4(Result, Opacity);
}
float4 VisualizeLODColoration(in FDebugPSIn DebugInputs, in bool bIsFrontFace)
{
float3 Color = DebugViewModeStruct.LODColors[LODIndex].rgb;
return ApplyDebugColor(DebugInputs, bIsFrontFace, Color);
}
float4 VisualizeGPUSkinCache(in FDebugPSIn DebugInputs, in bool bIsFrontFace)
{
return ApplyDebugColor(DebugInputs, bIsFrontFace, SkinCacheDebugColor);
}
#if !OUTPUT_PIXEL_DEPTH_OFFSET
#define PIXELSHADER_EARLYDEPTHSTENCIL EARLYDEPTHSTENCIL
#else
#define PIXELSHADER_EARLYDEPTHSTENCIL
#endif
PIXELSHADER_EARLYDEPTHSTENCIL
void Main(
in FDebugPSIn DebugInputs
OPTIONAL_IsFrontFace,
out float4 OutColor : SV_Target0
)
{
StereoSetupPS(DebugInputs.StereoInput);
// If we see pink something went wrong.
float4 VisualizeColor = float4(1, 0, 1, 1);
BRANCH
if (VisualizeMode == DVSM_ShaderComplexity ||
VisualizeMode == DVSM_ShaderComplexityContainedQuadOverhead ||
VisualizeMode == DVSM_ShaderComplexityBleedingQuadOverhead ||
VisualizeMode == DVSM_QuadComplexity ||
VisualizeMode == DVSM_LWCComplexity)
{
VisualizeColor = VisualizeShaderComplexityAccumulate(DebugInputs, bIsFrontFace);
}
else if (VisualizeMode == DVSM_PrimitiveDistanceAccuracy)
{
VisualizeColor = VisualizePrimitiveDistanceAccuracy(DebugInputs, bIsFrontFace);
}
else if (VisualizeMode == DVSM_MeshUVDensityAccuracy)
{
VisualizeColor = VisualizeMeshTexCoordSizeAccuracy(DebugInputs, bIsFrontFace);
}
else if (VisualizeMode == DVSM_MaterialTextureScaleAccuracy ||
VisualizeMode == DVSM_OutputMaterialTextureScales)
{
VisualizeColor = VisualizeMaterialTexCoordScales(DebugInputs, bIsFrontFace);
}
else if (VisualizeMode == DVSM_RequiredTextureResolution)
{
VisualizeColor = VisualizeRequiredTextureResolution(DebugInputs, bIsFrontFace);
}
else if (VisualizeMode == DVSM_LODColoration)
{
VisualizeColor = VisualizeLODColoration(DebugInputs, bIsFrontFace);
}
else if (VisualizeMode == DVSM_VisualizeGPUSkinCache)
{
VisualizeColor = VisualizeGPUSkinCache(DebugInputs, bIsFrontFace);
}
OutColor = RETURN_COLOR(VisualizeColor);
}