font sharpness computed in screen space (#751)
This commit is contained in:
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user