Draw low quality text for custom UI that is directly part of the game. (#434)

This commit is contained in:
Skyth (Asilkan)
2025-02-20 17:18:27 +03:00
committed by GitHub
parent 0afd01ff7e
commit ba522c0e42
11 changed files with 144 additions and 64 deletions

View File

@@ -11,6 +11,7 @@
#define IMGUI_SHADER_MODIFIER_TITLE_BEVEL 8
#define IMGUI_SHADER_MODIFIER_CATEGORY_BEVEL 9
#define IMGUI_SHADER_MODIFIER_RECTANGLE_BEVEL 10
#define IMGUI_SHADER_MODIFIER_LOW_QUALITY_TEXT 11
#ifdef __cplusplus

View File

@@ -12,6 +12,7 @@ struct PushConstants
uint GradientBottomLeft;
uint ShaderModifier;
uint Texture2DDescriptorIndex;
float2 DisplaySize;
float2 InverseDisplaySize;
float2 Origin;
float2 Scale;

View File

@@ -61,10 +61,10 @@ float4 SampleLinear(float2 uvTexspace)
float4 PixelAntialiasing(float2 uvTexspace)
{
if ((g_PushConstants.InverseDisplaySize.y / g_PushConstants.InverseDisplaySize.x) >= (4.0 / 3.0))
uvTexspace *= g_PushConstants.InverseDisplaySize.y * 720.0f;
if ((g_PushConstants.DisplaySize.x * g_PushConstants.InverseDisplaySize.y) >= (4.0 / 3.0))
uvTexspace *= g_PushConstants.InverseDisplaySize.y * 720.0;
else
uvTexspace *= g_PushConstants.InverseDisplaySize.x * 960.0f;
uvTexspace *= g_PushConstants.InverseDisplaySize.x * 960.0;
float2 seam = floor(uvTexspace + 0.5);
uvTexspace = (uvTexspace - seam) / fwidth(uvTexspace) + seam;
@@ -78,6 +78,51 @@ float median(float r, float g, float b)
return max(min(r, g), min(max(r, g), b));
}
float4 SampleSdfFont(float4 color, Texture2D<float4> texture, float2 uv, float2 screenTexSize)
{
float4 textureColor = texture.Sample(g_SamplerDescriptorHeap[0], uv);
uint width, height;
texture.GetDimensions(width, height);
float pxRange = 8.0;
float2 unitRange = pxRange / float2(width, height);
float screenPxRange = max(0.5 * dot(unitRange, screenTexSize), 1.0);
float sd = median(textureColor.r, textureColor.g, textureColor.b) - 0.5;
float screenPxDistance = screenPxRange * (sd + g_PushConstants.Outline / (pxRange * 2.0));
if (g_PushConstants.ShaderModifier == IMGUI_SHADER_MODIFIER_TITLE_BEVEL)
{
float2 normal = normalize(float3(ddx(sd), ddy(sd), 0.01)).xy;
float3 rimColor = float3(1, 0.8, 0.29);
float3 shadowColor = float3(0.84, 0.57, 0);
float cosTheta = dot(normal, normalize(float2(1, 1)));
float3 gradient = lerp(color.rgb, cosTheta >= 0.0 ? rimColor : shadowColor, abs(cosTheta));
color.rgb = lerp(gradient, color.rgb, pow(saturate(sd + 0.8), 32.0));
}
else if (g_PushConstants.ShaderModifier == IMGUI_SHADER_MODIFIER_CATEGORY_BEVEL)
{
float2 normal = normalize(float3(ddx(sd), ddy(sd), 0.25)).xy;
float cosTheta = dot(normal, normalize(float2(1, 1)));
float gradient = 1.0 + cosTheta * 0.5;
color.rgb = saturate(color.rgb * gradient);
}
else if (g_PushConstants.ShaderModifier == IMGUI_SHADER_MODIFIER_TEXT_SKEW)
{
float2 normal = normalize(float3(ddx(sd), ddy(sd), 0.5)).xy;
float cosTheta = dot(normal, normalize(float2(1, 1)));
float gradient = saturate(1.0 + cosTheta);
color.rgb = lerp(color.rgb * gradient, color.rgb, pow(saturate(sd + 0.77), 32.0));
}
color.a *= saturate(screenPxDistance + 0.5);
color.a *= textureColor.a;
return color;
}
float4 main(in Interpolators interpolators) : SV_Target
{
float4 color = interpolators.Color;
@@ -86,52 +131,50 @@ float4 main(in Interpolators interpolators) : SV_Target
if (g_PushConstants.Texture2DDescriptorIndex != 0)
{
Texture2D<float4> texture = g_Texture2DDescriptorHeap[g_PushConstants.Texture2DDescriptorIndex & 0x7FFFFFFF];
float4 textureColor = texture.Sample(g_SamplerDescriptorHeap[0], interpolators.UV);
if ((g_PushConstants.Texture2DDescriptorIndex & 0x80000000) != 0)
{
uint width, height;
texture.GetDimensions(width, height);
float pxRange = 8.0;
float2 unitRange = pxRange / float2(width, height);
float2 screenTexSize = 1.0 / fwidth(interpolators.UV);
float screenPxRange = max(0.5 * dot(unitRange, screenTexSize), 1.0);
float sd = median(textureColor.r, textureColor.g, textureColor.b) - 0.5;
float screenPxDistance = screenPxRange * (sd + g_PushConstants.Outline / (pxRange * 2.0));
if (g_PushConstants.ShaderModifier == IMGUI_SHADER_MODIFIER_TITLE_BEVEL)
if (g_PushConstants.ShaderModifier == IMGUI_SHADER_MODIFIER_LOW_QUALITY_TEXT)
{
float2 normal = normalize(float3(ddx(sd), ddy(sd), 0.01)).xy;
float3 rimColor = float3(1, 0.8, 0.29);
float3 shadowColor = float3(0.84, 0.57, 0);
float cosTheta = dot(normal, normalize(float2(1, 1)));
float3 gradient = lerp(color.rgb, cosTheta >= 0.0 ? rimColor : shadowColor, abs(cosTheta));
color.rgb = lerp(gradient, color.rgb, pow(saturate(sd + 0.8), 32.0));
float scale;
float invScale;
if ((g_PushConstants.DisplaySize.x * g_PushConstants.InverseDisplaySize.y) >= (4.0 / 3.0))
{
scale = g_PushConstants.InverseDisplaySize.y * 720.0;
invScale = g_PushConstants.DisplaySize.y / 720.0;
}
else
{
scale = g_PushConstants.InverseDisplaySize.x * 960.0;
invScale = g_PushConstants.DisplaySize.x / 960.0;
}
float2 lowQualityPosition = (interpolators.Position.xy - 0.5) * scale;
float2 fracPart = frac(lowQualityPosition);
float2 uvStep = fwidth(interpolators.UV) * invScale;
float2 lowQualityUV = interpolators.UV - fracPart * uvStep;
float2 screenTexSize = 1.0 / uvStep;
float4 topLeft = SampleSdfFont(color, texture, lowQualityUV + float2(0, 0), screenTexSize);
float4 topRight = SampleSdfFont(color, texture, lowQualityUV + float2(uvStep.x, 0), screenTexSize);
float4 bottomLeft = SampleSdfFont(color, texture, lowQualityUV + float2(0, uvStep.y), screenTexSize);
float4 bottomRight = SampleSdfFont(color, texture, lowQualityUV + uvStep.xy, screenTexSize);
float4 top = lerp(topLeft, topRight, fracPart.x);
float4 bottom = lerp(bottomLeft, bottomRight, fracPart.x);
color = lerp(top, bottom, fracPart.y);
}
else if (g_PushConstants.ShaderModifier == IMGUI_SHADER_MODIFIER_CATEGORY_BEVEL)
else
{
float2 normal = normalize(float3(ddx(sd), ddy(sd), 0.25)).xy;
float cosTheta = dot(normal, normalize(float2(1, 1)));
float gradient = 1.0 + cosTheta * 0.5;
color.rgb = saturate(color.rgb * gradient);
color = SampleSdfFont(color, texture, interpolators.UV, 1.0 / fwidth(interpolators.UV));
}
else if (g_PushConstants.ShaderModifier == IMGUI_SHADER_MODIFIER_TEXT_SKEW)
{
float2 normal = normalize(float3(ddx(sd), ddy(sd), 0.5)).xy;
float cosTheta = dot(normal, normalize(float2(1, 1)));
float gradient = saturate(1.0 + cosTheta);
color.rgb = lerp(color.rgb * gradient, color.rgb, pow(saturate(sd + 0.77), 32.0));
}
color.a *= saturate(screenPxDistance + 0.5);
color.a *= textureColor.a;
}
else
{
color *= textureColor;
color *= texture.Sample(g_SamplerDescriptorHeap[0], interpolators.UV);
}
}

View File

@@ -1340,6 +1340,7 @@ struct ImGuiPushConstants
ImU32 gradientBottomLeft{};
uint32_t shaderModifier{};
uint32_t texture2DDescriptorIndex{};
ImVec2 displaySize{};
ImVec2 inverseDisplaySize{};
ImVec2 origin{ 0.0f, 0.0f };
ImVec2 scale{ 1.0f, 1.0f };
@@ -2496,6 +2497,7 @@ static void ProcDrawImGui(const RenderCommand& cmd)
commandList->setViewports(RenderViewport(drawData.DisplayPos.x, drawData.DisplayPos.y, drawData.DisplaySize.x, drawData.DisplaySize.y));
ImGuiPushConstants pushConstants{};
pushConstants.displaySize = drawData.DisplaySize;
pushConstants.inverseDisplaySize = { 1.0f / drawData.DisplaySize.x, 1.0f / drawData.DisplaySize.y };
commandList->setGraphicsPushConstants(0, &pushConstants);