Add utility function to GUICommon.hlsl for MSDF fonts sampling in shaders

#3944
This commit is contained in:
Wojtek Figat
2026-03-12 20:24:03 +01:00
parent 48d86ac7ae
commit 88587fb6a4
4 changed files with 51 additions and 22 deletions

Binary file not shown.

View File

@@ -77,7 +77,7 @@ API_ENUM() enum class FontRasterMode : byte
Bitmap,
/// <summary>
/// Use the MSDF generator to render font atlases. Need to be rendered with a compatible material.
/// Use the Multi-channel Signed Distance Field (MSDF) generator to render font atlases. Need to be rendered with a compatible material.
/// </summary>
MSDF,
};
@@ -92,7 +92,7 @@ API_STRUCT() struct FontOptions
DECLARE_SCRIPTING_TYPE_MINIMAL(FontOptions);
/// <summary>
/// The hinting.
/// The font hinting used when rendering characters.
/// </summary>
API_FIELD() FontHinting Hinting;
@@ -102,7 +102,7 @@ API_STRUCT() struct FontOptions
API_FIELD() FontFlags Flags;
/// <summary>
/// The rasterization mode.
/// The font rasterization mode.
/// </summary>
API_FIELD() FontRasterMode RasterMode;
};

View File

@@ -92,7 +92,7 @@ float4 PS_Font(VS2PS input) : SV_Target0
PerformClipping(input);
float4 color = input.Color;
color.a *= Image.Sample(SamplerLinearClamp, input.TexCoord).r;
color.a *= SampleFont(Image, input.TexCoord);
return color;
}
@@ -102,22 +102,8 @@ float4 PS_FontMSDF(VS2PS input) : SV_Target0
PerformClipping(input);
float4 color = input.Color;
float3 msd = Image.Sample(SamplerLinearClamp, input.TexCoord).rgb;
float sd = max(min(msd.r, msd.g), min(max(msd.r, msd.g), msd.b));
uint width, height;
Image.GetDimensions(width, height);
float pxRange = 4.0f; // Must match C++ code
float unitRange = float2(pxRange, pxRange) / float2(width, height);
float2 dx = ddx(input.TexCoord);
float2 dy = ddy(input.TexCoord);
float2 screenTexSize = rsqrt(dx * dx + dy * dy);
float screenPxRange = max(0.5f * dot(screenTexSize, unitRange), 1.0f);
float screenPxDist = screenPxRange * (sd - 0.5f);
float opacity = saturate(screenPxDist + 0.5f);
return float4(color.rgb, opacity);
color.a *= SampleFontMSDF(Image, input.TexCoord);
return color;
}
float4 GetSample(float weight, float offset, float2 uv)

View File

@@ -54,4 +54,47 @@ void PerformClipping(VS2PS input)
PerformClipping(input.ClipOriginAndPos.xy, input.ClipOriginAndPos.zw, input.ClipExtents);
}
float SampleFont(Texture2D font, float2 uv)
{
return font.Sample(SamplerLinearClamp, uv).r;
}
float GetFontMSDFMedian(Texture2D font, float2 uv)
{
float4 msd = font.Sample(SamplerLinearClamp, uv);
return max(min(msd.r, msd.g), min(max(msd.r, msd.g), msd.b));
}
float GetFontMSDFPixelRange(Texture2D font, float2 uv)
{
uint width, height;
font.GetDimensions(width, height);
float pxRange = 4.0f; // Must match C++ code
float unitRange = float2(pxRange, pxRange) / float2(width, height);
float2 dx = ddx(uv);
float2 dy = ddy(uv);
float2 screenTexSize = rsqrt(dx * dx + dy * dy);
return max(0.5f * dot(screenTexSize, unitRange), 1.0f);
}
float SampleFontMSDF(Texture2D font, float2 uv)
{
float sd = GetFontMSDFMedian(font, uv);
float screenPxRange = GetFontMSDFPixelRange(font, uv);
float screenPxDist = screenPxRange * (sd - 0.5f);
return saturate(screenPxDist + 0.5f);
}
float SampleFontMSDFOutline(Texture2D font, float2 uv, float thickness)
{
float4 msd = font.Sample(SamplerLinearClamp, uv);
float sd = max(min(msd.r, msd.g), min(max(msd.r, msd.g), msd.b));
float screenPxRange = GetFontMSDFPixelRange(font, uv);
float thick = clamp(thickness, 0.0, screenPxRange * 0.5 - 1.0) / screenPxRange;
float outline = saturate((min(sd, msd.a) - 0.5 + thick) * screenPxRange + 0.5);
outline *= 1 - saturate(screenPxRange * (sd - 0.5f) + 0.5f);
return outline;
}
#endif