391 lines
15 KiB
HLSL
391 lines
15 KiB
HLSL
|
|
||
|
#ifndef UNIVERSAL_DEBUGGING3D_INCLUDED
|
||
|
#define UNIVERSAL_DEBUGGING3D_INCLUDED
|
||
|
|
||
|
// Ensure that we always include "DebuggingCommon.hlsl" even if we don't use it - saves extraneous includes elsewhere...
|
||
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Debug/DebuggingCommon.hlsl"
|
||
|
|
||
|
#if defined(DEBUG_DISPLAY)
|
||
|
|
||
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/BRDF.hlsl"
|
||
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/GlobalIllumination.hlsl"
|
||
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/RealtimeLights.hlsl"
|
||
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl"
|
||
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/SurfaceData.hlsl"
|
||
|
|
||
|
#define TERRAIN_STREAM_INFO float4(0.0f, 0.0f, float(6 | (4 << 4)), 0.0f) // 0-15 are reserved for per-texture codes (use "6" to indicate terrain); per-material code "4" signifies "warnings/issues"
|
||
|
#define SETUP_DEBUG_TEXTURE_DATA(inputData, uv) SetupDebugDataTexture(inputData, TRANSFORM_TEX(uv.xy, unity_MipmapStreaming_DebugTex), unity_MipmapStreaming_DebugTex_TexelSize, unity_MipmapStreaming_DebugTex_MipInfo, unity_MipmapStreaming_DebugTex_StreamInfo, unity_MipmapStreaming_DebugTex)
|
||
|
#define SETUP_DEBUG_TEXTURE_DATA_NO_UV(inputData) SetupDebugDataTexture(inputData, float2(0.0f, 0.0f), unity_MipmapStreaming_DebugTex_TexelSize, unity_MipmapStreaming_DebugTex_MipInfo, unity_MipmapStreaming_DebugTex_StreamInfo, unity_MipmapStreaming_DebugTex)
|
||
|
#define SETUP_DEBUG_TEXTURE_DATA_FOR_TEX(inputData, uv, texture) SetupDebugDataTexture(inputData, uv, texture##_TexelSize, texture##_MipInfo, texture##_StreamInfo, texture)
|
||
|
#define SETUP_DEBUG_TEXTURE_DATA_FOR_TERRAIN(inputData) SetupDebugDataTerrain(inputData)
|
||
|
|
||
|
void SetupDebugDataTexture(inout InputData inputData, float2 uv, float4 texelSize, float4 mipInfo, float4 streamInfo, TEXTURE2D(tex))
|
||
|
{
|
||
|
inputData.uv = uv;
|
||
|
inputData.texelSize = texelSize;
|
||
|
inputData.mipInfo = mipInfo;
|
||
|
inputData.streamInfo = streamInfo;
|
||
|
inputData.mipCount = GetMipCount(TEXTURE2D_ARGS(tex, sampler_PointClamp));
|
||
|
inputData.originalColor = 0.0f;
|
||
|
|
||
|
if (_DebugMipInfoMode != DEBUGMIPINFOMODE_NONE)
|
||
|
{
|
||
|
inputData.originalColor = SAMPLE_TEXTURE2D(tex, sampler_LinearRepeat, uv).xyz;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void SetupDebugDataBrdf(inout InputData inputData, half3 brdfDiffuse, half3 brdfSpecular)
|
||
|
{
|
||
|
inputData.brdfDiffuse = brdfDiffuse;
|
||
|
inputData.brdfSpecular = brdfSpecular;
|
||
|
}
|
||
|
|
||
|
void SetupDebugDataTerrain(inout InputData inputData)
|
||
|
{
|
||
|
// TERRAIN_STREAM_INFO: no streamInfo will have been set (no MeshRenderer); set status to "6" to reflect in the debug status that this is a terrain
|
||
|
// also, set the per-material status to "4" to indicate warnings
|
||
|
inputData.streamInfo = TERRAIN_STREAM_INFO;
|
||
|
}
|
||
|
|
||
|
bool UpdateSurfaceAndInputDataForDebug(inout SurfaceData surfaceData, inout InputData inputData)
|
||
|
{
|
||
|
bool changed = false;
|
||
|
|
||
|
if (_DebugLightingMode == DEBUGLIGHTINGMODE_LIGHTING_WITHOUT_NORMAL_MAPS || _DebugLightingMode == DEBUGLIGHTINGMODE_LIGHTING_WITH_NORMAL_MAPS)
|
||
|
{
|
||
|
surfaceData.albedo = 1;
|
||
|
surfaceData.emission = 0;
|
||
|
surfaceData.specular = 0;
|
||
|
surfaceData.occlusion = 1;
|
||
|
surfaceData.clearCoatMask = 0;
|
||
|
surfaceData.clearCoatSmoothness = 1;
|
||
|
surfaceData.metallic = 0;
|
||
|
surfaceData.smoothness = 0;
|
||
|
changed = true;
|
||
|
}
|
||
|
else if (_DebugLightingMode == DEBUGLIGHTINGMODE_REFLECTIONS || _DebugLightingMode == DEBUGLIGHTINGMODE_REFLECTIONS_WITH_SMOOTHNESS)
|
||
|
{
|
||
|
surfaceData.albedo = 0;
|
||
|
surfaceData.emission = 0;
|
||
|
surfaceData.occlusion = 1;
|
||
|
surfaceData.clearCoatMask = 0;
|
||
|
surfaceData.clearCoatSmoothness = 1;
|
||
|
surfaceData.specular = 1;
|
||
|
surfaceData.metallic = 0;
|
||
|
if (_DebugLightingMode == DEBUGLIGHTINGMODE_REFLECTIONS)
|
||
|
{
|
||
|
surfaceData.smoothness = 1;
|
||
|
}
|
||
|
changed = true;
|
||
|
}
|
||
|
|
||
|
if (_DebugLightingMode == DEBUGLIGHTINGMODE_LIGHTING_WITHOUT_NORMAL_MAPS || _DebugLightingMode == DEBUGLIGHTINGMODE_REFLECTIONS)
|
||
|
{
|
||
|
const half3 normalTS = half3(0, 0, 1);
|
||
|
#if defined(_NORMALMAP)
|
||
|
inputData.normalWS = TransformTangentToWorld(normalTS, inputData.tangentToWorld);
|
||
|
#else
|
||
|
inputData.normalWS = inputData.normalWS;
|
||
|
#endif
|
||
|
surfaceData.normalTS = normalTS;
|
||
|
changed = true;
|
||
|
}
|
||
|
|
||
|
return changed;
|
||
|
}
|
||
|
|
||
|
bool CalculateValidationMetallic(half3 albedo, half metallic, inout half4 debugColor)
|
||
|
{
|
||
|
if (metallic < _DebugValidateMetallicMinValue)
|
||
|
{
|
||
|
debugColor = _DebugValidateBelowMinThresholdColor;
|
||
|
}
|
||
|
else if (metallic > _DebugValidateMetallicMaxValue)
|
||
|
{
|
||
|
debugColor = _DebugValidateAboveMaxThresholdColor;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
half luminance = Luminance(albedo);
|
||
|
|
||
|
debugColor = half4(luminance, luminance, luminance, 1);
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool CalculateValidationColorForDebug(in InputData inputData, in SurfaceData surfaceData, inout half4 debugColor)
|
||
|
{
|
||
|
switch(_DebugMaterialValidationMode)
|
||
|
{
|
||
|
case DEBUGMATERIALVALIDATIONMODE_NONE:
|
||
|
return false;
|
||
|
|
||
|
case DEBUGMATERIALVALIDATIONMODE_ALBEDO:
|
||
|
return CalculateValidationAlbedo(surfaceData.albedo, debugColor);
|
||
|
|
||
|
case DEBUGMATERIALVALIDATIONMODE_METALLIC:
|
||
|
return CalculateValidationMetallic(surfaceData.albedo, surfaceData.metallic, debugColor);
|
||
|
|
||
|
default:
|
||
|
return TryGetDebugColorInvalidMode(debugColor);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
float3 GetRenderingLayerMasksDebugColor(float4 positionCS, float3 normalWS)
|
||
|
{
|
||
|
uint stripeSize = 8;
|
||
|
int renderingLayers = GetMeshRenderingLayer() & _DebugRenderingLayerMask;
|
||
|
uint layerId = 0, layerCount = countbits(renderingLayers);
|
||
|
float4 debugColor = float4(1, 1, 1, 1);
|
||
|
for (uint i = 0; (i < 32) && (layerId < layerCount); i++)
|
||
|
{
|
||
|
if (renderingLayers & (1U << i))
|
||
|
{
|
||
|
uint t = (positionCS.y / stripeSize) % layerCount;
|
||
|
if (t == layerId)
|
||
|
debugColor.rgb = _DebugRenderingLayerMaskColors[i].rgb;
|
||
|
layerId++;
|
||
|
}
|
||
|
}
|
||
|
float shading = saturate(dot(normalWS, TransformViewToWorldDir(float3(0.0f, 0.0f, 1.0f), true)));
|
||
|
shading = Remap(0.0f, 1.0f, 0.6, 1.0f, shading);
|
||
|
return shading * debugColor.xyz;
|
||
|
}
|
||
|
|
||
|
bool CalculateColorForDebugMaterial(in InputData inputData, in SurfaceData surfaceData, inout half4 debugColor)
|
||
|
{
|
||
|
// Debug materials...
|
||
|
switch(_DebugMaterialMode)
|
||
|
{
|
||
|
case DEBUGMATERIALMODE_NONE:
|
||
|
return false;
|
||
|
|
||
|
case DEBUGMATERIALMODE_ALBEDO:
|
||
|
debugColor = half4(surfaceData.albedo, 1);
|
||
|
return true;
|
||
|
|
||
|
case DEBUGMATERIALMODE_SPECULAR:
|
||
|
debugColor = half4(surfaceData.specular, 1);
|
||
|
return true;
|
||
|
|
||
|
case DEBUGMATERIALMODE_ALPHA:
|
||
|
debugColor = half4(surfaceData.alpha.rrr, 1);
|
||
|
return true;
|
||
|
|
||
|
case DEBUGMATERIALMODE_SMOOTHNESS:
|
||
|
debugColor = half4(surfaceData.smoothness.rrr, 1);
|
||
|
return true;
|
||
|
|
||
|
case DEBUGMATERIALMODE_AMBIENT_OCCLUSION:
|
||
|
debugColor = half4(surfaceData.occlusion.rrr, 1);
|
||
|
return true;
|
||
|
|
||
|
case DEBUGMATERIALMODE_EMISSION:
|
||
|
debugColor = half4(surfaceData.emission, 1);
|
||
|
return true;
|
||
|
|
||
|
case DEBUGMATERIALMODE_NORMAL_WORLD_SPACE:
|
||
|
debugColor = half4(inputData.normalWS.xyz * 0.5 + 0.5, 1);
|
||
|
return true;
|
||
|
|
||
|
case DEBUGMATERIALMODE_NORMAL_TANGENT_SPACE:
|
||
|
debugColor = half4(surfaceData.normalTS.xyz * 0.5 + 0.5, 1);
|
||
|
return true;
|
||
|
|
||
|
case DEBUGMATERIALMODE_METALLIC:
|
||
|
debugColor = half4(surfaceData.metallic.rrr, 1);
|
||
|
return true;
|
||
|
|
||
|
case DEBUGMATERIALMODE_RENDERING_LAYER_MASKS:
|
||
|
debugColor.xyz = GetRenderingLayerMasksDebugColor(inputData.positionCS, inputData.normalWS).xyz;
|
||
|
return true;
|
||
|
|
||
|
default:
|
||
|
return TryGetDebugColorInvalidMode(debugColor);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool CalculateColorForDebugMipmapStreaming(in InputData inputData, in SurfaceData surfaceData, inout half4 debugColor)
|
||
|
{
|
||
|
return CalculateColorForDebugMipmapStreaming(inputData.mipCount, inputData.positionCS.xy, inputData.texelSize, inputData.uv, inputData.mipInfo, inputData.streamInfo, inputData.originalColor, debugColor);
|
||
|
}
|
||
|
|
||
|
bool CalculateColorForDebug(in InputData inputData, in SurfaceData surfaceData, inout half4 debugColor)
|
||
|
{
|
||
|
if (CalculateColorForDebugSceneOverride(debugColor))
|
||
|
{
|
||
|
return true;
|
||
|
}
|
||
|
else if (CalculateColorForDebugMipmapStreaming(inputData, surfaceData, debugColor))
|
||
|
{
|
||
|
return true;
|
||
|
}
|
||
|
else if (CalculateColorForDebugMaterial(inputData, surfaceData, debugColor))
|
||
|
{
|
||
|
return true;
|
||
|
}
|
||
|
else if (CalculateValidationColorForDebug(inputData, surfaceData, debugColor))
|
||
|
{
|
||
|
return true;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
half3 CalculateDebugShadowCascadeColor(in InputData inputData)
|
||
|
{
|
||
|
float3 positionWS = inputData.positionWS;
|
||
|
half cascadeIndex = ComputeCascadeIndex(positionWS);
|
||
|
|
||
|
switch (uint(cascadeIndex))
|
||
|
{
|
||
|
case 0: return kDebugColorShadowCascade0.rgb;
|
||
|
case 1: return kDebugColorShadowCascade1.rgb;
|
||
|
case 2: return kDebugColorShadowCascade2.rgb;
|
||
|
case 3: return kDebugColorShadowCascade3.rgb;
|
||
|
default: return kDebugColorBlack.rgb;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
half4 CalculateDebugLightingComplexityColor(in InputData inputData, in SurfaceData surfaceData)
|
||
|
{
|
||
|
#if USE_FORWARD_PLUS
|
||
|
int numLights = URP_FP_DIRECTIONAL_LIGHTS_COUNT;
|
||
|
uint entityIndex;
|
||
|
ClusterIterator it = ClusterInit(inputData.normalizedScreenSpaceUV, inputData.positionWS, 0);
|
||
|
[loop] while (ClusterNext(it, entityIndex))
|
||
|
{
|
||
|
numLights++;
|
||
|
}
|
||
|
it = ClusterInit(inputData.normalizedScreenSpaceUV, inputData.positionWS, 1);
|
||
|
[loop] while (ClusterNext(it, entityIndex))
|
||
|
{
|
||
|
numLights++;
|
||
|
}
|
||
|
#else
|
||
|
// Assume a main light and add 1 to the additional lights.
|
||
|
int numLights = GetAdditionalLightsCount() + 1;
|
||
|
#endif
|
||
|
|
||
|
const uint2 tileSize = uint2(32,32);
|
||
|
const uint maxLights = 9;
|
||
|
const float opacity = 0.8f;
|
||
|
|
||
|
uint2 pixelCoord = uint2(inputData.normalizedScreenSpaceUV * _ScreenParams.xy);
|
||
|
half3 base = surfaceData.albedo;
|
||
|
half4 overlay = half4(OverlayHeatMap(pixelCoord, tileSize, numLights, maxLights, opacity));
|
||
|
|
||
|
uint2 tileCoord = (float2)pixelCoord / tileSize;
|
||
|
uint2 offsetInTile = pixelCoord - tileCoord * tileSize;
|
||
|
bool border = any(offsetInTile == 0 || offsetInTile == tileSize.x - 1);
|
||
|
if (border)
|
||
|
overlay = half4(1, 1, 1, 0.4f);
|
||
|
|
||
|
return half4(lerp(base.rgb, overlay.rgb, overlay.a), 1);
|
||
|
}
|
||
|
|
||
|
bool CanDebugOverrideOutputColor(inout InputData inputData, inout SurfaceData surfaceData, inout BRDFData brdfData, inout half4 debugColor)
|
||
|
{
|
||
|
if (_DebugMaterialMode == DEBUGMATERIALMODE_LIGHTING_COMPLEXITY)
|
||
|
{
|
||
|
debugColor = CalculateDebugLightingComplexityColor(inputData, surfaceData);
|
||
|
return true;
|
||
|
}
|
||
|
else if (_DebugLightingMode == DEBUGLIGHTINGMODE_GLOBAL_ILLUMINATION)
|
||
|
{
|
||
|
debugColor = half4(inputData.bakedGI, surfaceData.alpha);
|
||
|
return true;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
debugColor = half4(0, 0, 0, 1);
|
||
|
|
||
|
if (_DebugLightingMode == DEBUGLIGHTINGMODE_SHADOW_CASCADES)
|
||
|
{
|
||
|
surfaceData.albedo = CalculateDebugShadowCascadeColor(inputData);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (UpdateSurfaceAndInputDataForDebug(surfaceData, inputData))
|
||
|
{
|
||
|
// If we've modified any data we'll need to re-sample the GI to ensure that everything works correctly...
|
||
|
#if defined(DYNAMICLIGHTMAP_ON)
|
||
|
inputData.bakedGI = SAMPLE_GI(inputData.staticLightmapUV, inputData.dynamicLightmapUV.xy, inputData.vertexSH, inputData.normalWS);
|
||
|
#elif !defined(LIGHTMAP_ON) && (defined(PROBE_VOLUMES_L1) || defined(PROBE_VOLUMES_L2))
|
||
|
inputData.bakedGI = SAMPLE_GI(inputData.vertexSH,
|
||
|
GetAbsolutePositionWS(inputData.positionWS),
|
||
|
inputData.normalWS,
|
||
|
inputData.viewDirectionWS,
|
||
|
inputData.positionCS.xy,
|
||
|
inputData.probeOcclusion,
|
||
|
inputData.shadowMask);
|
||
|
#else
|
||
|
inputData.bakedGI = SAMPLE_GI(inputData.staticLightmapUV, inputData.vertexSH, inputData.normalWS);
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Update the BRDF data following any changes to the input/surface above...
|
||
|
InitializeBRDFData(surfaceData, brdfData);
|
||
|
|
||
|
return CalculateColorForDebug(inputData, surfaceData, debugColor);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool CanDebugOverrideOutputColor(inout InputData inputData, inout SurfaceData surfaceData, inout half4 debugColor)
|
||
|
{
|
||
|
if (_DebugMaterialMode == DEBUGMATERIALMODE_LIGHTING_COMPLEXITY)
|
||
|
{
|
||
|
debugColor = CalculateDebugLightingComplexityColor(inputData, surfaceData);
|
||
|
return true;
|
||
|
}
|
||
|
else if (_DebugLightingMode == DEBUGLIGHTINGMODE_GLOBAL_ILLUMINATION)
|
||
|
{
|
||
|
debugColor = half4(inputData.bakedGI, surfaceData.alpha);
|
||
|
return true;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (_DebugLightingMode == DEBUGLIGHTINGMODE_SHADOW_CASCADES)
|
||
|
{
|
||
|
surfaceData.albedo = CalculateDebugShadowCascadeColor(inputData);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (UpdateSurfaceAndInputDataForDebug(surfaceData, inputData))
|
||
|
{
|
||
|
// If we've modified any data we'll need to re-sample the GI to ensure that everything works correctly...
|
||
|
#if defined(DYNAMICLIGHTMAP_ON)
|
||
|
inputData.bakedGI = SAMPLE_GI(inputData.staticLightmapUV, inputData.dynamicLightmapUV.xy, inputData.vertexSH, inputData.normalWS);
|
||
|
#elif !defined(LIGHTMAP_ON) && (defined(PROBE_VOLUMES_L1) || defined(PROBE_VOLUMES_L2))
|
||
|
inputData.bakedGI = SAMPLE_GI(inputData.vertexSH,
|
||
|
GetAbsolutePositionWS(inputData.positionWS),
|
||
|
inputData.normalWS,
|
||
|
inputData.viewDirectionWS,
|
||
|
inputData.positionCS.xy,
|
||
|
inputData.probeOcclusion,
|
||
|
inputData.shadowMask);
|
||
|
#else
|
||
|
inputData.bakedGI = SAMPLE_GI(inputData.staticLightmapUV, inputData.vertexSH, inputData.normalWS);
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return CalculateColorForDebug(inputData, surfaceData, debugColor);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#else
|
||
|
|
||
|
// When "DEBUG_DISPLAY" isn't defined this macro does nothing - there's no debug-data to set-up...
|
||
|
#define SETUP_DEBUG_TEXTURE_DATA(inputData, uv)
|
||
|
#define SETUP_DEBUG_TEXTURE_DATA_NO_UV(inputData)
|
||
|
#define SETUP_DEBUG_TEXTURE_DATA_FOR_TEX(inputData, uv, texture)
|
||
|
#define SETUP_DEBUG_TEXTURE_DATA_FOR_TERRAIN(inputData)
|
||
|
|
||
|
#endif
|
||
|
|
||
|
#endif
|