/* * 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 #include #include #include #include #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 m_lightCount; Texture2D m_framebuffer; Texture2D 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; }