font sharpness computed in screen space (#751)

This commit is contained in:
Turánszki János
2023-09-22 19:38:06 +02:00
committed by GitHub
parent 820c042050
commit 2e3029887f
7 changed files with 66 additions and 26 deletions
+9 -2
View File
@@ -12,6 +12,13 @@ struct FontVertex
float2 uv;
};
namespace SDF
{
static const uint padding = 5;
static const uint onedge_value = 127;
static const float onedge_value_unorm = float(onedge_value) / 255.0f;
static const float pixel_dist_scale = float(onedge_value) / float(padding);
}
struct FontConstants
{
int buffer_index;
@@ -19,8 +26,8 @@ struct FontConstants
int texture_index;
uint color;
float sdf_threshold_top;
float sdf_threshold_bottom;
float softness;
float bolden;
uint flags;
float hdr_scaling;
+10 -2
View File
@@ -5,17 +5,25 @@ struct VertextoPixel
{
float4 pos : SV_Position;
float2 uv : TEXCOORD0;
float2 bary : TEXCOORD1;
};
float4 main(VertextoPixel input) : SV_TARGET
{
float value = bindless_textures[font.texture_index].SampleLevel(sampler_linear_clamp, input.uv, 0).r;
Texture2D tex = bindless_textures[font.texture_index];
float value = tex.SampleLevel(sampler_linear_clamp, input.uv, 0).r;
float4 color = unpack_rgba(font.color);
[branch]
if (font.flags & FONT_FLAG_SDF_RENDERING)
{
color.a *= smoothstep(font.sdf_threshold_bottom, font.sdf_threshold_top, value);
float2 bary_fw = fwidth(input.bary);
float w = max(bary_fw.x, bary_fw.y); // screen coverage dependency
w = max(0.005, w); // min softness to avoid pixelated hard edge in magnification
w += font.softness;
w = saturate(w);
float mid = lerp(SDF::onedge_value_unorm, 0, font.bolden);
color.a *= smoothstep(saturate(mid - w), saturate(mid + w), value);
}
else
{
+17
View File
@@ -5,6 +5,7 @@ struct VertextoPixel
{
float4 pos : SV_Position;
float2 uv : TEXCOORD0;
float2 bary : TEXCOORD1;
};
VertextoPixel main(uint vertexID : SV_VertexID, uint instanceID : SV_InstanceID)
@@ -15,5 +16,21 @@ VertextoPixel main(uint vertexID : SV_VertexID, uint instanceID : SV_InstanceID)
VertextoPixel Out;
Out.pos = mul(font.transform, float4(asfloat(vertex.pos), 0, 1));
Out.uv = vertex.uv;
switch (vertexID)
{
default:
case 0:
Out.bary = float2(0, 0);
break;
case 1:
Out.bary = float2(1, 0);
break;
case 2:
Out.bary = float2(0, 1);
break;
case 3:
Out.bary = float2(1, 1);
break;
}
return Out;
}
+27 -19
View File
@@ -95,13 +95,6 @@ namespace wi::font
wi::vector<uint8_t> data;
};
static wi::unordered_map<int32_t, Bitmap> bitmap_lookup;
namespace SDF
{
static constexpr int padding = 5;
static constexpr unsigned char onedge_value = 127;
static constexpr float onedge_value_float = onedge_value / 255.0f;
static constexpr float pixel_dist_scale = float(onedge_value) / float(padding);
}
union GlyphHash
{
struct
@@ -342,6 +335,7 @@ namespace wi::font
{
std::scoped_lock locker(glyphLock);
upscaling = std::max(1.5f, upscaling); // add some minimum upscaling, especially for SDF
static float upscaling_prev = 1;
const float upscaling_rcp = 1.0f / upscaling;
@@ -387,14 +381,34 @@ namespace wi::font
if (is_sdf)
{
unsigned char* data = stbtt_GetGlyphSDF(&fontStyle->fontInfo, fontScaling, glyphIndex, SDF::padding, SDF::onedge_value, SDF::pixel_dist_scale, &bitmap.width, &bitmap.height, &bitmap.xoff, &bitmap.yoff);
unsigned char* data = stbtt_GetGlyphSDF(
&fontStyle->fontInfo,
fontScaling,
glyphIndex,
(int)SDF::padding,
(unsigned char)SDF::onedge_value,
SDF::pixel_dist_scale,
&bitmap.width,
&bitmap.height,
&bitmap.xoff,
&bitmap.yoff
);
bitmap.data.resize(bitmap.width * bitmap.height);
std::memcpy(bitmap.data.data(), data, bitmap.data.size());
stbtt_FreeSDF(data, nullptr);
}
else
{
unsigned char* data = stbtt_GetGlyphBitmap(&fontStyle->fontInfo, fontScaling, fontScaling, glyphIndex, &bitmap.width, &bitmap.height, &bitmap.xoff, &bitmap.yoff);
unsigned char* data = stbtt_GetGlyphBitmap(
&fontStyle->fontInfo,
fontScaling,
fontScaling,
glyphIndex,
&bitmap.width,
&bitmap.height,
&bitmap.xoff,
&bitmap.yoff
);
bitmap.data.resize(bitmap.width * bitmap.height);
std::memcpy(bitmap.data.data(), data, bitmap.data.size());
stbtt_FreeBitmap(data, nullptr);
@@ -612,11 +626,8 @@ namespace wi::font
// font shadow render:
XMStoreFloat4x4(&font.transform, XMMatrixTranslation(params.shadow_offset_x, params.shadow_offset_y, 0) * M);
font.color = params.shadowColor.rgba;
const float boldness = std::max(0.0f, params.shadow_bolden);
const float mid = wi::math::Lerp(SDF::onedge_value_float, 0.0f, boldness);
const float softness = std::max(0.0f, params.shadow_softness);
font.sdf_threshold_bottom = wi::math::saturate(mid - softness);
font.sdf_threshold_top = wi::math::saturate(mid + softness);
font.bolden = params.shadow_bolden;
font.softness = params.shadow_softness;
device->BindDynamicConstantBuffer(font, CBSLOT_FONT, cmd);
device->DrawInstanced(4, status.quadCount, 0, 0, cmd);
@@ -625,11 +636,8 @@ namespace wi::font
// font base render:
XMStoreFloat4x4(&font.transform, M);
font.color = params.color.rgba;
const float boldness = std::max(0.0f, params.bolden);
const float mid = wi::math::Lerp(SDF::onedge_value_float, 0.0f, boldness);
const float softness = std::max(0.0f, params.softness);
font.sdf_threshold_bottom = wi::math::saturate(mid - softness);
font.sdf_threshold_top = wi::math::saturate(mid + softness);
font.bolden = params.bolden;
font.softness = params.softness;
device->BindDynamicConstantBuffer(font, CBSLOT_FONT, cmd);
device->DrawInstanced(4, status.quadCount, 0, 0, cmd);
+1 -1
View File
@@ -48,7 +48,7 @@ namespace wi::font
wi::Color shadowColor; // transparent disables, any other color enables shadow under text
float h_wrap = -1; // wrap start width (-1 default for no wrap) (logical canvas units)
int style = 0; // 0: use default font style, other values can be taken from the wi::font::AddFontStyle() funtion's return value
float softness = 0.1f; // value in [0,1] range (requires SDF rendering to be enabled)
float softness = 0; // value in [0,1] range (requires SDF rendering to be enabled)
float bolden = 0; // value in [0,1] range (requires SDF rendering to be enabled)
float shadow_softness = 0.5f; // value in [0,1] range (requires SDF rendering to be enabled)
float shadow_bolden = 0.1f; // value in [0,1] range (requires SDF rendering to be enabled)
+1 -1
View File
@@ -6965,7 +6965,7 @@ void DrawDebugWorld(
params.color = wi::Color::fromFloat4(x.params.color);
params.h_align = wi::font::WIFALIGN_CENTER;
params.v_align = wi::font::WIFALIGN_CENTER;
params.softness = 0.1f;
params.softness = 0.0f;
params.shadowColor = wi::Color::Black();
params.shadow_softness = 0.8f;
params.customProjection = &VP;
+1 -1
View File
@@ -9,7 +9,7 @@ namespace wi::version
// minor features, major updates, breaking compatibility changes
const int minor = 71;
// minor bug fixes, alterations, refactors, updates
const int revision = 292;
const int revision = 293;
const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision);