diff --git a/WickedEngine/shaders/ShaderInterop_Font.h b/WickedEngine/shaders/ShaderInterop_Font.h index ae9bf2ac2..804dd07a8 100644 --- a/WickedEngine/shaders/ShaderInterop_Font.h +++ b/WickedEngine/shaders/ShaderInterop_Font.h @@ -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; diff --git a/WickedEngine/shaders/fontPS.hlsl b/WickedEngine/shaders/fontPS.hlsl index d76229a89..3d40c35c3 100644 --- a/WickedEngine/shaders/fontPS.hlsl +++ b/WickedEngine/shaders/fontPS.hlsl @@ -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 { diff --git a/WickedEngine/shaders/fontVS.hlsl b/WickedEngine/shaders/fontVS.hlsl index acceee290..545b65034 100644 --- a/WickedEngine/shaders/fontVS.hlsl +++ b/WickedEngine/shaders/fontVS.hlsl @@ -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; } diff --git a/WickedEngine/wiFont.cpp b/WickedEngine/wiFont.cpp index 7783c8928..836ec2037 100644 --- a/WickedEngine/wiFont.cpp +++ b/WickedEngine/wiFont.cpp @@ -95,13 +95,6 @@ namespace wi::font wi::vector data; }; static wi::unordered_map 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); diff --git a/WickedEngine/wiFont.h b/WickedEngine/wiFont.h index 99d807988..66f3d4fe1 100644 --- a/WickedEngine/wiFont.h +++ b/WickedEngine/wiFont.h @@ -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) diff --git a/WickedEngine/wiRenderer.cpp b/WickedEngine/wiRenderer.cpp index 9053c5c3a..03aaa7d89 100644 --- a/WickedEngine/wiRenderer.cpp +++ b/WickedEngine/wiRenderer.cpp @@ -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; diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp index 69b4aed6a..7fe28ae5e 100644 --- a/WickedEngine/wiVersion.cpp +++ b/WickedEngine/wiVersion.cpp @@ -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);