You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Gems/Atom/Feature/Common/Assets/Shaders/LightCulling/LightCullingHeatmap.azsl

255 lines
7.0 KiB
Plaintext

/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
// The heatmap will change color as the light count increases up to TileCountMax
static const int TileCountMax = 75;
static const int OverflowDisplayNumber = 999;
static const float3 BarelyUsedColor = float3(0.05, 0.05, 0.20); // Deep dark blue
static const float3 LightlyUsedColor = float3(0.05, 0.05, 0.60); // Deep blue
static const float3 ModeratelyUsedColor = float3(0.05, 0.60, 0.05); // Green
static const float3 HeavilyUsedColor = float3(1.00, 1.00, 0.05); // Yellow
static const float3 OverUsedColor = float3(1.00, 0.05, 0.05); // Red
static const float3 OverflowColor = float3(1.0, 1.0, 1.0); // White
#include <Atom/Features/SrgSemantics.azsli>
#include <Atom/Features/PostProcessing/FullscreenPixelInfo.azsli>
#include <Atom/Features/PostProcessing/FullscreenVertex.azsli>
#include <Atom/Features/PostProcessing/PostProcessUtil.azsli>
#include <Atom/Features/LightCulling/LightCullingShared.azsli>
#define X 1
#define _ 0
#define PACK_GLYPH_UINT(a, b, c, d) ((d << 3) | (c << 2) | (b << 1) | a)
#define CHAR_W 4
#define GLYPH_HEIGHT 6
#define MAX_CHARS 10
static const uint NumberGlyphs[GLYPH_HEIGHT * MAX_CHARS] =
{
// Glpyh for the number 0
PACK_GLYPH_UINT(_, X, X, _),
PACK_GLYPH_UINT(X, _, _, X),
PACK_GLYPH_UINT(X, _, _, X),
PACK_GLYPH_UINT(X, _, _, X),
PACK_GLYPH_UINT(X, _, _, X),
PACK_GLYPH_UINT(_, X, X, _),
// Glpyh for the number 1
PACK_GLYPH_UINT(_, _, _, X),
PACK_GLYPH_UINT(_, _, _, X),
PACK_GLYPH_UINT(_, _, _, X),
PACK_GLYPH_UINT(_, _, _, X),
PACK_GLYPH_UINT(_, _, _, X),
PACK_GLYPH_UINT(_, _, _, X),
// Glpyh for the number 2
PACK_GLYPH_UINT(X, X, X, _),
PACK_GLYPH_UINT(_, _, _, X),
PACK_GLYPH_UINT(X, X, X, X),
PACK_GLYPH_UINT(X, _, _, _),
PACK_GLYPH_UINT(X, _, _, _),
PACK_GLYPH_UINT(X, X, X, X),
// Glpyh for the number 3
PACK_GLYPH_UINT(X, X, X, _),
PACK_GLYPH_UINT(_, _, _, X),
PACK_GLYPH_UINT(_, X, X, X),
PACK_GLYPH_UINT(_, _, _, X),
PACK_GLYPH_UINT(_, _, _, X),
PACK_GLYPH_UINT(X, X, X, _),
// Glpyh for the number 4
PACK_GLYPH_UINT(X, _, _, X),
PACK_GLYPH_UINT(X, _, _, X),
PACK_GLYPH_UINT(X, X, X, X),
PACK_GLYPH_UINT(_, _, _, X),
PACK_GLYPH_UINT(_, _, _, X),
PACK_GLYPH_UINT(_, _, _, X),
// Glpyh for the number 5
PACK_GLYPH_UINT(X, X, X, _),
PACK_GLYPH_UINT(X, _, _, _),
PACK_GLYPH_UINT(X, X, X, X),
PACK_GLYPH_UINT(_, _, _, X),
PACK_GLYPH_UINT(_, _, _, X),
PACK_GLYPH_UINT(X, X, X, X),
// Glpyh for the number 6
PACK_GLYPH_UINT(_, X, X, X),
PACK_GLYPH_UINT(X, _, _, _),
PACK_GLYPH_UINT(X, X, X, X),
PACK_GLYPH_UINT(X, _, _, X),
PACK_GLYPH_UINT(X, _, _, X),
PACK_GLYPH_UINT(X, X, X, _),
// Glpyh for the number 7
PACK_GLYPH_UINT(_, X, X, X),
PACK_GLYPH_UINT(_, _, _, X),
PACK_GLYPH_UINT(_, _, _, X),
PACK_GLYPH_UINT(_, _, _, X),
PACK_GLYPH_UINT(_, _, _, X),
PACK_GLYPH_UINT(_, _, _, X),
// Glpyh for the number 8
PACK_GLYPH_UINT(X, X, X, X),
PACK_GLYPH_UINT(X, _, _, X),
PACK_GLYPH_UINT(X, X, X, X),
PACK_GLYPH_UINT(X, _, _, X),
PACK_GLYPH_UINT(X, _, _, X),
PACK_GLYPH_UINT(X, X, X, X),
// Glpyh for the number 9
PACK_GLYPH_UINT(X, X, X, X),
PACK_GLYPH_UINT(X, _, _, X),
PACK_GLYPH_UINT(X, X, X, X),
PACK_GLYPH_UINT(_, _, _, X),
PACK_GLYPH_UINT(_, _, _, X),
PACK_GLYPH_UINT(X, X, X, _),
};
#define IS_UNINITIALIZED 0x0
#define IS_BACKGROUND 0x1
#define IS_FOREGROUND 0x2
#define PRINT_ITERATION(ch) \
{ \
r.x += r.z; \
if( r.x < r.z ) \
{ \
r.xy /= scale; \
mask = (NumberGlyphs[r.y + ch * GLYPH_HEIGHT] & (1 << r.x)) != 0 ? IS_FOREGROUND : IS_BACKGROUND; \
} \
}
uint4 InitPrintCoords(uint2 uv, uint2 origin, uint scale)
{
uint4 r;
r.xy = uv - origin;
r.zw = uint2(CHAR_W + 1, GLYPH_HEIGHT) * scale;
return r;
}
uint PrintNumbersInsideTileImpl(inout uint4 r, uint x, uint scale)
{
uint mask = IS_UNINITIALIZED;
while( x > 0 && mask == IS_UNINITIALIZED )
{
uint n = x % 10;
x /= 10;
PRINT_ITERATION(n);
}
return mask;
}
uint PrintNumbersInsideTile(uint x, uint2 origin, uint2 uv, uint scale)
{
uint4 r = InitPrintCoords(uv, origin, scale);
uint mask = IS_UNINITIALIZED;
if( r.y < r.w )
{
mask = PrintNumbersInsideTileImpl(r, x, scale);
}
return mask;
}
float3 ComputeTileColor(const uint2 uv, const uint print_me, const bool overflow)
{
int2 local_uv = int2( uv % uint2(TILE_DIM_X, TILE_DIM_Y) );
float x = float(print_me) / float(TileCountMax);
x = sqrt(x);
x = saturate(x);
float3 color;
if (overflow)
{
color = OverflowColor;
}
else if( x <= 0.0 )
{
color = float3(0.0, 0.0, 0.0);
}
else if( x >= 1.0 )
{
color = OverUsedColor;
}
else
{
color = lerp(BarelyUsedColor, LightlyUsedColor, saturate((x - 0.00) * 4.0));
color = lerp(color, ModeratelyUsedColor, saturate((x - 0.33) * 4.0));
color = lerp(color, HeavilyUsedColor, saturate((x - 0.66) * 4.0));
}
float border = (local_uv.x == TILE_DIM_X - 1 || local_uv.y == TILE_DIM_Y - 1) ? 1.0 : 0.0;
color *= lerp(1.0, 0.75, border);
// NOTE: numbers
uint mask = PrintNumbersInsideTile(print_me, uint2(TILE_DIM_X - 1, 1), local_uv, 1);
if( (mask & IS_FOREGROUND) != 0 )
{
color = float3(0.0, 0.0, 0.0);
}
return color;
}
ShaderResourceGroup PassSrg : SRG_PerPass
{
Texture2D<uint> m_lightCount;
Texture2D<float4> m_framebuffer;
Texture2D<uint4> m_tileLightData;
float m_heatmapOpacity;
}
PSOutput MainPS(VSOutput IN)
{
const uint2 tileId = ComputeTileId(IN.m_position.xy);
const uint tileLightDataW = PassSrg::m_tileLightData[tileId].w;
// check to see if we are overflowing the number of lights per tile
// expect the lighting to flicker if this happens
const bool overflow = (tileLightDataW >> 31);
// We subtract NUM_LIGHT_TYPES because it includes termination markers
const uint lightCount = overflow ? OverflowDisplayNumber : tileLightDataW - NUM_LIGHT_TYPES;
const float3 tileColor = ComputeTileColor(IN.m_position.xy, lightCount, overflow);
PSOutput OUT;
OUT.m_color.rgb = tileColor;
// Set this value to > 0 to actually see this pass. It is currently always active.
OUT.m_color.w = PassSrg::m_heatmapOpacity;
// ATOM-3682 (improve heatmap integration with the pass system)
return OUT;
}